diff --git a/.gitignore b/.gitignore
index 03a24d8d..c81546b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,3 +121,8 @@ dist
# package-lock (main is yarn.lock)
package-lock.json
+
+# Arquivo de configuração de backup remoto
+rclone.conf
+
+miaajuda.pem
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3f4d9d3b..ae034ee4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,6 +20,7 @@ build:
IMAGE_NAME: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
before_script:
- cat $FIREBASE_CONFIG > ./src/config/firebaseAuthConfig.js
+ - cat $RCLONE_CONFIG > ./config/rclone.conf
script:
- echo "Building image"
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
@@ -40,6 +41,7 @@ build stable:
IMAGE_NAME: "$CI_REGISTRY_IMAGE:stable"
before_script:
- cat $FIREBASE_CONFIG > ./src/config/firebaseAuthConfig.js
+ - cat $RCLONE_CONFIG > ./config/rclone.conf
script:
- echo "Building image"
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..e939734f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,101 @@
+# Guia de Contribuição :smile:
+
+Bem vindo ao Mia Ajuda!
+
+Adoramos quando novas pessoas contribuem com o projeto. Queremos que a sua contribuição para o Mia Ajuda se torne a mais simples possível. Todas as ajudas ao projeto são bem vindas, seja:
+
+* Reportando _bugs_ encontrados;
+* Enviando correção de _bugs_;
+* Propondo novas soluções para o projeto, seja: Visual, Arquitetural ou de Negócio;
+* Propondo novas funcionalidades;
+* Implementado novas funcionalidades previstas em _issues_ nos nossos repositórios.
+
+Caso queira conhecer melhor nosso projeto, acesse o nosso [site](https://miaajuda.netlify.app/), nosso [Instagram](https://www.instagram.com/miaajuda/) ou a nossa [Organização no Github](https://github.com/mia-ajuda).
+
+Para entrar em contato conosco, além de abrir uma _issue_ aqui no Github, você pode nos enviar um email, para: miaajudadev@gmail.com
+
+## Como Iniciar a sua Contribuição ao Mia Ajuda
+
+Muito Obrigado pelo interesse em contribuir para o Projeto.
+
+Para iniciar a sua jornada, você pode estar contribuindo para o projeto abrindo _issues_ em nosso repositório de documentação [repositório](https://github.com/mia-ajuda/Documentation/issues), seguindo o nosso [template](https://github.com/mia-ajuda/Documentation/tree/master/.github/ISSUE_TEMPLATE). Essas _issues_ podem ser abertas reportando possíveis _bugs_ ou sugerindo novas funcionalidades para o projeto.
+
+Caso você queira contribuir para o código do Mia Ajuda, basta seguir os próximos passos:
+
+* Busque a _issue_ na qual você se identifica, se marque e comente nessa _issue_. Atenção: Certifique-se antes, de que a _issue_ não está sendo resolvida por alguém, antes;
+* Faça um _fork_ dos nossos repositórios, se você for um contribuidor externo;
+* Crie uma _branch_ a partir da develop, seguindo nossas políticas de _branch_ abaixo;
+* Crie um _Pull Request_ com o status _WIP_, no repositório para nos certificarmos que você está trabalhando na sua _issue_;
+* Ao gerar _commits_, siga a nossa política de _commits_;
+* Ao concluir o desenvolvimento da _issue_, troque o status do seu _Pull Request_ de _WIP_ para _Solve_, seguindo o nosso [template de Pull Request](https://github.com/mia-ajuda/Backend/blob/develop/.github/pull_request_template.md);
+* Após um revisor aprovar o seu _Pull Request_, mescle-o com a a _branch_ base, seguindo a política do [_Squash Rebase_](https://docs.github.com/pt/github/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-pull-request-commits);
+
+## _Workflow_ de Trabalho
+
+Todo o nosso _workflow_ de trabalho é inteiramente baseado no [_GitFlow_](https://www.atlassian.com/br/git/tutorials/comparing-workflows/gitflow-workflow).
+
+## Politicas de _Branches_
+
+As _branches_ são dividas em camadas de desenvolvimento, baseado do modelo do [_GitFlow_](https://www.atlassian.com/br/git/tutorials/comparing-workflows/gitflow-workflow), sendo a `main` a camada que contém a aplicação em sua versão estável, a `develop` a versão de estado em desenvolvimento. Para a criação de `feature` _branches_ utilize a `develop` como base.
+
+O formato para os nomes das _feature_ _branches_ será composto por:
+
+US + NUMERO_DA_US + FUNCIONALIDADE.
+
+Exemplo:
+```
+US13-Creation_of_a_new_screen
+```
+
+Para _hotfix branches_, o formato do nome da _branch_ se dará pela seguinte forma:
+
+HOTFIX + NOME_DA_FIX
+
+Exemplo:
+```
+hotfix_login_bug
+```
+
+### Mantendo as _branches_ atualizadas
+
+Mantenha as suas _branches_ atualizadas com a _branch_ base. Utilize o comando _rebase_ para isso.
+
+Exemplo:
+
+```
+> git pull --rebase origin develop
+```
+
+## Política de _Commits_
+
+Os nossos _commits_ possuem um [_lint_](https://github.com/legend80s/commit-msg-linter#readme), sendo obrigatório seguir esse padrão:
+
+```
+tipo do commit: descrição concisa e em inglês do commit
+```
+
+Exemplo:
+
+```
+git commit -m "feat: create login button"
+```
+
+As nossas regras são:
+
+* _Commits_ devem ser redigidos em idioma inglês;
+* Devem seguir as regras do [_lint_](https://github.com/legend80s/commit-msg-linter#readme);
+* Devem ser simples e concisos, possuindo títulos curtos;
+* Devem iniciar com verbo no infinitivo informando o objetivo.
+
+### _Commits_ em equipes
+
+Caso mais de uma pessoa tenha trabalhado com você no _commit_, utilize do _Co-authored-by_, na descrição do _commit_.
+
+Exemplo:
+
+```
+fix: fix contacts modal
+
+
+Co-authored-by: Link
+```
diff --git a/README.md b/README.md
index 5311b2c2..a4eb1ffa 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,15 @@
-
-
-
-
+
+
+
+
## Rode o Backend com Docker
+
### Dependências
Inicialmente, instale localmente as seguintes dependências:
@@ -52,9 +53,13 @@ LONGITUDE_ENV=
SENTRY_DSN=
NODE_ENV=development
DATABASE_URL=mongodb://mongo/miaAjudaDB
+MONGODB_USERNAME=
+MONGODB_PASSWORD=
```
-* O preenchimento do serviço de monitoramento de erros ([Sentry](https://sentry.io/)) é opcional. A latitude e a longitude serão utilizadas para popular exemplos de pedido de ajuda próximos a essa coordenada.
+* O preenchimento do serviço de monitoramento de erros ([Sentry](https://sentry.io/)) é opcional.
+* A latitude e a longitude serão utilizadas para popular exemplos de pedido de ajuda próximos a essa coordenada.
+* As variáveis de ambiente `MONGODB_USERNAME` e `MONGODB_PASSWORD` destinam-se ao acesso da base de dados com autenticação. Ver detalhes de configuração de backup abaixo.
### Inicialização do Projeto
@@ -72,3 +77,25 @@ sudo docker-compose -f docker-compose.yml up --build
2. Na raiz do projeto, verifique a corretude do código com `eslint . --ext .js`; ou
3. Configure uma extensão no seu editor de texto preferido (exemplo: [VSCode - ESLINT](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint));
4. Abra o seu editor de texto na raiz do projeto `/Backend` e comece a desenvolver.
+
+### Backup da Base de Dados
+
+A aplicação realiza backups da base "miaAjudaDB" regularmente às 04h da manhã. O serviço guarda um total de 14 backups locais e sempre salva o backup no Google Drive. Para isso ser possível, proceda com as instruções:
+
+#### Configuração do Backup
+
+1. Preencha adequadamente as variáveis de ambiente do tópico "Arquivos de Configuração";
+2. Salve na pasta `/Backend/config/` o arquivo `rclone.conf`;
+3. Em produção, inicie os serviços de backend, banco e backup com:
+
+```sh
+sudo docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
+```
+
+#### Restauração do Backup
+
+1. Para realizar a restauração de um backup, proceda com o comando:
+
+```sh
+mongorestore --gzip --archive=backup-scheduler-1594607580.gz --drop
+```
diff --git a/config/backup-scheduler.yaml b/config/backup-scheduler.yaml
new file mode 100644
index 00000000..80f06998
--- /dev/null
+++ b/config/backup-scheduler.yaml
@@ -0,0 +1,24 @@
+scheduler:
+ # run every day at 4:00 UTC-3
+ cron: "0 7 */1 * *"
+ # number of backups to keep locally
+ retention: 14
+ # backup operation timeout in minutes
+ timeout: 60
+target:
+ # mongod IP or host name
+ host: "mongo"
+ # mongodb port
+ port: 27017
+ # mongodb database name, leave blank to backup all databases
+ database: "miaAjudaDB"
+ # leave blank if auth is not enabled
+ username: ${MONGODB_USERNAME}
+ password: ${MONGODB_PASSWORD}
+ # add custom params to mongodump (eg. Auth or SSL support), leave blank if not needed
+ params: "--authenticationDatabase admin" # "--ssl"
+rclone:
+ bucket: "MiaAjuda-Rclone"
+ # See https://rclone.org/docs/ for details on how to configure rclone
+ configFilePath: /config/rclone.conf
+ configSection: "MiaAjuda-Rclone"
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
new file mode 100644
index 00000000..da9e7594
--- /dev/null
+++ b/docker-compose.prod.yml
@@ -0,0 +1,16 @@
+version: "3"
+services:
+ mgob:
+ container_name: mgob
+ environment:
+ - MONGODB_USERNAME=${MONGODB_USERNAME}
+ - MONGODB_PASSWORD=${MONGODB_PASSWORD}
+ image: stefanprodan/mgob:edge
+ command: ./mgob -LogLevel=info
+ volumes:
+ - ./config:/config
+ - /mgob/storage:/storage
+ - /mgob/tmp:/tmp
+ - /mgob/data:/data
+ depends_on:
+ - mongo
diff --git a/package.json b/package.json
index a3fc6866..d32d3dbb 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
},
"dependencies": {
"@sentry/node": "5.18.0",
- "bcrypt": "^4.0.1",
+ "bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"cpf-cnpj-validator": "^1.0.1",
@@ -20,11 +20,11 @@
"express": "^4.17.1",
"faker": "^4.1.0",
"firebase-admin": "^8.10.0",
- "lodash": "^4.17.19",
+ "lodash": "^4.17.21",
"mongodb": "^3.5.9",
"mongoose": "^5.9.6",
"node-schedule": "^1.3.2",
- "socket.io": "^2.3.0",
+ "socket.io": "^2.4.0",
"swagger-ui-express": "^4.1.4",
"yamljs": "^0.3.0"
},
@@ -32,6 +32,7 @@
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-plugin-import": "^2.20.2",
+ "git-commit-msg-linter": "^3.2.6",
"nodemon": "^2.0.2"
}
}
diff --git a/src/config/database.js b/src/config/database.js
index 9afd0b35..04f9fc63 100644
--- a/src/config/database.js
+++ b/src/config/database.js
@@ -9,12 +9,9 @@ const envType = process.env.NODE_ENV || 'development';
const databaseConnect = async () => {
try {
- await mongoose.connect(databaseURL, { useNewUrlParser: true, useUnifiedTopology: true })
- .then(() => console.log('Banco de dados conectado!'))
- .catch((err) => {
- console.log('Não foi possível se conectar ao banco de dados!');
- console.log(err);
- });
+ await mongoose.connect(databaseURL, { useNewUrlParser: true, useUnifiedTopology: true });
+ console.log('Banco de dados conectado!');
+ mongoose.set('useFindAndModify', false);
await CategorySeed();
// só popula usuários e ajudas falsos em desenvolvimento
diff --git a/src/controllers/CampaignController.js b/src/controllers/CampaignController.js
new file mode 100644
index 00000000..8bba2160
--- /dev/null
+++ b/src/controllers/CampaignController.js
@@ -0,0 +1,141 @@
+const CampaignService = require('../services/CampaignService');
+const saveError = require('../utils/ErrorHistory');
+
+class CampaignController {
+ constructor() {
+ this.CampaignService = new CampaignService();
+ }
+
+ async createCampaign(req, res) {
+ try {
+ const newCampaign = await this.CampaignService.createNewCampaign(
+ req.body,
+ );
+ return res.json(newCampaign);
+ } catch (error) {
+ return res.status(400).json({ error: error.message });
+ }
+ }
+
+ async listCampaign(req, res) {
+ try {
+ const campaign = await this.CampaignService.listCampaign();
+ return res.json(campaign);
+ } catch (error) {
+ return res.status(400).json(error);
+ }
+ }
+
+ async getCampaignListByStatus(req, res, next) {
+ const { userId } = req.params;
+
+ const statusList = req.query.statusList.split(',');
+
+ try {
+ const result = await this.CampaignService.getCampaignListByStatus({
+ userId,
+ statusList,
+ });
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async listCampaignByOwnerId(req, res) {
+ const { ownerId } = req.params;
+ try {
+ const campaign = await this.CampaignService.listCampaignByOwnerId(
+ ownerId,
+ );
+ return res.json(campaign);
+ } catch (error) {
+ return res.status(400).json(error);
+ }
+ }
+
+ async deleteCampaignLogic(req, res, next) {
+ const { id } = req.params;
+ try {
+ const result = await this.CampaignService.deleteCampaign(id);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async listCampaignNear(req, res, next) {
+ const except = !!req.query['id.except'];
+ const helper = !!req.query['id.helper'];
+ let temp = null;
+ if (except) {
+ temp = 'except';
+ } else if (helper) {
+ temp = 'helper';
+ }
+
+ const id = temp ? req.query[`id.${temp}`] : req.query.id;
+ const categoryArray = req.query.categoryId
+ ? req.query.categoryId.split(',')
+ : null;
+
+ const near = !!req.query.near;
+ const coords = near
+ ? req.query.coords.split(',').map((coord) => Number(coord))
+ : null;
+
+ try {
+ let result;
+ if (near) {
+ result = await this.CampaignService.getNearCampaignList(
+ coords,
+ except,
+ id,
+ categoryArray,
+ );
+ }
+ res.status(200);
+ res.json(result);
+ next();
+ } catch (err) {
+ console.log(err);
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async finishCampaign(req, res, next) {
+ const { id } = req.params;
+ try {
+ const result = await this.CampaignService.finishCampaign(id);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async getCampaignById(req, res, next) {
+ const { id } = req.params;
+ try {
+ const result = await this.CampaignService.getCampaignById(id);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+}
+
+module.exports = CampaignController;
diff --git a/src/controllers/EntityController.js b/src/controllers/EntityController.js
new file mode 100644
index 00000000..19bab5cc
--- /dev/null
+++ b/src/controllers/EntityController.js
@@ -0,0 +1,143 @@
+const EntityService = require('../services/EntityService');
+const saveError = require('../utils/ErrorHistory');
+
+class EntityController {
+ constructor() {
+ this.entityService = new EntityService();
+ }
+
+ async createEntity(req, res, next) {
+ const { latitude, longitude } = req.body;
+
+ const location = {
+ type: 'Point',
+ coordinates: [longitude, latitude],
+ };
+
+ const data = {
+ location,
+ ...req.body,
+ hasEntity: req.query.hasEntity === 'true',
+ };
+
+ try {
+ const result = await this.entityService.createEntity(data);
+ res.status(201).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async editEntityById(req, res, next) {
+ const data = {
+ email: req.decodedToken.email,
+ photo: req.body.photo,
+ name: req.body.name,
+ phone: req.body.phone,
+ notificationToken: req.body.notificationToken,
+ deviceId: req.body.deviceId,
+ };
+ try {
+ const result = await this.entityService.editEntityById(data);
+ res.status(200).json(result);
+ return next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ return next();
+ }
+ }
+
+ async editEntityAddressById(req, res, next) {
+ const data = {
+ email: req.decodedToken.email,
+ cep: req.body.cep,
+ number: req.body.number,
+ city: req.body.city,
+ state: req.body.state,
+ complement: req.body.complement,
+ };
+
+ try {
+ const result = await this.entityService.editEntityAddressById(data);
+ res.status(200).json(result);
+ return next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ return next();
+ }
+ }
+
+ async deleteEntityLogic(req, res, next) {
+ const { email } = req.decodedToken;
+
+ try {
+ const result = await this.entityService.deleteEntityLogically(email);
+ res.status(200).json(result);
+ return next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ return next();
+ }
+ }
+
+ async getEntityById(req, res, next) {
+ const data = {
+ id: req.params.id,
+ email: req.decodedToken.email,
+ };
+
+ try {
+ const result = await this.entityService.getEntity(data);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(404).json({ error: err.message });
+ next();
+ }
+ }
+
+ async updateEntityLocationById(req, res, next) {
+ const data = {
+ email: req.decodedToken.email,
+ latitude: req.body.latitude,
+ longitude: req.body.longitude,
+ };
+
+ try {
+ const result = await this.entityService.updateEntityLocationById(data);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
+ async checkEntityExistence(req, res, next) {
+ let { entityIdentifier } = req.params;
+
+ if (!entityIdentifier) {
+ entityIdentifier = req.decodedToken.email;
+ }
+
+ try {
+ const result = await this.entityService.checkEntityExistence(entityIdentifier);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(404).json({ error: err.message });
+ next();
+ }
+ }
+}
+
+module.exports = EntityController;
diff --git a/src/controllers/HelpController.js b/src/controllers/HelpController.js
index c33ae77a..310b5737 100644
--- a/src/controllers/HelpController.js
+++ b/src/controllers/HelpController.js
@@ -14,21 +14,22 @@ class HelpController {
};
try {
- const result = await this.HelpService.createHelp(data);
- res.status(201).json(result);
+ await this.HelpService.createHelp(data);
+ res.status(201).send();
next();
} catch (err) {
+ console.log(err);
saveError(err);
res.status(400).send({ error: err.message });
next();
}
}
- async getHelpById(req, res, next) {
+ async getHelpWithAggregationById(req, res, next) {
const { id } = req.params;
try {
- const result = await this.HelpService.getHelpByid(id);
+ const result = await this.HelpService.getHelpWithAggregationById(id);
res.status(200).json(result);
next();
} catch (err) {
@@ -39,36 +40,19 @@ class HelpController {
}
async getHelpList(req, res, next) {
- const except = !!req.query['id.except'];
- const helper = !!req.query['id.helper'];
- const temp = except ? 'except' : helper ? 'helper' : null;
- const id = temp ? req.query[`id.${temp}`] : req.query.id;
- const status = req.query.status || null;
+ const { id } = req.query;
+ const isUserEntity = global.isUserEntity;
+ const coords = req.query.coords.split(',').map((coord) => Number(coord));
const categoryArray = req.query.categoryId ? req.query.categoryId.split(',') : null;
/* A requisição do Query é feita com o formato "34312ID12312,12312ID13213",
sendo que não é aceito o formato "34312ID12312, 12312ID13213" com espaço */
-
- const near = !!req.query.near;
- const coords = near ? req.query.coords.split(',').map((coord) => Number(coord)) : null;
-
try {
- let result;
- if (near) {
- result = await this.HelpService.getNearHelpList(
- coords,
- except,
- id,
- categoryArray,
- );
- } else {
- result = await this.HelpService.getHelpList(
- id,
- status,
- except,
- helper,
- categoryArray,
- );
- }
+ const result = await this.HelpService.getHelpList(
+ coords,
+ id,
+ isUserEntity,
+ categoryArray,
+ );
res.status(200);
res.json(result);
next();
@@ -106,8 +90,8 @@ class HelpController {
const { id } = req.params;
try {
- const result = await this.HelpService.deleteHelpLogically(id);
- res.status(200).json(result);
+ await this.HelpService.deleteHelpLogically(id);
+ res.status(204).send();
next();
} catch (err) {
saveError(err);
@@ -120,8 +104,8 @@ class HelpController {
const data = { ...req.params };
try {
- const result = await this.HelpService.helperConfirmation(data);
- res.status(200).json(result);
+ await this.HelpService.helperConfirmation(data);
+ res.status(204).send();
next();
} catch (err) {
saveError(err);
@@ -134,8 +118,8 @@ class HelpController {
const data = { ...req.params };
try {
- const result = await this.HelpService.ownerConfirmation(data);
- res.status(200).json(result);
+ await this.HelpService.ownerConfirmation(data);
+ res.status(204).send();
next();
} catch (err) {
saveError(err);
@@ -163,7 +147,7 @@ class HelpController {
try {
await this.HelpService.addPossibleHelpers(id, idHelper);
- res.status(204).json();
+ res.status(204).send();
next();
} catch (err) {
saveError(err);
@@ -184,6 +168,20 @@ class HelpController {
next();
}
}
+
+ async getHelpInfoById(req, res, next) {
+ try {
+ const { helpId } = req.params;
+ const result = await this.HelpService.getHelpInfoById(helpId);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
+
}
module.exports = HelpController;
diff --git a/src/controllers/HelpOfferController.js b/src/controllers/HelpOfferController.js
new file mode 100644
index 00000000..b87df59d
--- /dev/null
+++ b/src/controllers/HelpOfferController.js
@@ -0,0 +1,92 @@
+const HelpOfferService = require("../services/HelpOfferService");
+const saveError = require("../utils/ErrorHistory");
+
+class OfferedHelpController {
+ constructor() {
+ this.HelpOfferService = new HelpOfferService();
+ }
+
+ async createHelpOffer(req, res) {
+ try {
+ const newHelpOffer = await this.HelpOfferService.createNewHelpOffer(
+ req.body
+ );
+ return res.json(newHelpOffer);
+ } catch (error) {
+ return res.status(400).json({ error: error.message });
+ }
+ }
+
+ async getHelpWithAggregationById(req, res, next) {
+ const { id } = req.params;
+
+ try {
+ const result = await this.HelpOfferService.getHelpOfferWithAggregationById(id);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(400).send({ error: err.message });
+ next();
+ }
+ }
+
+ async listHelpsOffers(req, res) {
+ const userId = req.query.userId;
+ const getOtherUsers = req.query.getOtherUsers == 'true' ? true : false;
+ const isUserEntity = global.isUserEntity;
+ try {
+ const helpOffers = await this.HelpOfferService.listHelpsOffers(userId, isUserEntity, null, getOtherUsers);
+ return res.json(helpOffers);
+ } catch (error) {
+ return res.status(400).json({ error: error.message });
+ }
+ }
+
+ async listHelpOffersByHelpedUserId(req, res) {
+ const { helpedUserId } = req.params;
+ try {
+ const helpOffers = await this.HelpOfferService.listHelpOffersByHelpedUserId(
+ helpedUserId
+ );
+ return res.json(helpOffers);
+ } catch (error) {
+ return res.status(400).json(error);
+ }
+ }
+
+ async addPossibleHelpedUsers(req, res) {
+ const { helpedId, helpOfferId } = req.params;
+ try {
+ await this.HelpOfferService.addPossibleHelpedUsers(helpedId, helpOfferId);
+ return res.status(204).json();
+ } catch (error) {
+ return res.status(400).json({ error: error.message });
+ }
+ }
+
+ async chooseHelpedUsers(req, res) {
+ const { helpedId, helpOfferId } = req.params;
+ try {
+ await this.HelpOfferService.addHelpedUsers(helpedId, helpOfferId);
+ return res.status(204).json();
+ } catch (error) {
+ return res.status(400).json({ error: error.message });
+ }
+ }
+
+ async finishHelpOfferByOwner(req, res) {
+ const { helpOfferId } = req.params;
+ const { email } = req.decodedToken;
+
+ try {
+ await this.HelpOfferService.finishHelpOfferByOwner(helpOfferId, email);
+ return res.status(204).json();
+ } catch (error) {
+ saveError(error);
+ return res.status(400).send({ error: error.message });
+ }
+ }
+}
+
+module.exports = OfferedHelpController;
diff --git a/src/controllers/NotificationController.js b/src/controllers/NotificationController.js
index 3ab67641..cd7bb479 100644
--- a/src/controllers/NotificationController.js
+++ b/src/controllers/NotificationController.js
@@ -19,6 +19,18 @@ class NotificationController {
next();
}
}
+
+ async sendNotifications(req, res, next) {
+ const { title, body } = req.body;
+ try {
+ const result = await this.notificationService.createAndSendNotifications(title, body);
+ res.status(200).json(result);
+ } catch (err) {
+ saveError(err);
+ res.status(400).json({ error: err.message });
+ next();
+ }
+ }
}
module.exports = NotificationController;
diff --git a/src/controllers/UserController.js b/src/controllers/UserController.js
index 19c95816..eeb40ad8 100644
--- a/src/controllers/UserController.js
+++ b/src/controllers/UserController.js
@@ -1,6 +1,6 @@
-const UserService = require('../services/UserService');
-const { riskGroups } = require('../models/RiskGroup');
-const saveError = require('../utils/ErrorHistory');
+const UserService = require("../services/UserService");
+const { riskGroups } = require("../models/RiskGroup");
+const saveError = require("../utils/ErrorHistory");
class UserController {
constructor() {
@@ -11,14 +11,14 @@ class UserController {
const { latitude, longitude } = req.body;
const location = {
- type: 'Point',
+ type: "Point",
coordinates: [longitude, latitude],
};
const data = {
location,
...req.body,
- hasUser: req.query.hasUser === 'true',
+ hasUser: req.query.hasUser === "true",
};
try {
@@ -92,7 +92,6 @@ class UserController {
id: req.params.id,
email: req.decodedToken.email,
};
-
try {
const result = await this.userService.getUser(data);
res.status(200).json(result);
@@ -104,6 +103,21 @@ class UserController {
}
}
+ async getAnyUserById(req, res, next) {
+ const data = {
+ id: req.params.id,
+ };
+ try {
+ const result = await this.userService.getAnyUser(data);
+ res.status(200).json(result);
+ next();
+ } catch (err) {
+ saveError(err);
+ res.status(404).json({ error: err.message });
+ next();
+ }
+ }
+
async updateUserLocationById(req, res, next) {
const data = {
email: req.decodedToken.email,
@@ -123,10 +137,14 @@ class UserController {
}
async checkUserExistence(req, res, next) {
- const { value } = req.params;
+ let { userIdentifier } = req.params;
+
+ if (!userIdentifier) {
+ userIdentifier = req.decodedToken.email;
+ }
try {
- const result = await this.userService.checkUserExistence(value);
+ const result = await this.userService.checkUserExistence(userIdentifier);
res.status(200).json(result);
next();
} catch (err) {
diff --git a/src/models/Campaign.js b/src/models/Campaign.js
new file mode 100644
index 00000000..5081fb6c
--- /dev/null
+++ b/src/models/Campaign.js
@@ -0,0 +1,91 @@
+const mongoose = require('mongoose');
+const helpStatusEnum = require('../utils/enums/helpStatusEnum');
+const {
+ getDistance,
+ calculateDistance,
+} = require('../utils/geolocation/calculateDistance');
+
+const campaignSchema = new mongoose.Schema({
+ title: {
+ type: String,
+ required: true,
+ },
+ description: {
+ type: String,
+ maxlength: 500,
+ required: true,
+ },
+ status: {
+ type: String,
+ enum: Object.values(helpStatusEnum),
+ default: helpStatusEnum.WAITING,
+ },
+ categoryId: {
+ type: [mongoose.Schema.Types.ObjectId],
+ ref: 'Category',
+ },
+ ownerId: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'User',
+ required: true,
+ },
+ helperId: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'User',
+ required: false,
+ },
+ creationDate: {
+ type: Date,
+ default: Date.now,
+ },
+ finishedDate: {
+ type: Date,
+ required: false,
+ },
+ active: {
+ default: true,
+ type: Boolean,
+ },
+},
+ {
+ collection: 'campaign',
+ toObject: {
+ virtuals: true,
+ },
+ toJSON: {
+ virtuals: true,
+ },
+ });
+
+campaignSchema.virtual('categories', {
+ ref: 'Category',
+ localField: 'categoryId',
+ foreignField: '_id',
+});
+campaignSchema.virtual('entity', {
+ ref: 'Entity',
+ localField: 'ownerId',
+ foreignField: '_id',
+ justOne: true,
+});
+
+campaignSchema.virtual('distances')
+ .set(({ campaignCoords, coords }) => {
+ campaignCoords = {
+ longitude: campaignCoords[0],
+ latitude: campaignCoords[1],
+ };
+ const coordinates = {
+ longitude: coords[0],
+ latitude: coords[1],
+ };
+ this.distanceValue = calculateDistance(coordinates, campaignCoords);
+ this.distance = getDistance(coordinates, campaignCoords);
+ })
+
+campaignSchema.virtual('distanceValue')
+ .get(() => this.distanceValue);
+campaignSchema.virtual('distance')
+ .get(() => this.distance);
+
+module.exports = mongoose.model('Campaign', campaignSchema);
diff --git a/src/models/Entity.js b/src/models/Entity.js
new file mode 100644
index 00000000..bc802ff2
--- /dev/null
+++ b/src/models/Entity.js
@@ -0,0 +1,74 @@
+const mongoose = require('mongoose');
+const { cnpj } = require('cpf-cnpj-validator');
+const Point = require('./Point');
+
+const entitySchema = new mongoose.Schema({
+ name: {
+ type: String,
+ required: true,
+ },
+ deviceId: {
+ type: String,
+ required: false,
+ },
+ email: {
+ type: String,
+ required: true,
+ unique: true,
+ index: true,
+ },
+ cnpj: {
+ type: String,
+ required: true,
+ unique: true,
+ index: true,
+ validate: {
+ validator: (v) => cnpj.isValid(v),
+ message: (props) => `${props.value} não é um cnpj válido`,
+ },
+ },
+ photo: {
+ type: String,
+ required: true,
+ },
+ notificationToken: {
+ type: String,
+ },
+ address: {
+ cep: {
+ type: String,
+ required: true,
+ },
+ number: {
+ type: Number,
+ required: true,
+ },
+ city: {
+ type: String,
+ required: true,
+ },
+ state: {
+ type: String,
+ required: true,
+ },
+ complement: String,
+ },
+ location: {
+ type: Point,
+ index: '2dsphere',
+ },
+ phone: {
+ type: String,
+ required: true,
+ },
+ registerDate: {
+ type: Date,
+ default: Date.now,
+ },
+ active: {
+ default: true,
+ type: Boolean,
+ },
+}, { collection: 'entity' });
+
+module.exports = mongoose.model('Entity', entitySchema);
diff --git a/src/models/Help.js b/src/models/Help.js
index 6dd49872..17b5a9ac 100644
--- a/src/models/Help.js
+++ b/src/models/Help.js
@@ -1,64 +1,75 @@
const mongoose = require('mongoose');
const helpStatusEnum = require('../utils/enums/helpStatusEnum');
+const {
+ getDistance,
+ calculateDistance,
+} = require('../utils/geolocation/calculateDistance');
-const helpSchema = new mongoose.Schema({
- title: {
- type: String,
- required: true,
+const helpSchema = new mongoose.Schema(
+ {
+ title: {
+ type: String,
+ required: true,
+ },
+ description: {
+ type: String,
+ maxlength: 300,
+ required: true,
+ },
+ status: {
+ type: String,
+ enum: Object.values(helpStatusEnum),
+ default: helpStatusEnum.WAITING,
+ },
+ possibleHelpers: [{
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'User',
+ required: false,
+ }],
+ possibleEntities: [{
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'Entity',
+ required: false,
+ }],
+ categoryId: [{
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'Category',
+ }],
+ ownerId: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'User',
+ required: true,
+ },
+ helperId: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: 'User',
+ required: false,
+ },
+ creationDate: {
+ type: Date,
+ default: Date.now,
+ },
+ finishedDate: {
+ type: Date,
+ required: false,
+ },
+ active: {
+ default: true,
+ type: Boolean,
+ },
},
- description: {
- type: String,
- maxlength: 300,
- required: true,
+ {
+ collection: 'userHelp',
+ toObject: {
+ virtuals: true,
+ },
+ toJSON: {
+ virtuals: true,
+ },
},
- status: {
- type: String,
- enum: Object.values(helpStatusEnum),
- default: helpStatusEnum.WAITING,
- },
- possibleHelpers: {
- type: [mongoose.Schema.Types.ObjectId],
- ref: 'User',
- required: false,
- },
- categoryId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Category',
- },
- ownerId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'User',
- required: true,
- },
- helperId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'User',
- required: false,
- },
- creationDate: {
- type: Date,
- default: Date.now,
- },
- finishedDate: {
- type: Date,
- required: false,
- },
- active: {
- default: true,
- type: Boolean,
- },
-},
-{
- collection: 'userHelp',
- toObject: {
- virtuals: true,
- },
- toJSON: {
- virtuals: true,
- },
-});
+);
-helpSchema.virtual('category', {
+helpSchema.virtual('categories', {
ref: 'Category',
localField: 'categoryId',
foreignField: '_id',
@@ -67,6 +78,26 @@ helpSchema.virtual('user', {
ref: 'User',
localField: 'ownerId',
foreignField: '_id',
+ justOne: true
});
+helpSchema.virtual('distances')
+ .set(({ userCoords, coords }) => {
+ userCoords = {
+ longitude: userCoords[0],
+ latitude: userCoords[1],
+ };
+ const coordinates = {
+ longitude: coords[0],
+ latitude: coords[1],
+ };
+ this.distanceValue = calculateDistance(coordinates, userCoords);
+ this.distance = getDistance(coordinates, userCoords);
+ });
+
+helpSchema.virtual('distanceValue')
+ .get(() => this.distanceValue);
+helpSchema.virtual('distance')
+ .get(() => this.distance);
+
module.exports = mongoose.model('Help', helpSchema);
diff --git a/src/models/HelpOffer.js b/src/models/HelpOffer.js
new file mode 100644
index 00000000..f25ea38b
--- /dev/null
+++ b/src/models/HelpOffer.js
@@ -0,0 +1,87 @@
+const { Schema, model } = require('mongoose');
+const helpStatusEnum = require('../utils/enums/helpStatusEnum');
+
+const offeredHelpSchema = new Schema(
+ {
+ title: {
+ type: String,
+ required: true,
+ },
+ description: {
+ type: String,
+ maxlength: 300,
+ required: true,
+ },
+ status: {
+ type: String,
+ enum: Object.values(helpStatusEnum),
+ default: helpStatusEnum.WAITING,
+ },
+ possibleHelpedUsers: [{
+ type: Schema.Types.ObjectId,
+ ref: 'User',
+ required: false,
+ }],
+ possibleEntities: [{
+ type: Schema.Types.ObjectId,
+ ref: 'Entity',
+ required: false,
+ }],
+ categoryId: [{
+ type: Schema.Types.ObjectId,
+ ref: 'Category',
+ }],
+ ownerId: {
+ type: Schema.Types.ObjectId,
+ ref: 'User',
+ required: true,
+ },
+ helpedUserId: [{
+ type: Schema.Types.ObjectId,
+ ref: ['User' , 'Entity'],
+ required: false,
+ }],
+ creationDate: {
+ type: Date,
+ default: Date.now,
+ },
+ finishedDate: {
+ type: Date,
+ required: false,
+ },
+ active: {
+ default: true,
+ type: Boolean,
+ },
+ },
+ {
+ collection: 'helpOffer',
+ toObject: {
+ virtuals: true,
+ },
+ toJSON: {
+ virtuals: true,
+ },
+ }
+);
+
+offeredHelpSchema.virtual('user', {
+ ref: 'User',
+ localField: 'ownerId',
+ foreignField: '_id',
+ justOne: true,
+});
+
+offeredHelpSchema.virtual('categories', {
+ ref: 'Category',
+ localField: 'categoryId',
+ foreignField: '_id',
+});
+
+offeredHelpSchema.virtual('helpedUsers', {
+ ref: ['User', 'Entity'],
+ localField: 'helpedUserId',
+ foreignField: '_id',
+});
+
+module.exports = model('OfferedHelp', offeredHelpSchema);
\ No newline at end of file
diff --git a/src/models/Notification.js b/src/models/Notification.js
index 0394f010..dc6b6376 100644
--- a/src/models/Notification.js
+++ b/src/models/Notification.js
@@ -5,6 +5,8 @@ const notificationTypes = {
ajudaAceita: 'Sua oferta de ajuda foi aceita!',
ajudaFinalizada: 'Seu pedido de ajuda foi finalizado!',
ajudaExpirada: 'Seu pedido de ajuda expirou!',
+ ofertaRequerida: 'Sua oferta de ajuda possui um usuário interessado!',
+ ofertaAceita: 'Seu pedido de ajuda foi aceito!',
outros: 'Demais tipos de notificação!',
};
@@ -13,6 +15,9 @@ const notificationTypesEnum = {
ajudaAceita: 'ajudaAceita',
ajudaFinalizada: 'ajudaFinalizada',
ajudaExpirada: 'ajudaExpirada',
+ notificacaoManual: 'notificacaoManual',
+ ofertaRequerida: 'ofertaRequerida',
+ ofertaAceita: 'ofertaAceita',
outros: 'outros',
};
@@ -22,6 +27,11 @@ const NotificationSchema = new mongoose.Schema({
ref: 'User',
required: false,
},
+ isOffer: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
helpId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Help',
diff --git a/src/repository/BaseRepository.js b/src/repository/BaseRepository.js
index 23f15071..81dd81cf 100644
--- a/src/repository/BaseRepository.js
+++ b/src/repository/BaseRepository.js
@@ -15,6 +15,11 @@ class BaseRepository {
return savedModel;
}
+ async $populateExistingDoc(doc, populate) {
+ const populatedDoc = doc.populate(populate).execPopulate();
+ return populatedDoc;
+ }
+
async $saveMany(itemsModel, mongoSession = {}) {
itemsModel.forEach((item) => {
item.lastUpdateDate = Date.now();
@@ -65,9 +70,10 @@ class BaseRepository {
return recordModel;
}
- async $list(query, populate = null) {
- const recordModel = await this.modelClass.find(query).populate(populate);
- return recordModel;
+ async $list(query, selectedField, populate = null, sort = null) {
+ return this.modelClass.find(query, selectedField)
+ .populate(populate)
+ .sort(sort);
}
async $countDocuments(query) {
@@ -75,24 +81,19 @@ class BaseRepository {
return numberDocuments;
}
- async findOne(query, mongoSession = {}) {
- let result;
-
- if (mongoSession !== undefined || mongoSession.session !== undefined) {
- result = await this.modelClass
- .findOne(query)
- .session(mongoSession.session);
- return result;
- }
- result = await this.modelClass.findOne(query);
-
- return result;
+ async $findOne(query, projection, populate = null) {
+ return this.modelClass.findOne(query, projection)
+ .populate(populate);
}
async $destroy(query) {
const result = await this.modelClass.deleteOne(query);
return result;
}
+
+ async $findOneAndUpdate(filter, update) {
+ await this.modelClass.findOneAndUpdate(filter, update);
+ }
}
module.exports = BaseRepository;
diff --git a/src/repository/CampaignRepository.js b/src/repository/CampaignRepository.js
new file mode 100644
index 00000000..c03666ed
--- /dev/null
+++ b/src/repository/CampaignRepository.js
@@ -0,0 +1,82 @@
+const { ObjectID } = require('mongodb');
+const BaseRepository = require('./BaseRepository');
+const Campaign = require('../models/Campaign');
+const EntitySchema = require('../models/Entity');
+
+class CampaignRepository extends BaseRepository {
+ constructor() {
+ super(Campaign);
+ }
+
+ async create(campaign) {
+ const newCampaign = await super.$save(campaign);
+ return newCampaign;
+ }
+
+ async list() {
+ const query = null;
+ const populate = 'campaign';
+ const campaigns = await super.$list(query, populate);
+ return campaigns;
+ }
+
+ async listByOwnerId(ownerId) {
+ const query = { ownerId };
+ const campaigns = await super.$list(query);
+ return campaigns;
+ }
+
+ async getById(id) {
+ const campaign = await super.$getById(id);
+ return campaign;
+ }
+
+ async update(campaign) {
+ await super.$update(campaign);
+ }
+
+ async listNear(coords, except, id, categoryArray) {
+ const userQuery = {
+ _id: except ? { $ne: id } : null,
+ };
+ const users = await EntitySchema.find(userQuery);
+ const arrayUsersId = users.map((user) => user._id);
+ const matchQuery = {
+ active: true,
+ ownerId: { $in: arrayUsersId },
+ status: 'waiting'
+ };
+ const populate = ['entity', 'categories'];
+
+ if (categoryArray) {
+ matchQuery.categoryId = {
+ $in: categoryArray.map((categoryString) => ObjectID(categoryString)),
+ };
+ }
+
+ const campaigns = await super.$list(matchQuery, {}, populate);
+ const campaignsWithDistances = campaigns.map(campaign => {
+ campaign.distances = { campaignCoords: campaign.entity.location.coordinates, coords }
+ return campaign.toObject();
+ })
+
+ campaignsWithDistances.sort((a, b) => a.distanceValue - b.distanceValue);
+
+ return campaignsWithDistances;
+ }
+
+ async getCampaignListByStatus(userId, statusList) {
+ const matchQuery = {
+ ownerId: ObjectID(userId),
+ status: {
+ $in: [...statusList],
+ },
+ active: true,
+ };
+ const entity = 'entity';
+ const categories = 'categories';
+ return super.$list(matchQuery, {}, [entity, categories]);
+ }
+}
+
+module.exports = CampaignRepository;
diff --git a/src/repository/EntityRepository.js b/src/repository/EntityRepository.js
new file mode 100644
index 00000000..2da68fab
--- /dev/null
+++ b/src/repository/EntityRepository.js
@@ -0,0 +1,66 @@
+const BaseRepository = require('./BaseRepository');
+const EntitySchema = require('../models/Entity');
+
+class EntityRepository extends BaseRepository {
+ constructor() {
+ super(EntitySchema);
+ }
+
+ async create(entity) {
+ const result = await super.$save(entity);
+ return result;
+ }
+
+ async getById(id) {
+ const result = await super.$getById(id);
+ return result;
+ }
+
+ async getEntityByEmail(email) {
+ const result = await super.$list({ email });
+ return result[0];
+ }
+
+ async update(entity) {
+ const result = await super.$update(entity);
+ return result;
+ }
+
+ async checkEntityExistence(id) {
+ const entities = await super.$listAggregate([
+ {
+ $match: {
+ $or: [
+ { cnpj: id },
+ { email: id },
+ ],
+ },
+ }, {
+ $count: 'id',
+ },
+ ]);
+
+ let result = 0;
+
+ if (entities[0] && entities[0].id > 0) {
+ result = entities[0].id;
+ }
+
+ return result;
+ }
+
+ async removeEntity({ id, email }) {
+ const query = {};
+ query._id = id;
+ query.email = email;
+
+ await super.$destroy(query);
+ }
+
+ async findOneEntityWithProjection(query,projection){
+ const entity = await super.$findOne(query,projection);
+ return entity;
+ }
+}
+
+module.exports = EntityRepository;
diff --git a/src/repository/HelpOfferRepository.js b/src/repository/HelpOfferRepository.js
new file mode 100644
index 00000000..1642e213
--- /dev/null
+++ b/src/repository/HelpOfferRepository.js
@@ -0,0 +1,151 @@
+const { ObjectID } = require('mongodb');
+const BaseRepository = require('./BaseRepository');
+const OfferedHelp = require('../models/HelpOffer');
+
+class OfferdHelpRepository extends BaseRepository {
+ constructor() {
+ super(OfferedHelp);
+ }
+
+ async create(offeredHelp) {
+ const newOfferdHelp = await super.$save(offeredHelp);
+ return newOfferdHelp;
+ }
+
+ async update(helpOffer) {
+ await super.$update(helpOffer);
+ }
+
+ async getByIdWithAggregation(id) {
+ const query = { _id: ObjectID(id) };
+ const helpOfferFields = [
+ '_id',
+ 'description',
+ 'title',
+ 'status',
+ 'ownerId',
+ 'categoryId',
+ 'possibleHelpedUsers',
+ 'possibleEntities',
+ 'helpedUserId'
+ ];
+ const user = {
+ path: 'user',
+ select: ['photo', 'phone', 'name', 'birthday', 'address.city']
+ };
+ const categories = {
+ path: 'categories',
+ select: ['_id', 'name']
+ };
+ const possibleHelpedUsers = {
+ path: 'possibleHelpedUsers',
+ select: ['_id', 'name', 'photo', 'birthday', 'phone', 'address.city']
+ };
+ const possibleEntities = {
+ path: 'possibleEntities',
+ select: ['_id', 'name', 'photo', 'birthday', 'address.city']
+ };
+ const helpedUsers = {
+ path: 'helpedUsers',
+ select: ['_id', 'name', 'photo', 'birthday', 'phone', 'address.city']
+ };
+
+ const populate = [user, categories, possibleHelpedUsers, possibleEntities, helpedUsers];
+ return super.$findOne(query, helpOfferFields, populate);
+ }
+
+ async list(userId, isUserEntity, categoryArray, getOtherUsers) {
+ const matchQuery = this.getHelpOfferListQuery(
+ userId,
+ isUserEntity,
+ true,
+ getOtherUsers,
+ categoryArray
+ );
+ const helpOfferFields = ['_id', 'title', 'categoryId', 'ownerId', 'helpedUserId'];
+ const sort = { creationDate: -1 }
+ const user = {
+ path: 'user',
+ select: ['name', 'address', 'birthday', 'location.coordinates']
+ }
+
+ const categories = 'categories';
+
+ const possibleHelpedUsers = {
+ path: 'possibleHelpedUsers',
+ select: ['_id', 'name']
+ };
+
+ const possibleEntities = {
+ path: 'possibleEntities',
+ select: ['_id', 'name']
+ };
+
+ const populate = [user, categories, possibleHelpedUsers, possibleEntities];
+
+ return super.$list(matchQuery, helpOfferFields, populate, sort);
+ }
+ getHelpOfferListQuery(userId, isUserEntity, active, getOtherUsers, categoryArray) {
+ var matchQuery = { active };
+ if (!getOtherUsers) {
+ matchQuery.ownerId = { $ne: ObjectID(userId) };
+
+ if(isUserEntity){
+ matchQuery.possibleEntities = { $nin: [ObjectID(userId)] };
+ }else{
+ matchQuery.possibleHelpedUsers = { $nin: [ObjectID(userId)] };
+ }
+ } else {
+ matchQuery.ownerId = { $eq: ObjectID(userId) };
+ }
+
+ if (categoryArray) {
+ matchQuery.categoryId = {
+ $in: categoryArray.map((category) => ObjectID(category)),
+ };
+ }
+ return matchQuery;
+ }
+
+ async listByOwnerId(ownerId) {
+ const query = { ownerId };
+ const helpOffers = await super.$list(query);
+ return helpOffers;
+ }
+
+ async listByHelpedUserId(helpedUserId) {
+ const query = { helpedUserId };
+ const helpOffers = await super.$list(query);
+ return helpOffers;
+ }
+
+ async getById(id) {
+ const helpOffer = await super.$getById(id);
+ return helpOffer;
+ }
+
+ async findOne(query, projection, populate = null) {
+ return super.$findOne(query, projection, populate);
+ }
+
+ async finishHelpOfferByOwner(helpOffer) {
+ helpOffer.active = false;
+ return super.$update(helpOffer);
+ }
+
+ async getEmailByHelpOfferId(helpOfferId) {
+ const matchQuery = { _id: ObjectID(helpOfferId) };
+ const helpProjection = {
+ _id: 0,
+ ownerId: 1,
+ }
+ const user = {
+ path: 'user',
+ select: 'email -_id'
+ }
+ const helpOffer = await super.$findOne(matchQuery, helpProjection, user);
+ return helpOffer.user.email;
+ }
+}
+
+module.exports = OfferdHelpRepository;
\ No newline at end of file
diff --git a/src/repository/HelpRepository.js b/src/repository/HelpRepository.js
index a11ad7bf..795aa499 100644
--- a/src/repository/HelpRepository.js
+++ b/src/repository/HelpRepository.js
@@ -1,8 +1,8 @@
+// eslint-disable-next-line import/no-unresolved
const { ObjectID } = require('mongodb');
const BaseRepository = require('./BaseRepository');
const HelpSchema = require('../models/Help');
-const UserSchema = require('../models/User');
-const { getDistance, calculateDistance } = require('../utils/geolocation/calculateDistance');
+const sharedAgreggationInfo = require('../utils/sharedAggregationInfo');
class HelpRepository extends BaseRepository {
constructor() {
@@ -10,38 +10,26 @@ class HelpRepository extends BaseRepository {
}
async create(help) {
- const result = await super.$save(help);
-
- const aggregation = [
- {
- $match: { _id: result._id },
- },
- {
- $lookup: {
- from: 'user',
- localField: 'ownerId',
- foreignField: '_id',
- as: 'user',
- },
- },
+ const doc = await super.$save(help);
+ const populate = [
{
- $unwind: {
- path: '$user',
- preserveNullAndEmptyArrays: false,
- },
+ path: 'user',
+ select: ['name', 'riskGroup', 'location.coordinates']
},
{
- $lookup: {
- from: 'category',
- localField: 'categoryId',
- foreignField: '_id',
- as: 'category',
- },
- },
- ];
-
- const helps = await super.$listAggregate(aggregation);
- return helps[0];
+ path: 'categories',
+ select: ['name']
+ }
+ ]
+ let result = await super.$populateExistingDoc(doc, populate);
+ return {
+ _id: result._id,
+ ownerId: result.ownerId,
+ title: result.title,
+ categoryId: result.categoryId,
+ categories: result.categories,
+ user: result.user
+ }
}
async getById(id) {
@@ -49,194 +37,75 @@ class HelpRepository extends BaseRepository {
return help;
}
- async update(help) {
- const helpUpdated = await super.$update(help);
- return helpUpdated;
+ async getByIdWithAggregation(id) {
+ const matchQuery = { _id: ObjectID(id) };
+ const helpFields = [
+ '_id', 'ownerId', 'categoryId',
+ 'possibleHelpers', 'possibleEntities',
+ 'description', 'helperId', 'status', 'title'
+ ];
+ const user = {
+ path: 'user',
+ select: ['photo', 'name', 'phone', 'birthday', 'address.city', 'location.coordinates']
+ }
+ const categories = {
+ path: 'categories',
+ select: ['_id', 'name']
+ }
+ const possibleHelpers = {
+ path: 'possibleHelpers',
+ select: ['_id', 'name', 'phone', 'photo', 'birthday', 'address.city']
+ }
+ const possibleEntities = {
+ path: 'possibleEntities',
+ select: ['_id', 'name', 'photo', 'address.city']
+ }
+ return super.$findOne(
+ matchQuery,
+ helpFields,
+ [user, categories, possibleHelpers, possibleEntities]
+ );
}
- async list(id, status, except, helper, categoryArray) {
- const ownerId = except
- ? { $ne: ObjectID(id) }
- : helper
- ? null
- : ObjectID(id);
- const helperId = helper ? ObjectID(id) : null;
- const query = {};
- if (status) query.status = status;
- if (categoryArray) query.categoryId = { $in: categoryArray };
- if (helper) query.helperId = helperId;
- else query.ownerId = ownerId;
-
- const result = await super.$listAggregate([
- {
- $match: query,
- },
- {
- $lookup: {
- from: 'user',
- localField: 'ownerId',
- foreignField: '_id',
- as: 'user',
- },
- },
- {
- $unwind: {
- path: '$user',
- preserveNullAndEmptyArrays: false,
- },
- },
- {
- $addFields: {
- ageRisk: {
- $cond: [
- {
- $gt: [
- {
- $subtract: [
- {
- $year: '$$NOW',
- },
- {
- $year: '$user.birthday',
- },
- ],
- },
- 60,
- ],
- },
- 1,
- 0,
- ],
- },
- cardio: {
- $cond: [
- {
- $in: ['$user.riskGroup', [['doenCardio']]],
- },
- 1,
- 0,
- ],
- },
- risco: {
- $size: '$user.riskGroup',
- },
- },
- },
- {
- $sort: {
- ageRisk: -1,
- cardio: -1,
- risco: -1,
- },
- },
- {
- $project: {
- ageRisk: 0,
- cardio: 0,
- risco: 0,
- },
- },
- {
- $lookup: {
- from: 'category',
- localField: 'categoryId',
- foreignField: '_id',
- as: 'category',
- },
- },
- {
- $lookup: {
- from: 'user',
- localField: 'possibleHelpers',
- foreignField: '_id',
- as: 'possibleHelpers',
- },
- },
- ]);
- return result;
+ async update(help) {
+ await super.$update(help);
}
- async listNear(coords, except, id, categoryArray) {
- const query = {};
- const ownerId = except ? { $ne: id } : null;
-
- query._id = ownerId;
-
- const users = await UserSchema.find(query);
- const arrayUsersId = users.map((user) => user._id);
-
- const matchQuery = {};
-
- matchQuery.active = true;
- matchQuery.possibleHelpers = { $not: { $in: [ObjectID(id)] } };
- matchQuery.ownerId = {
- $in: arrayUsersId,
+ async shortList(coords, id, isUserEntity, categoryArray) {
+ const matchQuery = {
+ active: true,
+ ownerId: { $ne: ObjectID(id) },
+ status: 'waiting'
};
- matchQuery.status = 'waiting';
+
+ if(isUserEntity){
+ matchQuery.possibleEntities = { $nin: [ObjectID(id)] };
+ }else{
+ matchQuery.possibleHelpers = { $nin: [ObjectID(id)] };
+ }
if (categoryArray) {
matchQuery.categoryId = {
$in: categoryArray.map((categoryString) => ObjectID(categoryString)),
};
}
- const aggregation = [
- {
- $match: matchQuery,
- },
- {
- $lookup: {
- from: 'user',
- localField: 'ownerId',
- foreignField: '_id',
- as: 'user',
- },
- },
- {
- $unwind: {
- path: '$user',
- preserveNullAndEmptyArrays: false,
- },
- },
- {
- $lookup: {
- from: 'category',
- localField: 'categoryId',
- foreignField: '_id',
- as: 'category',
- },
- },
- {
- $lookup: {
- from: 'user',
- localField: 'possibleHelpers',
- foreignField: '_id',
- as: 'possibleHelpers',
- },
- },
- ];
-
- const helps = await super.$listAggregate(aggregation);
- const helpsWithDistance = helps.map((help) => {
- const coordinates = {
- latitude: coords[1],
- longitude: coords[0],
- };
- const helpCoords = {
- latitude: help.user.location.coordinates[1],
- longitude: help.user.location.coordinates[0],
- };
- help.distance = getDistance(coordinates, helpCoords);
- help.distanceValue = calculateDistance(coordinates, helpCoords);
- return help;
- });
- helpsWithDistance.sort((a, b) => {
- if (a.distanceValue < b.distanceValue) {
- return -1;
- } if (a.distanceValue > b.distanceValue) {
- return 1;
- }
- return 0;
+ const helpFields = ['_id', 'title', 'description', 'categoryId', 'ownerId'];
+ const user = {
+ path: 'user',
+ select: ['name', 'riskGroup', 'location.coordinates']
+ };
+ const categories = {
+ path: 'categories',
+ select: ['_id', 'name']
+ }
+ const helps = await super.$list(matchQuery, helpFields, [user, categories])
+ const helpsWithDistance = helps.map(help => {
+ help.distances = { userCoords: help.user.location.coordinates, coords }
+ return help.toObject();
});
+
+ helpsWithDistance.sort((a, b) => a.distanceValue - b.distanceValue);
+
return helpsWithDistance;
}
@@ -254,7 +123,7 @@ class HelpRepository extends BaseRepository {
const date = new Date();
date.setDate(date.getDate() - 14);
- return await super.$list({
+ return super.$list({
creationDate: { $lt: new Date(date) },
active: true,
});
@@ -268,7 +137,29 @@ class HelpRepository extends BaseRepository {
active: true,
};
+ const fields = [
+ '_id',
+ 'description',
+ 'title',
+ 'status',
+ 'ownerId',
+ 'categoryId'
+ ];
+
+ const user = {
+ path: 'user',
+ select: ['photo', 'phone', 'name', 'birthday', 'address.city'],
+ };
+
+ const categories = {
+ path: 'categories',
+ select: ['_id', 'name'],
+ };
+
+ const populate = [user, categories];
+
if (helper) {
+ user.select.push('location.coordinates');
matchQuery.$or = [
{
possibleHelpers: { $in: [ObjectID(userId)] },
@@ -277,46 +168,48 @@ class HelpRepository extends BaseRepository {
helperId: ObjectID(userId),
},
];
- } else {
- matchQuery.ownerId = ObjectID(userId);
- }
- const helpList = await super.$listAggregate([
- {
- $match: matchQuery,
- },
- {
- $lookup: {
- from: 'user',
- localField: 'possibleHelpers',
- foreignField: '_id',
- as: 'possibleHelpers',
- },
- },
- {
- $lookup: {
- from: 'user',
- localField: 'ownerId',
- foreignField: '_id',
- as: 'user',
- },
- },
- {
- $lookup: {
- from: 'category',
- localField: 'categoryId',
- foreignField: '_id',
- as: 'category',
- },
- },
- {
- $unwind: {
- path: '$user',
- preserveNullAndEmptyArrays: false,
- },
- },
- ]);
+ } else {
+ const possibleHelpers = {
+ path: 'possibleHelpers',
+ select: ['_id', 'photo', 'name', 'birthday', 'address.city'],
+ };
+
+ const possibleEntities = {
+ path: 'possibleEntities',
+ select: ['_id', 'photo', 'name', 'birthday', 'address.city'],
+ };
+
+ fields.push('helperId');
+
+ populate.push(possibleHelpers);
+ populate.push(possibleEntities);
+
+ matchQuery.ownerId = ObjectID(userId);
+ }
+
+ const helpList = await super.$list(matchQuery, fields, populate);
return helpList;
}
+
+ async getHelpInfoById(helpId) {
+ const matchQuery = { _id: ObjectID(helpId) };
+
+ const populate = {
+ path: 'user',
+ select: ['photo', 'birthday', 'address.city']
+ }
+
+ const projection = {
+ description: 1,
+ _id: 0,
+ };
+
+ return super.$findOne(
+ matchQuery,
+ projection,
+ populate
+ );
+ }
}
module.exports = HelpRepository;
diff --git a/src/repository/UserRepository.js b/src/repository/UserRepository.js
index ae0a5052..ebf85cf0 100644
--- a/src/repository/UserRepository.js
+++ b/src/repository/UserRepository.js
@@ -56,6 +56,17 @@ class UserRepository extends BaseRepository {
await super.$destroy(query);
}
+
+ async getUsersWithDevice() {
+ const users = await super.$list({ deviceId: { $ne: null } });
+
+ return users;
+ }
+
+ async findOneUserWithProjection(query,projection){
+ const user = await super.$findOne(query,projection);
+ return user;
+ }
}
module.exports = UserRepository;
diff --git a/src/routes/BaseRoutes.js b/src/routes/BaseRoutes.js
index 0050379f..7c9b5f78 100644
--- a/src/routes/BaseRoutes.js
+++ b/src/routes/BaseRoutes.js
@@ -1,13 +1,16 @@
const YAML = require('yamljs');
const swaggerUi = require('swagger-ui-express');
const userRoutes = require('./UserRoutes');
+const entityRoutes = require('./EntityRoutes');
const helpRoutes = require('./HelpRoutes');
const categoryRoutes = require('./CategoryRoutes');
const notificationRoutes = require('./NotificationRoutes');
+const helpOfferRoutes = require('./HelpOfferRoutes');
+const campaignRoutes = require('./CampaignRoutes');
const swaggerDocument = YAML.load('docs/swagger.yaml');
module.exports = (app) => {
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
- app.use('/api', [userRoutes, helpRoutes, categoryRoutes, notificationRoutes]);
+ app.use('/api', [userRoutes, helpRoutes, categoryRoutes, notificationRoutes, entityRoutes, helpOfferRoutes, campaignRoutes]);
};
diff --git a/src/routes/CampaignRoutes.js b/src/routes/CampaignRoutes.js
new file mode 100644
index 00000000..9467249e
--- /dev/null
+++ b/src/routes/CampaignRoutes.js
@@ -0,0 +1,35 @@
+const express = require('express');
+const CampaignController = require('../controllers/CampaignController');
+const isAuthenticated = require('../validation/middlewares/authFirebase');
+
+const campaignController = new CampaignController();
+const routes = express.Router();
+
+routes.post('/campaign', isAuthenticated, (req, res, next) => {
+ campaignController.createCampaign(req, res, next);
+});
+
+routes.get('/campaign', isAuthenticated, (req, res, next) => {
+ campaignController.listCampaignNear(req, res, next);
+});
+
+routes.get(
+ '/campaign/listbyStatus/:userId',
+ isAuthenticated,
+ (req, res, next) => {
+ campaignController.getCampaignListByStatus(req, res, next);
+ },
+);
+
+routes.put('/campaign/:id', isAuthenticated, (req, res, next) => {
+ campaignController.finishCampaign(req, res, next);
+});
+
+routes.delete('/campaign/:id', isAuthenticated, async (req, res, next) => {
+ campaignController.finishCampaign(req, res, next);
+});
+routes.get('/campaign/:id', isAuthenticated, (req, res, next) => {
+ campaignController.getCampaignById(req, res, next);
+});
+
+module.exports = routes;
diff --git a/src/routes/EntityRoutes.js b/src/routes/EntityRoutes.js
new file mode 100644
index 00000000..cdb96cdb
--- /dev/null
+++ b/src/routes/EntityRoutes.js
@@ -0,0 +1,37 @@
+const express = require('express');
+const EntityController = require('../controllers/EntityController');
+const isAuthenticated = require('../validation/middlewares/authFirebase');
+
+const routes = express.Router();
+const entityController = new EntityController();
+
+routes.post('/entity', async (req, res, next) => {
+ entityController.createEntity(req, res, next);
+});
+
+routes.get('/entity/getEntity/:id*?/', isAuthenticated, async (req, res, next) => {
+ entityController.getEntityById(req, res, next);
+});
+
+routes.put('/entity', isAuthenticated, async (req, res, next) => {
+ entityController.editEntityById(req, res, next);
+});
+
+routes.put('/entity/address', isAuthenticated, async (req, res, next) => {
+ entityController.editEntityAddressById(req, res, next);
+});
+
+routes.put('/entity/location', isAuthenticated, async (req, res, next) => {
+ entityController.updateEntityLocationById(req, res, next);
+});
+
+routes.delete('/entity', isAuthenticated, async (req, res, next) => {
+ entityController.deleteEntityLogic(req, res, next);
+});
+
+// Verifica a existência de uma entidade/ONG baseado no email ou CNPJ
+routes.get('/checkEntityExistence/:entityIdentifier', async (req, res, next) => {
+ entityController.checkEntityExistence(req, res, next);
+});
+
+module.exports = routes;
diff --git a/src/routes/HelpOfferRoutes.js b/src/routes/HelpOfferRoutes.js
new file mode 100644
index 00000000..a5c068d1
--- /dev/null
+++ b/src/routes/HelpOfferRoutes.js
@@ -0,0 +1,48 @@
+const express = require('express');
+const HelpOfferController = require('../controllers/HelpOfferController');
+const isAuthenticated = require('../validation/middlewares/authFirebase');
+
+const helpOfferController = new HelpOfferController();
+const routes = express.Router();
+
+routes.post('/helpOffer', isAuthenticated, (req, res, next) => {
+ helpOfferController.createHelpOffer(req, res, next);
+});
+
+routes.get('/helpOffer/list', isAuthenticated, (req, res, next) => {
+ helpOfferController.listHelpsOffers(req, res, next);
+});
+
+routes.get('/helpOffer/aggregation/:id', isAuthenticated, async (req, res, next) => {
+ helpOfferController.getHelpWithAggregationById(req, res, next);
+});
+
+routes.get(
+ '/helpOffer/list/:helpedUserId',
+ isAuthenticated,
+ (req, res, next) => {
+ helpOfferController.listHelpOffersByHelpedUserId(req, res, next);
+ },
+);
+
+routes.put(
+ '/helpOffer/possibleHelpedUsers/:helpedId/:helpOfferId',
+ isAuthenticated,
+ (req, res, next) => {
+ helpOfferController.addPossibleHelpedUsers(req, res, next);
+ },
+);
+
+routes.put(
+ '/helpOffer/chooseHelpedUsers/:helpedId/:helpOfferId',
+ isAuthenticated,
+ (req, res, next) => {
+ helpOfferController.chooseHelpedUsers(req, res, next);
+ }
+);
+
+routes.delete('/helpOffer/:helpOfferId', isAuthenticated, async (req, res, next) => {
+ helpOfferController.finishHelpOfferByOwner(req, res, next);
+});
+
+module.exports = routes;
diff --git a/src/routes/HelpRoutes.js b/src/routes/HelpRoutes.js
index 02a2e39f..c9235e85 100644
--- a/src/routes/HelpRoutes.js
+++ b/src/routes/HelpRoutes.js
@@ -9,15 +9,19 @@ routes.post('/help', isAuthenticated, async (req, res, next) => {
helpController.createHelp(req, res, next);
});
-routes.get('/help/:id', isAuthenticated, async (req, res, next) => {
- helpController.getHelpById(req, res, next);
+routes.get('/help/aggregation/:id', isAuthenticated, async (req, res, next) => {
+ helpController.getHelpWithAggregationById(req, res, next);
+});
+
+routes.get('/help/helpInfo/:helpId', isAuthenticated, async (req, res, next) => {
+ helpController.getHelpInfoById(req, res, next);
});
routes.get('/help', isAuthenticated, async (req, res, next) => {
helpController.getHelpList(req, res, next);
});
-routes.get('/help/listbyStatus/:userId', async (req, res, next) => {
+routes.get('/help/listbyStatus/:userId', isAuthenticated, async (req, res, next) => {
helpController.getHelpListByStatus(req, res, next);
});
diff --git a/src/routes/NotificationRoutes.js b/src/routes/NotificationRoutes.js
index b4dec354..e2d2fa2e 100644
--- a/src/routes/NotificationRoutes.js
+++ b/src/routes/NotificationRoutes.js
@@ -9,4 +9,8 @@ routes.get('/notification/user/:id', isAuthenticated, async (req, res, next) =>
notificationController.getUserNotificationsById(req, res, next);
});
+routes.post('/notifications/send', isAuthenticated, async (req, res, next) => {
+ notificationController.sendNotifications(req, res, next);
+});
+
module.exports = routes;
diff --git a/src/routes/UserRoutes.js b/src/routes/UserRoutes.js
index 3e526acf..7b7ee246 100644
--- a/src/routes/UserRoutes.js
+++ b/src/routes/UserRoutes.js
@@ -1,38 +1,47 @@
-const express = require('express');
-const UserController = require('../controllers/UserController');
-const isAuthenticated = require('../validation/middlewares/authFirebase');
+const express = require("express");
+const UserController = require("../controllers/UserController");
+const isAuthenticated = require("../validation/middlewares/authFirebase");
const routes = express.Router();
const userController = new UserController();
-routes.post('/user', async (req, res, next) => {
+routes.post("/user", async (req, res, next) => {
userController.createUser(req, res, next);
});
-routes.get('/user/getUser/:id*?/', isAuthenticated, async (req, res, next) => {
+routes.get("/user/getUser/:id*?/", isAuthenticated, async (req, res, next) => {
userController.getUserById(req, res, next);
});
-routes.put('/user', isAuthenticated, async (req, res, next) => {
+routes.get(
+ "/user/getAnyUser/:id*?/",
+ isAuthenticated,
+ async (req, res, next) => {
+ userController.getAnyUserById(req, res, next);
+ }
+);
+
+routes.put("/user", isAuthenticated, async (req, res, next) => {
userController.editUserById(req, res, next);
});
-routes.put('/user/address', isAuthenticated, async (req, res, next) => {
+routes.put("/user/address", isAuthenticated, async (req, res, next) => {
userController.editUserAddressById(req, res, next);
});
-routes.put('/user/location', isAuthenticated, async (req, res, next) => {
+routes.put("/user/location", isAuthenticated, async (req, res, next) => {
userController.updateUserLocationById(req, res, next);
});
-routes.delete('/user', isAuthenticated, async (req, res, next) => {
+routes.delete("/user", isAuthenticated, async (req, res, next) => {
userController.deleteUserLogic(req, res, next);
});
-routes.get('/groupRisk', async (req, res, next) => {
+routes.get("/groupRisk", async (req, res, next) => {
userController.getUserGroupRiskList(req, res, next);
});
-routes.get('/checkUserExistence/:value', async (req, res, next) => {
+// Verifica a existência de um usuário baseado no email ou CPF
+routes.get("/checkUserExistence/:userIdentifier", async (req, res, next) => {
userController.checkUserExistence(req, res, next);
});
diff --git a/src/services/CampaignService.js b/src/services/CampaignService.js
new file mode 100644
index 00000000..bd8e7f1a
--- /dev/null
+++ b/src/services/CampaignService.js
@@ -0,0 +1,92 @@
+const CampaignRepository = require('../repository/CampaignRepository');
+const CategoryService = require('./CategoryService');
+const helpStatusEnum = require('../utils/enums/helpStatusEnum');
+
+class CampaignService {
+ constructor() {
+ this.CampaignRepository = new CampaignRepository();
+ this.CategoryService = new CategoryService();
+ }
+
+ async createNewCampaign(campaignInfo) {
+ await this.CategoryService.getCategoryByid(campaignInfo.categoryId);
+ const newCampaign = await this.CampaignRepository.create(campaignInfo);
+ return newCampaign;
+ }
+
+ async listCampaign() {
+ const campaign = await this.CampaignRepository.list();
+ return campaign;
+ }
+
+ async getCampaignListByStatus({ userId, statusList }) {
+ const checkHelpStatusExistence = statusList.filter(
+ (item) => !Object.values(helpStatusEnum).includes(item),
+ );
+
+ if (checkHelpStatusExistence.length > 0) {
+ throw new Error('Um dos status informados é ínvalido');
+ }
+
+ const helpList = await this.CampaignRepository.getCampaignListByStatus(
+ userId,
+ statusList,
+ );
+
+ return helpList;
+ }
+
+ async getNearCampaignList(coords, except, id, categoryArray) {
+ const CampaignList = await this.CampaignRepository.listNear(
+ coords,
+ except,
+ id,
+ categoryArray,
+ );
+ if (!CampaignList) {
+ throw new Error(
+ 'Nenhuma campanha foi encontrada no seu raio de distância',
+ );
+ }
+
+ return CampaignList;
+ }
+
+ async getCampaignById(id) {
+ const Campaign = await this.CampaignRepository.getById(id);
+
+ if (!Campaign) {
+ throw new Error('Campanha não encontrada');
+ }
+
+ return Campaign;
+ }
+
+ async deleteCampaign(id) {
+ let campaign = await this.getCampaignById(id);
+ console.log(campaign);
+ campaign.active = false;
+
+ await this.CampaignRepository.update(campaign);
+
+
+ campaign = JSON.parse(JSON.stringify(campaign));
+ return { message: `Campaign ${id} deleted!` };
+ }
+
+ async listCampaignByOwnerId(ownerId) {
+ const campaign = await this.CampaignRepository.listByOwnerId(ownerId);
+ return campaign;
+ }
+
+ async finishCampaign(id) {
+ const campaign = await this.getCampaignById(id);
+
+ campaign.status = 'finished';
+
+ const result = await this.CampaignRepository.update(campaign);
+ return result;
+ }
+}
+
+module.exports = CampaignService;
diff --git a/src/services/EntityService.js b/src/services/EntityService.js
new file mode 100644
index 00000000..0e4161f3
--- /dev/null
+++ b/src/services/EntityService.js
@@ -0,0 +1,161 @@
+const EntityRepository = require("../repository/EntityRepository");
+const UserRepository = require("../repository/UserRepository");
+const firebase = require("../config/authFirebase");
+const { ObjectID } = require("mongodb");
+
+class EntityService {
+ constructor() {
+ this.entityRepository = new EntityRepository();
+ this.userRepository = new UserRepository();
+ }
+
+ async createEntity(data) {
+ const isUserRegistered = await this.userRepository.getUserByEmail(
+ data.email
+ );
+
+ if (isUserRegistered) {
+ throw new Error("Email já sendo utilizado");
+ }
+
+ if (data.password.length < 8) {
+ throw new Error("Senha inválida");
+ }
+
+ if (data.cnpj.length >= 14) {
+ data.cnpj = data.cnpj.replace(/([^0-9])+/g, "");
+ }
+
+ data.email = data.email.toLowerCase();
+ try {
+ const createdEntity = await this.entityRepository.create(data);
+
+ if (!data.hasUser) {
+ console.log("Usuario Criado");
+ // Cria o usuário no firebase
+ await firebase
+ .auth()
+ .createUser({
+ email: data.email,
+ password: data.password,
+ displayName: `${data.name} | PJ`,
+ emailVerified: false,
+ })
+ .catch(async (err) => {
+ await this.removeEntity(data.email);
+ throw err;
+ });
+ }
+
+ return createdEntity;
+ } catch (err) {
+ throw err;
+ }
+ }
+
+ async getEntity({ id = undefined, email = undefined }) {
+ if (!id && !email) {
+ throw new Error("Nenhum identificador encontrado");
+ }
+ let entity;
+
+ if (id) {
+ entity = await this.entityRepository.getById(id);
+ } else {
+ entity = await this.entityRepository.getEntityByEmail(email);
+ }
+ if (!entity) {
+ throw new Error("Usuário não encontrado");
+ }
+ return entity;
+ }
+
+ async editEntityById({
+ email,
+ photo,
+ name,
+ phone,
+ notificationToken,
+ deviceId,
+ }) {
+ const entity = await this.getEntity({ email });
+
+ entity.photo = photo || entity.photo;
+ entity.name = name || entity.name;
+ entity.phone = phone || entity.phone;
+ entity.notificationToken = notificationToken || entity.notificationToken;
+ entity.deviceId = deviceId || entity.deviceId;
+
+ const result = await this.entityRepository.update(entity);
+
+ return result;
+ }
+
+ async editEntityAddressById({ email, cep, number, city, state, complement }) {
+ const entity = await this.getEntity({ email });
+
+ const address = {
+ cep: cep || entity.address.cep,
+ number: number || entity.address.number,
+ city: city || entity.address.city,
+ state: state || entity.address.state,
+ complement: complement || entity.address.complement,
+ };
+
+ entity.address = address;
+
+ const result = await this.entityRepository.update(entity);
+
+ return result;
+ }
+
+ async updateEntityLocationById({ email, longitude, latitude }) {
+ const entity = await this.getEntity({ email });
+
+ if (longitude || latitude) {
+ entity.location.coordinates[0] =
+ longitude || entity.location.coordinates[0];
+ entity.location.coordinates[1] =
+ latitude || entity.location.coordinates[1];
+ }
+
+ const result = await this.entityRepository.update(entity);
+
+ return result;
+ }
+
+ async deleteEntityLogically(email) {
+ const entity = await this.getEntity({ email });
+
+ entity.active = false;
+
+ await this.entityRepository.update(entity);
+
+ return { message: `Entity ${entity._id} deleted!` };
+ }
+
+ async removeEntity(email) {
+ const entity = await this.getEntity({ email });
+ await this.entityRepository.removeEntity({ id: entity._id, email });
+ }
+
+ async checkEntityExistence(entityIdentifier) {
+ const result = await this.entityRepository.checkEntityExistence(
+ entityIdentifier
+ );
+
+ if (result) {
+ return true;
+ }
+
+ return false;
+ }
+ async findOneEntityWithProjection(entityId,projection){
+ const query = { _id: ObjectID(entityId) };
+ const entity = await this.entityRepository.findOneEntityWithProjection(query,projection);
+
+ return entity;
+ }
+}
+
+module.exports = EntityService;
diff --git a/src/services/HelpOfferService.js b/src/services/HelpOfferService.js
new file mode 100644
index 00000000..c025d76b
--- /dev/null
+++ b/src/services/HelpOfferService.js
@@ -0,0 +1,202 @@
+const OfferedHelpRepository = require("../repository/HelpOfferRepository");
+const UserService = require("./UserService");
+const EntityService = require("./EntityService");
+const NotificationService = require("./NotificationService");
+const NotificationMixin = require("../utils/NotificationMixin");
+const { notificationTypesEnum } = require("../models/Notification");
+const saveError = require('../utils/ErrorHistory');
+const { findConnections, sendMessage } = require("../../websocket");
+const { ObjectID } = require('mongodb');
+
+class OfferedHelpService {
+ constructor() {
+ this.OfferedHelpRepository = new OfferedHelpRepository();
+ this.UserService = new UserService();
+ this.NotificationService = new NotificationService();
+ this.NotificationMixin = new NotificationMixin();
+ this.EntityService = new EntityService();
+ }
+
+ async createNewHelpOffer(offeredHelpInfo) {
+ const newOfferdHelp = await this.OfferedHelpRepository.create(
+ offeredHelpInfo
+ );
+ return newOfferdHelp;
+ }
+
+ async getHelpOfferWithAggregationById(id) {
+ const help = await this.OfferedHelpRepository.getByIdWithAggregation(id);
+
+ if (!help) {
+ throw new Error('Oferta não encontrada');
+ }
+
+ return help;
+ }
+
+ async listHelpsOffers(userId, isUserEntity, categoryArray,getOtherUsers) {
+ const helpOffers = await this.OfferedHelpRepository.list(userId, isUserEntity, categoryArray,getOtherUsers);
+ return helpOffers;
+ }
+
+ async listHelpsOffersByOwnerId(ownerId) {
+ const helpOffers = await this.OfferedHelpRepository.listByOwnerId(ownerId);
+ return helpOffers;
+ }
+
+ async listHelpOffersByHelpedUserId(helpedUserId) {
+ const helpOffers = await this.OfferedHelpRepository.listByHelpedUserId(
+ helpedUserId
+ );
+ return helpOffers;
+ }
+
+ validateOwnerAndHelpedUser(helpedId, helpOffer) {
+ if (helpOffer.ownerId == helpedId)
+ throw new Error("Dono não pode ser ajudado da própria oferta");
+ else if (helpOffer.helpedUserId != null && helpOffer.helpedUserId.includes(helpedId))
+ throw new Error("Usuário já está sendo ajudado");
+ }
+
+ validateOwner(helpOffer, email){
+ if (helpOffer.user.email !== email) {
+ throw new Error('Usuário não autorizado');
+ }
+ }
+
+ isUserInPossibleHelpedUsers(helpedUser, helpOffer, helpedId) {
+ if (!helpedUser.isEntity)
+ return helpOffer.possibleHelpedUsers.includes(helpedId)
+ else
+ return helpOffer.possibleEntities.includes(helpedId)
+ }
+
+ possibleInterestedArray(helpOffer, helpedUser){
+ if(helpedUser.isEntity)
+ return helpOffer.possibleEntities
+ else
+ return helpOffer.possibleHelpedUsers
+ }
+
+ async addPossibleHelpedUsers(helpedId, helpOfferId) {
+ const helpOffer = await this.getHelpOfferById(helpOfferId);
+ const helpedUser = await this.verifyUserEntity(helpedId);
+ const possibleHelpedUser = this.possibleInterestedArray(helpOffer, helpedUser)
+
+ // Validacao
+ this.validateOwnerAndHelpedUser(helpedId, helpOffer)
+ if (this.isUserInPossibleHelpedUsers(helpedUser, helpOffer, helpedId))
+ throw new Error("Usuário já é um possível ajudado");
+
+ // Alteracao do array
+ await this.useService(possibleHelpedUser, "push", [helpedId]);
+ await this.OfferedHelpRepository.update(helpOffer);
+
+
+ //Notificação
+ const ownerProjection = { deviceId: 1, _id: 0 };
+ const { deviceId: ownerDeviceId } = await this.useService(this.UserService, "findOneUserWithProjection", [helpOffer.ownerId, ownerProjection]);
+
+ const title = `${helpedUser.name} quer sua ajuda!`;
+ const body = `Sua oferta ${helpOffer.title} recebeu um interessado`;
+
+ await this.sendHelpOfferNotification(ownerDeviceId, title, body, helpOffer.ownerId, helpOfferId, notificationTypesEnum.ofertaRequerida);
+
+ }
+
+ async addHelpedUsers(helpedId, helpOfferId) {
+ const helpOffer = await this.getHelpOfferById(helpOfferId);
+ const helpedUser = await this.verifyUserEntity(helpedId);
+ const interestedArray = this.possibleInterestedArray(helpOffer, helpedUser)
+
+ // Validacao
+ this.validateOwnerAndHelpedUser(helpedId, helpOffer)
+ if (!this.isUserInPossibleHelpedUsers(helpedUser, helpOffer, helpedId))
+ throw new Error("Usuário não é um interessado na ajuda");
+
+ // Alteracao do array
+ await this.useService(helpOffer.helpedUserId, "push", [helpedId]);
+ await this.useService(interestedArray, "pull", [helpedId]);
+ await this.OfferedHelpRepository.update(helpOffer);
+
+ //Notificacao
+ const ownerProjection = { name: 1, _id: 0 };
+ const { name: ownerName } = await this.useService(this.UserService, "findOneUserWithProjection", [helpOffer.ownerId, ownerProjection]);
+
+ const title = `${ownerName} escolheu ajudar você!`;
+ const body = `Você foi escolhido para ser ajudado na oferta ${helpOffer.title}`;
+
+ await this.sendHelpOfferNotification(helpedUser.deviceId, title, body, helpedId, helpOfferId, notificationTypesEnum.ofertaAceita);
+ }
+
+ async verifyUserEntity(helpedId) {
+ let helpedUserProjection = { name: 1, deviceId: 1, cpf: 1, _id: 0 };
+ let helpedUserName;
+
+ helpedUserName = await this.useService(this.UserService, "findOneUserWithProjection", [helpedId, helpedUserProjection]);
+ if (helpedUserName == null) {
+ helpedUserProjection = { name: 1, deviceId: 1, cnpj: 1, _id: 0 };
+ helpedUserName = await this.useService(this.EntityService, "findOneEntityWithProjection", [helpedId, helpedUserProjection]);
+ }
+
+ const isUserEntity = (helpedUserName.cnpj ? true : false);
+ return { name: helpedUserName.name, deviceId: helpedUserName.deviceId, isEntity: isUserEntity };
+ }
+
+ async sendHelpOfferNotification(deviceId, title, body, userId, helpOfferId, notificationType) {
+ const notificationHistory = {
+ userId: userId,
+ helpId: helpOfferId,
+ isOffer: true,
+ title,
+ body,
+ notificationType: notificationType,
+ };
+
+ try {
+ await this.NotificationMixin.sendNotification(
+ deviceId,
+ title,
+ body
+ );
+ await this.NotificationService.createNotification(notificationHistory);
+ } catch (err) {
+ console.log("Não foi possível enviar a notificação!");
+ saveError(err);
+ }
+ }
+
+ async getHelpOfferById(helpOfferId) {
+ const helpOffer = await this.OfferedHelpRepository.getById(helpOfferId);
+ return helpOffer;
+ }
+
+ async finishHelpOfferByOwner(helpOfferId, email) {
+ const query = {_id: ObjectID(helpOfferId)};
+ const helpOfferProjection = ['ownerId', 'categoryId', 'active'];
+ const owner = {
+ path: 'user',
+ select: 'email'
+ }
+ let helpOffer = await this.OfferedHelpRepository.findOne(query, helpOfferProjection, owner);
+
+ this.validateOwner(helpOffer, email);
+
+ helpOffer = await this.OfferedHelpRepository.finishHelpOfferByOwner(helpOffer);
+
+ const sendSocketMessageTo = findConnections(helpOffer.categoryId, helpOffer.ownerId.toString());
+ sendMessage(sendSocketMessageTo, 'delete-help-offer', helpOfferId);
+ }
+
+ async getEmailByHelpOfferId(helpOfferId) {
+ const ownerEmail = await this.OfferedHelpRepository.getEmailByHelpOfferId(helpOfferId);
+ return ownerEmail;
+ }
+
+ async useService(service, functionName, params = []) {
+ let functionReturn = await service[functionName](...params);
+ return functionReturn;
+ }
+}
+
+module.exports = OfferedHelpService;
diff --git a/src/services/HelpService.js b/src/services/HelpService.js
index c70c3f1c..0cf56c43 100644
--- a/src/services/HelpService.js
+++ b/src/services/HelpService.js
@@ -1,17 +1,19 @@
-const HelpRepository = require('../repository/HelpRepository');
-const NotificationService = require('./NotificationService');
-const { notificationTypesEnum } = require('../models/Notification');
-const UserService = require('./UserService');
-const CategoryService = require('./CategoryService');
-const { findConnections, sendMessage } = require('../../websocket');
-const NotificationMixin = require('../utils/NotificationMixin');
-const helpStatusEnum = require('../utils/enums/helpStatusEnum');
-const saveError = require('../utils/ErrorHistory');
+const HelpRepository = require("../repository/HelpRepository");
+const NotificationService = require("./NotificationService");
+const { notificationTypesEnum } = require("../models/Notification");
+const UserService = require("./UserService");
+const EntityService = require("./EntityService");
+const CategoryService = require("./CategoryService");
+const { findConnections, sendMessage } = require("../../websocket");
+const NotificationMixin = require("../utils/NotificationMixin");
+const helpStatusEnum = require("../utils/enums/helpStatusEnum");
+const saveError = require("../utils/ErrorHistory");
class HelpService {
constructor() {
this.HelpRepository = new HelpRepository();
this.UserService = new UserService();
+ this.EntityService = new EntityService();
this.CategoryService = new CategoryService();
this.NotificationService = new NotificationService();
this.NotificationMixin = new NotificationMixin();
@@ -20,7 +22,7 @@ class HelpService {
async createHelp(data) {
const countHelp = await this.HelpRepository.countDocuments(data.ownerId);
if (countHelp >= 5) {
- throw new Error('Limite máximo de pedidos atingido');
+ throw new Error("Limite máximo de pedidos atingido");
}
await this.CategoryService.getCategoryByid(data.categoryId);
@@ -29,47 +31,43 @@ class HelpService {
const sendSocketMessageTo = findConnections(
createdHelp.categoryId,
- JSON.parse(JSON.stringify(createdHelp.ownerId)),
+ JSON.parse(JSON.stringify(createdHelp.ownerId))
);
sendMessage(sendSocketMessageTo, 'new-help', createdHelp);
-
- return createdHelp;
}
async getHelpByid(id) {
const Help = await this.HelpRepository.getById(id);
if (!Help) {
- throw new Error('Ajuda não encontrada');
+ throw new Error("Ajuda não encontrada");
}
return Help;
}
- async getHelpList(id, status, category, except, helper) {
- const Helplist = await this.HelpRepository.list(
- id,
- status,
- category,
- except,
- helper,
- );
- if (!Helplist) {
- throw new Error('Nenhuma Ajuda com esse status foi encontrada');
+
+ async getHelpWithAggregationById(id) {
+ const Help = await this.HelpRepository.getByIdWithAggregation(id);
+
+ if (!Help) {
+ throw new Error('Ajuda não encontrada');
}
- return Helplist;
+ return Help;
}
- async getNearHelpList(coords, except, id, categoryArray) {
- const Helplist = await this.HelpRepository.listNear(
+ async getHelpList(coords, id, isUserEntity, categoryArray) {
+ const Helplist = await this.HelpRepository.shortList(
coords,
- except,
id,
- categoryArray,
+ isUserEntity,
+ categoryArray
);
if (!Helplist) {
- throw new Error('Pedidos de ajuda não encontrados no seu raio de distância');
+ throw new Error(
+ "Pedidos de ajuda não encontrados no seu raio de distância"
+ );
}
return Helplist;
@@ -85,18 +83,22 @@ class HelpService {
help = JSON.parse(JSON.stringify(help));
const sendSocketMessageTo = findConnections(help.categoryId, JSON.parse(JSON.stringify(help.ownerId)));
sendMessage(sendSocketMessageTo, 'delete-help', id);
-
- return { message: `Help ${id} deleted!` };
}
async getHelpListByStatus({ userId, statusList, helper = false }) {
- const checkHelpStatusExistence = statusList.filter((item) => !Object.values(helpStatusEnum).includes(item));
+ const checkHelpStatusExistence = statusList.filter(
+ (item) => !Object.values(helpStatusEnum).includes(item)
+ );
if (checkHelpStatusExistence.length > 0) {
- throw new Error('Um dos status informados é ínvalido');
+ throw new Error("Um dos status informados é ínvalido");
}
- const helpList = await this.HelpRepository.getHelpListByStatus(userId, statusList, helper);
+ const helpList = await this.HelpRepository.getHelpListByStatus(
+ userId,
+ statusList,
+ helper
+ );
return helpList;
}
@@ -105,28 +107,38 @@ class HelpService {
const { idHelper } = data;
const help = await this.getHelpByid(data.idHelp);
const { ownerId } = help;
- const helper = await this.UserService.getUser({ id: idHelper });
+ let helper;
+ try {
+ helper = await this.UserService.getUser({ id: idHelper });
+ } catch {
+ helper = await this.EntityService.getEntity({ id: idHelper });
+ }
+
const owner = await this.UserService.getUser({ id: ownerId });
if (help.helperId) {
- throw new Error('Ajuda já possui ajudante');
+ throw new Error("Ajuda já possui ajudante");
}
const sendSocketMessageTo = findConnections(
help.categoryId,
- JSON.parse(JSON.stringify(ownerId)),
+ JSON.parse(JSON.stringify(ownerId))
);
- sendMessage(sendSocketMessageTo, 'delete-help', help._id);
+ sendMessage(sendSocketMessageTo, "delete-help", help._id);
const title = `${owner.name} aceitou sua oferta de ajuda!`;
const body = `Sua oferta para ${help.title} foi aceita`;
const userPosition = help.possibleHelpers.indexOf(data.idHelper);
- if (userPosition >= 0) {
+ const entityPosition = help.possibleEntities.indexOf(data.idHelper);
+ if (userPosition < 0 && entityPosition < 0) {
+ throw new Error('Ajudante não encontrado');
+ } else {
help.helperId = data.idHelper;
- help.status = 'on_going';
+ help.status = "on_going";
help.possibleHelpers = [];
- const result = await this.HelpRepository.update(help);
+ help.possibleEntities = [];
+ await this.HelpRepository.update(help);
const notificationHistory = {
userId: helper._id,
@@ -137,27 +149,32 @@ class HelpService {
};
try {
- this.NotificationService.createNotification(notificationHistory);
- this.NotificationMixin.sendNotification(helper.deviceId, title, body);
+ await this.NotificationService.createNotification(notificationHistory);
+ await this.NotificationMixin.sendNotification(
+ helper.deviceId,
+ title,
+ body
+ );
} catch (err) {
- console.log('Não foi possível enviar a notificação!');
+ console.log("Não foi possível enviar a notificação!");
saveError(err);
}
-
- return result;
}
- throw new Error('Ajudante não encontrado');
}
async helperConfirmation(data) {
const help = await this.getHelpByid(data.helpId);
const owner = await this.UserService.getUser({ id: help.ownerId });
- const helper = await this.UserService.getUser({ id: help.helperId });
-
+ let helper;
+ try {
+ helper = await this.UserService.getUser({ id: help.helperId });
+ } catch {
+ helper = await this.EntityService.getEntity({ id: help.helperId });
+ }
if (help.helperId != data.helperId) {
- throw new Error('Usuário não é o ajudante dessa ajuda');
- } else if (help.status === 'owner_finished') {
- const ownerTitle = 'Pedido de ajuda finalizado!';
+ throw new Error("Usuário não é o ajudante dessa ajuda");
+ } else if (help.status === "owner_finished") {
+ const ownerTitle = "Pedido de ajuda finalizado!";
const ownerBody = `Seu pedido ${help.title} foi finalizado`;
const ownerNotificationHistory = {
@@ -168,7 +185,7 @@ class HelpService {
notificationType: notificationTypesEnum.ajudaFinalizada,
};
- const helperTitle = 'Oferta de ajuda finalizada!';
+ const helperTitle = "Oferta de ajuda finalizada!";
const helperBody = `Sua oferta da ajuda ${help.title} foi finalizada`;
const helperNotificationHistory = {
userId: help.helperId,
@@ -179,38 +196,53 @@ class HelpService {
};
try {
- this.NotificationMixin.sendNotification(owner.deviceId, ownerTitle, ownerBody);
- this.NotificationService.createNotification(ownerNotificationHistory);
- this.NotificationMixin.sendNotification(helper.deviceId, helperTitle, helperBody);
- this.NotificationService.createNotification(helperNotificationHistory);
+ await this.NotificationMixin.sendNotification(
+ owner.deviceId,
+ ownerTitle,
+ ownerBody
+ );
+ await this.NotificationService.createNotification(
+ ownerNotificationHistory
+ );
+ await this.NotificationMixin.sendNotification(
+ helper.deviceId,
+ helperTitle,
+ helperBody
+ );
+ await this.NotificationService.createNotification(
+ helperNotificationHistory
+ );
} catch (err) {
- console.log('Não foi possível enviar a notificação!');
+ console.log("Não foi possível enviar a notificação!");
saveError(err);
}
- help.status = 'finished';
- } else if (help.status === 'helper_finished') {
- throw new Error('Usuário já confirmou a finalização da ajuda');
- } else if (help.status === 'finished') {
- throw new Error('Ajuda já foi finalizada');
+ help.status = "finished";
+ } else if (help.status === "helper_finished") {
+ throw new Error("Usuário já confirmou a finalização da ajuda");
+ } else if (help.status === "finished") {
+ throw new Error("Ajuda já foi finalizada");
} else {
- help.status = 'helper_finished';
+ help.status = "helper_finished";
}
- const result = await this.HelpRepository.update(help);
-
- return result;
+ await this.HelpRepository.update(help);
}
async ownerConfirmation(data) {
const help = await this.getHelpByid(data.helpId);
const owner = await this.UserService.getUser({ id: help.ownerId });
- const helper = await this.UserService.getUser({ id: help.helperId });
+ let helper;
+ try {
+ helper = await this.UserService.getUser({ id: help.helperId });
+ } catch {
+ helper = await this.EntityService.getEntity({ id: help.helperId });
+ }
if (help.ownerId != data.ownerId) {
- throw new Error('Usuário não é o dono da ajuda');
- } else if (help.status === 'helper_finished') {
- const ownerTitle = 'Pedido de ajuda finalizado!';
+ throw new Error("Usuário não é o dono da ajuda");
+ } else if (help.status === "helper_finished") {
+ const ownerTitle = "Pedido de ajuda finalizado!";
const ownerBody = `Seu pedido ${help.title} foi finalizado`;
const ownerNotificationHistory = {
@@ -221,7 +253,7 @@ class HelpService {
notificationType: notificationTypesEnum.ajudaFinalizada,
};
- const helperTitle = 'Oferta de ajuda finalizada!';
+ const helperTitle = "Oferta de ajuda finalizada!";
const helperBody = `Sua oferta da ajuda ${help.title} foi finalizada`;
const helperNotificationHistory = {
userId: help.helperId,
@@ -232,49 +264,75 @@ class HelpService {
};
try {
- this.NotificationMixin.sendNotification(owner.deviceId, ownerTitle, ownerBody);
- this.NotificationService.createNotification(ownerNotificationHistory);
- this.NotificationMixin.sendNotification(helper.deviceId, helperTitle, helperBody);
- this.NotificationService.createNotification(helperNotificationHistory);
+ await this.NotificationMixin.sendNotification(
+ owner.deviceId,
+ ownerTitle,
+ ownerBody
+ );
+ await this.NotificationService.createNotification(
+ ownerNotificationHistory
+ );
+ await this.NotificationMixin.sendNotification(
+ helper.deviceId,
+ helperTitle,
+ helperBody
+ );
+ await this.NotificationService.createNotification(
+ helperNotificationHistory
+ );
} catch (err) {
- console.log('Não foi possível enviar a notificação!');
+ console.log("Não foi possível enviar a notificação!");
saveError(err);
}
- help.status = 'finished';
- } else if (help.status === 'owner_finished') {
- throw new Error('Usuário já confirmou a finalização da ajuda');
- } else if (help.status === 'finished') {
- throw new Error('Essa ajuda já foi finalizada');
+ help.status = "finished";
+ } else if (help.status === "owner_finished") {
+ throw new Error("Usuário já confirmou a finalização da ajuda");
+ } else if (help.status === "finished") {
+ throw new Error("Essa ajuda já foi finalizada");
} else {
- help.status = 'owner_finished';
+ help.status = "owner_finished";
}
- const result = await this.HelpRepository.update(help);
- return result;
+ await this.HelpRepository.update(help);
}
async addPossibleHelpers(id, idHelper) {
const help = await this.getHelpByid(id);
const owner = await this.UserService.getUser({ id: help.ownerId });
-
if (idHelper == help.ownerId) {
- throw new Error('Você não pode ser ajudante de sua própria ajuda');
+ throw new Error("Você não pode ser ajudante de sua própria ajuda");
}
if (help.helperId) {
- throw new Error('Ajuda já possui ajudante');
+ throw new Error("Ajuda já possui ajudante");
+ }
+ let helper;
+ let isUser = false;
+ try {
+ helper = await this.UserService.getUser({ id: idHelper });
+ isUser = true;
+ } catch {
+ helper = await this.EntityService.getEntity({ id: idHelper });
}
+ if (isUser) {
+ const userPosition = help.possibleHelpers.indexOf(idHelper);
- const helper = await this.UserService.getUser({ id: idHelper });
- const userPosition = help.possibleHelpers.indexOf(idHelper);
+ if (userPosition > -1) {
+ throw new Error("Usuário já é um possível ajudante");
+ }
- if (userPosition > -1) {
- throw new Error('Usuário já é um possível ajudante');
- }
+ help.possibleHelpers.push(idHelper);
+ } else {
+ const userPosition = help.possibleEntities.indexOf(idHelper);
- help.possibleHelpers.push(idHelper);
+ if (userPosition > -1) {
+ throw new Error("Usuário já é um possível ajudante");
+ }
- const result = await this.HelpRepository.update(help);
+ help.possibleEntities.push(idHelper);
+ }
+
+ await this.HelpRepository.update(help);
const title = `${helper.name} quer te ajudar!`;
const body = `Seu pedido ${help.title} recebeu uma oferta de ajuda`;
@@ -288,24 +346,34 @@ class HelpService {
};
try {
- this.NotificationMixin.sendNotification(owner.deviceId, title, body);
- this.NotificationService.createNotification(notificationHistory);
+ await this.NotificationMixin.sendNotification(
+ owner.deviceId,
+ title,
+ body
+ );
+ await this.NotificationService.createNotification(notificationHistory);
} catch (err) {
- console.log('Não foi possível enviar a notificação!');
+ console.log("Não foi possível enviar a notificação!");
saveError(err);
}
-
- return result;
}
async getListToDelete() {
const Helplist = await this.HelpRepository.listToExpire();
if (!Helplist) {
- throw new Error('Pedidos de ajuda não encontrados');
+ throw new Error("Pedidos de ajuda não encontrados");
}
return Helplist;
}
+
+ async getHelpInfoById(helpId) {
+ const helpInfo = await this.HelpRepository.getHelpInfoById(helpId);
+ if (!helpInfo) {
+ throw new Error('Pedido de ajuda não encontrado');
+ }
+ return helpInfo;
+ }
}
module.exports = HelpService;
diff --git a/src/services/NotificationService.js b/src/services/NotificationService.js
index f8bccb56..30f5e144 100644
--- a/src/services/NotificationService.js
+++ b/src/services/NotificationService.js
@@ -1,4 +1,7 @@
+const { notificationTypesEnum } = require('../models/Notification');
const NotificationRepository = require('../repository/NotificationRepository');
+const notify = require('../utils/Notification');
+const UserService = require('./UserService');
class NotificationService {
constructor() {
@@ -16,6 +19,38 @@ class NotificationService {
return notificationCreated;
}
+
+ async createAndSendNotifications(title, body) {
+ const userService = new UserService();
+ const users = await userService.getUsersWithDevice();
+
+ const messages = [];
+ const notifications = [];
+ users.forEach((user) => {
+ messages.push({
+ to: user.deviceId,
+ sound: 'default',
+ title,
+ body,
+ });
+ notifications.push({
+ userId: user._id,
+ title,
+ body,
+ notificationType: notificationTypesEnum.notificacaoManual,
+ });
+ });
+
+ try {
+ notify(messages);
+
+ notifications.forEach(async (notification) => {
+ await this.createNotification(notification);
+ });
+ } catch (err) {
+ throw new Error(err);
+ }
+ }
}
module.exports = NotificationService;
diff --git a/src/services/UserService.js b/src/services/UserService.js
index f6d37b52..caff3905 100644
--- a/src/services/UserService.js
+++ b/src/services/UserService.js
@@ -1,33 +1,44 @@
-const UserRepository = require('../repository/UserRepository');
-const firebase = require('../config/authFirebase');
+const UserRepository = require("../repository/UserRepository");
+const EntityRepository = require("../repository/EntityRepository");
+const firebase = require("../config/authFirebase");
+const { ObjectID } = require("mongodb");
class UserService {
constructor() {
this.userRepository = new UserRepository();
+ this.entityRepository = new EntityRepository();
}
async createUser(data) {
+ const isEntityRegistered = await this.entityRepository.checkEntityExistence(
+ data.email
+ );
+
+ if (isEntityRegistered) {
+ throw new Error("Email já sendo utilizado");
+ }
+
if (data.password.length < 8) {
- throw new Error('Senha inválida');
+ throw new Error("Senha inválida");
}
if (data.cpf.length >= 11) {
- data.cpf = data.cpf.replace(/[-.]/g, '');
+ data.cpf = data.cpf.replace(/[-.]/g, "");
}
+
data.email = data.email.toLowerCase();
try {
const createdUser = await this.userRepository.create(data);
if (!data.hasUser) {
- console.log('Usuario Criado');
// Cria o usuário no firebase
await firebase
.auth()
.createUser({
email: data.email,
password: data.password,
- displayName: data.name,
- emailVerified: false
+ displayName: `${data.name} | PF`,
+ emailVerified: false,
})
.catch(async (err) => {
await this.removeUser(data.email);
@@ -39,13 +50,20 @@ class UserService {
} catch (err) {
throw err;
}
+ }
- return createdUser;
+ async getUsersWithDevice() {
+ try {
+ const users = await this.userRepository.getUsersWithDevice();
+ return users;
+ } catch (err) {
+ throw err;
+ }
}
async getUser({ id = undefined, email = undefined }) {
if (!id && !email) {
- throw new Error('Nenhum identificador encontrado');
+ throw new Error("Nenhum identificador encontrado");
}
let user;
@@ -55,7 +73,23 @@ class UserService {
user = await this.userRepository.getUserByEmail(email);
}
if (!user) {
- throw new Error('Usuário não encontrado');
+ throw new Error("Usuário não encontrado");
+ }
+ return user;
+ }
+
+ async getAnyUser({ id = undefined, email = undefined }) {
+ if (!id && !email) {
+ throw new Error("Nenhum identificador encontrado");
+ }
+ let user;
+
+ if (id) {
+ user = await this.userRepository.getById(id);
+ if (!user) user = await this.entityRepository.getById(id);
+ }
+ if (!user) {
+ throw new Error("Usuário não encontrado");
}
return user;
}
@@ -81,9 +115,7 @@ class UserService {
return result;
}
- async editUserAddressById({
- email, cep, number, city, state, complement,
- }) {
+ async editUserAddressById({ email, cep, number, city, state, complement }) {
const user = await this.getUser({ email });
const address = {
@@ -129,8 +161,8 @@ class UserService {
await this.userRepository.removeUser({ id: user._id, email });
}
- async checkUserExistence(identificator) {
- const result = await this.userRepository.checkUserExistence(identificator);
+ async checkUserExistence(userIdentifier) {
+ const result = await this.userRepository.checkUserExistence(userIdentifier);
if (result) {
return true;
@@ -138,6 +170,14 @@ class UserService {
return false;
}
+
+ async findOneUserWithProjection(userId,projection){
+ const query = { _id: ObjectID(userId) };
+
+ const user = await this.userRepository.findOneUserWithProjection(query,projection);
+
+ return user;
+ }
}
module.exports = UserService;
diff --git a/src/utils/IsEntity.js b/src/utils/IsEntity.js
new file mode 100644
index 00000000..cd4a1ea9
--- /dev/null
+++ b/src/utils/IsEntity.js
@@ -0,0 +1,13 @@
+const isEntity = (userName) =>
+{
+ let userType = userName.trim().split(' ');
+ userType = userType.pop();
+
+ if (userType == 'PJ'){
+ return true;
+ } else {
+ return false;
+ }
+}
+
+module.exports = isEntity;
\ No newline at end of file
diff --git a/src/utils/seed/HelpSeed.js b/src/utils/seed/HelpSeed.js
index fc201642..ca00d91f 100644
--- a/src/utils/seed/HelpSeed.js
+++ b/src/utils/seed/HelpSeed.js
@@ -44,7 +44,7 @@ const seedHelp = async () => {
description: faker.lorem.lines(1),
status: sampleStatus,
possibleHelpers: samplePossibleHelpsID,
- categoryId: sampleCategory._id,
+ categoryId: [sampleCategory._id],
ownerId: sampleUsers[0]._id,
finishedDate: faker.date.future(),
}),
diff --git a/src/utils/sharedAggregationInfo.js b/src/utils/sharedAggregationInfo.js
new file mode 100644
index 00000000..1c0b5322
--- /dev/null
+++ b/src/utils/sharedAggregationInfo.js
@@ -0,0 +1,49 @@
+const sharedAgreggationInfo = [
+ {
+ $lookup: {
+ from: 'user',
+ localField: 'ownerId',
+ foreignField: '_id',
+ as: 'user',
+ },
+ },
+ {
+ $lookup: {
+ from: 'categories',
+ localField: 'categoryId',
+ foreignField: '_id',
+ as: 'categories',
+ },
+ },
+ {
+ $unwind: {
+ path: '$user',
+ preserveNullAndEmptyArrays: false,
+ },
+ },
+ {
+ $project: {
+ _id: 1,
+ description: 1,
+ title: 1,
+ status: 1,
+ ownerId: 1,
+ user: {
+ photo: 1,
+ phone: 1,
+ name: 1,
+ birthday: 1,
+ address: {
+ city: 1,
+ },
+ },
+ categories: {
+ _id: 1,
+ name: 1,
+ },
+ },
+ },
+
+]
+
+module.exports = sharedAgreggationInfo;
\ No newline at end of file
diff --git a/src/validation/middlewares/authFirebase.js b/src/validation/middlewares/authFirebase.js
index 85fd9988..922379ca 100644
--- a/src/validation/middlewares/authFirebase.js
+++ b/src/validation/middlewares/authFirebase.js
@@ -1,5 +1,6 @@
const admin = require('../../config/authFirebase');
const saveError = require('../../utils/ErrorHistory');
+const isEntity = require('../../utils/IsEntity');
const isAuthenticated = async (req, res, next) => {
if (req.headers.authorization
@@ -9,7 +10,11 @@ const isAuthenticated = async (req, res, next) => {
try {
const idToken = await admin.auth().verifyIdToken(token);
+
req.decodedToken = idToken;
+
+ global.isUserEntity = isEntity(req.decodedToken.name);
+
return next();
} catch (err) {
saveError(err);
@@ -21,4 +26,5 @@ const isAuthenticated = async (req, res, next) => {
return res.status(403).json({ error: err.message });
};
+
module.exports = isAuthenticated;
diff --git a/websocket.js b/websocket.js
index a7e14129..0cbe5a35 100644
--- a/websocket.js
+++ b/websocket.js
@@ -8,12 +8,11 @@ exports.setupWebsocket = (server) => {
io = socketio(server);
io.on('connection', (socket) => {
- const { currentRegion, userId } = socket.handshake.query;
-
+ const { userPosition, userId } = socket.handshake.query;
connections.push({
id: socket.id,
userId,
- currentRegion,
+ userPosition,
categories: [],
});
@@ -59,7 +58,7 @@ exports.findConnections = (category, userId) => {
exports.sendMessage = (to, message, data) => {
to.forEach((connection) => {
if (typeof (data) === 'object' && message == 'new-help') {
- const userLocation = JSON.parse(connection.currentRegion);
+ const userLocation = JSON.parse(connection.userPosition);
const helpLocation = {
latitude: data.user.location.coordinates[1],
longitude: data.user.location.coordinates[0],
diff --git a/yarn.lock b/yarn.lock
index 75ab4c1d..f502b2db 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -203,7 +203,7 @@
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
- integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
+ integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
"@protobufjs/base64@^1.1.2":
version "1.1.2"
@@ -218,12 +218,12 @@
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
- integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
+ integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
- integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
+ integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
@@ -231,27 +231,27 @@
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
- integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
+ integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
- integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
+ integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
- integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
+ integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
- integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
+ integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
- integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
+ integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@sentry/apm@5.18.0":
version "5.18.0"
@@ -367,19 +367,14 @@
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/long@^4.0.0", "@types/long@^4.0.1":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
- integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
-
-"@types/node@*":
- version "14.0.13"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9"
- integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
+ integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
-"@types/node@^13.7.0":
- version "13.13.12"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.12.tgz#9c72e865380a7dc99999ea0ef20fc9635b503d20"
- integrity sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw==
+"@types/node@*", "@types/node@>=13.7.0":
+ version "17.0.38"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947"
+ integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==
"@types/node@^8.10.59":
version "8.10.61"
@@ -434,9 +429,9 @@ agent-base@6:
debug "4"
ajv@^6.10.0, ajv@^6.10.2:
- version "6.12.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
- integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
@@ -562,11 +557,6 @@ astral-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
-
available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
@@ -599,20 +589,13 @@ base64id@2.0.0:
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
-bcrypt@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-4.0.1.tgz#06e21e749a061020e4ff1283c1faa93187ac57fe"
- integrity sha512-hSIZHkUxIDS5zA2o00Kf2O5RfVbQ888n54xQoF/eIaquU4uaLxK8vhhBdktd0B3n2MjkcAWzv4mnhogykBKOUQ==
- dependencies:
- node-addon-api "^2.0.0"
- node-pre-gyp "0.14.0"
-
-better-assert@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
- integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
+bcrypt@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.0.tgz#051407c7cd5ffbfb773d541ca3760ea0754e37e2"
+ integrity sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==
dependencies:
- callsite "1.0.0"
+ node-addon-api "^3.0.0"
+ node-pre-gyp "0.15.0"
bignumber.js@^9.0.0:
version "9.0.0"
@@ -625,9 +608,9 @@ binary-extensions@^2.0.0:
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
bl@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
- integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5"
+ integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==
dependencies:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
@@ -720,11 +703,6 @@ cacheable-request@^6.0.0:
normalize-url "^4.1.0"
responselike "^1.0.2"
-callsite@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
- integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
-
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -735,7 +713,7 @@ camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-chalk@^2.0.0, chalk@^2.1.0:
+chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -772,7 +750,7 @@ chokidar@^3.2.2:
optionalDependencies:
fsevents "~2.1.2"
-chownr@^1.1.1:
+chownr@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
@@ -921,16 +899,21 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-cookie@0.3.1, cookie@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
- integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
-
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookie@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+ integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+
+cookie@~0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
+ integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
+
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -1089,6 +1072,14 @@ dicer@^0.3.0:
dependencies:
streamsearch "0.1.2"
+did-you-mean@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/did-you-mean/-/did-you-mean-0.0.1.tgz#8851ce82407903cb62c12cb6ad4f676921ccdec3"
+ integrity sha1-iFHOgkB5A8tiwSy2rU9naSHM3sM=
+ dependencies:
+ levenshtein "*"
+ underscore "*"
+
doctrine@1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
@@ -1175,20 +1166,20 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
-engine.io-client@~3.4.0:
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.3.tgz#192d09865403e3097e3575ebfeb3861c4d01a66c"
- integrity sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==
+engine.io-client@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.5.0.tgz#fc1b4d9616288ce4f2daf06dcf612413dec941c7"
+ integrity sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==
dependencies:
component-emitter "~1.3.0"
component-inherit "0.0.3"
- debug "~4.1.0"
+ debug "~3.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
- parseqs "0.0.5"
- parseuri "0.0.5"
- ws "~6.1.0"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
+ ws "~7.4.2"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
@@ -1203,17 +1194,17 @@ engine.io-parser@~2.2.0:
blob "0.0.5"
has-binary2 "~1.0.2"
-engine.io@~3.4.0:
- version "3.4.2"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.2.tgz#8fc84ee00388e3e228645e0a7d3dfaeed5bd122c"
- integrity sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==
+engine.io@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
+ integrity sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==
dependencies:
accepts "~1.3.4"
base64id "2.0.0"
- cookie "0.3.1"
+ cookie "~0.4.1"
debug "~4.1.0"
engine.io-parser "~2.2.0"
- ws "^7.1.2"
+ ws "~7.4.2"
ent@^2.2.0:
version "2.2.0"
@@ -1615,7 +1606,7 @@ fresh@0.5.2:
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-fs-minipass@^1.2.5:
+fs-minipass@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
@@ -1712,10 +1703,18 @@ get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
+git-commit-msg-linter@^3.2.6:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/git-commit-msg-linter/-/git-commit-msg-linter-3.2.6.tgz#e2894fc21d3b69635433e1c5b161e25e6b6068d1"
+ integrity sha512-u9LolsJjHFLm12FWCnZhrhMJmHzDBP4Uz31F+OLpTSGvZW9ms6/+0hscJA9nisFU0HK0tJJ991ISomc5ajoO6A==
+ dependencies:
+ chalk "^2.4.2"
+ did-you-mean "^0.0.1"
+
glob-parent@^5.0.0, glob-parent@~5.1.0:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
- integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
@@ -1872,9 +1871,9 @@ hash-stream-validation@^0.2.2:
through2 "^2.0.0"
hosted-git-info@^2.1.4:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
- integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
http-cache-semantics@^4.0.0:
version "4.1.0"
@@ -2340,6 +2339,11 @@ latest-version@^5.0.0:
dependencies:
package-json "^6.3.0"
+levenshtein@*:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/levenshtein/-/levenshtein-1.0.5.tgz#3911737a9cb56da345d008f55782c6f138979ba3"
+ integrity sha1-ORFzepy1baNF0Aj1V4LG8TiXm6M=
+
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@@ -2416,10 +2420,10 @@ lodash.once@^4.0.0:
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
-lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19:
- version "4.17.19"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
- integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
+lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
long-timeout@0.1.1:
version "0.1.1"
@@ -2520,11 +2524,11 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
+minipass@^2.6.0, minipass@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
@@ -2532,14 +2536,14 @@ minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
safe-buffer "^5.1.2"
yallist "^3.0.0"
-minizlib@^1.2.1:
+minizlib@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
dependencies:
minipass "^2.9.0"
-mkdirp@^0.5.0, mkdirp@^0.5.1:
+mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@@ -2634,7 +2638,7 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-needle@^2.2.1:
+needle@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.0.tgz#e6fc4b3cc6c25caed7554bd613a5cf0bac8c31c0"
integrity sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==
@@ -2653,15 +2657,17 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-node-addon-api@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.1.tgz#4fd0931bf6d7e48b219ff3e6abc73cbb0252b7a3"
- integrity sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==
+node-addon-api@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.0.tgz#812446a1001a54f71663bed188314bba07e09247"
+ integrity sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==
node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.6.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
- integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+ version "2.6.7"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
+ integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
+ dependencies:
+ whatwg-url "^5.0.0"
node-forge@0.7.4:
version "0.7.4"
@@ -2673,14 +2679,14 @@ node-forge@^0.9.0:
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5"
integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==
-node-pre-gyp@0.14.0:
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
- integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==
+node-pre-gyp@0.15.0:
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz#c2fc383276b74c7ffa842925241553e8b40f1087"
+ integrity sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==
dependencies:
detect-libc "^1.0.2"
- mkdirp "^0.5.1"
- needle "^2.2.1"
+ mkdirp "^0.5.3"
+ needle "^2.5.0"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
@@ -2745,9 +2751,9 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-url@^4.1.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
- integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
+ integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
npm-bundled@^1.0.1:
version "1.1.1"
@@ -2790,11 +2796,6 @@ object-assign@^4, object-assign@^4.1.0:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-object-component@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
- integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
-
object-inspect@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
@@ -2953,19 +2954,15 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
-parseqs@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
- integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
- dependencies:
- better-assert "~1.0.0"
+parseqs@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5"
+ integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==
-parseuri@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
- integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
- dependencies:
- better-assert "~1.0.0"
+parseuri@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
+ integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
parseurl@~1.3.3:
version "1.3.3"
@@ -2988,9 +2985,9 @@ path-key@^2.0.1:
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-to-regexp@0.1.7:
version "0.1.7"
@@ -3047,9 +3044,9 @@ promise-limit@^2.7.0:
integrity sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==
protobufjs@^6.8.6, protobufjs@^6.8.9:
- version "6.9.0"
- resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.9.0.tgz#c08b2bf636682598e6fabbf0edb0b1256ff090bd"
- integrity sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==
+ version "6.11.3"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
+ integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
@@ -3062,7 +3059,7 @@ protobufjs@^6.8.6, protobufjs@^6.8.9:
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/long" "^4.0.1"
- "@types/node" "^13.7.0"
+ "@types/node" ">=13.7.0"
long "^4.0.0"
proxy-addr@~2.0.5:
@@ -3294,7 +3291,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -3426,32 +3423,29 @@ socket.io-adapter@~1.1.0:
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
-socket.io-client@2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
- integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+socket.io-client@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
+ integrity sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==
dependencies:
backo2 "1.0.2"
- base64-arraybuffer "0.1.5"
component-bind "1.0.0"
- component-emitter "1.2.1"
- debug "~4.1.0"
- engine.io-client "~3.4.0"
+ component-emitter "~1.3.0"
+ debug "~3.1.0"
+ engine.io-client "~3.5.0"
has-binary2 "~1.0.2"
- has-cors "1.1.0"
indexof "0.0.1"
- object-component "0.0.3"
- parseqs "0.0.5"
- parseuri "0.0.5"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
- integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
+ integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
dependencies:
- component-emitter "1.2.1"
+ component-emitter "~1.3.0"
debug "~3.1.0"
isarray "2.0.1"
@@ -3464,16 +3458,16 @@ socket.io-parser@~3.4.0:
debug "~4.1.0"
isarray "2.0.1"
-socket.io@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
- integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+socket.io@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.0.tgz#01030a2727bd8eb2e85ea96d69f03692ee53d47e"
+ integrity sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ==
dependencies:
debug "~4.1.0"
- engine.io "~3.4.0"
+ engine.io "~3.5.0"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
- socket.io-client "2.3.0"
+ socket.io-client "2.4.0"
socket.io-parser "~3.4.0"
sorted-array-functions@^1.0.0:
@@ -3691,17 +3685,17 @@ table@^5.2.3:
string-width "^3.0.0"
tar@^4.4.2:
- version "4.4.13"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
- integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
- dependencies:
- chownr "^1.1.1"
- fs-minipass "^1.2.5"
- minipass "^2.8.6"
- minizlib "^1.2.1"
- mkdirp "^0.5.0"
- safe-buffer "^5.1.2"
- yallist "^3.0.3"
+ version "4.4.19"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
+ integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==
+ dependencies:
+ chownr "^1.1.4"
+ fs-minipass "^1.2.7"
+ minipass "^2.9.0"
+ minizlib "^1.3.3"
+ mkdirp "^0.5.5"
+ safe-buffer "^5.2.1"
+ yallist "^3.1.1"
teeny-request@^6.0.0:
version "6.0.3"
@@ -3780,6 +3774,11 @@ touch@^3.1.0:
dependencies:
nopt "~1.0.10"
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
tsconfig-paths@^3.9.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
@@ -3839,6 +3838,11 @@ undefsafe@^2.0.2:
dependencies:
debug "^2.2.0"
+underscore@*:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1"
+ integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==
+
unique-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
@@ -3871,9 +3875,9 @@ update-notifier@^4.0.0:
xdg-basedir "^4.0.0"
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
@@ -3922,6 +3926,11 @@ walkdir@^0.4.0:
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39"
integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
websocket-driver@>=0.5.1:
version "0.7.4"
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"
@@ -3936,6 +3945,14 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
which-boxed-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1"
@@ -4017,17 +4034,10 @@ write@1.0.3:
dependencies:
mkdirp "^0.5.1"
-ws@^7.1.2:
- version "7.3.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd"
- integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==
-
-ws@~6.1.0:
- version "6.1.4"
- resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
- integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
- dependencies:
- async-limiter "~1.0.0"
+ws@~7.4.2:
+ version "7.4.6"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
+ integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
xdg-basedir@^4.0.0:
version "4.0.0"
@@ -4044,7 +4054,7 @@ xtend@^4.0.1, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
+yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==