Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server
1 result
Show changes
Commits on Source (12)
Showing
with 148 additions and 158 deletions
......@@ -36,7 +36,6 @@ build_branch:
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
stage: build
only:
- dev
- merge_requests
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
......
......@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [2.2.0](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v2.1.3...v2.2.0) (2023-03-30)
### Features
* **structure:** disable aptic api ([#271](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/issues/271)) ([65a5ee5](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/65a5ee5ff3c1b13194d9af721f08874b47f1ca5b))
### Bug Fixes
* **newsletter:** add message for fake email ([3338103](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/33381037bed271fafe66618ca48412606dda3cc5))
* **newsletter:** subscription of unsubscribed email bug ([3b76a5d](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/3b76a5d80011765c43ce04352d4745efe4361bfa))
* **structure:** avoid date update in CTM script ([7e3f686](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/7e3f686121fca7a32a67c3267771d3b855b8a016))
* **structure:** delete structure by admin ([a69939f](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/a69939f8528bf9b0e3d002141424d90ad7ce7e0c))
### [2.1.3](https://forge.grandlyon.com/web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v2.1.2...v2.1.3) (2023-03-02)
......
......@@ -28,6 +28,9 @@ services:
ELASTICSEARCH_NODE: ${ELASTICSEARCH_NODE}
ELASTICSEARCH_USERNAME: ${ELASTICSEARCH_USERNAME}
ELASTICSEARCH_PASSWORD: ${ELASTICSEARCH_PASSWORD}
MC_API_KEY: ${MC_API_KEY}
MC_SERVER: ${MC_SERVER}
MC_LIST_ID: ${MC_LIST_ID}
restart: unless-stopped
networks:
- backend
......
{
"name": "ram_server",
"version": "2.1.3",
"version": "2.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "ram_server",
"private": true,
"version": "2.1.3",
"version": "2.2.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
......
......@@ -5,7 +5,7 @@ module.exports = {
data: [
{
_id: mongoose.Types.ObjectId('6001a35f16b08100062e415f'),
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-16T15:37:00.000Z',
updatedAt: '2021-03-02T12:36:53.000Z',
structureName: "Maison de l'Emploi (Feyzin)",
......@@ -164,7 +164,7 @@ module.exports = {
handicaps: ['physicalDisability'],
publicOthers: ['uniquementFemmes'],
},
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-16T10:19:00.000Z',
updatedAt: '2020-12-16T10:19:00.000Z',
structureName: 'Pôle emploi (Vénissieux)',
......@@ -270,7 +270,7 @@ module.exports = {
},
{
_id: mongoose.Types.ObjectId('6001a38516b08100062e4161'),
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-16T14:15:00.000Z',
updatedAt: '2021-04-27T14:19:17.000Z',
structureName: 'Centre social Quartier Vitalité',
......@@ -371,7 +371,7 @@ module.exports = {
handicaps: ['physicalDisability'],
publicOthers: ['uniquementFemmes'],
},
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-16T09:30:00.000Z',
updatedAt: '2021-04-12T08:48:00.000Z',
structureName: "L'Atelier Numérique",
......@@ -514,7 +514,7 @@ module.exports = {
handicaps: ['physicalDisability'],
publicOthers: ['uniquementFemmes'],
},
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-16T08:53:00.000Z',
updatedAt: '2021-04-27T17:06:46.000Z',
structureName: 'Cyber-base / MJC Louis Aragon',
......@@ -618,7 +618,7 @@ module.exports = {
handicaps: ['physicalDisability'],
publicOthers: ['uniquementFemmes'],
},
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-04T09:27:00.000Z',
updatedAt: '2021-03-02T10:07:48.000Z',
structureName: 'Oasis Informatique',
......@@ -730,7 +730,7 @@ module.exports = {
handicaps: ['physicalDisability'],
publicOthers: ['uniquementFemmes'],
},
freeWorkShop: false,
freeWorkShop: 'Non',
createdAt: '2020-11-13T14:13:00.000Z',
updatedAt: '2021-03-02T10:09:30.000Z',
structureName: 'Le Son du Clic',
......@@ -848,7 +848,7 @@ module.exports = {
pmrAccess: false,
remoteAccompaniment: false,
accountVerified: true,
freeWorkShop: false,
freeWorkShop: 'Non',
nbComputers: 0,
nbPrinters: 0,
nbScanners: 0,
......@@ -917,7 +917,7 @@ module.exports = {
pmrAccess: false,
remoteAccompaniment: false,
accountVerified: true,
freeWorkShop: false,
freeWorkShop: 'Non',
nbComputers: 0,
nbPrinters: 0,
nbScanners: 0,
......
......@@ -328,26 +328,6 @@ describe('AdminController', () => {
});
});
describe('Search user newsletter subscription', () => {
it('should return all subscribed users, empty string', async () => {
expect((await controller.getNewsletterSubscriptions({ searchString: '' })).length).toBe(3);
});
it('should return all subscribed users, null input', async () => {
expect((await controller.getNewsletterSubscriptions({ searchString: null })).length).toBe(3);
});
it('should find one user', async () => {
expect((await controller.getNewsletterSubscriptions({ searchString: 'a@a.com' })).length).toBe(1);
expect((await controller.getNewsletterSubscriptions({ searchString: 'a@a.com' }))[0].email).toBe('a@a.com');
});
it('should find no user', async () => {
expect((await controller.getNewsletterSubscriptions({ searchString: 'adgdgsdg@a.com' })).length).toBe(0);
});
});
it('should count user subscribed to newsletter', async () => {
expect(await controller.countNewsletterSubscriptions()).toBe(246);
});
describe('Search delete a user subscription', () => {
it('should return a deleted object', async () => {
expect((await controller.unsubscribeUserFromNewsletter('a@a.com')).email).toBe('a@a.com');
......
......@@ -251,24 +251,6 @@ export class AdminController {
});
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth('JWT')
@Post('searchNewsletterSubscriptions')
public async getNewsletterSubscriptions(@Body() searchString: { searchString: string }) {
if (searchString && searchString.searchString && searchString.searchString.length > 0)
return this.newsletterService.searchNewsletterSubscription(searchString.searchString);
else return this.newsletterService.findAll();
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth('JWT')
@Get('countNewsletterSubscriptions')
public async countNewsletterSubscriptions(): Promise<number> {
return this.newsletterService.countNewsletterSubscriptions();
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth('JWT')
......
import { Db } from 'mongodb';
import { StructureDocument } from '../../structures/schemas/structure.schema';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
const cursor = db.collection('structures').find({});
let document;
while ((document = await cursor.next())) {
const newDoc: StructureDocument = removeUnknownContactMail(document);
await db.collection('structures').updateOne({ _id: document._id }, [{ $set: newDoc }]);
}
console.log('Update done: Contact emails unknown@unknown.com emptied');
};
export const down = async () => {
// Nothing can be done since we can't know which null contactMail fields were previously filled with unknow@unknown.com
console.log('Downgrade done');
};
function removeUnknownContactMail(doc: StructureDocument): StructureDocument {
if (doc.contactMail && doc.contactMail === 'unknown@unknown.com') {
doc.contactMail = null;
}
return doc;
}
......@@ -51,24 +51,21 @@ describe('NewsletterService', () => {
});
describe('newsletterSubscribe', () => {
it('it should not add subscription for email test2@test.com : already exist', async () => {
const result = { email: 'test2@test.com' } as INewsletterSubscription;
it('it should add subscription for email test2@test.com even if it exists', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription;
mailchimp.lists.setListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
try {
await service.newsletterSubscribe('test2@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Email already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => _doc);
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
const subscription = await service.newsletterSubscribe('test2@test.com');
expect(subscription).toEqual(_doc);
});
it('it should add a subscription for email test2@test.com', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const result = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
mailchimp.lists.setListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
......@@ -76,12 +73,12 @@ describe('NewsletterService', () => {
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
const subscription = await service.newsletterSubscribe('test2@test.com');
expect(subscription).toEqual({ email: 'test2@test.com' });
expect(subscription).toEqual(_doc);
});
it('it should return mailchimp 400 issue', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
it('it should return error if mailchimp 400 issue', async () => {
const result = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockRejectedValueOnce({ status: 400 });
mailchimp.lists.setListMember.mockRejectedValueOnce({ status: 400 });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
......@@ -92,14 +89,14 @@ describe('NewsletterService', () => {
await service.newsletterSubscribe('test2@test.com');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Email already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
expect(e.message).toBe('Subscribe error');
expect(e.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
}
});
it('it should return mailchimp 500 issue', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
it('it should return error if mailchimp 500 issue', async () => {
const result = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockRejectedValueOnce({ status: 500 });
mailchimp.lists.setListMember.mockRejectedValueOnce({ status: 500 });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
......@@ -110,28 +107,27 @@ describe('NewsletterService', () => {
await service.newsletterSubscribe('test2@test.com');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Server error');
expect(e.message).toBe('Subscribe error');
expect(e.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
}
});
});
describe('newsletterUnsubscribe', () => {
it('it should not remove subscription for email test@test.com : does not exist', async () => {
const result: INewsletterSubscription = undefined;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
mailchimp.lists.getListMember.mockRejectedValueOnce({ status: 404 });
try {
await service.newsletterUnsubscribe('test@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Invalid email');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
expect(e.message).toEqual('Email not found');
expect(e.status).toEqual(HttpStatus.NOT_FOUND);
}
});
it('it should remove a subscription for email test2@test.com', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.getListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
mailchimp.lists.setListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
const result = {
email: 'test2@test.com',
deleteOne: async () => _doc,
......@@ -145,15 +141,6 @@ describe('NewsletterService', () => {
});
});
describe('countNewsletterSubscriptions', () => {
it('it should count subscriptions', async () => {
mockNewsletterModel.countDocuments.mockResolvedValueOnce(69);
const count = await service.countNewsletterSubscriptions();
expect(count).toEqual(69);
});
});
describe('findOne', () => {
it('it should not find a subscription with email test@test.com', async () => {
mockNewsletterModel.findOne.mockResolvedValueOnce(undefined);
......@@ -175,18 +162,6 @@ describe('NewsletterService', () => {
expect(findOneEmail).toEqual(_docs);
});
});
describe('searchNewsletterSubscription', () => {
it('it should find 2 search result', async () => {
const _docs = [
{ _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription,
{ _id: 'bbbbb', email: 'test@test.com' } as INewsletterSubscription,
];
mockNewsletterModel.find.mockResolvedValueOnce(_docs);
const findOneEmail = await service.searchNewsletterSubscription('test');
expect(findOneEmail.length).toBe(2);
});
});
describe('updateNewsletterSubscription', () => {
it('should update existing user subscription', () => {
mailchimp.lists.getListMembersInfo.mockResolvedValueOnce({ total_items: 10 }).mockResolvedValueOnce({
......@@ -198,10 +173,9 @@ describe('NewsletterService', () => {
});
const result = { email: 'test2@test.com' } as INewsletterSubscription;
const spyer = jest.spyOn(mockNewsletterModel, 'findOne');
// jest.spyOn(service, 'findOne').mockResolvedValueOnce(result).mockResolvedValueOnce(result);
mockNewsletterModel.findOne.mockResolvedValueOnce(result).mockResolvedValueOnce(null);
service.updateNewsletterSubscription();
expect(spyer).toBeCalledTimes(2);
expect(spyer).toBeCalledTimes(3);
// expect(spyerDelete).toBeCalledTimes(1);
});
});
......
......@@ -2,11 +2,12 @@ import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Model } from 'mongoose';
import { md5 } from '../shared/utils';
import { IMailchimpSubscription } from './interface/mailchimp-subscription';
import { INewsletterSubscription } from './interface/newsletter-subscription.interface';
import { NewsletterSubscription, NewsletterSubscriptionDocument } from './newsletter-subscription.schema';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const mailchimp = require('@mailchimp/mailchimp_marketing');
import { NewsletterSubscription } from './newsletter-subscription.schema';
import mailchimp = require('@mailchimp/mailchimp_marketing');
@Injectable()
export class NewsletterService {
private readonly logger = new Logger(NewsletterService.name);
......@@ -41,40 +42,64 @@ export class NewsletterService {
}
public async newsletterSubscribe(email: string): Promise<NewsletterSubscription> {
this.logger.debug('newsletterSubscribe');
const existingEmail = await this.findOne(email);
if (existingEmail) {
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
}
this.logger.debug(`newsletterSubscribe: ${email}`);
email = email.toLocaleLowerCase();
try {
const member = await mailchimp.lists.addListMember(this.LIST_ID, {
// Add or update list member (to be able to subscribe again a member who had already subscribed then unsubscribed)
// (the second parameter is the MD5 hash of the lowercase email, we actually don't need to maintain a mapping in newsletterSubscription : cf. https://mailchimp.com/developer/marketing/docs/methods-parameters/#path-parameters )
const member = await mailchimp.lists.setListMember(this.LIST_ID, md5(email), {
email_address: email,
status_if_new: 'subscribed', // cf. https://mailchimp.com/developer/marketing/api/list-members/add-or-update-list-member/
status: 'subscribed',
});
await this.newsletterSubscriptionModel.create({ email: email, mailchimpId: member.id });
return this.findOne(email);
// We may not be aware that the user has unsubscribed from the newsletter, so it is ok if it already exists in newsletterSubscription
let newsletterSubscription = await this.findOne(email);
if (!newsletterSubscription) {
newsletterSubscription = await this.newsletterSubscriptionModel.create({
email: email,
mailchimpId: member.id,
});
}
return newsletterSubscription;
} catch (e) {
if (e.status === 400) {
this.logger.error(`Error ${e.status}, user might already exist in mailchimplist`);
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
if (e.status === 400 && e.response?.text?.includes('fake')) {
throw new HttpException('Fake or invalid email', HttpStatus.I_AM_A_TEAPOT);
} else {
this.logger.error(`Mailchimp configuration error`);
throw new HttpException('Server error', HttpStatus.INTERNAL_SERVER_ERROR);
this.logger.error(`newsletterSubscribe ${email}: ${JSON.stringify(e)}`);
throw new HttpException('Subscribe error', HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
public async newsletterUnsubscribe(email: string): Promise<NewsletterSubscription> {
this.logger.debug('newsletterUnsubscribe');
const subscription = await this.findOne(email);
if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
this.logger.debug(`newsletterUnsubscribe: ${email}`);
email = email.toLocaleLowerCase();
const emailMd5Hashed = md5(email);
let newsletterSubscription = await this.findOne(email);
if (newsletterSubscription) {
newsletterSubscription = newsletterSubscription.deleteOne();
}
await mailchimp.lists.setListMember(this.LIST_ID, subscription.mailchimpId, {
email_address: email,
status: 'unsubscribed',
});
return subscription.deleteOne();
try {
const response = await mailchimp.lists.getListMember(this.LIST_ID, emailMd5Hashed);
if (response.status === 'unsubscribed') {
throw new HttpException('Email not found', HttpStatus.NOT_FOUND);
}
await mailchimp.lists.setListMember(this.LIST_ID, emailMd5Hashed, {
status: 'unsubscribed',
});
} catch (e) {
if (e.status === 404) {
throw new HttpException('Email not found', HttpStatus.NOT_FOUND);
} else {
this.logger.error(`newsletterUnsubscribe ${email}: ${JSON.stringify(e)}`);
throw new HttpException('Unsubscribe error', HttpStatus.INTERNAL_SERVER_ERROR);
}
}
return newsletterSubscription;
}
public async findOne(mail: string): Promise<INewsletterSubscription | undefined> {
......@@ -82,16 +107,6 @@ export class NewsletterService {
return this.newsletterSubscriptionModel.findOne({ email: mail });
}
public async searchNewsletterSubscription(searchString: string): Promise<NewsletterSubscriptionDocument[]> {
this.logger.debug('searchNewsletterSubscription');
return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') });
}
public async countNewsletterSubscriptions(): Promise<number> {
this.logger.debug('countNewsletterSubscriptions');
return this.newsletterSubscriptionModel.countDocuments({});
}
public async findAll(): Promise<NewsletterSubscription[]> {
this.logger.debug('findAll');
return this.newsletterSubscriptionModel.find();
......
......@@ -4,6 +4,9 @@ import { Page } from '../pages/schemas/page.schema';
import { Post } from '../posts/schemas/post.schema';
import { UserRole } from '../users/enum/user-role.enum';
import { User } from '../users/schemas/user.schema';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const crypto = require('crypto');
export const md5 = (data: string): string => crypto.createHash('md5').update(data).digest('hex');
export function rewriteGhostImgUrl(configService: ConfigurationService, itemData: Page | Post): Page | Post {
// Handle image display. Rewrite image URL to fit ghost infra issue.
......
import { HttpService } from '@nestjs/axios';
import { Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cron, CronExpression } from '@nestjs/schedule';
import { AxiosResponse } from 'axios';
import * as https from 'https';
import * as _ from 'lodash';
......@@ -80,7 +79,7 @@ export class ApticStructuresService {
createdStructure.structureName = structure.name;
createdStructure.contactPhone = structure.phone;
// Unkown fields (but mandatory)
createdStructure.contactMail = 'unknown@unknown.com';
createdStructure.contactMail = null;
createdStructure.categories.labelsQualifications = ['passNumerique'];
createdStructure.structureType = await this.structureTypeService.findByValue('autre');
createdStructure.pmrAccess = false;
......@@ -226,7 +225,6 @@ export class ApticStructuresService {
/**
* Get Metropole new aptic structure evey week. For testing, please change the expression
*/
@Cron(CronExpression.EVERY_WEEK)
public getMetropoleMunicipality(): void {
const req =
'https://download.data.grandlyon.com/ws/grandlyon/adr_voie_lieu.adrcomgl/all.json?maxfeatures=-1&start=1';
......
......@@ -7,7 +7,7 @@ import * as ejs from 'ejs';
import * as _ from 'lodash';
import { DateTime } from 'luxon';
import { DocumentDefinition, FilterQuery, Model, Types } from 'mongoose';
import { lastValueFrom, map, Observable, tap } from 'rxjs';
import { lastValueFrom, map, tap } from 'rxjs';
import { PendingStructureDto } from '../../admin/dto/pending-structure.dto';
import { UnclaimedStructureDto } from '../../admin/dto/unclaimed-structure-dto';
import { Categories } from '../../categories/schemas/categories.schema';
......@@ -275,10 +275,6 @@ export class StructuresService {
.select('-_id -accountVerified -otherDescription -dataShareConsentDate')
.exec()
).map((structure) => {
// If structure has temp email, hide it
if (this.hasTempMail(structure)) {
structure.contactMail = null;
}
const repositoryKeys = categories.map((category) => category.id);
repositoryKeys.forEach((el) => {
// Add referentiel
......@@ -937,10 +933,6 @@ export class StructuresService {
this.mailerService.send(emailsObject, jsonConfig.subject, html);
}
private hasTempMail(structure: Structure): boolean {
return structure.contactMail === 'unknown@unknown.com';
}
public async getAllUserCompletedStructures(users: IUser[]) {
return Promise.all(
users.map(async (user) => {
......@@ -1162,7 +1154,9 @@ export class StructuresService {
const structures: StructureDocument[] = await this.findAll();
for (const structure of structures) {
this.setCtmTerritory(structure).then(async (updatedStructure) => {
await this.structureModel.findByIdAndUpdate(new Types.ObjectId(structure._id), updatedStructure).exec();
await this.structureModel
.findByIdAndUpdate(new Types.ObjectId(structure._id), updatedStructure, { timestamps: false })
.exec();
});
}
return null;
......
......@@ -25,6 +25,7 @@ import { ITempUser } from '../temp-user/temp-user.interface';
import { TempUser } from '../temp-user/temp-user.schema';
import { TempUserService } from '../temp-user/temp-user.service';
import { Roles } from '../users/decorators/roles.decorator';
import { UserRole } from '../users/enum/user-role.enum';
import { IsStructureOwnerGuard } from '../users/guards/isStructureOwner.guard';
import { RolesGuard } from '../users/guards/roles.guard';
import { pendingStructuresLink } from '../users/interfaces/pendingStructure';
......@@ -181,10 +182,10 @@ export class StructuresController {
description: `Mettre à jour les territoires CTM des structures à partir de Data Grand Lyon`,
})
@ApiResponse({
status: 204,
status: 201,
description: 'The CTM territories have been updated successfully.',
})
@Get('/ctm/update')
@Post('/ctm/update')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
public async updateCTM(): Promise<void> {
......@@ -204,10 +205,10 @@ export class StructuresController {
const otherOwners: IUser[] = (await this.userService.getStructureOwners(id)).filter((owner) => {
return !owner._id.equals(req.user._id);
});
if (otherOwners.length) {
return this.structureService.setToBeDeleted(req.user, structure);
} else {
if (otherOwners.length === 0 || req.user.role === UserRole.admin) {
return this.structureService.deleteOne(structure);
} else {
return this.structureService.setToBeDeleted(req.user, structure);
}
}
......
import { Body, Controller, Get, Logger, Post, UseGuards } from '@nestjs/common';
import { Body, Controller, Logger, Post, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { Roles } from '../users/decorators/roles.decorator';
......@@ -17,10 +17,10 @@ export class TclStopPointController {
description: `Mettre à jour les points d'arrêt TCL à partir de Data Grand Lyon`,
})
@ApiResponse({
status: 204,
status: 201,
description: 'The stop points have been updated successfully.',
})
@Get('/update')
@Post('/update')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
public updateStopPoints(): Promise<void> {
......