Skip to content

Commit

Permalink
update claim location (v2) (#319)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joao Pedro da Silva authored Jun 20, 2022
1 parent c96f2a1 commit 69417f7
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 3 deletions.
43 changes: 43 additions & 0 deletions packages/api/src/controllers/v2/claimLocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { services } from '@impactmarket/core';
import { Request, Response } from 'express';

import { RequestWithUser } from '../../middlewares/core';
import { standardResponse } from '../../utils/api';

class ClaimLocationController {
private claimLocationService: services.ubi.ClaimLocationServiceV2;
constructor() {
this.claimLocationService = new services.ubi.ClaimLocationServiceV2();
}

getAll = (req: Request, res: Response) => {
this.claimLocationService.getAll()
.then((r) => {
res.send(r);
})
.catch((e) => standardResponse(res, 400, false, '', { error: e }));
};

add = (req: RequestWithUser, res: Response) => {
if (req.user === undefined) {
standardResponse(res, 401, false, '', {
error: {
name: 'USER_NOT_FOUND',
message: 'User not identified!',
},
});
return;
}
const { communityId, gps } = req.body;

this.claimLocationService.add(communityId, gps, req.user.address)
.then(() => {
res.sendStatus(200);
})
.catch((e) => standardResponse(res, 400, false, '', { error: e }));
};
}

export { ClaimLocationController };


10 changes: 10 additions & 0 deletions packages/api/src/controllers/v2/community/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { standardResponse } from '../../../utils/api';

class CommunityController {
private detailsService: services.ubi.CommunityDetailsService;
private claimLocationService: services.ubi.ClaimLocationServiceV2;
constructor() {
this.detailsService = new services.ubi.CommunityDetailsService();
this.claimLocationService = new services.ubi.ClaimLocationServiceV2();
}

getManagers = (req: Request, res: Response) => {
Expand Down Expand Up @@ -163,6 +165,14 @@ class CommunityController {
.catch((e) => standardResponse(res, 400, false, '', { error: e }));
};

getClaimLocation = (req: Request, res: Response) => {
this.claimLocationService.getByCommunity(
parseInt(req.params.id, 10)
)
.then((r) => standardResponse(res, 200, true, r))
.catch((e) => standardResponse(res, 400, false, '', { error: e }));
};

getPresignedUrlMedia = (req: Request, res: Response) => {
this.detailsService.getPresignedUrlMedia(
req.params.mime,
Expand Down
7 changes: 4 additions & 3 deletions packages/api/src/routes/v2/claimLocation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { database } from '@impactmarket/core';
import { Router } from 'express';

import claimLocationController from '../../controllers/claimLocation';
import { ClaimLocationController } from '../../controllers/v2/claimLocation';
import { authenticateToken } from '../../middlewares';
import claimLocationValidators from '../../validators/claimLocation';

export default (app: Router): void => {
const controller = new ClaimLocationController();
const route = Router();
app.use('/claims-location', route);

Expand All @@ -26,7 +27,7 @@ export default (app: Router): void => {
route.get(
'/',
database.cacheWithRedis('1 day', database.cacheOnlySuccess),
claimLocationController.getAll
controller.getAll
);

/**
Expand Down Expand Up @@ -70,6 +71,6 @@ export default (app: Router): void => {
'/',
authenticateToken,
claimLocationValidators.add,
claimLocationController.add
controller.add
);
};
36 changes: 36 additions & 0 deletions packages/api/src/routes/v2/community/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,42 @@ export default (route: Router): void => {
*/
route.get('/:idOrAddress', optionalAuthentication, controller.findBy);

/**
* @swagger
*
* /communities/{id}/claims-location:
* get:
* tags:
* - "communities"
* summary: Get community claims location
* parameters:
* - in: path
* name: id
* schema:
* type: integer
* required: true
* description: community id
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* latitude:
* type: integer
* longitude:
* type: integer
*/
route.get(
'/:id/claims-location',
database.cacheWithRedis('1 day', database.cacheOnlySuccess),
controller.getClaimLocation
);

/**
* @swagger
*
Expand Down
127 changes: 127 additions & 0 deletions packages/core/src/services/ubi/claimLocation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { point, multiPolygon } from '@turf/helpers';
import pointsWithinPolygon from '@turf/points-within-polygon';
import { Op } from 'sequelize';

import config from '../../../config';
import { models } from '../../../database';
import { BeneficiaryAttributes } from '../../../interfaces/ubi/beneficiary';
import { BaseError } from '../../../utils/baseError';
import countryNeighbors from '../../../utils/countryNeighbors.json';
import countriesGeoJSON from '../../../utils/geoCountries.json';
import iso3Countries from '../../../utils/iso3Countries.json';

export default class ClaimLocationService {
public async add(
communityId: string | number,
gps: {
latitude: number;
longitude: number;
},
address: string
): Promise<void> {
try {
const countries = (countriesGeoJSON as any).features;
const community = await models.community.findOne({
attributes: ['country'],
where: { id: communityId },
});
const contries = [community!.country];
contries.push(...countryNeighbors[community!.country].neighbours);

let valid = false;
for (let i = 0; i < contries.length; i++) {
const countryCode = iso3Countries[contries[i]];
const coordinates = countries.find(
(el) => el.properties.ISO_A3 === countryCode
);
const points = point([gps.longitude, gps.latitude]);
const countryCoordinate: [any] =
coordinates.geometry.coordinates;
const searchWithin = multiPolygon(countryCoordinate);

const ptsWithin = pointsWithinPolygon(points, searchWithin);
if (ptsWithin.features.length) {
valid = true;
break;
}
}

if (!valid) {
throw new BaseError(
'INVALID_LOCATION',
'Claim location outside community country'
);
}

const beneficiary: BeneficiaryAttributes | null =
await models.beneficiary.findOne({
attributes: [],
include: [
{
attributes: ['id', 'publicId'],
model: models.community,
as: 'community',
},
],
where: { address },
});

if (!beneficiary || !beneficiary.community) {
throw new BaseError('NOT_BENEFICIARY', 'Not a beneficiary');
}

if (
beneficiary.community.id === communityId ||
beneficiary.community.publicId === communityId
) {
await models.ubiClaimLocation.create({
communityId: beneficiary.community.id,
gps,
});
} else {
throw new BaseError(
'NOT_ALLOWED',
'Beneficiary does not belong to this community'
);
}
} catch (error) {
throw error;
}
}

public async getByCommunity(communityId: number) {
const threeMonthsAgo = new Date();
threeMonthsAgo.setDate(threeMonthsAgo.getDate() - 90);
threeMonthsAgo.setHours(0, 0, 0, 0);

const res = await models.ubiClaimLocation.findAll({
attributes: ['gps'],
where: {
createdAt: { [Op.gte]: threeMonthsAgo },
communityId,
},
});
return res.map((r) => r.gps);
}

public async getAll(): Promise<
{
latitude: number;
longitude: number;
}[]
> {
const fiveMonthsAgo = new Date();
fiveMonthsAgo.setDate(
fiveMonthsAgo.getDate() - config.claimLocationTimeframe
);
return models.ubiClaimLocation.findAll({
attributes: ['gps'],
where: {
createdAt: {
[Op.gte]: fiveMonthsAgo,
},
},
raw: true,
}) as any;
}
}
2 changes: 2 additions & 0 deletions packages/core/src/services/ubi/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BeneficiaryService from './beneficiary';
import ClaimService from './claim';
import ClaimLocationService from './claimLocation';
import ClaimLocationServiceV2 from './claimLocation/index';
import CommunityService from './community';
import { CommunityCreateService } from './community/create';
import { CommunityDetailsService } from './community/details';
Expand All @@ -15,6 +16,7 @@ export {
BeneficiaryService,
ClaimService,
ClaimLocationService,
ClaimLocationServiceV2,
CommunityService,
CommunityContractService,
CommunityDailyMetricsService,
Expand Down

0 comments on commit 69417f7

Please sign in to comment.