Compare commits
5 Commits
philip/ref
...
no-host-mo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9005ab0e3
|
||
|
|
a775c176dd
|
||
|
|
da80ee56cb
|
||
| fda452fccb | |||
| 49308f6efc |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,6 +8,3 @@ gmon.out
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
**/*sqlite
|
|
||||||
**/.nyc_output
|
|
||||||
**/coverage
|
|
||||||
|
|||||||
2
apps/cic-meta/.gitignore
vendored
2
apps/cic-meta/.gitignore
vendored
@@ -3,5 +3,3 @@ dist
|
|||||||
dist-web
|
dist-web
|
||||||
dist-server
|
dist-server
|
||||||
scratch
|
scratch
|
||||||
coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|||||||
@@ -3,38 +3,17 @@
|
|||||||
variables:
|
variables:
|
||||||
APP_NAME: cic-meta
|
APP_NAME: cic-meta
|
||||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||||
IMAGE_TAG: $CI_REGISTRY_IMAGE/$APP_NAME:unittest-$CI_COMMIT_SHORT_SHA
|
|
||||||
|
|
||||||
.cic_meta_changes_target:
|
.cic_meta_changes_target:
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
- changes:
|
||||||
# - changes:
|
- $CONTEXT/$APP_NAME/*
|
||||||
# - $CONTEXT/$APP_NAME/*
|
|
||||||
- when: always
|
|
||||||
|
|
||||||
cic-meta-build-mr:
|
build-mr-cic-meta:
|
||||||
stage: build
|
|
||||||
extends:
|
|
||||||
- .cic_meta_variables
|
|
||||||
- .cic_meta_changes_target
|
|
||||||
script:
|
|
||||||
- mkdir -p /kaniko/.docker
|
|
||||||
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > "/kaniko/.docker/config.json"
|
|
||||||
# - /kaniko/executor --context $CONTEXT --dockerfile $DOCKERFILE_PATH $KANIKO_CACHE_ARGS --destination $IMAGE_TAG
|
|
||||||
- /kaniko/executor --context $CONTEXT --dockerfile $DOCKERFILE_PATH $KANIKO_CACHE_ARGS --destination $IMAGE_TAG
|
|
||||||
|
|
||||||
test-mr-cic-meta:
|
|
||||||
extends:
|
extends:
|
||||||
- .cic_meta_variables
|
|
||||||
- .cic_meta_changes_target
|
- .cic_meta_changes_target
|
||||||
stage: test
|
- .py_build_merge_request
|
||||||
image: $IMAGE_TAG
|
- .cic_meta_variables
|
||||||
script:
|
|
||||||
- cd /tmp/src/cic-meta
|
|
||||||
- npm install --dev
|
|
||||||
- npm run test
|
|
||||||
- npm run test:coverage
|
|
||||||
needs: ["cic-meta-build-mr"]
|
|
||||||
|
|
||||||
build-push-cic-meta:
|
build-push-cic-meta:
|
||||||
extends:
|
extends:
|
||||||
|
|||||||
@@ -4,28 +4,29 @@ WORKDIR /tmp/src/cic-meta
|
|||||||
|
|
||||||
RUN apk add --no-cache postgresql bash
|
RUN apk add --no-cache postgresql bash
|
||||||
|
|
||||||
# required to build the cic-client-meta module
|
COPY cic-meta/package.json \
|
||||||
COPY cic-meta/src/ src/
|
./
|
||||||
COPY cic-meta/scripts/ scripts/
|
|
||||||
|
|
||||||
# copy the dependencies
|
COPY cic-meta/src/ src/
|
||||||
COPY cic-meta/package.json .
|
COPY cic-meta/tests/ tests/
|
||||||
COPY cic-meta/tsconfig.json .
|
COPY cic-meta/scripts/ scripts/
|
||||||
COPY cic-meta/webpack.config.js .
|
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY cic-meta/tests/ tests/
|
# see exports_dir gpg.ini
|
||||||
COPY cic-meta/tests/*.asc /root/pgp/
|
COPY cic-meta/tests/*.asc /root/pgp/
|
||||||
|
RUN alias tsc=node_modules/typescript/bin/tsc
|
||||||
|
|
||||||
|
|
||||||
# copy runtime configs
|
|
||||||
COPY cic-meta/.config/ /usr/local/etc/cic-meta/
|
COPY cic-meta/.config/ /usr/local/etc/cic-meta/
|
||||||
|
# COPY cic-meta/scripts/server/initdb/server.postgres.sql /usr/local/share/cic-meta/sql/server.sql
|
||||||
|
|
||||||
# db migrations
|
|
||||||
COPY cic-meta/docker/db.sh ./db.sh
|
COPY cic-meta/docker/db.sh ./db.sh
|
||||||
RUN chmod 755 ./db.sh
|
RUN chmod 755 ./db.sh
|
||||||
|
|
||||||
RUN alias tsc=node_modules/typescript/bin/tsc
|
#RUN alias ts-node=/tmp/src/cic-meta/node_modules/ts-node/dist/bin.js
|
||||||
|
#ENTRYPOINT [ "./node_modules/ts-node/dist/bin.js", "./scripts/server/server.ts" ]
|
||||||
|
|
||||||
COPY cic-meta/docker/start_server.sh ./start_server.sh
|
COPY cic-meta/docker/start_server.sh ./start_server.sh
|
||||||
RUN chmod 755 ./start_server.sh
|
RUN chmod 755 ./start_server.sh
|
||||||
ENTRYPOINT ["sh", "./start_server.sh"]
|
ENTRYPOINT ["sh", "./start_server.sh"]
|
||||||
|
|||||||
2362
apps/cic-meta/package-lock.json
generated
2362
apps/cic-meta/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,6 @@
|
|||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha -r node_modules/node-localstorage/register -r ts-node/register tests/*.ts",
|
"test": "mocha -r node_modules/node-localstorage/register -r ts-node/register tests/*.ts",
|
||||||
"test:coverage": "nyc mocha tests/*.ts --timeout 3000 --check-coverage=true",
|
|
||||||
"build": "node_modules/typescript/bin/tsc -d --outDir dist src/index.ts",
|
"build": "node_modules/typescript/bin/tsc -d --outDir dist src/index.ts",
|
||||||
"build-server": "tsc -d --outDir dist-server scripts/server/*.ts",
|
"build-server": "tsc -d --outDir dist-server scripts/server/*.ts",
|
||||||
"pack": "node_modules/typescript/bin/tsc -d --outDir dist && webpack",
|
"pack": "node_modules/typescript/bin/tsc -d --outDir dist && webpack",
|
||||||
@@ -35,9 +34,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^8.0.3",
|
"@types/mocha": "^8.0.3",
|
||||||
"mocha": "^8.2.0",
|
"mocha": "^8.2.0",
|
||||||
"nock": "^13.1.0",
|
|
||||||
"node-localstorage": "^2.1.6",
|
"node-localstorage": "^2.1.6",
|
||||||
"nyc": "^15.1.0",
|
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
"typescript": "^4.0.5",
|
"typescript": "^4.0.5",
|
||||||
"webpack": "^5.4.0",
|
"webpack": "^5.4.0",
|
||||||
@@ -53,26 +50,5 @@
|
|||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.16.1"
|
"node": ">=14.16.1"
|
||||||
},
|
|
||||||
"nyc": {
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts"
|
|
||||||
],
|
|
||||||
"extension": [
|
|
||||||
".ts"
|
|
||||||
],
|
|
||||||
"require": [
|
|
||||||
"ts-node/register"
|
|
||||||
],
|
|
||||||
"reporter": [
|
|
||||||
"text",
|
|
||||||
"html"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"instrument": true,
|
|
||||||
"branches": ">80",
|
|
||||||
"lines": ">80",
|
|
||||||
"functions": ">80",
|
|
||||||
"statements": ">80"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ async function processRequest(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (content === undefined) {
|
if (content === undefined) {
|
||||||
console.error('empty content', data);
|
console.error('empty onctent', data);
|
||||||
res.writeHead(400, {"Content-Type": "text/plain"});
|
res.writeHead(400, {"Content-Type": "text/plain"});
|
||||||
res.end();
|
res.end();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Custom extends Syncable implements Addressable {
|
|||||||
super('', v);
|
super('', v);
|
||||||
Custom.toKey(name).then((cid) => {
|
Custom.toKey(name).then((cid) => {
|
||||||
this.id = cid;
|
this.id = cid;
|
||||||
this.name = name;
|
this.value = v;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,15 +100,13 @@ class Meta {
|
|||||||
identifier = await User.toKey(name);
|
identifier = await User.toKey(name);
|
||||||
} else if (type === 'phone') {
|
} else if (type === 'phone') {
|
||||||
identifier = await Phone.toKey(name);
|
identifier = await Phone.toKey(name);
|
||||||
} else if (type === 'custom') {
|
|
||||||
identifier = await Custom.toKey(name);
|
|
||||||
} else {
|
} else {
|
||||||
identifier = await Custom.toKey(name, type);
|
identifier = await Custom.toKey(name);
|
||||||
}
|
}
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap(syncable: Syncable): Promise<Envelope> {
|
private wrap(syncable: Syncable): Promise<Envelope> {
|
||||||
return new Promise<Envelope>(async (resolve, reject) => {
|
return new Promise<Envelope>(async (resolve, reject) => {
|
||||||
syncable.setSigner(this.signer);
|
syncable.setSigner(this.signer);
|
||||||
syncable.onwrap = async (env) => {
|
syncable.onwrap = async (env) => {
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
import {Custom} from "../src";
|
|
||||||
|
|
||||||
const testName = 'areas';
|
|
||||||
const testObject = {
|
|
||||||
area: ['Nairobi', 'Mombasa', 'Kilifi']
|
|
||||||
}
|
|
||||||
const testNameKey = '8f3da0c90ba2b89ff217da96f6088cbaf987a1b58bc33c3a5e526e53cec7cfed';
|
|
||||||
const testIdentifier = ':cic.area'
|
|
||||||
const testIdentifierKey = 'da6194e6f33726546e82c328df4c120b844d6427859156518bd600765bf8b2b7';
|
|
||||||
|
|
||||||
describe('custom', () => {
|
|
||||||
|
|
||||||
context('with predefined data', () => {
|
|
||||||
it('should create a custom object', () => {
|
|
||||||
const custom = new Custom(testName, testObject);
|
|
||||||
setTimeout(() => {
|
|
||||||
assert.strictEqual(custom.name, testName);
|
|
||||||
assert.deepStrictEqual(custom.m.data, testObject);
|
|
||||||
assert.strictEqual(custom.key(), testNameKey)
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('without predefined data', () => {
|
|
||||||
it('should create a custom object', () => {
|
|
||||||
const custom = new Custom(testName);
|
|
||||||
setTimeout(() => {
|
|
||||||
assert.strictEqual(custom.name, testName);
|
|
||||||
assert.deepStrictEqual(custom.m.data, {});
|
|
||||||
assert.strictEqual(custom.key(), testNameKey)
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#toKey()', () => {
|
|
||||||
context('without a custom identifier', () => {
|
|
||||||
it('should generate a key from the custom name', async () => {
|
|
||||||
assert.strictEqual(await Custom.toKey(testName), testNameKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with a custom identifier', () => {
|
|
||||||
it('should generate a key from the custom name with a custom identifier', async () => {
|
|
||||||
assert.strictEqual(await Custom.toKey(testName, testIdentifier), testIdentifierKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
const nock = require('nock');
|
|
||||||
import {Meta} from "../src";
|
|
||||||
import {getResponse, metaData, networkErrorResponse, notFoundResponse, putResponse} from "./response";
|
|
||||||
import {Syncable} from "@cicnet/crdt-meta";
|
|
||||||
|
|
||||||
const metaUrl = 'https://meta.dev.grassrootseconomics.net';
|
|
||||||
const testAddress = '0xc1912fee45d61c87cc5ea59dae31190fffff232d';
|
|
||||||
const testAddressKey = 'a51472cb4df63b199a4de01335b1b4d1bbee27ff4f03340aa1d592f26c6acfe2';
|
|
||||||
const testPhone = '+254123456789';
|
|
||||||
const testPhoneKey = 'be3cc8212b7eb57c6217ddd42230bd8ccd2f01382bf8c1c77d3a683fa5a9bb16';
|
|
||||||
const testName = 'areas'
|
|
||||||
const testNameKey = '8f3da0c90ba2b89ff217da96f6088cbaf987a1b58bc33c3a5e526e53cec7cfed';
|
|
||||||
const testIdentifier = ':cic.area'
|
|
||||||
const testIdentifierKey = 'da6194e6f33726546e82c328df4c120b844d6427859156518bd600765bf8b2b7';
|
|
||||||
|
|
||||||
function readFile(filename) {
|
|
||||||
if(!fs.existsSync(filename)) {
|
|
||||||
console.error(`File ${filename} not found`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return fs.readFileSync(filename, {encoding: 'utf8', flag: 'r'});
|
|
||||||
}
|
|
||||||
|
|
||||||
const privateKey = readFile('./privatekeys.asc');
|
|
||||||
|
|
||||||
describe('meta', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
nock(metaUrl)
|
|
||||||
.get(`/${testAddressKey}`)
|
|
||||||
.reply(200, getResponse);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.get(`/${testPhoneKey}`)
|
|
||||||
.reply(200, getResponse);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.get(`/${testAddress}`)
|
|
||||||
.reply(404);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.get(`/${testIdentifier}`)
|
|
||||||
.replyWithError(networkErrorResponse);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.put(`/${testAddressKey}`)
|
|
||||||
.reply(200, putResponse);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.put(`/${testAddress}`)
|
|
||||||
.reply(404);
|
|
||||||
|
|
||||||
nock(metaUrl)
|
|
||||||
.post('/post')
|
|
||||||
.reply(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#get()', () => {
|
|
||||||
it('should fetch data from the meta service', async () => {
|
|
||||||
const account = await Meta.get(testAddressKey, metaUrl);
|
|
||||||
assert.strictEqual(account.toJSON(account), getResponse.payload);
|
|
||||||
});
|
|
||||||
|
|
||||||
context('if item is not found', () => {
|
|
||||||
it('should respond with an error', async () => {
|
|
||||||
const account = await Meta.get(testAddress, metaUrl);
|
|
||||||
assert.strictEqual(account, `404: Not Found`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('in case of network error', () => {
|
|
||||||
it('should respond with an error', async () => {
|
|
||||||
const account = await Meta.get(testIdentifier, metaUrl);
|
|
||||||
assert.strictEqual(account, `Request to ${metaUrl}/${testIdentifier} failed. Connection error.`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#set()', () => {
|
|
||||||
context('object data', () => {
|
|
||||||
it('should set data to the meta server', () => {
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.set(testAddressKey, metaData);
|
|
||||||
assert.strictEqual(response, `${putResponse.status}: ${putResponse.statusText}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('string data', () => {
|
|
||||||
it('should set data to the meta server', () => {
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.set(testPhoneKey, testAddress);
|
|
||||||
assert.strictEqual(response, `${putResponse.status}: ${putResponse.statusText}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('in case of network error', () => {
|
|
||||||
it('should respond with an error', () => {
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.set(testIdentifier, metaData);
|
|
||||||
assert.strictEqual(response, `Request to ${metaUrl}/${testIdentifier} failed. Connection error.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#updateMeta()', () => {
|
|
||||||
it('should update data in the meta server', async () => {
|
|
||||||
const syncable = new Syncable(testAddressKey, metaData);
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.updateMeta(syncable, testAddressKey);
|
|
||||||
assert.strictEqual(response, putResponse);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
context('if item is not found', () => {
|
|
||||||
it('should respond with an error', () => {
|
|
||||||
const syncable = new Syncable(testAddress, metaData);
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.updateMeta(syncable, testAddress);
|
|
||||||
assert.strictEqual(response, notFoundResponse);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#wrap()', () => {
|
|
||||||
it('should sign a syncable object', function () {
|
|
||||||
const syncable = new Syncable(testAddressKey, metaData);
|
|
||||||
const meta = new Meta(metaUrl, privateKey);
|
|
||||||
meta.onload = async (status) => {
|
|
||||||
const response = await meta.wrap(syncable);
|
|
||||||
assert.strictEqual(response.toJSON(), getResponse);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#getIdentifier()', () => {
|
|
||||||
context('without type', () => {
|
|
||||||
it('should return an identifier', async () => {
|
|
||||||
assert.strictEqual(await Meta.getIdentifier(testName), testNameKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with user type', () => {
|
|
||||||
it('should return an identifier', async () => {
|
|
||||||
assert.strictEqual(await Meta.getIdentifier(testAddress, 'user'), testAddressKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with phone type', () => {
|
|
||||||
it('should return an identifier', async () => {
|
|
||||||
assert.strictEqual(await Meta.getIdentifier(testPhone, 'phone'), testPhoneKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with custom type', () => {
|
|
||||||
it('should return an identifier', async () => {
|
|
||||||
assert.strictEqual(await Meta.getIdentifier(testName, 'custom'), testNameKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with unrecognised type', () => {
|
|
||||||
it('should return an identifier', async () => {
|
|
||||||
assert.strictEqual(await Meta.getIdentifier(testName, testIdentifier), testIdentifierKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
import {Phone} from "../src";
|
|
||||||
|
|
||||||
const testAddress = '0xc1912fee45d61c87cc5ea59dae31190fffff232d';
|
|
||||||
const testPhone = '+254123456789';
|
|
||||||
const testPhoneKey = 'be3cc8212b7eb57c6217ddd42230bd8ccd2f01382bf8c1c77d3a683fa5a9bb16';
|
|
||||||
|
|
||||||
describe('phone', () => {
|
|
||||||
|
|
||||||
it('should create a phone object', () => {
|
|
||||||
const phone = new Phone(testAddress, testPhone);
|
|
||||||
setTimeout(() => {
|
|
||||||
assert.strictEqual(phone.address, testAddress);
|
|
||||||
assert.strictEqual(phone.m.data.msisdn, testPhone);
|
|
||||||
assert.strictEqual(phone.key(), testPhoneKey)
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#toKey()', () => {
|
|
||||||
it('should generate a key from the phone number', async () => {
|
|
||||||
assert.strictEqual(await Phone.toKey(testPhone), testPhoneKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,54 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
|
|
||||||
import { User } from "../src";
|
|
||||||
|
|
||||||
const testAddress = '0xc1912fee45d61c87cc5ea59dae31190fffff232d';
|
|
||||||
const testAddressKey = 'a51472cb4df63b199a4de01335b1b4d1bbee27ff4f03340aa1d592f26c6acfe2';
|
|
||||||
const testUser = {
|
|
||||||
user: {
|
|
||||||
firstName: 'Test',
|
|
||||||
lastName: 'User'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('user', () => {
|
|
||||||
|
|
||||||
context('without predefined data', () => {
|
|
||||||
it('should create a user object', () => {
|
|
||||||
const user = new User(testAddress);
|
|
||||||
setTimeout(() => {
|
|
||||||
assert.strictEqual(user.address, testAddress);
|
|
||||||
assert.strictEqual(user.key(), testAddressKey);
|
|
||||||
assert.strictEqual(user.m.data.user.firstName, '');
|
|
||||||
assert.strictEqual(user.m.data.user.lastName, '');
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('with predefined data', () => {
|
|
||||||
it('should create a user object', () => {
|
|
||||||
const user = new User(testAddress, testUser);
|
|
||||||
setTimeout(() => {
|
|
||||||
assert.strictEqual(user.address, testAddress);
|
|
||||||
assert.strictEqual(user.key(), testAddressKey);
|
|
||||||
assert.strictEqual(user.m.data.user.firstName, testUser.user.firstName);
|
|
||||||
assert.strictEqual(user.m.data.user.lastName, testUser.user.lastName);
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#setName()', () => {
|
|
||||||
it('should set user\'s names to metadata', () => {
|
|
||||||
const user = new User(testAddress);
|
|
||||||
user.setName(testUser.user.firstName, testUser.user.lastName);
|
|
||||||
assert.strictEqual(user.m.data.user.firstName, testUser.user.firstName);
|
|
||||||
assert.strictEqual(user.m.data.user.lastName, testUser.user.lastName);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#toKey()', () => {
|
|
||||||
it('should generate a key from the user\'s address', async () => {
|
|
||||||
assert.strictEqual(await User.toKey(testAddress), testAddressKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"outDir": "./dist.browser",
|
"outDir": "./dist.browser",
|
||||||
"target": "es2015",
|
"target": "es5",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"lib": ["es2016", "dom", "es5"],
|
"lib": ["es2016", "dom", "es5"],
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ LOCALE_PATH=/usr/src/cic-ussd/var/lib/locale/
|
|||||||
MAX_BODY_LENGTH=1024
|
MAX_BODY_LENGTH=1024
|
||||||
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
|
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
|
||||||
SERVICE_CODE=*483*46#,*483*061#,*384*96#
|
SERVICE_CODE=*483*46#,*483*061#,*384*96#
|
||||||
SUPPORT_PHONE_NUMBER=0757628885
|
|
||||||
|
|
||||||
[phone_number]
|
[phone_number]
|
||||||
REGION=KE
|
REGION=KE
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ LOCALE_PATH=var/lib/locale/
|
|||||||
MAX_BODY_LENGTH=1024
|
MAX_BODY_LENGTH=1024
|
||||||
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
|
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
|
||||||
SERVICE_CODE=*483*46#
|
SERVICE_CODE=*483*46#
|
||||||
SUPPORT_PHONE_NUMBER=0757628885
|
|
||||||
|
|
||||||
[ussd]
|
[ussd]
|
||||||
MENU_FILE=/usr/local/lib/python3.8/site-packages/cic_ussd/db/ussd_menu.json
|
MENU_FILE=/usr/local/lib/python3.8/site-packages/cic_ussd/db/ussd_menu.json
|
||||||
|
|||||||
@@ -41,7 +41,3 @@ def get_user_by_phone_number(phone_number: str) -> Optional[Account]:
|
|||||||
phone_number = process_phone_number(phone_number=phone_number, region='KE')
|
phone_number = process_phone_number(phone_number=phone_number, region='KE')
|
||||||
user = Account.session.query(Account).filter_by(phone_number=phone_number).first()
|
user = Account.session.query(Account).filter_by(phone_number=phone_number).first()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class Support:
|
|
||||||
phone_number = None
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from cic_ussd.db.models.ussd_session import UssdSession
|
|||||||
from cic_ussd.error import MetadataNotFoundError, SeppukuError
|
from cic_ussd.error import MetadataNotFoundError, SeppukuError
|
||||||
from cic_ussd.menu.ussd_menu import UssdMenu
|
from cic_ussd.menu.ussd_menu import UssdMenu
|
||||||
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
||||||
from cic_ussd.phone_number import get_user_by_phone_number, Support
|
from cic_ussd.phone_number import get_user_by_phone_number
|
||||||
from cic_ussd.redis import cache_data, create_cached_data_key, get_cached_data
|
from cic_ussd.redis import cache_data, create_cached_data_key, get_cached_data
|
||||||
from cic_ussd.state_machine import UssdStateMachine
|
from cic_ussd.state_machine import UssdStateMachine
|
||||||
from cic_ussd.conversions import to_wei, from_wei
|
from cic_ussd.conversions import to_wei, from_wei
|
||||||
@@ -270,24 +270,7 @@ def process_display_user_metadata(user: Account, display_key: str):
|
|||||||
products=products
|
products=products
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# TODO [Philip]: All these translations could be moved to translation files.
|
raise MetadataNotFoundError(f'Expected person metadata but found none in cache for key: {key}')
|
||||||
logg.warning(f'Expected person metadata but found none in cache for key: {key}')
|
|
||||||
|
|
||||||
absent = ''
|
|
||||||
if user.preferred_language == 'en':
|
|
||||||
absent = 'Not provided'
|
|
||||||
elif user.preferred_language == 'sw':
|
|
||||||
absent = 'Haijawekwa'
|
|
||||||
|
|
||||||
return translation_for(
|
|
||||||
key=display_key,
|
|
||||||
preferred_language=user.preferred_language,
|
|
||||||
full_name=absent,
|
|
||||||
gender=absent,
|
|
||||||
location=absent,
|
|
||||||
products=absent
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def process_account_statement(user: Account, display_key: str, ussd_session: dict):
|
def process_account_statement(user: Account, display_key: str, ussd_session: dict):
|
||||||
@@ -484,14 +467,6 @@ def next_state(ussd_session: dict, user: Account, user_input: str) -> str:
|
|||||||
return new_state
|
return new_state
|
||||||
|
|
||||||
|
|
||||||
def process_exit_invalid_menu_option(display_key: str, preferred_language: str):
|
|
||||||
return translation_for(
|
|
||||||
key=display_key,
|
|
||||||
preferred_language=preferred_language,
|
|
||||||
support_phone=Support.phone_number
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def custom_display_text(
|
def custom_display_text(
|
||||||
display_key: str,
|
display_key: str,
|
||||||
menu_name: str,
|
menu_name: str,
|
||||||
@@ -528,7 +503,5 @@ def custom_display_text(
|
|||||||
return process_account_statement(display_key=display_key, user=user, ussd_session=ussd_session)
|
return process_account_statement(display_key=display_key, user=user, ussd_session=ussd_session)
|
||||||
elif menu_name == 'display_user_metadata':
|
elif menu_name == 'display_user_metadata':
|
||||||
return process_display_user_metadata(display_key=display_key, user=user)
|
return process_display_user_metadata(display_key=display_key, user=user)
|
||||||
elif menu_name == 'exit_invalid_menu_option':
|
|
||||||
return process_exit_invalid_menu_option(display_key=display_key, preferred_language=user.preferred_language)
|
|
||||||
else:
|
else:
|
||||||
return translation_for(key=display_key, preferred_language=user.preferred_language)
|
return translation_for(key=display_key, preferred_language=user.preferred_language)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from cic_ussd.metadata.base import Metadata
|
|||||||
from cic_ussd.operations import (define_response_with_content,
|
from cic_ussd.operations import (define_response_with_content,
|
||||||
process_menu_interaction_requests,
|
process_menu_interaction_requests,
|
||||||
define_multilingual_responses)
|
define_multilingual_responses)
|
||||||
from cic_ussd.phone_number import process_phone_number, Support
|
from cic_ussd.phone_number import process_phone_number
|
||||||
from cic_ussd.processor import get_default_token_data
|
from cic_ussd.processor import get_default_token_data
|
||||||
from cic_ussd.redis import cache_data, create_cached_data_key, InMemoryStore
|
from cic_ussd.redis import cache_data, create_cached_data_key, InMemoryStore
|
||||||
from cic_ussd.requests import (get_request_endpoint,
|
from cic_ussd.requests import (get_request_endpoint,
|
||||||
@@ -126,8 +126,6 @@ else:
|
|||||||
|
|
||||||
valid_service_codes = config.get('APP_SERVICE_CODE').split(",")
|
valid_service_codes = config.get('APP_SERVICE_CODE').split(",")
|
||||||
|
|
||||||
Support.phone_number = config.get('APP_SUPPORT_PHONE_NUMBER')
|
|
||||||
|
|
||||||
|
|
||||||
def application(env, start_response):
|
def application(env, start_response):
|
||||||
"""Loads python code for application to be accessible over web server
|
"""Loads python code for application to be accessible over web server
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from cic_ussd.balance import BalanceManager, compute_operational_balance
|
|||||||
from cic_ussd.chain import Chain
|
from cic_ussd.chain import Chain
|
||||||
from cic_ussd.db.models.account import AccountStatus, Account
|
from cic_ussd.db.models.account import AccountStatus, Account
|
||||||
from cic_ussd.operations import save_to_in_memory_ussd_session_data
|
from cic_ussd.operations import save_to_in_memory_ussd_session_data
|
||||||
from cic_ussd.phone_number import get_user_by_phone_number, process_phone_number
|
from cic_ussd.phone_number import get_user_by_phone_number
|
||||||
from cic_ussd.processor import retrieve_token_symbol
|
from cic_ussd.processor import retrieve_token_symbol
|
||||||
from cic_ussd.redis import create_cached_data_key, get_cached_data
|
from cic_ussd.redis import create_cached_data_key, get_cached_data
|
||||||
from cic_ussd.transactions import OutgoingTransactionProcessor
|
from cic_ussd.transactions import OutgoingTransactionProcessor
|
||||||
@@ -30,7 +30,7 @@ def is_valid_recipient(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
|||||||
"""
|
"""
|
||||||
user_input, ussd_session, user = state_machine_data
|
user_input, ussd_session, user = state_machine_data
|
||||||
recipient = get_user_by_phone_number(phone_number=user_input)
|
recipient = get_user_by_phone_number(phone_number=user_input)
|
||||||
is_not_initiator = process_phone_number(user_input, 'KE') != user.phone_number
|
is_not_initiator = user_input != user.phone_number
|
||||||
has_active_account_status = user.get_account_status() == AccountStatus.ACTIVE.name
|
has_active_account_status = user.get_account_status() == AccountStatus.ACTIVE.name
|
||||||
return is_not_initiator and has_active_account_status and recipient is not None
|
return is_not_initiator and has_active_account_status and recipient is not None
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cic_base[full_graph]~=0.1.2b15
|
cic_base[full_graph]~=0.1.2b14
|
||||||
cic-eth~=0.11.0b16
|
cic-eth~=0.11.0b15
|
||||||
cic-notify~=0.4.0a5
|
cic-notify~=0.4.0a5
|
||||||
cic-types~=0.1.0a10
|
cic-types~=0.1.0a10
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
# INTEGRATION TESTING
|
|
||||||
|
|
||||||
This folder contains integration tests.
|
|
||||||
|
|
||||||
## OVERVIEW
|
|
||||||
|
|
||||||
There are four files defining the integration tests.
|
|
||||||
|
|
||||||
* **test_account_creation**: Tests account sign up process.
|
|
||||||
* **test_transactions**: Tests transactions between two accounts.
|
|
||||||
* **test_profile_management**: Tests that account metadata can be edited.
|
|
||||||
* **test_account_management**: Tests that account management functionalities are intact.
|
|
||||||
|
|
||||||
## REQUIREMENTS
|
|
||||||
|
|
||||||
In order to run the transaction tests, please ensure that the faucet amount is set to a non-zero value, ideally `50000000`
|
|
||||||
which is the value set in the config file `.config/test/integration.ini`.
|
|
||||||
|
|
||||||
This implies setting the `DEV_FAUCET_AMOUNT` to a non-zero value before bringing up the contract-migration image:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
export DEV_FAUCET_AMOUNT=50000000
|
|
||||||
RUN_MASK=1 docker-compose up contract-migration
|
|
||||||
RUN_MASK=2 docker-compose up contract-migration
|
|
||||||
```
|
|
||||||
@@ -214,13 +214,12 @@ stages:
|
|||||||
status_code:
|
status_code:
|
||||||
- 200
|
- 200
|
||||||
headers:
|
headers:
|
||||||
Content-Length: '51'
|
Content-Length: '28'
|
||||||
Content-Type: "text/plain"
|
Content-Type: "text/plain"
|
||||||
verify_response_with:
|
verify_response_with:
|
||||||
function: ext.validator:validate_response
|
function: ext.validator:validate_response
|
||||||
extra_kwargs:
|
extra_kwargs:
|
||||||
expected_response: "CON Balance {gift_value} {token_symbol}\n1. Send\n2. My Account\n3. Help"
|
expected_response: "CON Enter first name\n0. Back"
|
||||||
delay_before: 10
|
|
||||||
|
|
||||||
- name: Pin number confirmation [{second_account_pin_number} - second account]
|
- name: Pin number confirmation [{second_account_pin_number} - second account]
|
||||||
request:
|
request:
|
||||||
@@ -233,6 +232,227 @@ stages:
|
|||||||
headers:
|
headers:
|
||||||
content-type: "application/x-www-form-urlencoded"
|
content-type: "application/x-www-form-urlencoded"
|
||||||
method: POST
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '37'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Weka jina lako la kwanza\n0. Nyuma"
|
||||||
|
|
||||||
|
- name: Enter first name [first_account_given_name - first account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{first_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{first_account_phone_number}"
|
||||||
|
text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '29'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Enter family name\n0. Back"
|
||||||
|
|
||||||
|
- name: Enter first name [second_account_given_name - second account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{second_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{second_account_phone_number}"
|
||||||
|
text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '37'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Weka jina lako la mwisho\n0. Nyuma"
|
||||||
|
|
||||||
|
- name: Enter last name [first_account_family_name - first account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{first_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{first_account_phone_number}"
|
||||||
|
text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '51'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Enter gender\n1. Male\n2. Female\n3. Other\n0. Back"
|
||||||
|
|
||||||
|
- name: Enter last name [second_account_family_name - second account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{second_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{second_account_phone_number}"
|
||||||
|
text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '64'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Weka jinsia yako\n1. Mwanaume\n2. Mwanamke\n3. Nyngine\n0. Nyuma"
|
||||||
|
|
||||||
|
- name: Select gender [Male - first account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{first_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{first_account_phone_number}"
|
||||||
|
text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '31'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Enter your location\n0. Back"
|
||||||
|
|
||||||
|
- name: Select gender [Female - second account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{second_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{second_account_phone_number}"
|
||||||
|
text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '27'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Weka eneo lako\n0. Nyuma"
|
||||||
|
|
||||||
|
- name: Enter location [first_account_location - first account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{first_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{first_account_phone_number}"
|
||||||
|
text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1*{first_account_location}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '55'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Please enter a product or service you offer\n0. Back"
|
||||||
|
|
||||||
|
- name: Enter location [second_account_location - second account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{second_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{second_account_phone_number}"
|
||||||
|
text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2*{second_account_location}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '42'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Weka bidhaa ama huduma unauza\n0. Nyuma"
|
||||||
|
|
||||||
|
- name: Enter product [first_account_product - first account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{first_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{first_account_phone_number}"
|
||||||
|
text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1*{first_account_location}*{first_account_product}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
|
response:
|
||||||
|
status_code:
|
||||||
|
- 200
|
||||||
|
headers:
|
||||||
|
Content-Length: '51'
|
||||||
|
Content-Type: "text/plain"
|
||||||
|
verify_response_with:
|
||||||
|
function: ext.validator:validate_response
|
||||||
|
extra_kwargs:
|
||||||
|
expected_response: "CON Balance {gift_value} {token_symbol}\n1. Send\n2. My Account\n3. Help"
|
||||||
|
delay_before: 10
|
||||||
|
|
||||||
|
- name: Enter product [second_account_product - second account]
|
||||||
|
request:
|
||||||
|
url: "{server_url}"
|
||||||
|
data:
|
||||||
|
serviceCode: "*483*46#"
|
||||||
|
sessionId: "{second_metadata_entry_session_id}"
|
||||||
|
phoneNumber: "{second_account_phone_number}"
|
||||||
|
text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2*{second_account_location}*{second_account_product}"
|
||||||
|
headers:
|
||||||
|
content-type: "application/x-www-form-urlencoded"
|
||||||
|
method: POST
|
||||||
response:
|
response:
|
||||||
status_code:
|
status_code:
|
||||||
- 200
|
- 200
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -170,7 +170,7 @@ stages:
|
|||||||
verify_response_with:
|
verify_response_with:
|
||||||
function: ext.validator:validate_response
|
function: ext.validator:validate_response
|
||||||
extra_kwargs:
|
extra_kwargs:
|
||||||
expected_response: "CON {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_phone_number}.\nPlease enter your PIN to confirm.\n0. Back"
|
expected_response: "CON {second_account_given_name} {second_account_family_name} {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_given_name} {first_account_family_name} {first_account_phone_number}.\nPlease enter your PIN to confirm.\n0. Back"
|
||||||
|
|
||||||
- name: Enter transcation amount [second account]
|
- name: Enter transcation amount [second account]
|
||||||
request:
|
request:
|
||||||
@@ -191,7 +191,7 @@ stages:
|
|||||||
verify_response_with:
|
verify_response_with:
|
||||||
function: ext.validator:validate_response
|
function: ext.validator:validate_response
|
||||||
extra_kwargs:
|
extra_kwargs:
|
||||||
expected_response: "CON {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_phone_number}.\nTafadhali weka nambari yako ya siri kudhibitisha.\n0. Nyuma"
|
expected_response: "CON {first_account_given_name} {first_account_family_name} {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_given_name} {second_account_family_name} {second_account_phone_number}.\nTafadhali weka nambari yako ya siri kudhibitisha.\n0. Nyuma"
|
||||||
|
|
||||||
- name: Pin to authorize transaction [first account]
|
- name: Pin to authorize transaction [first account]
|
||||||
request:
|
request:
|
||||||
@@ -212,7 +212,7 @@ stages:
|
|||||||
verify_response_with:
|
verify_response_with:
|
||||||
function: ext.validator:validate_response
|
function: ext.validator:validate_response
|
||||||
extra_kwargs:
|
extra_kwargs:
|
||||||
expected_response: "CON Your request has been sent. {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_phone_number}.\n00. Back\n99. Exit"
|
expected_response: "CON Your request has been sent. {second_account_given_name} {second_account_family_name} {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_given_name} {first_account_family_name} {first_account_phone_number}.\n00. Back\n99. Exit"
|
||||||
|
|
||||||
- name: Pin to authorize transaction [second account]
|
- name: Pin to authorize transaction [second account]
|
||||||
request:
|
request:
|
||||||
@@ -233,7 +233,7 @@ stages:
|
|||||||
verify_response_with:
|
verify_response_with:
|
||||||
function: ext.validator:validate_response
|
function: ext.validator:validate_response
|
||||||
extra_kwargs:
|
extra_kwargs:
|
||||||
expected_response: "CON Ombi lako limetumwa. {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_phone_number}.\n00. Nyuma\n99. Ondoka"
|
expected_response: "CON Ombi lako limetumwa. {first_account_given_name} {first_account_family_name} {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_given_name} {second_account_family_name} {second_account_phone_number}.\n00. Nyuma\n99. Ondoka"
|
||||||
|
|
||||||
- name: Verify balance changes [first account]
|
- name: Verify balance changes [first account]
|
||||||
delay_before: 10
|
delay_before: 10
|
||||||
|
|||||||
@@ -36,12 +36,26 @@
|
|||||||
"source": "initial_pin_entry",
|
"source": "initial_pin_entry",
|
||||||
"dest": "exit_invalid_pin"
|
"dest": "exit_invalid_pin"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"trigger": "scan_data",
|
||||||
|
"source": "initial_pin_confirmation",
|
||||||
|
"dest": "start",
|
||||||
|
"conditions": [
|
||||||
|
"cic_ussd.state_machine.logic.pin.pins_match",
|
||||||
|
"cic_ussd.state_machine.logic.validator.has_cached_user_metadata"
|
||||||
|
],
|
||||||
|
"after": [
|
||||||
|
"cic_ussd.state_machine.logic.pin.complete_pin_change",
|
||||||
|
"cic_ussd.state_machine.logic.user.get_user_metadata",
|
||||||
|
"cic_ussd.state_machine.logic.user.update_account_status_to_active"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"trigger": "scan_data",
|
"trigger": "scan_data",
|
||||||
"source": "initial_pin_confirmation",
|
"source": "initial_pin_confirmation",
|
||||||
"unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata",
|
"unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata",
|
||||||
"conditions": "cic_ussd.state_machine.logic.pin.pins_match",
|
"conditions": "cic_ussd.state_machine.logic.pin.pins_match",
|
||||||
"dest": "start",
|
"dest": "enter_given_name",
|
||||||
"after": [
|
"after": [
|
||||||
"cic_ussd.state_machine.logic.pin.complete_pin_change",
|
"cic_ussd.state_machine.logic.pin.complete_pin_change",
|
||||||
"cic_ussd.state_machine.logic.user.update_account_status_to_active"
|
"cic_ussd.state_machine.logic.user.update_account_status_to_active"
|
||||||
|
|||||||
@@ -51,13 +51,19 @@ ENV PATH $NVM_DIR/versions/node//v$NODE_VERSION/bin:$PATH
|
|||||||
# WORKDIR /home/grassroots
|
# WORKDIR /home/grassroots
|
||||||
# USER grassroots
|
# USER grassroots
|
||||||
|
|
||||||
COPY contract-migration/requirements.txt .
|
|
||||||
|
|
||||||
ARG pip_extra_args=""
|
ARG pip_extra_args=""
|
||||||
ARG pip_index_url=https://pypi.org/simple
|
ARG pip_index_url=https://pypi.org/simple
|
||||||
ARG pip_extra_index_url=https://pip.grassrootseconomics.net:8433
|
ARG pip_extra_index_url=https://pip.grassrootseconomics.net:8433
|
||||||
RUN pip install --index-url https://pypi.org/simple \
|
ARG cic_base_version=0.1.2b15
|
||||||
--extra-index-url $pip_extra_index_url -r requirements.txt
|
ARG cic_eth_version=0.11.0b16
|
||||||
|
ARG sarafu_token_version=0.0.1a8
|
||||||
|
ARG sarafu_faucet_version=0.0.3a3
|
||||||
|
RUN pip install --index-url https://pypi.org/simple --extra-index-url $pip_extra_index_url \
|
||||||
|
cic-base[full_graph]==$cic_base_version \
|
||||||
|
cic-eth==$cic_eth_version \
|
||||||
|
sarafu-faucet==$sarafu_faucet_version \
|
||||||
|
sarafu-token==$sarafu_token_version \
|
||||||
|
cic-eth==$cic_eth_version
|
||||||
|
|
||||||
# -------------- begin runtime container ----------------
|
# -------------- begin runtime container ----------------
|
||||||
FROM python:3.8.6-slim-buster as runtime-image
|
FROM python:3.8.6-slim-buster as runtime-image
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
cic-base[full_graph]==0.1.2b15
|
|
||||||
sarafu-faucet==0.0.3a3
|
|
||||||
sarafu-token==0.0.1a8
|
|
||||||
cic-eth==0.11.0b16
|
|
||||||
@@ -47,7 +47,7 @@ EOF
|
|||||||
|
|
||||||
>&2 echo "create account for gas gifter"
|
>&2 echo "create account for gas gifter"
|
||||||
old_gas_provider=$DEV_ETH_ACCOUNT_GAS_PROVIDER
|
old_gas_provider=$DEV_ETH_ACCOUNT_GAS_PROVIDER
|
||||||
DEV_ETH_ACCOUNT_GAS_GIFTER=`cic-eth-create --timeout 120 $debug --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
|
DEV_ETH_ACCOUNT_GAS_GIFTER=`cic-eth-create $debug --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
|
||||||
echo DEV_ETH_ACCOUNT_GAS_GIFTER=$DEV_ETH_ACCOUNT_GAS_GIFTER >> $env_out_file
|
echo DEV_ETH_ACCOUNT_GAS_GIFTER=$DEV_ETH_ACCOUNT_GAS_GIFTER >> $env_out_file
|
||||||
cic-eth-tag -i $CIC_CHAIN_SPEC GAS_GIFTER $DEV_ETH_ACCOUNT_GAS_GIFTER
|
cic-eth-tag -i $CIC_CHAIN_SPEC GAS_GIFTER $DEV_ETH_ACCOUNT_GAS_GIFTER
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,4 @@ Should exit with code 0 if all input data is found in the respective services.
|
|||||||
|
|
||||||
- Running the balance script should be _optional_ in all cases, but is currently required in the case of `cic_ussd` because it is needed to generate the metadata. An improvement would be moving the task to `import_users.py`, for a different queue than the balance tx handler.
|
- Running the balance script should be _optional_ in all cases, but is currently required in the case of `cic_ussd` because it is needed to generate the metadata. An improvement would be moving the task to `import_users.py`, for a different queue than the balance tx handler.
|
||||||
|
|
||||||
- MacOS BigSur issue when installing psycopg2: ld: library not found for -lssl -> https://github.com/psycopg/psycopg2/issues/1115#issuecomment-831498953
|
|
||||||
|
|
||||||
- `cic_ussd` imports is poorly implemented, and consumes a lot of resources. Therefore it takes a long time to complete. Reducing the amount of polls for the phone pointer would go a long way to improve it.
|
- `cic_ussd` imports is poorly implemented, and consumes a lot of resources. Therefore it takes a long time to complete. Reducing the amount of polls for the phone pointer would go a long way to improve it.
|
||||||
|
|||||||
Reference in New Issue
Block a user