From 16869f4ffca34a81a47e2c61e8940ee9316471b0 Mon Sep 17 00:00:00 2001 From: Bernardo Vieira Date: Fri, 22 Sep 2023 18:13:16 +0100 Subject: [PATCH 1/3] loan managers by country and countries --- .../src/controllers/v2/microcredit/list.ts | 9 ++- .../api/src/routes/v2/microcredit/list.ts | 18 ++++- packages/core/src/database/db.ts | 2 + ...2170956-create-microcredit-loan-manager.js | 24 +++++++ ...2170957-update-microcredit-loan-manager.js | 52 +++++++++++++++ .../src/database/models/associations/user.ts | 9 ++- packages/core/src/database/models/index.ts | 2 + .../models/microCredit/loanManagers.ts | 46 +++++++++++++ .../src/interfaces/microCredit/loanManager.ts | 10 +++ .../core/src/services/microcredit/list.ts | 66 ++++++------------- 10 files changed, 188 insertions(+), 50 deletions(-) create mode 100644 packages/core/src/database/migrations/z20230922170956-create-microcredit-loan-manager.js create mode 100644 packages/core/src/database/migrations/z20230922170957-update-microcredit-loan-manager.js create mode 100644 packages/core/src/database/models/microCredit/loanManagers.ts create mode 100644 packages/core/src/interfaces/microCredit/loanManager.ts diff --git a/packages/api/src/controllers/v2/microcredit/list.ts b/packages/api/src/controllers/v2/microcredit/list.ts index daf61f377..b4d38a3e2 100644 --- a/packages/api/src/controllers/v2/microcredit/list.ts +++ b/packages/api/src/controllers/v2/microcredit/list.ts @@ -115,7 +115,14 @@ class MicroCreditController { const country = req.params.country as string; this.microCreditService - .getLoanManagersByCountry(country) + .getLoanManagersByCountry(country.toUpperCase()) + .then(r => standardResponse(res, 200, true, r)) + .catch(e => standardResponse(res, 400, false, '', { error: e })); + }; + + getMicroCreditCountries = (_req: RequestWithUser, res: Response) => { + this.microCreditService + .getMicroCreditCountries() .then(r => standardResponse(res, 200, true, r)) .catch(e => standardResponse(res, 400, false, '', { error: e })); }; diff --git a/packages/api/src/routes/v2/microcredit/list.ts b/packages/api/src/routes/v2/microcredit/list.ts index 876e3dbda..e0809ce13 100644 --- a/packages/api/src/routes/v2/microcredit/list.ts +++ b/packages/api/src/routes/v2/microcredit/list.ts @@ -280,10 +280,24 @@ export default (route: Router): void => { * schema: * type: string * required: true - * description: country tag (eg. NG, KE, GH, etc.) + * description: country tag (eg. NG, VE, GH, etc.) * responses: * "200": * description: OK */ - route.get('/managers/:country', cache(cacheIntervals.halfHour), controller.getLoanManagersByCountry); + route.get('/managers/:country', controller.getLoanManagersByCountry); + + /** + * @swagger + * + * /microcredit: + * get: + * tags: + * - "microcredit" + * summary: "Get countries where microcredit is available" + * responses: + * "200": + * description: OK + */ + route.get('/', controller.getMicroCreditCountries); }; diff --git a/packages/core/src/database/db.ts b/packages/core/src/database/db.ts index 748faf71a..6cc777f3d 100644 --- a/packages/core/src/database/db.ts +++ b/packages/core/src/database/db.ts @@ -37,6 +37,7 @@ import { MicroCreditApplicationModel } from './models/microCredit/applications'; import { MicroCreditBorrowersHumaModel } from './models/microCredit/borrowersHuma'; import { MicroCreditBorrowersModel } from './models/microCredit/borrowers'; import { MicroCreditDocsModel } from './models/microCredit/docs'; +import { MicroCreditLoanManagerModel } from './models/microCredit/loanManagers'; import { MicroCreditNoteModel } from './models/microCredit/note'; import { StoryCommentModel } from './models/story/storyComment'; import { StoryCommunityModel } from './models/story/storyCommunity'; @@ -123,6 +124,7 @@ export type DbModels = { microCreditBorrowersHuma: ModelStatic; microCreditNote: ModelStatic; subgraphMicroCreditBorrowers: ModelStatic; + microCreditLoanManager: ModelStatic; // exchangeRegistry: ModelStatic; }; diff --git a/packages/core/src/database/migrations/z20230922170956-create-microcredit-loan-manager.js b/packages/core/src/database/migrations/z20230922170956-create-microcredit-loan-manager.js new file mode 100644 index 000000000..6fe5b28ab --- /dev/null +++ b/packages/core/src/database/migrations/z20230922170956-create-microcredit-loan-manager.js @@ -0,0 +1,24 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('microcredit_loan_manager', { + id: { + type: Sequelize.INTEGER, + autoIncrement: true, + primaryKey: true + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false + }, + country: { + type: Sequelize.STRING, + allowNull: false + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('microcredit_loan_manager'); + } +}; diff --git a/packages/core/src/database/migrations/z20230922170957-update-microcredit-loan-manager.js b/packages/core/src/database/migrations/z20230922170957-update-microcredit-loan-manager.js new file mode 100644 index 000000000..2e0d4fe07 --- /dev/null +++ b/packages/core/src/database/migrations/z20230922170957-update-microcredit-loan-manager.js @@ -0,0 +1,52 @@ +'use strict'; + +// eslint-disable-next-line no-undef +module.exports = { + async up(queryInterface, Sequelize) { + if (process.env.NODE_ENV === 'test') { + return; + } + + if (process.env.API_ENVIRONMENT === 'staging') { + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5857, 'BR')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5855, 'BR')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5898, 'BR')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5855, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5801, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5896, 'UG')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5853, 'NG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5700, 'NG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5893, 'NG')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5853, 'GH')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5857, 'GH')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5801, 'GH')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5891, 'GH')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (5853, 'VE')`); + } else if (process.env.API_ENVIRONMENT === 'production') { + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (106251, 'BR')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (12928, 'BR')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (106251, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (30880, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (99878, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (101542, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (52493, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (47511, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (32522, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (27371, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (107433, 'UG')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (56673, 'UG')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (106251, 'GH')`); + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (108792, 'GH')`); + + await queryInterface.sequelize.query(`insert into microcredit_loan_manager ("userId", country) values (88662, 'VE')`); + } + + }, + down: queryInterface => {} +}; diff --git a/packages/core/src/database/models/associations/user.ts b/packages/core/src/database/models/associations/user.ts index 1dcd69ad9..c5117cd42 100644 --- a/packages/core/src/database/models/associations/user.ts +++ b/packages/core/src/database/models/associations/user.ts @@ -9,7 +9,8 @@ export function userAssociation(sequelize: Sequelize) { microCreditBorrowers, appReferralCode, microCreditNote, - subgraphMicroCreditBorrowers + subgraphMicroCreditBorrowers, + microCreditLoanManager } = sequelize.models as DbModels; appLog.belongsTo(appUser, { @@ -65,4 +66,10 @@ export function userAssociation(sequelize: Sequelize) { sourceKey: 'userId', as: 'loan' }); + + microCreditLoanManager.belongsTo(appUser, { + foreignKey: 'userId', + targetKey: 'id', + as: 'user' + }); } diff --git a/packages/core/src/database/models/index.ts b/packages/core/src/database/models/index.ts index 05477d84f..646455248 100644 --- a/packages/core/src/database/models/index.ts +++ b/packages/core/src/database/models/index.ts @@ -37,6 +37,7 @@ import { initializeMicroCreditApplication } from './microCredit/applications'; import { initializeMicroCreditBorrowers } from './microCredit/borrowers'; import { initializeMicroCreditBorrowersHuma } from './microCredit/borrowersHuma'; import { initializeMicroCreditDocs } from './microCredit/docs'; +import { initializeMicroCreditLoanManager } from './microCredit/loanManagers'; import { initializeMicroCreditNote } from './microCredit/note'; import { initializeStoryComment } from './story/storyComment'; import { initializeStoryCommunity } from './story/storyCommunity'; @@ -137,6 +138,7 @@ export default function initModels(sequelize: Sequelize): void { initializeMicroCreditBorrowersHuma(sequelize); initializeMicroCreditNote(sequelize); initializeSubgraphMicroCreditBorrowers(sequelize); + initializeMicroCreditLoanManager(sequelize); // Exchange initializeExchangeRegistry(sequelize); diff --git a/packages/core/src/database/models/microCredit/loanManagers.ts b/packages/core/src/database/models/microCredit/loanManagers.ts new file mode 100644 index 000000000..fa58551cc --- /dev/null +++ b/packages/core/src/database/models/microCredit/loanManagers.ts @@ -0,0 +1,46 @@ +import { DataTypes, Model, Sequelize } from 'sequelize'; + +import { AppUserModel } from '../app/appUser'; +import { DbModels } from '../../../database/db'; +import { MicroCreditLoanManager, MicroCreditLoanManagerAttributes } from '../../../interfaces/microCredit/loanManager'; + +export class MicroCreditLoanManagerModel extends Model { + public id!: number; + public userId!: number; + public country!: string; + + public readonly user?: AppUserModel; +} + +export function initializeMicroCreditLoanManager(sequelize: Sequelize): typeof MicroCreditLoanManagerModel { + const { appUser } = sequelize.models as DbModels; + MicroCreditLoanManagerModel.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true + }, + userId: { + type: DataTypes.INTEGER, + references: { + model: appUser, + key: 'id' + }, + onDelete: 'CASCADE', + allowNull: false + }, + country: { + type: DataTypes.STRING, + allowNull: false + } + }, + { + tableName: 'microcredit_loan_manager', + modelName: 'microCreditLoanManager', + sequelize, + timestamps: false + } + ); + return MicroCreditLoanManagerModel; +} diff --git a/packages/core/src/interfaces/microCredit/loanManager.ts b/packages/core/src/interfaces/microCredit/loanManager.ts new file mode 100644 index 000000000..2e4ad828d --- /dev/null +++ b/packages/core/src/interfaces/microCredit/loanManager.ts @@ -0,0 +1,10 @@ +export interface MicroCreditLoanManager { + id: number; + userId: number; + country: string; +} + +export interface MicroCreditLoanManagerAttributes { + userId: number; + country: string; +} diff --git a/packages/core/src/services/microcredit/list.ts b/packages/core/src/services/microcredit/list.ts index b8ccc5168..d2c25c223 100644 --- a/packages/core/src/services/microcredit/list.ts +++ b/packages/core/src/services/microcredit/list.ts @@ -1,6 +1,6 @@ import { MicroCreditApplication, MicroCreditApplicationStatus } from '../../interfaces/microCredit/applications'; import { MicroCreditBorrowers } from '../../interfaces/microCredit/borrowers'; -import { Op, Order, WhereOptions, literal } from 'sequelize'; +import { Op, Order, WhereOptions, col, fn, literal } from 'sequelize'; import { config } from '../../..'; import { getAddress } from '@ethersproject/address'; import { @@ -658,54 +658,28 @@ export default class MicroCreditList { }; public getLoanManagersByCountry = async (country: string) => { - let loanManagers: number[] = []; - - // TODO: this is hardcoded for now, but we should have a better way to do this - if (config.jsonRpcUrl.indexOf('alfajores') !== -1) { - switch (country.toLowerCase()) { - case 'br': - loanManagers = [5857, 5855, 5898]; - break; - case 'ug': - loanManagers = [5855, 5801, 5896]; - break; - case 'ng': - loanManagers = [5853, 5700, 5893]; - break; - // case 've': - default: - loanManagers = [5853, 5857, 5801, 5891]; - break; - } - } else { - switch (country.toLowerCase()) { - case 'br': - loanManagers = [106251, 12928]; - break; - case 'ug': - loanManagers = [106251, 30880, 99878, 101542, 52493, 47511, 32522, 27371, 107433, 56673]; - break; - case 'gh': - loanManagers = [106251, 108792]; - break; - case 've': - loanManagers = [88662]; - break; - default: - loanManagers = [106251]; - break; - } - } - - const users = await models.appUser.findAll({ - attributes: ['id', 'address', 'firstName', 'lastName', 'avatarMediaPath'], - where: { - id: { - [Op.in]: loanManagers + const loanManagers = await models.microCreditLoanManager.findAll({ + attributes: [], + include: [ + { + model: models.appUser, + attributes: ['id', 'address', 'firstName', 'lastName', 'avatarMediaPath'], + as: 'user' } + ], + where: { + country } }); - return users.map(u => u.toJSON()); + return loanManagers.map(u => u.user!.toJSON()); + }; + + public getMicroCreditCountries = async () => { + const countries = await models.microCreditLoanManager.findAll({ + attributes: [[fn('DISTINCT', col('country')) ,'country']] + }); + + return countries.map(c => c.country); }; } From 74dc611fe0264126e218a4e1353c8b3d89e9df87 Mon Sep 17 00:00:00 2001 From: Bernardo Vieira Date: Fri, 22 Sep 2023 18:37:05 +0100 Subject: [PATCH 2/3] [skip ci] add cache to endpoints --- packages/api/src/routes/v2/microcredit/list.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api/src/routes/v2/microcredit/list.ts b/packages/api/src/routes/v2/microcredit/list.ts index e0809ce13..ada9e0b3a 100644 --- a/packages/api/src/routes/v2/microcredit/list.ts +++ b/packages/api/src/routes/v2/microcredit/list.ts @@ -285,7 +285,7 @@ export default (route: Router): void => { * "200": * description: OK */ - route.get('/managers/:country', controller.getLoanManagersByCountry); + route.get('/managers/:country', cache(cacheIntervals.oneHour), controller.getLoanManagersByCountry); /** * @swagger @@ -299,5 +299,5 @@ export default (route: Router): void => { * "200": * description: OK */ - route.get('/', controller.getMicroCreditCountries); + route.get('/', cache(cacheIntervals.oneHour), controller.getMicroCreditCountries); }; From a80a58022639985fd80bdd0613b8e00bd169b9d5 Mon Sep 17 00:00:00 2001 From: Bernardo Vieira Date: Fri, 22 Sep 2023 18:37:42 +0100 Subject: [PATCH 3/3] fix ci --- packages/core/src/services/microcredit/list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/services/microcredit/list.ts b/packages/core/src/services/microcredit/list.ts index d2c25c223..7d09727e5 100644 --- a/packages/core/src/services/microcredit/list.ts +++ b/packages/core/src/services/microcredit/list.ts @@ -677,7 +677,7 @@ export default class MicroCreditList { public getMicroCreditCountries = async () => { const countries = await models.microCreditLoanManager.findAll({ - attributes: [[fn('DISTINCT', col('country')) ,'country']] + attributes: [[fn('DISTINCT', col('country')), 'country']] }); return countries.map(c => c.country);