diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md
new file mode 100644
index 0000000000000000000000000000000000000000..4aabf73667e583c772e1f9ae0c4487a4a31c155a
--- /dev/null
+++ b/.gitlab/issue_templates/bug.md
@@ -0,0 +1,46 @@
+## Description du problème
+
+_Donnez une briève description du problème_
+
+## L'environnement
+
+#### Utilisez vous l'application sur :
+
+- [ ] Mobile
+- [ ] Ordinateur
+
+##### En cas de mobile
+
+###### Quel type de mobile utilisez-vous?
+
+- [ ] Android
+- [ ] Iphone
+
+###### Quel navigateur utilisez-vous?
+
+- [ ] Chrome
+- [ ] Safari
+- [ ] Autre
+
+##### En cas d'ordinateur
+
+###### Quel navigateur utilisez-vous?
+
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari
+- [ ] Autre
+
+## Le bug
+
+#### Quelles sont les étapes qui ont menées au problème?
+
+_Donnez une description des étapes, il est fortemment conseillé de l'accompagner par des captures d'écran_
+
+#### Quel est le comportement obtenu?
+
+_Donnez une description du comportement obtenu, il est fortemment conseillé de l'accompagner par des captures d'écran_
+
+#### Quel est le comportement attendu?
+
+_Donnez une description du comportement attendu_
diff --git a/README.md b/README.md
index b42a00f565b5af59c7a86633dae94af758db373c..81dfff4ff237e7c40910e2d9d3e1fae3e69179d3 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 
 [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
 [circleci-url]: https://circleci.com/gh/nestjs/nest
-  
+
   <p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
     <p align="center">
 <a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
@@ -47,7 +47,6 @@ $ npm install
 
 ### Base de donnée
 
-
 ```bash
 $ docker-compose up -d database-ram
 $ docker-compose up -d mongo-express
@@ -70,17 +69,20 @@ $ npm run start:prod
 
 ```bash
 # Lien vers le swagger
-$ http://localhost:3000/api
+$ http://localhost:3000/doc
 
 # Lien vers le mongo-express
 $ http://localhost:8081
 ```
 
-## Documentation 
+## Documentation
+
 A documentation is generated with compodoc in addition of the existing documentation on the wiki.
+
 ```sh
 npm run doc:serve
 ```
+
 You can now visualize it at : `localhost:8080`
 
 ## Test
diff --git a/package.json b/package.json
index d04b8b75788e9abce5c79a143d4f5d65e2747092..085845eb99348cc1e4392877ee20051c9282e8a8 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
     "release": "standard-version",
     "init-db": "node ./scripts/init-db.js",
     "test": "jest",
-    "test:watch": "jest --config ./test/jest.json --watch",
+    "test:watch": "jest --config ./test/jest.json --watch --coverage",
     "test:cov": "jest --config ./test/jest.json --coverage --ci --reporters=default --reporters=jest-junit",
     "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
     "test:e2e": "jest --config ./test/jest-e2e.json",
diff --git a/src/admin/admin.controller.spec.ts b/src/admin/admin.controller.spec.ts
index 7d859527c4792d72464fabbf2781da7e7ef89eb3..c3e8b200ea5df78c072f272e1bdefa64ca23ad40 100644
--- a/src/admin/admin.controller.spec.ts
+++ b/src/admin/admin.controller.spec.ts
@@ -1,27 +1,66 @@
 import { HttpModule } from '@nestjs/common';
 import { getModelToken } from '@nestjs/mongoose';
 import { Test, TestingModule } from '@nestjs/testing';
+import { Types } from 'mongoose';
+import { mockJwtAuthGuard } from '../../test/mock/guards/jwt-auth.mock.guard';
+import { mockRoleGuard } from '../../test/mock/guards/role.mock.guard';
+import { NewsletterServiceMock } from '../../test/mock/services/newsletter.mock.service';
+import { StructuresServiceMock } from '../../test/mock/services/structures.mock.service';
+import { UsersServiceMock } from '../../test/mock/services/user.mock.service';
+import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
 import { ConfigurationModule } from '../configuration/configuration.module';
 import { MailerService } from '../mailer/mailer.service';
 import { NewsletterSubscription } from '../newsletter/newsletter-subscription.schema';
 import { NewsletterService } from '../newsletter/newsletter.service';
 import { SearchModule } from '../search/search.module';
 import { Structure } from '../structures/schemas/structure.schema';
-import { StructuresService } from '../structures/services/structures.service';
 import { StructuresSearchService } from '../structures/services/structures-search.service';
+import { StructuresService } from '../structures/services/structures.service';
+import { RolesGuard } from '../users/guards/roles.guard';
 import { User } from '../users/schemas/user.schema';
+import { EmployerSearchService } from '../users/services/employer-search.service';
+import { EmployerService } from '../users/services/employer.service';
+import { JobsService } from '../users/services/jobs.service';
 import { UsersService } from '../users/services/users.service';
 import { AdminController } from './admin.controller';
-import { mockJwtAuthGuard } from '../../test/mock/guards/jwt-auth.mock.guard';
-import { mockRoleGuard } from '../../test/mock/guards/role.mock.guard';
-import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
-import { RolesGuard } from '../users/guards/roles.guard';
-import { UsersServiceMock } from '../../test/mock/services/user.mock.service';
-import { StructuresServiceMock } from '../../test/mock/services/structures.mock.service';
-import { NewsletterServiceMock } from '../../test/mock/services/newsletter.mock.service';
 
 describe('AdminController', () => {
   let controller: AdminController;
+  let userService: UsersService;
+
+  const mockEmployerSearchService = {
+    indexEmployer: jest.fn(),
+    search: jest.fn(),
+    dropIndex: jest.fn(),
+    createEmployerIndex: jest.fn(),
+    deleteIndex: jest.fn(),
+  };
+
+  const mockEmployerService = {
+    findOne: jest.fn(),
+    deleteOneId: jest.fn(),
+    findByName: jest.fn(),
+    findAllValidated: jest.fn(),
+    findAllUnvalidated: jest.fn(),
+    createEmployerFromAdmin: jest.fn(),
+    validate: jest.fn(),
+    update: jest.fn(),
+    mergeEmployer: jest.fn(),
+    deleteInvalidEmployer: jest.fn(),
+  };
+
+  const mockJobService = {
+    findOne: jest.fn(),
+    findByName: jest.fn(),
+    deleteOneId: jest.fn(),
+    findAll: jest.fn(),
+    findAllUnvalidated: jest.fn(),
+    createJobFromAdmin: jest.fn(),
+    validate: jest.fn(),
+    update: jest.fn(),
+    mergeJob: jest.fn(),
+    deleteInvalidJob: jest.fn(),
+  };
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
@@ -41,6 +80,18 @@ describe('AdminController', () => {
         },
         StructuresSearchService,
         MailerService,
+        {
+          provide: EmployerService,
+          useValue: mockEmployerService,
+        },
+        {
+          provide: JobsService,
+          useValue: mockJobService,
+        },
+        {
+          provide: EmployerSearchService,
+          useValue: mockEmployerSearchService,
+        },
         {
           provide: getModelToken('User'),
           useValue: User,
@@ -63,6 +114,7 @@ describe('AdminController', () => {
       .compile();
 
     controller = module.get<AdminController>(AdminController);
+    userService = module.get<UsersService>(UsersService);
   });
 
   it('should be defined', () => {
@@ -71,7 +123,7 @@ describe('AdminController', () => {
 
   it('should get pending attachments', async () => {
     expect((await controller.getPendingAttachments()).length).toBe(2);
-    expect(Object.keys((await controller.getPendingAttachments())[0]).length).toBe(3);
+    expect(Object.keys((await controller.getPendingAttachments())[0]).length).toBe(4);
   });
 
   describe('Pending structures validation', () => {
@@ -80,9 +132,10 @@ describe('AdminController', () => {
         structureId: '6093ba0e2ab5775cfc01ed3e',
         structureName: 'test',
         userEmail: 'jean.paul@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       };
       expect((await controller.validatePendingStructure(pendingStructureTest)).length).toBe(2);
-      expect(Object.keys((await controller.validatePendingStructure(pendingStructureTest))[0]).length).toBe(3);
+      expect(Object.keys((await controller.validatePendingStructure(pendingStructureTest))[0]).length).toBe(4);
     });
 
     it('should get structure does not exist', async () => {
@@ -90,6 +143,7 @@ describe('AdminController', () => {
         structureId: '1093ba0e2ab5775cfc01z2ki',
         structureName: 'test',
         userEmail: 'jean.paul@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       };
       try {
         await controller.validatePendingStructure(pendingStructureTest);
@@ -106,9 +160,10 @@ describe('AdminController', () => {
         structureId: '6093ba0e2ab5775cfc01ed3e',
         structureName: 'test',
         userEmail: 'jean.paul@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       };
       expect((await controller.refusePendingStructure(pendingStructureTest)).length).toBe(2);
-      expect(Object.keys((await controller.refusePendingStructure(pendingStructureTest))[0]).length).toBe(3);
+      expect(Object.keys((await controller.refusePendingStructure(pendingStructureTest))[0]).length).toBe(4);
     });
 
     it('should get structure does not exist', async () => {
@@ -116,6 +171,7 @@ describe('AdminController', () => {
         structureId: '1093ba0e2ab5775cfc01z2ki',
         structureName: 'test',
         userEmail: 'jean.paul@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       };
       try {
         await controller.refusePendingStructure(pendingStructureTest);
@@ -140,6 +196,134 @@ describe('AdminController', () => {
     });
   });
 
+  describe('setUserEmployer', () => {
+    it('should set a new employer to the user', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserEmployer');
+      const mockUserId = '6231aefe76598527c8d0b5bc';
+      const mockEmployer = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      };
+      mockEmployerService.findOne.mockResolvedValueOnce(mockEmployer);
+      const reply = await controller.setUserEmployer({
+        userId: mockUserId,
+        employerId: String(mockEmployer._id),
+      });
+      expect(spyer).toBeCalledTimes(1);
+      expect(spyer).toBeCalledWith(mockUserId, mockEmployer);
+      expect(reply).toBeTruthy();
+    });
+
+    it('should not set a new employer to the user if the employer does not exist', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserEmployer');
+      const mockUserId = '6231aefe76598527c8d0b5bc';
+      const mockEmployer = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      };
+      mockEmployerService.findOne.mockResolvedValueOnce(null);
+      try {
+        await controller.setUserEmployer({
+          userId: mockUserId,
+          employerId: String(mockEmployer._id),
+        });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(spyer).toBeCalledTimes(0);
+        expect(e.message).toBe('Employer does not exist');
+        expect(e.status).toBe(400);
+      }
+    });
+
+    it('should not set a new employer to the user if the user does not exist', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserEmployer');
+      const mockUserId = 'thisuserdoesnotexist';
+      const mockEmployer = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      };
+      mockEmployerService.findOne.mockResolvedValueOnce(mockEmployer);
+      try {
+        await controller.setUserEmployer({
+          userId: mockUserId,
+          employerId: String(mockEmployer._id),
+        });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(spyer).toBeCalledTimes(0);
+        expect(e.message).toBe('User does not exist');
+        expect(e.status).toBe(400);
+      }
+    });
+  });
+
+  describe('setUserJob', () => {
+    it('should set a new job to the user', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserJob');
+      const mockUserId = '6231aefe76598527c8d0b5bc';
+      const mockJob = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Toto',
+        validated: true,
+      };
+      mockJobService.findOne.mockResolvedValueOnce(mockJob);
+      const reply = await controller.setUserJob({
+        userId: mockUserId,
+        jobId: String(mockJob._id),
+      });
+      expect(spyer).toBeCalledTimes(1);
+      expect(spyer).toBeCalledWith(mockUserId, mockJob);
+      expect(reply).toBeTruthy();
+    });
+
+    it('should not set a new job to the user if the job does not exist', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserJob');
+      const mockUserId = '6231aefe76598527c8d0b5bc';
+      const mockJob = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      };
+      mockJobService.findOne.mockResolvedValueOnce(null);
+      try {
+        await controller.setUserJob({
+          userId: mockUserId,
+          jobId: String(mockJob._id),
+        });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(spyer).toBeCalledTimes(0);
+        expect(e.message).toBe('Job does not exist');
+        expect(e.status).toBe(400);
+      }
+    });
+
+    it('should not set a new job to the user if the user does not exist', async () => {
+      const spyer = jest.spyOn(userService, 'updateUserJob');
+      const mockUserId = 'thisuserdoesntexist';
+      const mockJob = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      };
+      mockJobService.findOne.mockResolvedValueOnce(mockJob);
+      try {
+        await controller.setUserJob({
+          userId: mockUserId,
+          jobId: String(mockJob._id),
+        });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(spyer).toBeCalledTimes(0);
+        expect(e.message).toBe('User does not exist');
+        expect(e.status).toBe(400);
+      }
+    });
+  });
+
   describe('Search user', () => {
     it('should return all users, empty string', async () => {
       expect((await controller.searchUsers({ searchString: '' })).length).toBe(2);
@@ -156,7 +340,7 @@ describe('AdminController', () => {
     });
   });
 
-  describe('Search user newleetter subscription', () => {
+  describe('Search user newsletter subscription', () => {
     it('should return all subscribed users, empty string', async () => {
       expect((await controller.getNewsletterSubscriptions({ searchString: '' })).length).toBe(3);
     });
diff --git a/src/admin/admin.controller.ts b/src/admin/admin.controller.ts
index c3de17af253a1a1cd8c396fefd20fbe628bad364..92ff38d7eafa64e23a2fdcb9fa5f4be95cb2ded2 100644
--- a/src/admin/admin.controller.ts
+++ b/src/admin/admin.controller.ts
@@ -1,27 +1,33 @@
-import { ApiOperation, ApiParam } from '@nestjs/swagger';
-import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
 import {
   Body,
-  Delete,
-  Param,
   Controller,
+  Delete,
   Get,
-  Post,
-  UseGuards,
-  HttpStatus,
   HttpException,
+  HttpStatus,
   Logger,
+  Param,
+  Post,
+  Put,
+  UseGuards,
 } from '@nestjs/common';
+import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
+import { validate } from 'class-validator';
+import { DateTime, Interval } from 'luxon';
+import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
 import { NewsletterSubscription } from '../newsletter/newsletter-subscription.schema';
 import { NewsletterService } from '../newsletter/newsletter.service';
+import { Structure } from '../structures/schemas/structure.schema';
 import { StructuresService } from '../structures/services/structures.service';
 import { Roles } from '../users/decorators/roles.decorator';
 import { RolesGuard } from '../users/guards/roles.guard';
+import { IUser } from '../users/interfaces/user.interface';
+import { EmployerService } from '../users/services/employer.service';
+import { JobsService } from '../users/services/jobs.service';
 import { UsersService } from '../users/services/users.service';
 import { PendingStructureDto } from './dto/pending-structure.dto';
-import { validate } from 'class-validator';
-import { Structure } from '../structures/schemas/structure.schema';
-import { IUser } from '../users/interfaces/user.interface';
+import { SetUserEmployerDto } from './dto/set-user-employer.dto';
+import { SetUserJobDto } from './dto/set-user-job.dto';
 
 @Controller('admin')
 export class AdminController {
@@ -29,18 +35,22 @@ export class AdminController {
   constructor(
     private usersService: UsersService,
     private structuresService: StructuresService,
+    private jobsService: JobsService,
+    private employerService: EmployerService,
     private newsletterService: NewsletterService
   ) {}
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
   @Get('pendingStructures')
-  @ApiOperation({ description: 'Get pending structre for validation' })
+  @ApiOperation({ description: 'Get pending structures for validation' })
   public async getPendingAttachments(): Promise<PendingStructureDto[]> {
     const pendingStructure = await this.usersService.getPendingStructures();
     return Promise.all(
       pendingStructure.map(async (structure) => {
-        structure.structureName = (await this.structuresService.findOne(structure.structureId)).structureName;
+        const structureDocument = await this.structuresService.findOne(structure.structureId);
+        structure.structureName = structureDocument.structureName;
+        structure.updatedAt = structureDocument.updatedAt;
         return structure;
       })
     );
@@ -49,13 +59,30 @@ export class AdminController {
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
   @Get('adminStructuresList')
-  @ApiOperation({ description: 'Get pending structre for validation' })
+  @ApiOperation({ description: 'Get pending structures for validation' })
   public async getAdminStructuresList(): Promise<any> {
     const structuresList = { claimed: [], inClaim: [], toClaim: [], incomplete: [] };
-    structuresList.inClaim = await this.getPendingAttachments();
-    structuresList.toClaim = (await this.structuresService.findAllUnclaimed()).filter(
-      (demand) => !structuresList.inClaim.find((elem) => elem.structureId == demand.structureId)
-    );
+    const today = DateTime.local().setZone('utc', { keepLocalTime: true });
+    const inClaimStructures = await this.getPendingAttachments();
+    structuresList.inClaim = inClaimStructures.map((structure) => {
+      return {
+        structureId: structure.structureId,
+        structureName: structure.structureName,
+        updatedAt: structure.updatedAt,
+        isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
+      };
+    });
+    const toClaimStructures = await this.structuresService.findAllUnclaimed();
+    structuresList.toClaim = toClaimStructures
+      .filter((demand) => !structuresList.inClaim.find((elem) => elem.structureId == demand.structureId))
+      .map((structure) => {
+        return {
+          structureId: structure.structureId,
+          structureName: structure.structureName,
+          updatedAt: structure.updatedAt,
+          isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
+        };
+      });
     const allStructures = await this.structuresService.findAll();
     structuresList.claimed = allStructures
       .filter(
@@ -64,14 +91,25 @@ export class AdminController {
           !structuresList.toClaim.find((elem) => elem.structureId == demand.id)
       )
       .map((structure) => {
-        return { structureId: structure.id, structureName: structure.structureName };
+        return {
+          structureId: structure.id,
+          structureName: structure.structureName,
+          updatedAt: structure.updatedAt,
+          isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
+        };
       });
     structuresList.incomplete = await Promise.all(
       allStructures.map(async (struct) => {
         const validity = await validate(new Structure(struct));
         if (validity.length > 0) {
           this.logger.debug(`getAdminStructuresList - validation failed. errors: ${validity.toString()}`);
-          return { structureId: struct.id, structureName: struct.structureName };
+
+          return {
+            structureId: struct.id,
+            structureName: struct.structureName,
+            updatedAt: struct.updatedAt,
+            isOutdated: Interval.fromDateTimes(DateTime.fromISO(struct.updatedAt), today).length('months') > 6,
+          };
         } else {
           this.logger.debug('getAdminStructuresList - validation succeed');
           return null;
@@ -141,6 +179,7 @@ export class AdminController {
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
   @Delete('user/:id')
+  @ApiBearerAuth('JWT')
   @ApiParam({ name: 'id', type: String, required: true })
   public async deleteUser(@Param() params) {
     const user = await this.usersService.deleteOneId(params.id);
@@ -156,6 +195,7 @@ export class AdminController {
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
+  @ApiBearerAuth('JWT')
   @Post('searchUsers')
   public async searchUsers(@Body() searchString: { searchString: string }) {
     if (searchString && searchString.searchString && searchString.searchString.length > 0)
@@ -165,14 +205,28 @@ export class AdminController {
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
-  @Get('getUnAttachedUsers')
+  @ApiBearerAuth('JWT')
+  @Get('unAttachedUsers')
   public async findUnattachedUsers() {
-    return this.usersService.findAllUnattached();
+    return this.usersService.findAllUnattached().then((formatUsers) => {
+      return formatUsers.map((user) => {
+        return {
+          id: user._id,
+          surname: user.surname,
+          name: user.name,
+          email: user.email,
+          phone: user.phone,
+          job: user.job,
+          employer: user.employer,
+        };
+      });
+    });
   }
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
-  @Get('getAttachedUsers')
+  @ApiBearerAuth('JWT')
+  @Get('attachedUsers')
   public async findAttachedUsers() {
     return this.usersService.findAllAttached().then(async (users: IUser[]) => {
       return this.structuresService.getAllUserCompletedStructures(users);
@@ -180,8 +234,9 @@ export class AdminController {
   }
 
   @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
   @Roles('admin')
-  @Get('getUnVerifiedUsers')
+  @Get('unVerifiedUsers')
   public async findUnVerifiedUsers() {
     return this.usersService.findAllUnVerified().then(async (users: IUser[]) => {
       return this.structuresService.getAllUserCompletedStructures(users);
@@ -190,6 +245,7 @@ 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)
@@ -199,6 +255,7 @@ export class AdminController {
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
+  @ApiBearerAuth('JWT')
   @Get('countNewsletterSubscriptions')
   public async countNewsletterSubscriptions(): Promise<number> {
     return this.newsletterService.countNewsletterSubscriptions();
@@ -206,9 +263,60 @@ export class AdminController {
 
   @UseGuards(JwtAuthGuard, RolesGuard)
   @Roles('admin')
+  @ApiBearerAuth('JWT')
   @Delete('newsletterSubscription/:email')
   @ApiParam({ name: 'email', type: String, required: true })
   public async unsubscribeUserFromNewsletter(@Param() params): Promise<NewsletterSubscription> {
     return this.newsletterService.newsletterUnsubscribe(params.email);
   }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @Roles('admin')
+  @ApiBearerAuth('JWT')
+  @ApiOperation({ description: 'Set user job' })
+  @ApiResponse({ status: HttpStatus.OK, description: 'Return user profile' })
+  @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'User does not exist' })
+  @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Job does not exist' })
+  @Put('setUserJob')
+  public async setUserJob(@Body() setUserJob: SetUserJobDto): Promise<IUser> {
+    this.logger.debug(`setUserJob`);
+    const jobDocument = await this.jobsService.findOne(setUserJob.jobId);
+    if (!jobDocument) {
+      this.logger.warn(`Job does not exist: ${setUserJob.jobId}`);
+      throw new HttpException('Job does not exist', HttpStatus.BAD_REQUEST);
+    }
+
+    const userDocument = await this.usersService.findById(setUserJob.userId);
+    if (!userDocument) {
+      this.logger.warn(`User does not exist: ${setUserJob.userId}`);
+      throw new HttpException('User does not exist', HttpStatus.BAD_REQUEST);
+    }
+    await this.usersService.updateUserJob(userDocument._id, jobDocument);
+    return this.usersService.findById(setUserJob.userId);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @Roles('admin')
+  @ApiBearerAuth('JWT')
+  @ApiOperation({ description: 'Set user employer' })
+  @ApiResponse({ status: HttpStatus.OK, description: 'Return user profile' })
+  @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'User does not exist' })
+  @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Employer does not exist' })
+  @Put('setUserEmployer')
+  public async setUserEmployer(@Body() setUserEmployer: SetUserEmployerDto): Promise<IUser> {
+    this.logger.debug(`setUserEmployer`);
+    const employerDocument = await this.employerService.findOne(setUserEmployer.employerId);
+    if (!employerDocument) {
+      this.logger.warn(`Employer does not exist: ${setUserEmployer.employerId}`);
+      throw new HttpException('Employer does not exist', HttpStatus.BAD_REQUEST);
+    }
+
+    const userDocument = await this.usersService.findById(setUserEmployer.userId);
+    if (!userDocument) {
+      this.logger.warn(`User does not exist: ${setUserEmployer.userId}`);
+      throw new HttpException('User does not exist', HttpStatus.BAD_REQUEST);
+    }
+    await this.usersService.updateUserEmployer(userDocument._id, employerDocument);
+    return this.usersService.findById(setUserEmployer.userId);
+  }
 }
diff --git a/src/admin/dto/merge-employer.dto.ts b/src/admin/dto/merge-employer.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53cbcef191aea707c4989290f7da2edd44fe4a8c
--- /dev/null
+++ b/src/admin/dto/merge-employer.dto.ts
@@ -0,0 +1,12 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsNotEmpty } from 'class-validator';
+
+export class MergeEmployerDto {
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  sourceEmployerId: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  targetEmployerId: string;
+}
diff --git a/src/admin/dto/merge-job.dto.ts b/src/admin/dto/merge-job.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d661802522cafaf1c1c019fe128f9ed751d5c1ee
--- /dev/null
+++ b/src/admin/dto/merge-job.dto.ts
@@ -0,0 +1,12 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsNotEmpty } from 'class-validator';
+
+export class MergeJobDto {
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  sourceJobId: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  targetJobId: string;
+}
diff --git a/src/admin/dto/pending-structure.dto.ts b/src/admin/dto/pending-structure.dto.ts
index 1f735be0f4256472524dba43286ab53cba836fcc..84d20b18b2490a8b062f931e272f8c5cc12363c0 100644
--- a/src/admin/dto/pending-structure.dto.ts
+++ b/src/admin/dto/pending-structure.dto.ts
@@ -1,5 +1,5 @@
 import { ApiProperty } from '@nestjs/swagger';
-import { IsEmail, IsMongoId, IsNotEmpty, IsString } from 'class-validator';
+import { IsDate, IsEmail, IsMongoId, IsNotEmpty, IsString } from 'class-validator';
 
 export class PendingStructureDto {
   @IsNotEmpty()
@@ -16,4 +16,9 @@ export class PendingStructureDto {
   @IsString()
   @ApiProperty({ type: String })
   structureName: string;
+
+  @IsNotEmpty()
+  @IsDate()
+  @ApiProperty({ type: String })
+  updatedAt: string;
 }
diff --git a/src/admin/dto/set-user-employer.dto.ts b/src/admin/dto/set-user-employer.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bd824100fbaa748d25a46294854ab4f3c913e416
--- /dev/null
+++ b/src/admin/dto/set-user-employer.dto.ts
@@ -0,0 +1,12 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class SetUserEmployerDto {
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  userId: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  employerId: string;
+}
diff --git a/src/admin/dto/set-user-job.dto.ts b/src/admin/dto/set-user-job.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e622e5d21a61ef2f6c9b37da18312e6f954e7268
--- /dev/null
+++ b/src/admin/dto/set-user-job.dto.ts
@@ -0,0 +1,12 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class SetUserJobDto {
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  userId: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  jobId: string;
+}
diff --git a/src/admin/dto/unclaimed-structure-dto.ts b/src/admin/dto/unclaimed-structure-dto.ts
index c57eedbd30d908debab1d539676731e1a7c79388..b9d7632b917869c637d5e97deeb7abf6f1c7955c 100644
--- a/src/admin/dto/unclaimed-structure-dto.ts
+++ b/src/admin/dto/unclaimed-structure-dto.ts
@@ -1,5 +1,5 @@
 import { ApiProperty } from '@nestjs/swagger';
-import { IsNotEmpty, IsString } from 'class-validator';
+import { IsDate, IsNotEmpty, IsString } from 'class-validator';
 
 export class UnclaimedStructureDto {
   @IsNotEmpty()
@@ -11,4 +11,9 @@ export class UnclaimedStructureDto {
   @IsString()
   @ApiProperty({ type: String })
   structureName: string;
+
+  @IsNotEmpty()
+  @IsDate()
+  @ApiProperty({ type: String })
+  updatedAt: string;
 }
diff --git a/src/configuration/config.ts b/src/configuration/config.ts
index f81023c4e753c40854020b92c241d54d156772f9..67e56cc1eccac899f0a3b2f65ee2596b0cd24911 100644
--- a/src/configuration/config.ts
+++ b/src/configuration/config.ts
@@ -61,6 +61,14 @@ export const config = {
       ejs: 'structureDeletionNotification.ejs',
       json: 'structureDeletionNotification.json',
     },
+    adminJobCreate: {
+      ejs: 'adminJobCreate.ejs',
+      json: 'adminJobCreate.json',
+    },
+    adminEmployerCreate: {
+      ejs: 'adminEmployerCreate.ejs',
+      json: 'adminEmployerCreate.json',
+    },
     contactMessage: {
       ejs: 'contactMessage.ejs',
       json: 'contactMessage.json',
diff --git a/src/mailer/mail-templates/adminEmployerCreate.ejs b/src/mailer/mail-templates/adminEmployerCreate.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..35ec278fc3ccd874f8550d91cba3f7a3839ea227
--- /dev/null
+++ b/src/mailer/mail-templates/adminEmployerCreate.ejs
@@ -0,0 +1,6 @@
+Bonjour,<br />
+<br />
+Un nouvel employeur <%= employerName %> vient d'être créé,
+<a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/admin>"
+  >cliquez ici pour le valider.</a
+>
diff --git a/src/mailer/mail-templates/adminEmployerCreate.json b/src/mailer/mail-templates/adminEmployerCreate.json
new file mode 100644
index 0000000000000000000000000000000000000000..e92f86bef76c521db3275f3ab8908c202d813aa7
--- /dev/null
+++ b/src/mailer/mail-templates/adminEmployerCreate.json
@@ -0,0 +1,3 @@
+{
+  "subject": "Nouvelle création d'employeur"
+}
diff --git a/src/mailer/mail-templates/adminJobCreate.ejs b/src/mailer/mail-templates/adminJobCreate.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..26262721d55b682a0077214a0e586867d2fe0c44
--- /dev/null
+++ b/src/mailer/mail-templates/adminJobCreate.ejs
@@ -0,0 +1,6 @@
+Bonjour,<br />
+<br />
+Une nouvelle fonction <%= jobName %> vient d'être créée,
+<a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/admin>"
+  >cliquez ici pour la valider.</a
+>
diff --git a/src/mailer/mail-templates/adminJobCreate.json b/src/mailer/mail-templates/adminJobCreate.json
new file mode 100644
index 0000000000000000000000000000000000000000..10e50f6e73f662ae58cb3c90150ba785f4a42614
--- /dev/null
+++ b/src/mailer/mail-templates/adminJobCreate.json
@@ -0,0 +1,3 @@
+{
+  "subject": "Nouvelle création de fonction"
+}
diff --git a/src/shared/utils.ts b/src/shared/utils.ts
index e48d93157982e7fdd7b70139af8bfccc4cbf2b90..0bca461a48a19ee86e63a7ddf490d0555a4b1ed2 100644
--- a/src/shared/utils.ts
+++ b/src/shared/utils.ts
@@ -1,6 +1,8 @@
 import { ConfigurationService } from '../configuration/configuration.service';
 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';
 
 export function rewriteGhostImgUrl(configService: ConfigurationService, itemData: Page | Post): Page | Post {
   // Handle image display. Rewrite image URL to fit ghost infra issue.
@@ -15,3 +17,7 @@ export function rewriteGhostImgUrl(configService: ConfigurationService, itemData
   }
   return itemData;
 }
+
+export function hasAdminRole(user: User): boolean {
+  return user.role === UserRole.admin;
+}
diff --git a/src/structures/services/structures.service.ts b/src/structures/services/structures.service.ts
index 21d458e6d8e393d89f853ea047605e32284691cc..fa1bdb55f594faf9accf125df99c85729c083c09 100644
--- a/src/structures/services/structures.service.ts
+++ b/src/structures/services/structures.service.ts
@@ -240,7 +240,11 @@ export class StructuresService {
     await Promise.all(
       structures.map(async (structure: StructureDocument) => {
         if (!(await this.userService.isStructureClaimed(structure.id))) {
-          unclaimedStructures.push({ structureId: structure.id, structureName: structure.structureName });
+          unclaimedStructures.push({
+            structureId: structure.id,
+            structureName: structure.structureName,
+            updatedAt: structure.updatedAt,
+          });
         }
       })
     );
@@ -778,6 +782,8 @@ export class StructuresService {
           name: user.name,
           email: user.email,
           phone: user.phone,
+          job: user.job,
+          employer: user.employer,
           structures: await Promise.all(
             user.structuresLink.map(async (id) => {
               return this.findOne(id.toHexString());
diff --git a/src/users/controllers/employer.controller.spec.ts b/src/users/controllers/employer.controller.spec.ts
index f83962fced079b73a408b3b5b8688c41b09fca27..347edb87cc0f9d03e9e0af25a3fad621b62554da 100644
--- a/src/users/controllers/employer.controller.spec.ts
+++ b/src/users/controllers/employer.controller.spec.ts
@@ -1,15 +1,17 @@
-import { HttpModule } from '@nestjs/common';
+import { HttpModule, HttpStatus } from '@nestjs/common';
 import { getModelToken } from '@nestjs/mongoose';
 import { Test, TestingModule } from '@nestjs/testing';
 import { Types } from 'mongoose';
+import { UsersServiceMock } from '../../../test/mock/services/user.mock.service';
 import { ConfigurationModule } from '../../configuration/configuration.module';
-import { CreateEmployerDto } from '../dto/create-employer.dto';
 import { Employer } from '../schemas/employer.schema';
 import { EmployerService } from '../services/employer.service';
+import { UsersService } from '../services/users.service';
 import { EmployerController } from './employer.controller';
 
 describe('EmployerController', () => {
   let controller: EmployerController;
+  let userService: UsersService;
 
   const employerServiceMock = {
     findAll: jest.fn(),
@@ -18,12 +20,24 @@ describe('EmployerController', () => {
     create: jest.fn(),
     deleteByName: jest.fn(),
     initEmployerIndex: jest.fn(),
+    findOne: jest.fn(),
+    deleteOneId: jest.fn(),
+    findAllValidated: jest.fn(),
+    findAllUnvalidated: jest.fn(),
+    validate: jest.fn(),
+    update: jest.fn(),
+    mergeEmployer: jest.fn(),
+    deleteInvalidEmployer: jest.fn(),
   };
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
       imports: [ConfigurationModule, HttpModule],
       providers: [
+        {
+          provide: UsersService,
+          useClass: UsersServiceMock,
+        },
         {
           provide: EmployerService,
           useValue: employerServiceMock,
@@ -37,6 +51,7 @@ describe('EmployerController', () => {
     }).compile();
 
     controller = module.get<EmployerController>(EmployerController);
+    userService = module.get<UsersService>(UsersService);
   });
 
   it('should be defined', () => {
@@ -77,89 +92,208 @@ describe('EmployerController', () => {
       expect(findAllReply.length).toBe(2);
     });
   });
-  describe('createEmployer', () => {
-    it('should create new employer `Metro`', async () => {
-      const newEmployer: CreateEmployerDto = {
-        name: 'Metro',
-      };
-      const newCreatedEmployer: Employer = {
-        name: 'Metro',
-        validated: false,
-      };
+
+  // describe('deleteEmployer', () => {
+  //   it('should delete employer `Metro`', async () => {
+  //     const employer: Employer = {
+  //       name: 'Metro',
+  //       validated: true,
+  //     };
+  //     const employerToRemove: CreateEmployerDto = {
+  //       name: 'Metro',
+  //     };
+  //     employerServiceMock.findByName.mockResolvedValueOnce(employer);
+  //     employerServiceMock.deleteByName.mockResolvedValueOnce({
+  //       ok: 1,
+  //       n: 1,
+  //       deletedCount: 1,
+  //     });
+  //     const deleteEmployer = await controller.deleteEmployer(employerToRemove);
+  //     expect(deleteEmployer.name).toBe('Metro');
+  //     expect(deleteEmployer.validated).toBe(true);
+  //   });
+
+  //   it('should throw error on unexisting employer `Metro`', async () => {
+  //     const employerToRemove: CreateEmployerDto = {
+  //       name: 'Metro',
+  //     };
+  //     employerServiceMock.deleteByName.mockResolvedValueOnce(null);
+  //     try {
+  //       await controller.deleteEmployer(employerToRemove);
+  //       expect(true).toBe(false);
+  //     } catch (e) {
+  //       expect(e.message).toBe('Employer does not exist');
+  //       expect(e.status).toBe(404);
+  //     }
+  //   });
+  // });
+  describe('resetES', () => {
+    it('should reset search index', async () => {
+      employerServiceMock.initEmployerIndex.mockResolvedValueOnce([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
+          name: 'CAF',
+          validated: true,
+        },
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
+          name: 'CARSAT',
+          validated: true,
+        },
+      ]);
+      const index = await controller.resetES();
+      expect(index.length).toBe(2);
+    });
+  });
+
+  describe('Create Employer', () => {
+    it('should create a employer', async () => {
       employerServiceMock.findByName.mockResolvedValueOnce(null);
-      employerServiceMock.create.mockResolvedValueOnce(newCreatedEmployer);
-      const createReply = await controller.createEmployer(newEmployer);
-      expect(createReply).toEqual(newCreatedEmployer);
+      employerServiceMock.create.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      });
+      const req = { user: { _id: '6036721022462b001334c4bb', role: 0 } };
+      const reply = await controller.createEmployer({ name: 'Sopra' }, req);
+      expect(reply).toBeTruthy();
     });
-    it('should throw error on already existing employer `Metro`', async () => {
-      const newEmployer: CreateEmployerDto = {
-        name: 'Metro',
-      };
+    it('should not create if employer already exists', async () => {
       employerServiceMock.findByName.mockResolvedValueOnce({
-        _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
-        name: 'Metro',
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
         validated: true,
       });
+      const req = { user: { _id: '6036721022462b001334c4bb' }, role: 0 };
       try {
-        await controller.createEmployer(newEmployer);
-        expect(true).toBe(false);
+        await controller.createEmployer({ name: 'Sopra' }, req);
+        expect;
       } catch (e) {
         expect(e.message).toBe('Employer already exist');
-        expect(e.status).toBe(422);
+        expect(e.status).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
       }
     });
+    it('should call create with send notification to true if admin', async () => {
+      employerServiceMock.findByName.mockResolvedValueOnce(null);
+      const employer = {
+        name: 'Sopra',
+      };
+      employerServiceMock.create.mockResolvedValueOnce({ ...employer, validated: true });
+      const req = { user: { _id: '6036721022462b001334c4bb', role: 1 } };
+
+      const reply = await controller.createEmployer(employer, req);
+      expect(reply).toBeTruthy();
+      expect(employerServiceMock.create).toHaveBeenCalledWith(employer, true, false);
+    });
   });
+  describe('Validate Employer', () => {
+    it('should validate an employer', async () => {
+      employerServiceMock.validate.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      });
+      expect(await controller.validateEmployer({ id: '6231aefe76598527c8d0b5bc' })).toBeTruthy();
+    });
+  });
+  describe('Get Employers', () => {
+    it('should call all validated employers and populate them with users attached to it', async () => {
+      const spyer = jest.spyOn(userService, 'populateEmployerswithUsers');
+      employerServiceMock.findAllValidated.mockResolvedValueOnce([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Metro',
+          validated: true,
+        },
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Sopra',
+          validated: true,
+        },
+      ]);
+      await controller.findValidatedEmployers();
+      expect(employerServiceMock.findAllValidated.mock.calls.length).toBe(1);
+      expect(spyer.mock.calls.length).toBe(1);
+    });
 
-  describe('deleteEmployer', () => {
-    it('should delete employer `Metro`', async () => {
-      const employer: Employer = {
-        name: 'Metro',
+    it('should call all unvalidated employers and populate them with users attached to it', async () => {
+      const spyer = jest.spyOn(userService, 'populateEmployerswithUsers');
+      employerServiceMock.findAllUnvalidated.mockResolvedValueOnce([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Metro',
+          validated: false,
+        },
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Sopra',
+          validated: false,
+        },
+      ]);
+      await controller.findUnvalidatedEmployers();
+      expect(employerServiceMock.findAllUnvalidated.mock.calls.length).toBe(1);
+      expect(spyer.mock.calls.length).toBe(1);
+    });
+  });
+  describe('Edit Employer', () => {
+    it('should update employer', async () => {
+      employerServiceMock.update.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'SopraMod',
         validated: true,
-      };
-      const employerToRemove: CreateEmployerDto = {
-        name: 'Metro',
-      };
-      employerServiceMock.findByName.mockResolvedValueOnce(employer);
-      employerServiceMock.deleteByName.mockResolvedValueOnce({
+      });
+      expect(await controller.updateEmployer('6231aefe76598527c8d0b5bc', { name: 'SopraMod' })).toBeTruthy();
+    });
+
+    it('should delete an unvalidated employer and replace all its occurence with a chosen validated employer', async () => {
+      employerServiceMock.mergeEmployer.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      });
+      employerServiceMock.deleteInvalidEmployer.mockResolvedValueOnce({
+        n: 1,
         ok: 1,
+        deletedCount: 1,
+      });
+
+      const reply = await controller.mergeEmployer({
+        sourceEmployerId: '6231aefe76598527c8d0b5ba',
+        targetEmployerId: '6231aefe76598527c8d0b5bc',
+      });
+      expect(reply).toBeTruthy();
+    });
+  });
+  describe('Delete Employer', () => {
+    it('should delete employer', async () => {
+      employerServiceMock.deleteOneId.mockResolvedValueOnce({
         n: 1,
+        ok: 1,
         deletedCount: 1,
       });
-      const deleteEmployer = await controller.deleteEmployer(employerToRemove);
-      expect(deleteEmployer.name).toBe('Metro');
-      expect(deleteEmployer.validated).toBe(true);
+
+      employerServiceMock.findOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Sopra',
+        validated: true,
+      });
+      const reply = await controller.deleteEmployer({ id: '6231aefe76598527c8d0b5ba' });
+      expect(reply).toBeTruthy();
     });
 
-    it('should throw error on unexisting employer `Metro`', async () => {
-      const employerToRemove: CreateEmployerDto = {
-        name: 'Metro',
-      };
-      employerServiceMock.deleteByName.mockResolvedValueOnce(null);
+    it('should not delete employer if a user is linked', async () => {
+      employerServiceMock.findOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: true,
+      });
       try {
-        await controller.deleteEmployer(employerToRemove);
+        await controller.deleteEmployer({ id: '6231aefe76598527c8d0b5bc' });
         expect(true).toBe(false);
       } catch (e) {
-        expect(e.message).toBe('Employer does not exist');
-        expect(e.status).toBe(404);
+        expect(e.message).toEqual('Cannot delete employer. It has user(s) attached to it.');
+        expect(e.status).toEqual(HttpStatus.FORBIDDEN);
       }
     });
   });
-  describe('resetES', () => {
-    it('should reset search index', async () => {
-      employerServiceMock.initEmployerIndex.mockResolvedValueOnce([
-        {
-          _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
-          name: 'CAF',
-          validated: true,
-        },
-        {
-          _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
-          name: 'CARSAT',
-          validated: true,
-        },
-      ]);
-      const index = await controller.resetES();
-      expect(index.length).toBe(2);
-    });
-  });
 });
diff --git a/src/users/controllers/employer.controller.ts b/src/users/controllers/employer.controller.ts
index aff9d2e619e91b09ec9ff98ae2468d175d6c1df9..31eb7777f7a4581c704cea4b6ab520b0332900fc 100644
--- a/src/users/controllers/employer.controller.ts
+++ b/src/users/controllers/employer.controller.ts
@@ -6,23 +6,30 @@ import {
   HttpException,
   HttpStatus,
   Logger,
+  Param,
   Post,
+  Put,
   Query,
+  Request,
   UseGuards,
 } from '@nestjs/common';
-import { ApiParam } from '@nestjs/swagger';
+import { ApiBearerAuth, ApiOperation, ApiParam } from '@nestjs/swagger';
+import { MergeEmployerDto } from '../../admin/dto/merge-employer.dto';
 import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
+import { hasAdminRole } from '../../shared/utils';
 import { Roles } from '../decorators/roles.decorator';
 import { CreateEmployerDto } from '../dto/create-employer.dto';
 import { RolesGuard } from '../guards/roles.guard';
+import { IEmployer } from '../interfaces/employer.interface';
 import { Employer } from '../schemas/employer.schema';
 import { EmployerService } from '../services/employer.service';
+import { UsersService } from '../services/users.service';
 
 @Controller('employer')
 export class EmployerController {
   private readonly logger = new Logger(EmployerController.name);
 
-  constructor(private employerService: EmployerService) {}
+  constructor(private employerService: EmployerService, private usersService: UsersService) {}
 
   /**
    * Find all employer. If search is given as param, filter on it. Otherwise return everything
@@ -45,35 +52,21 @@ export class EmployerController {
    * @returns {Employer}
    */
   @Post()
+  @UseGuards(JwtAuthGuard)
+  @ApiBearerAuth('JWT')
   @ApiParam({ name: 'newEmployer', type: CreateEmployerDto, required: true })
-  public async createEmployer(@Body() newEmployer: CreateEmployerDto): Promise<Employer> {
+  public async createEmployer(@Body() newEmployer: CreateEmployerDto, @Request() req): Promise<Employer> {
     this.logger.debug(`createEmployer: ${newEmployer.name}`);
     const existingEmployer = await this.employerService.findByName(newEmployer.name);
     if (existingEmployer) {
       this.logger.warn(`Employer already exist: ${newEmployer.name}`);
       throw new HttpException('Employer already exist', HttpStatus.UNPROCESSABLE_ENTITY);
     }
-    return this.employerService.create(newEmployer);
-  }
-
-  /**
-   * Delete Employer if exist
-   * @param employer {CreateEmployerDto} - Employer to delete
-   * @returns {Employer}
-   */
-  @Delete()
-  @UseGuards(JwtAuthGuard, RolesGuard)
-  @Roles('admin')
-  @ApiParam({ name: 'employer', type: CreateEmployerDto, required: true })
-  public async deleteEmployer(@Body() employer: CreateEmployerDto): Promise<Employer> {
-    this.logger.debug(`deleteEmployer: ${employer.name}`);
-    const existingEmployer = await this.employerService.findByName(employer.name);
-    if (!existingEmployer) {
-      this.logger.warn(`Employer does not exist: ${employer.name}`);
-      throw new HttpException('Employer does not exist', HttpStatus.NOT_FOUND);
+    // if user is admin, do not send notification
+    if (hasAdminRole(req.user)) {
+      return this.employerService.create(newEmployer, true, false);
     }
-    await this.employerService.deleteByName(employer.name);
-    return existingEmployer;
+    return this.employerService.create(newEmployer);
   }
 
   // SEARCH
@@ -88,4 +81,82 @@ export class EmployerController {
   public async resetES(): Promise<Employer[]> {
     return this.employerService.initEmployerIndex();
   }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Get('validated')
+  @ApiOperation({ description: 'Get validated employers populated with users attached to it' })
+  public async findValidatedEmployers() {
+    return this.employerService.findAllValidated().then(async (employers: IEmployer[]) => {
+      return this.usersService.populateEmployerswithUsers(employers);
+    });
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Get('unvalidated')
+  @ApiOperation({ description: 'Get unvalidated employers for validation or merge' })
+  public async findUnvalidatedEmployers() {
+    return this.employerService.findAllUnvalidated().then(async (employers: IEmployer[]) => {
+      return this.usersService.populateEmployerswithUsers(employers);
+    });
+  }
+
+  /*
+   ** All users attached to this employer will be affected to the targeted employer
+   ** The original unvalidated employer will be deleted
+   */
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Put('merge')
+  public async mergeEmployer(@Body() mergeEmployer: MergeEmployerDto) {
+    return this.employerService.mergeEmployer(mergeEmployer);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Post('validate/:id')
+  @ApiParam({ name: 'id', type: String, required: true })
+  @ApiOperation({ description: 'Validate employer' })
+  public async validateEmployer(@Param() params) {
+    return this.employerService.validate(params.id);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Put(':id')
+  public async updateEmployer(@Param('id') id: string, @Body() body: CreateEmployerDto) {
+    return this.employerService.update(id, body);
+  }
+
+  /**
+   * Delete Employer if exist
+   * @param employer {CreateEmployerDto} - Employer to delete
+   * @returns {Employer}
+   */
+  @Delete(':id')
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @Roles('admin')
+  @ApiParam({ name: 'employer', type: CreateEmployerDto, required: true })
+  public async deleteEmployer(@Param() params): Promise<Employer> {
+    this.logger.debug(`deleteEmployer: ${params.id}`);
+    // look for employer
+    const researchedEmployer = await this.employerService.findOne(params.id);
+    // look for any relations within user collection, reject action if found
+    if (researchedEmployer !== null) {
+      const isEmployerLinked = await this.usersService.isEmployerLinkedtoUser(researchedEmployer._id);
+      if (!isEmployerLinked) {
+        return this.employerService.deleteOneId(params.id);
+      } else {
+        throw new HttpException('Cannot delete employer. It has user(s) attached to it.', HttpStatus.FORBIDDEN);
+      }
+    } else {
+      throw new HttpException('Employer does not exists', HttpStatus.NOT_FOUND);
+    }
+  }
 }
diff --git a/src/users/controllers/jobs.controller.spec.ts b/src/users/controllers/jobs.controller.spec.ts
index 776fefaf6a589cb8fa1ec6167a9c1a4266bec2b1..e097cd60ac52bb6bef701cfbf518b278f9b35e76 100644
--- a/src/users/controllers/jobs.controller.spec.ts
+++ b/src/users/controllers/jobs.controller.spec.ts
@@ -1,11 +1,13 @@
-import { HttpModule } from '@nestjs/common';
+import { HttpModule, HttpStatus } from '@nestjs/common';
 import { getModelToken } from '@nestjs/mongoose';
 import { Test, TestingModule } from '@nestjs/testing';
 import { Types } from 'mongoose';
 import { ConfigurationModule } from '../../configuration/configuration.module';
 import { CreateJobDto } from '../dto/create-job.dto';
 import { Job } from '../schemas/job.schema';
+import { User } from '../schemas/user.schema';
 import { JobsService } from '../services/jobs.service';
+import { UsersService } from '../services/users.service';
 import { JobsController } from './jobs.controller';
 
 describe('JobsController', () => {
@@ -15,6 +17,19 @@ describe('JobsController', () => {
     findAll: jest.fn(),
     findByName: jest.fn(),
     create: jest.fn(),
+    findOne: jest.fn(),
+    deleteOneId: jest.fn(),
+    findAllUnvalidated: jest.fn(),
+    createJobFromAdmin: jest.fn(),
+    validate: jest.fn(),
+    update: jest.fn(),
+    mergeJob: jest.fn(),
+    deleteInvalidJob: jest.fn(),
+  };
+
+  const userServiceMock = {
+    populateJobswithUsers: jest.fn(),
+    isJobLinkedtoUser: jest.fn(),
   };
 
   beforeEach(async () => {
@@ -25,10 +40,18 @@ describe('JobsController', () => {
           provide: JobsService,
           useValue: jobServiceMock,
         },
+        {
+          provide: UsersService,
+          useValue: userServiceMock,
+        },
         {
           provide: getModelToken('Job'),
           useValue: Job,
         },
+        {
+          provide: getModelToken('User'),
+          useValue: User,
+        },
       ],
       controllers: [JobsController],
     }).compile();
@@ -65,6 +88,7 @@ describe('JobsController', () => {
     it('should create job `Dev`', async () => {
       const newJob: CreateJobDto = {
         name: 'Dev',
+        hasPersonalOffer: false,
       };
       const newCreatedJob: Job = {
         name: 'Dev',
@@ -73,12 +97,14 @@ describe('JobsController', () => {
       };
       jobServiceMock.findByName.mockResolvedValueOnce(null);
       jobServiceMock.create.mockResolvedValueOnce(newCreatedJob);
-      const createReply = await controller.createJob(newJob);
+      const req = { user: { _id: '6036721022462b001334c4bb' } };
+      const createReply = await controller.createJob(req, newJob);
       expect(createReply).toEqual(newCreatedJob);
     });
     it('should throw error on already existing job `Dev`', async () => {
       const newJob: CreateJobDto = {
         name: 'Dev',
+        hasPersonalOffer: false,
       };
       jobServiceMock.findByName.mockResolvedValueOnce({
         _id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
@@ -87,7 +113,8 @@ describe('JobsController', () => {
         hasPersonalOffer: false,
       });
       try {
-        await controller.createJob(newJob);
+        const req = { user: { _id: '6036721022462b001334c4bb' } };
+        await controller.createJob(req, newJob);
         expect(true).toBe(false);
       } catch (e) {
         expect(e.message).toBe('Job already exist');
@@ -95,4 +122,159 @@ describe('JobsController', () => {
       }
     });
   });
+
+  describe('Create Job', () => {
+    it('should create a job', async () => {
+      jobServiceMock.findByName.mockResolvedValueOnce(null);
+      jobServiceMock.create.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      const req = { user: { _id: '6036721022462b001334c4bb', role: 0 } };
+      const reply = await controller.createJob(req, { name: 'Dev', hasPersonalOffer: true });
+      expect(reply).toBeTruthy();
+    });
+    it('should not create if job already exists', async () => {
+      jobServiceMock.findByName.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      const req = { user: { _id: '6036721022462b001334c4bb', role: 0 } };
+      try {
+        await controller.createJob(req, { name: 'Dev', hasPersonalOffer: true });
+      } catch (e) {
+        expect(e.message).toBe('Job already exist');
+        expect(e.status).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
+      }
+    });
+    it('should call create with send notification to true if admin', async () => {
+      jobServiceMock.findByName.mockResolvedValueOnce(null);
+      jobServiceMock.create.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      const req = { user: { _id: '6036721022462b001334c4bb', role: 1 } };
+      const job = { name: 'Dev', hasPersonalOffer: true };
+      const reply = await controller.createJob(req, job);
+      expect(reply).toBeTruthy();
+      expect(jobServiceMock.create).toHaveBeenCalledWith(job, true, true, false);
+    });
+  });
+  describe('Validate Job', () => {
+    it('should validate a given job', async () => {
+      jobServiceMock.validate.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      expect(await controller.validateJob({ id: '6231aefe76598527c8d0b5bc' })).toBeTruthy();
+    });
+  });
+  describe('Get Jobs', () => {
+    it('should call all validated jobs and populate them with users attached to it', async () => {
+      const spyer = jest.spyOn(userServiceMock, 'populateJobswithUsers');
+      jobServiceMock.findAll.mockResolvedValueOnce([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Dev',
+          validated: true,
+        },
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Scrum',
+          validated: true,
+        },
+      ]);
+      await controller.findValidatedJobs();
+      expect(jobServiceMock.findAll.mock.calls.length).toBe(2);
+      expect(spyer.mock.calls.length).toBe(1);
+    });
+
+    it('should call all unvalidated jobs and populate them with users attached to it', async () => {
+      const spyer = jest.spyOn(userServiceMock, 'populateJobswithUsers');
+      jobServiceMock.findAllUnvalidated.mockResolvedValueOnce([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Dev',
+          validated: false,
+        },
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'Scrum',
+          validated: false,
+        },
+      ]);
+      await controller.findUnvalidatedJobs();
+      expect(jobServiceMock.findAllUnvalidated.mock.calls.length).toBe(1);
+      expect(spyer.mock.calls.length).toBe(2);
+    });
+  });
+  describe('Edit Job', () => {
+    it('should update job', async () => {
+      jobServiceMock.update.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'DevMod',
+        validated: true,
+      });
+      expect(
+        await controller.updateJob('6231aefe76598527c8d0b5bc', { name: 'DevMod', hasPersonalOffer: false })
+      ).toBeTruthy();
+    });
+
+    it('should delete an unvalidated job and replace all its occurence with a chosen validated job', async () => {
+      jobServiceMock.mergeJob.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      jobServiceMock.deleteInvalidJob.mockResolvedValueOnce({
+        n: 1,
+        ok: 1,
+        deletedCount: 1,
+      });
+
+      const reply = await controller.mergeJob({
+        sourceJobId: '6231aefe76598527c8d0b5ba',
+        targetJobId: '6231aefe76598527c8d0b5bc',
+      });
+      expect(reply).toBeTruthy();
+    });
+  });
+  describe('Delete Job', () => {
+    jobServiceMock.deleteOneId.mockResolvedValueOnce({
+      n: 1,
+      ok: 1,
+      deletedCount: 1,
+    });
+
+    it('should delete job', async () => {
+      jobServiceMock.findOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
+        name: 'Dev',
+        validated: true,
+      });
+      userServiceMock.isJobLinkedtoUser.mockResolvedValueOnce(false);
+      const reply = await controller.deleteJob({ id: '6231aefe76598527c8d0b5ba' });
+      expect(reply).toBeTruthy();
+    });
+
+    it('should not delete job if a user is linked', async () => {
+      jobServiceMock.findOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Dev',
+        validated: true,
+      });
+      userServiceMock.isJobLinkedtoUser.mockResolvedValueOnce(true);
+      try {
+        await controller.deleteJob({ id: '6231aefe76598527c8d0b5bc' });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toEqual('Cannot delete job. It has user(s) attached to it.');
+        expect(e.status).toEqual(HttpStatus.FORBIDDEN);
+      }
+    });
+  });
 });
diff --git a/src/users/controllers/jobs.controller.ts b/src/users/controllers/jobs.controller.ts
index 7a6ceee14b3cf134a884928f05db60b1c36514fb..b716a01e68969435472252e30fbdfc4a4f8f7d3e 100644
--- a/src/users/controllers/jobs.controller.ts
+++ b/src/users/controllers/jobs.controller.ts
@@ -1,15 +1,34 @@
-import { Body, Controller, Get, HttpException, HttpStatus, Logger, Post } from '@nestjs/common';
-import { ApiParam } from '@nestjs/swagger';
-import { CreateEmployerDto } from '../dto/create-employer.dto';
+import {
+  Body,
+  Controller,
+  Delete,
+  Get,
+  HttpException,
+  HttpStatus,
+  Logger,
+  Param,
+  Post,
+  Put,
+  Request,
+  UseGuards,
+} from '@nestjs/common';
+import { ApiBearerAuth, ApiOperation, ApiParam } from '@nestjs/swagger';
+import { MergeJobDto } from '../../admin/dto/merge-job.dto';
+import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
+import { hasAdminRole } from '../../shared/utils';
+import { Roles } from '../decorators/roles.decorator';
 import { CreateJobDto } from '../dto/create-job.dto';
+import { RolesGuard } from '../guards/roles.guard';
+import { IJob } from '../interfaces/job.interface';
 import { Job } from '../schemas/job.schema';
 import { JobsService } from '../services/jobs.service';
+import { UsersService } from '../services/users.service';
 
 @Controller('jobs')
 export class JobsController {
   private readonly logger = new Logger(JobsController.name);
 
-  constructor(private jobsService: JobsService) {}
+  constructor(private jobsService: JobsService, private usersService: UsersService) {}
 
   /**
    * Return every jobs
@@ -22,18 +41,95 @@ export class JobsController {
 
   /**
    * Create a new job
-   * @param job {CreateEmployerDto}
+   * @param job {CreateJobDto}
    * @returns {Job}
    */
   @Post()
+  @UseGuards(JwtAuthGuard)
+  @ApiBearerAuth('JWT')
   @ApiParam({ name: 'job', type: CreateJobDto, required: true })
-  public async createJob(@Body() job: CreateEmployerDto): Promise<Job> {
+  public async createJob(@Request() req, @Body() job: CreateJobDto): Promise<Job> {
     this.logger.debug(`createJob: ${job.name}`);
     const existingJob = await this.jobsService.findByName(job.name);
     if (existingJob) {
       this.logger.warn(`Job already exist: ${job.name}`);
       throw new HttpException('Job already exist', HttpStatus.UNPROCESSABLE_ENTITY);
     }
+    // if user is admin, do not send notification
+    if (hasAdminRole(req.user)) {
+      return this.jobsService.create(job, true, job.hasPersonalOffer, false);
+    }
     return this.jobsService.create(job);
   }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Get('validated')
+  @ApiOperation({ description: 'Get validated jobs populated with users attached to it' })
+  public async findValidatedJobs() {
+    return this.jobsService.findAll().then(async (jobs: IJob[]) => {
+      return this.usersService.populateJobswithUsers(jobs);
+    });
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Get('unvalidated')
+  @ApiOperation({ description: 'Get unvalidated jobs populated with users attached to it' })
+  public async findUnvalidatedJobs() {
+    return this.jobsService.findAllUnvalidated().then(async (jobs: IJob[]) => {
+      return this.usersService.populateJobswithUsers(jobs);
+    });
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Post('validate/:id')
+  @ApiParam({ name: 'id', type: String, required: true })
+  @ApiOperation({ description: 'Validate job' })
+  public async validateJob(@Param() params) {
+    return this.jobsService.validate(params.id);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Put('merge')
+  public async mergeJob(@Body() mergeJob: MergeJobDto) {
+    this.logger.debug('mergeJob');
+    return this.jobsService.mergeJob(mergeJob);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @ApiBearerAuth('JWT')
+  @Roles('admin')
+  @Put(':id')
+  public async updateJob(@Param('id') id: string, @Body() body: CreateJobDto) {
+    this.logger.debug('updateJob');
+    return this.jobsService.update(id, body);
+  }
+
+  @UseGuards(JwtAuthGuard, RolesGuard)
+  @Roles('admin')
+  @Delete(':id')
+  @ApiBearerAuth('JWT')
+  @ApiParam({ name: 'id', type: String, required: true })
+  public async deleteJob(@Param() params) {
+    // look for job
+    const researchedJob = await this.jobsService.findOne(params.id);
+    // look for any relations within user collection, reject action if found
+    if (researchedJob !== null) {
+      const isJobLinked = await this.usersService.isJobLinkedtoUser(researchedJob._id);
+      if (!isJobLinked) {
+        return this.jobsService.deleteOneId(params.id);
+      } else {
+        throw new HttpException('Cannot delete job. It has user(s) attached to it.', HttpStatus.FORBIDDEN);
+      }
+    } else {
+      throw new HttpException('Job does not exists', HttpStatus.NOT_FOUND);
+    }
+  }
 }
diff --git a/src/users/dto/create-employer.dto.ts b/src/users/dto/create-employer.dto.ts
index e90ac1a6ac56bc1d05bc13bff1bbc949eec39c62..78682d2dd3848cb0d1567d40e2f354a78c071ea0 100644
--- a/src/users/dto/create-employer.dto.ts
+++ b/src/users/dto/create-employer.dto.ts
@@ -1,5 +1,5 @@
-import { IsNotEmpty, IsString } from 'class-validator';
 import { ApiProperty } from '@nestjs/swagger';
+import { IsNotEmpty, IsString } from 'class-validator';
 
 export class CreateEmployerDto {
   @ApiProperty({ type: String, example: 'PIMMS Vaise' })
diff --git a/src/users/dto/create-job.dto.ts b/src/users/dto/create-job.dto.ts
index 12eb86e2b94a2ccddba8c64eb0519cc95733e0fd..d120a8b182afee8cecff07c5e3f558962044e3bc 100644
--- a/src/users/dto/create-job.dto.ts
+++ b/src/users/dto/create-job.dto.ts
@@ -1,4 +1,4 @@
-import { IsNotEmpty, IsString } from 'class-validator';
+import { IsBoolean, IsNotEmpty, IsString } from 'class-validator';
 import { ApiProperty } from '@nestjs/swagger';
 
 export class CreateJobDto {
@@ -6,4 +6,8 @@ export class CreateJobDto {
   @IsNotEmpty()
   @IsString()
   readonly name: string;
+  @ApiProperty({ type: Boolean, example: false })
+  @IsNotEmpty()
+  @IsBoolean()
+  readonly hasPersonalOffer: boolean;
 }
diff --git a/src/users/interfaces/employer.interface.ts b/src/users/interfaces/employer.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f3ca8d206c7f4fa2e45005a867b445bef6030636
--- /dev/null
+++ b/src/users/interfaces/employer.interface.ts
@@ -0,0 +1,4 @@
+import { Document } from 'mongoose';
+import { Employer } from '../schemas/employer.schema';
+
+export type IEmployer = Employer & Document;
diff --git a/src/users/interfaces/job.interface.ts b/src/users/interfaces/job.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..737e2264d38aafb19d6d00b30b42ca47f2175be2
--- /dev/null
+++ b/src/users/interfaces/job.interface.ts
@@ -0,0 +1,4 @@
+import { Document } from 'mongoose';
+import { Job } from '../schemas/job.schema';
+
+export type IJob = Job & Document;
diff --git a/src/users/services/employer.service.spec.ts b/src/users/services/employer.service.spec.ts
index 0dad1f2838e685100441a9bac2116fdf25e3c218..628eafc330cdd5f5d1f3668c6e310c3884254e34 100644
--- a/src/users/services/employer.service.spec.ts
+++ b/src/users/services/employer.service.spec.ts
@@ -1,14 +1,20 @@
+import { HttpModule, HttpStatus } from '@nestjs/common';
 import { getModelToken } from '@nestjs/mongoose';
 import { Test, TestingModule } from '@nestjs/testing';
+import { AxiosResponse } from 'axios';
 import { Types } from 'mongoose';
 import { ConfigurationModule } from '../../configuration/configuration.module';
+import { MailerService } from '../../mailer/mailer.service';
 import { CreateEmployerDto } from '../dto/create-employer.dto';
 import { EmployerDocument } from '../schemas/employer.schema';
+import { User } from '../schemas/user.schema';
 import { EmployerSearchService } from './employer-search.service';
 import { EmployerService } from './employer.service';
+import { UsersService } from './users.service';
 
 describe('EmployerService', () => {
   let service: EmployerService;
+  let mailer: MailerService;
 
   const mockEmployerSearchService = {
     indexEmployer: jest.fn(),
@@ -20,13 +26,18 @@ describe('EmployerService', () => {
   const mockEmployerModel = {
     create: jest.fn(),
     findOne: jest.fn(),
+    findById: jest.fn(),
     deleteOne: jest.fn(),
     find: jest.fn(() => mockEmployerModel),
     sort: jest.fn(() => mockEmployerModel),
   };
+  const mockUserService = {
+    replaceEmployers: jest.fn(),
+    getAdmins: jest.fn(),
+  };
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
-      imports: [ConfigurationModule],
+      imports: [ConfigurationModule, HttpModule],
       providers: [
         EmployerService,
         {
@@ -37,9 +48,19 @@ describe('EmployerService', () => {
           provide: getModelToken('Employer'),
           useValue: mockEmployerModel,
         },
+        {
+          provide: UsersService,
+          useValue: mockUserService,
+        },
+        {
+          provide: getModelToken('User'),
+          useValue: User,
+        },
+        MailerService,
       ],
     }).compile();
     service = module.get<EmployerService>(EmployerService);
+    mailer = module.get<MailerService>(MailerService);
   });
 
   it('should be defined', () => {
@@ -62,35 +83,118 @@ describe('EmployerService', () => {
     const reply = await service.findAll();
     expect(reply.length).toBe(2);
   });
-
-  it('findByName', async () => {
-    mockEmployerModel.findOne.mockResolvedValue({
+  it('findOne', async () => {
+    mockEmployerModel.findById.mockResolvedValueOnce({
       _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
       name: 'Sopra',
       validated: true,
     });
-    const reply = await service.findByName('Sopra');
+    const reply = await service.findOne('6231aefe76598527c8d0b5bc');
     expect(reply).toBeTruthy();
   });
+  it('findAllValidated', async () => {
+    mockEmployerModel.find.mockResolvedValueOnce([
+      {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: true,
+      },
+    ]);
+    const reply = await service.findAllValidated();
+    expect(reply.length).toBe(1);
+  });
 
-  it('create', async () => {
-    mockEmployerModel.create.mockResolvedValue({
-      _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
-      name: 'Sopra',
-      validated: true,
-    });
+  it('findAllUnvalidated', async () => {
+    mockEmployerModel.find.mockResolvedValueOnce([
+      {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: false,
+      },
+    ]);
+    const reply = await service.findAllValidated();
+    expect(reply.length).toBe(1);
+  });
+
+  it('finds all unvalidated employers', async () => {
+    mockEmployerModel.find.mockResolvedValueOnce([
+      {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Metro',
+        validated: false,
+      },
+    ]);
+    const reply = await service.findAllUnvalidated();
+    expect(reply[0].validated).toBeFalsy;
+  });
+
+  it('finds all validated employers', async () => {
+    mockEmployerModel.find.mockResolvedValueOnce([
+      {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Metro',
+        validated: true,
+      },
+      {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5b2'),
+        name: 'Sopra',
+        validated: true,
+      },
+    ]);
+    const reply = await service.findAllUnvalidated();
+    expect(reply.length).toBe(2);
+  });
+
+  it('findByName', async () => {
     mockEmployerModel.findOne.mockResolvedValue({
       _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
       name: 'Sopra',
       validated: true,
     });
-    const createJob: CreateEmployerDto = {
-      name: 'Sopra',
-    };
-    const reply = await service.create(createJob);
+    const reply = await service.findByName('Sopra');
     expect(reply).toBeTruthy();
   });
 
+  describe('createEmployer', () => {
+    it('create', async () => {
+      mockEmployerModel.create.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: false,
+      });
+      mockEmployerModel.findOne.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: false,
+      });
+      const createEmployer: CreateEmployerDto = {
+        name: 'Sopra',
+      };
+      jest.spyOn(service, 'sendAdminCreateNotification').mockResolvedValueOnce();
+      const reply = await service.create(createEmployer);
+      expect(reply).toBeTruthy();
+      expect(service.sendAdminCreateNotification).toBeCalledTimes(1);
+    });
+
+    it('should create validated employer and not send email to admins', async () => {
+      mockEmployerModel.create.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: false,
+      });
+      mockEmployerModel.findOne.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Sopra',
+        validated: false,
+      });
+      const createEmployer: CreateEmployerDto = {
+        name: 'Sopra',
+      };
+      const reply = await service.create(createEmployer, true, false);
+      expect(reply).toBeTruthy();
+    });
+  });
+
   it('delete', async () => {
     mockEmployerModel.findOne.mockResolvedValueOnce({
       _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
@@ -145,4 +249,218 @@ describe('EmployerService', () => {
       expect(reply.length).toBe(2);
     });
   });
+
+  describe('mergeEmployer', () => {
+    it('should delete source employer', async () => {
+      const reply = {
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e61'),
+        name: 'Metro',
+        validated: true,
+      };
+      mockEmployerModel.findById
+        .mockResolvedValueOnce({
+          _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+          name: 'Sopra',
+          validated: false,
+        })
+        .mockResolvedValueOnce(reply);
+      jest.spyOn(service, 'deleteInvalidEmployer').mockRejectedValueOnce({});
+      mockUserService.replaceEmployers.mockResolvedValueOnce(null);
+      expect(
+        await service.mergeEmployer({
+          sourceEmployerId: '623aed68c5d45b6fbbaa7e60',
+          targetEmployerId: '623aed68c5d45b6fbbaa7e61',
+        })
+      ).toEqual(reply);
+    });
+    it('should delete source employer', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce(null).mockResolvedValueOnce(null);
+      jest.spyOn(service, 'deleteInvalidEmployer').mockRejectedValueOnce({});
+      mockUserService.replaceEmployers.mockResolvedValueOnce(null);
+      try {
+        await service.mergeEmployer({
+          sourceEmployerId: '623aed68c5d45b6fbbaa7e60',
+          targetEmployerId: '623aed68c5d45b6fbbaa7e61',
+        });
+      } catch (e) {
+        expect(e.message).toBe('Cannot operate on employer.');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+  });
+
+  describe('sendAdminCreateNotification', () => {
+    it('should sendAdminCreateNotification', async () => {
+      const employer = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Metro',
+        validated: true,
+      };
+      const result: AxiosResponse = {
+        data: {
+          status: 200,
+          content: {
+            success: true,
+            response: [7010],
+          },
+        },
+        status: 200,
+        statusText: 'OK',
+        headers: {},
+        config: {},
+      };
+      jest.spyOn(mailer, 'send').mockResolvedValueOnce(result);
+      const spyer = jest.spyOn(mailer, 'send');
+      mockUserService.getAdmins.mockResolvedValueOnce([
+        {
+          _id: '6231aefe76598527c8d0b5bc',
+          validationToken:
+            'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+          emailVerified: true,
+          email: 'admin@admin.com',
+          password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+          role: 0,
+          name: 'admin',
+          surname: 'admin',
+          personalOffers: [],
+        },
+      ]);
+      await service.sendAdminCreateNotification(
+        employer as EmployerDocument,
+        'adminEmployerCreate.ejs',
+        'adminEmployerCreate.json'
+      );
+      expect(spyer.mock.calls.length).toBe(1);
+    });
+  });
+
+  describe('validate', () => {
+    it('should validate employer', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Sopra',
+        validated: false,
+        save: jest.fn().mockResolvedValueOnce(null),
+      });
+      const employer = await service.validate('623aed68c5d45b6fbbaa7e60');
+      expect(employer.validated).toBe(true);
+    });
+    it('should throw exception', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce(null);
+      try {
+        await service.validate('623aed68c5d45b6fbbaa7e60');
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Cannot validate employer. It might have been already validate');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+  });
+
+  describe('update', () => {
+    it('should update employer', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Sopraaa',
+        validated: false,
+        save: jest.fn().mockResolvedValueOnce(null),
+      });
+      const employer = await service.update('623aed68c5d45b6fbbaa7e60', { name: 'Sopra' });
+      expect(employer.name).toBe('Sopra');
+    });
+    it('should throw exception', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce(null);
+      try {
+        await service.update('623aed68c5d45b6fbbaa7e60', { name: 'Sopra' });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Cannot edit employer. It was not found in database.');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+  });
+
+  describe('deleteInvalidEmployer', () => {
+    it('should delete invalid employer', async () => {
+      mockEmployerModel.findById.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Sopra',
+        validated: false,
+        save: jest.fn().mockResolvedValueOnce(null),
+      });
+      mockEmployerSearchService.deleteIndex.mockResolvedValueOnce(null);
+      mockEmployerModel.deleteOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Sopra',
+        validated: false,
+        save: jest.fn().mockResolvedValueOnce(null),
+      });
+      await service.deleteInvalidEmployer('6231aefe76598527c8d0b5bc');
+      expect(mockEmployerSearchService.deleteIndex).toBeCalled();
+      expect(mockEmployerModel.deleteOne).toBeCalled();
+    });
+  });
+
+  describe('deleteOneId', () => {
+    it('should delete ', async () => {
+      mockEmployerModel.findOne.mockResolvedValueOnce({
+        _id: '6231aefe76598527c8d0b5bc',
+        validationToken:
+          'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+        emailVerified: true,
+        email: 'admin@admin.com',
+        password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+        role: 0,
+        name: 'admin',
+        surname: 'admin',
+        personalOffers: [],
+        deleteOne: jest.fn().mockResolvedValueOnce({
+          _id: '6231aefe76598527c8d0b5bc',
+          validationToken:
+            'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+          emailVerified: true,
+          email: 'admin@admin.com',
+          password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+          role: 0,
+          name: 'admin',
+          surname: 'admin',
+          personalOffers: [],
+        }),
+      });
+      expect(await service.deleteOneId('6231aefe76598527c8d0b5bc')).toStrictEqual({
+        _id: '6231aefe76598527c8d0b5bc',
+        validationToken:
+          'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+        emailVerified: true,
+        email: 'admin@admin.com',
+        password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+        role: 0,
+        name: 'admin',
+        surname: 'admin',
+        personalOffers: [],
+      });
+    });
+    it('should throw an error ', async () => {
+      mockEmployerModel.findOne.mockResolvedValueOnce(null);
+
+      try {
+        expect(await service.deleteOneId('6231aefe76598527c8d0b5bc')).toStrictEqual({
+          _id: '6231aefe76598527c8d0b5bc',
+          validationToken:
+            'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+          emailVerified: true,
+          email: 'admin@admin.com',
+          password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+          role: 0,
+          name: 'admin',
+          surname: 'admin',
+          personalOffers: [],
+        });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Invalid employer id');
+        expect(e.status).toBe(HttpStatus.BAD_REQUEST);
+      }
+    });
+  });
 });
diff --git a/src/users/services/employer.service.ts b/src/users/services/employer.service.ts
index 79a50594d47db379c06680332c2c019e188c83af..f1fb4e2e05aa850f0a8679c49711162af8aedaf2 100644
--- a/src/users/services/employer.service.ts
+++ b/src/users/services/employer.service.ts
@@ -1,9 +1,14 @@
-import { Injectable, Logger } from '@nestjs/common';
+import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
 import { InjectModel } from '@nestjs/mongoose';
-import { Model, Query } from 'mongoose';
+import * as ejs from 'ejs';
+import { Model, Query, Types } from 'mongoose';
+import { MergeEmployerDto } from '../../admin/dto/merge-employer.dto';
+import { MailerService } from '../../mailer/mailer.service';
 import { CreateEmployerDto } from '../dto/create-employer.dto';
+import { IEmployer } from '../interfaces/employer.interface';
 import { Employer, EmployerDocument } from '../schemas/employer.schema';
 import { EmployerSearchService } from './employer-search.service';
+import { UsersService } from './users.service';
 
 @Injectable()
 export class EmployerService {
@@ -11,6 +16,8 @@ export class EmployerService {
 
   constructor(
     @InjectModel(Employer.name) private employerModel: Model<EmployerDocument>,
+    private readonly userService: UsersService,
+    private readonly mailerService: MailerService,
     private readonly employerSearchService: EmployerSearchService
   ) {}
 
@@ -19,19 +26,124 @@ export class EmployerService {
     return this.employerModel.find().sort({ name: 1 });
   }
 
+  public async findOne(idParam: string): Promise<EmployerDocument> {
+    this.logger.debug('findOne');
+    return await this.employerModel.findById(Types.ObjectId(idParam));
+  }
+
+  public async findAllUnvalidated(): Promise<Employer[]> {
+    this.logger.debug('findAllUnvalidated');
+    return this.employerModel.find({ validated: false });
+  }
+
+  public async findAllValidated(): Promise<IEmployer[]> {
+    this.logger.debug(`findAllValidated`);
+    return this.employerModel.find({ validated: true });
+  }
+
   public async findByName(name: string): Promise<EmployerDocument> {
     this.logger.debug('findByName');
     return this.employerModel.findOne({ name });
   }
 
-  public async create(employer: CreateEmployerDto, validated = false): Promise<Employer> {
+  public async create(employer: CreateEmployerDto, validated = false, sendAdminNotification = true): Promise<Employer> {
     this.logger.debug(`createEmployer: ${employer.name}`);
-    await this.employerModel.create({ name: employer.name, validated: validated });
+    await this.employerModel.create({ name: employer.name, validated });
     const document = await this.findByName(employer.name);
     this.employerSearchService.indexEmployer(document);
+    if (sendAdminNotification) {
+      this.sendAdminCreateNotification(
+        document,
+        this.mailerService.config.templates.adminEmployerCreate.ejs,
+        this.mailerService.config.templates.adminEmployerCreate.json
+      );
+    }
     return document;
   }
 
+  public async sendAdminCreateNotification(
+    employer: EmployerDocument,
+    templateLocation: any,
+    jsonConfigLocation: any
+  ): Promise<void> {
+    const config = this.mailerService.config;
+    const ejsPath = this.mailerService.getTemplateLocation(templateLocation);
+    const jsonConfig = this.mailerService.loadJsonConfig(jsonConfigLocation);
+    const html = await ejs.renderFile(ejsPath, {
+      config,
+      employerName: employer ? employer.name : '',
+    });
+    const admins = await this.userService.getAdmins();
+    admins.forEach((admin) => {
+      this.mailerService.send(admin.email, jsonConfig.subject, html);
+    });
+  }
+
+  public async validate(employerId: string): Promise<Employer> {
+    this.logger.debug(`validateEmployer: ${employerId}`);
+    const employer = await this.employerModel.findById(Types.ObjectId(employerId));
+    if (employer) {
+      employer.validated = true;
+      employer.save();
+      return employer;
+    } else {
+      throw new HttpException('Cannot validate employer. It might have been already validate', HttpStatus.NOT_FOUND);
+    }
+  }
+
+  public async update(employerId: string, newEmployer: CreateEmployerDto): Promise<Employer> {
+    this.logger.debug(`editEmployer: ${employerId}`);
+    const employer = await this.employerModel.findById(Types.ObjectId(employerId));
+    if (employer) {
+      employer.name = newEmployer.name;
+      employer.save();
+      return employer;
+    } else {
+      throw new HttpException('Cannot edit employer. It was not found in database.', HttpStatus.NOT_FOUND);
+    }
+  }
+
+  public async mergeEmployer({
+    sourceEmployerId,
+    targetEmployerId,
+  }: MergeEmployerDto): Promise<Employer | HttpException> {
+    this.logger.debug(`mergeEmployer: ${sourceEmployerId} into ${targetEmployerId}`);
+    const sourceEmployer = await this.employerModel.findById(Types.ObjectId(sourceEmployerId));
+    const targetEmployer = await this.employerModel.findById(Types.ObjectId(targetEmployerId));
+    if (targetEmployer && sourceEmployer) {
+      this.userService.replaceEmployers(sourceEmployer, targetEmployer);
+      if (!sourceEmployer.validated) {
+        this.deleteInvalidEmployer(sourceEmployerId);
+      }
+      return targetEmployer;
+    } else {
+      throw new HttpException('Cannot operate on employer.', HttpStatus.NOT_FOUND);
+    }
+  }
+
+  public async deleteInvalidEmployer(
+    id: string
+  ): Promise<
+    Query<{
+      ok?: number;
+      n?: number;
+      deletedCount?: number;
+    }>
+  > {
+    this.logger.debug(`deleteInvalidEmployer: ${id}`);
+    const document = await this.employerModel.findById(Types.ObjectId(id));
+    this.employerSearchService.deleteIndex(document, document._id);
+    return this.employerModel.deleteOne({ _id: id });
+  }
+
+  public async deleteOneId(id: string): Promise<Employer> {
+    const employer = await this.employerModel.findOne({ _id: id });
+    if (!employer) {
+      throw new HttpException('Invalid employer id', HttpStatus.BAD_REQUEST);
+    }
+    return employer.deleteOne();
+  }
+
   public async deleteByName(
     name: string
   ): Promise<
diff --git a/src/users/services/jobs.service.spec.ts b/src/users/services/jobs.service.spec.ts
index 697adbcc021ccef26fe62d26ca8c1d72c5132375..083f6531f0b160b25544c3f9f00ad6ffa1a517a5 100644
--- a/src/users/services/jobs.service.spec.ts
+++ b/src/users/services/jobs.service.spec.ts
@@ -1,48 +1,106 @@
+import { HttpModule, HttpService, HttpStatus } from '@nestjs/common';
 import { getModelToken } from '@nestjs/mongoose';
 import { Test, TestingModule } from '@nestjs/testing';
+import { AxiosResponse } from 'axios';
 import { Types } from 'mongoose';
+import { of } from 'rxjs';
 import { ConfigurationModule } from '../../configuration/configuration.module';
+import { MailerService } from '../../mailer/mailer.service';
 import { CreateJobDto } from '../dto/create-job.dto';
+import { JobDocument } from '../schemas/job.schema';
 import { JobsService } from './jobs.service';
+import { UsersService } from './users.service';
 
 describe('JobsService', () => {
   let service: JobsService;
+  let httpService: HttpService;
+  let mailer: MailerService;
 
   const mockJobModel = {
     create: jest.fn(),
     find: jest.fn(),
     findOne: jest.fn(),
+    findById: jest.fn(),
+    deleteOne: jest.fn(),
+  };
+
+  const mockUserModel = {
+    find: jest.fn(),
+    findOne: jest.fn(),
+    findById: jest.fn(),
+  };
+  const mockUserService = {
+    replaceJobs: jest.fn(),
+    getAdmins: jest.fn(),
   };
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
-      imports: [ConfigurationModule],
+      imports: [ConfigurationModule, HttpModule],
       providers: [
         JobsService,
         {
           provide: getModelToken('Job'),
           useValue: mockJobModel,
         },
+        {
+          provide: UsersService,
+          useValue: mockUserService,
+        },
+        {
+          provide: getModelToken('User'),
+          useValue: mockUserModel,
+        },
+        MailerService,
       ],
     }).compile();
     service = module.get<JobsService>(JobsService);
+    mailer = module.get<MailerService>(MailerService);
+    httpService = module.get<HttpService>(HttpService);
   });
 
   it('should be defined', () => {
     expect(service).toBeDefined();
   });
 
-  it('findAll', async () => {
+  describe('findAll', () => {
+    it('should findAll validated jobs', async () => {
+      mockJobModel.find.mockResolvedValue([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'CNFS',
+          validated: true,
+          hasPersonalOffer: true,
+        },
+      ]);
+      const reply = await service.findAll();
+      expect(reply.length).toBe(1);
+    });
+    it('should findAll all jobs', async () => {
+      mockJobModel.find.mockResolvedValue([
+        {
+          _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+          name: 'CNFSssss',
+          validated: false,
+          hasPersonalOffer: true,
+        },
+      ]);
+      const reply = await service.findAll(false);
+      expect(reply.length).toBe(1);
+    });
+  });
+
+  it('findUnvalidated', async () => {
     mockJobModel.find.mockResolvedValue([
       {
         _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
         name: 'CNFS',
-        validated: true,
+        validated: false,
         hasPersonalOffer: true,
       },
     ]);
-    const reply = await service.findAll();
-    expect(reply.length).toBe(1);
+    const reply = await service.findAllUnvalidated();
+    expect(reply[0].validated).toBeFalsy;
   });
 
   it('findByName', async () => {
@@ -55,18 +113,255 @@ describe('JobsService', () => {
     const reply = await service.findByName('CNFS');
     expect(reply).toBeTruthy();
   });
-
-  it('create', async () => {
-    mockJobModel.create.mockResolvedValue({
+  it('findOne', async () => {
+    mockJobModel.findById.mockResolvedValue({
       _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
       name: 'CNFS',
       validated: true,
       hasPersonalOffer: true,
     });
+    const reply = await service.findOne('6231aefe76598527c8d0b5bc');
+    expect(reply).toBeTruthy();
+  });
+
+  describe('createJob', () => {
+    it('create', async () => {
+      mockJobModel.create.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Dev',
+        validated: false,
+        hasPersonalOffer: false,
+      });
+      const createJob: CreateJobDto = {
+        name: 'Dev',
+        hasPersonalOffer: false,
+      };
+      const reply = await service.create(createJob);
+      expect(reply).toBeTruthy();
+    });
+
+    it('should send an email to admins', async () => {
+      //todo fetch admin infos and check httpservice is called further
+      const result: AxiosResponse = {
+        data: {
+          status: 200,
+          content: {
+            success: true,
+            response: [7010],
+          },
+        },
+        status: 200,
+        statusText: 'OK',
+        headers: {},
+        config: {},
+      };
+      jest.spyOn(httpService, 'post').mockImplementationOnce(() => of(result));
+      expect(await mailer.send('a@a.com', 'test', '<p>This is a test</p>')).toBe(result);
+    });
+  });
+
+  it('createFromAdmin', async () => {
+    mockJobModel.create.mockResolvedValue({
+      _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+      name: 'Dev',
+      validated: true,
+      hasPersonalOffer: false,
+    });
     const createJob: CreateJobDto = {
       name: 'Dev',
+      hasPersonalOffer: false,
     };
     const reply = await service.create(createJob);
     expect(reply).toBeTruthy();
   });
+
+  describe('sendAdminCreateNotification', () => {
+    it('should sendAdminCreateNotification', async () => {
+      const job = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'Metro',
+        validated: true,
+      };
+      const result: AxiosResponse = {
+        data: {
+          status: 200,
+          content: {
+            success: true,
+            response: [7010],
+          },
+        },
+        status: 200,
+        statusText: 'OK',
+        headers: {},
+        config: {},
+      };
+      jest.spyOn(mailer, 'send').mockResolvedValueOnce(result);
+      const spyer = jest.spyOn(mailer, 'send');
+      mockUserService.getAdmins.mockResolvedValueOnce([
+        {
+          _id: '6231aefe76598527c8d0b5bc',
+          validationToken:
+            'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+          emailVerified: true,
+          email: 'admin@admin.com',
+          password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+          role: 0,
+          name: 'admin',
+          surname: 'admin',
+          personalOffers: [],
+        },
+      ]);
+      await service.sendAdminCreateNotification(job as JobDocument, 'adminJobCreate.ejs', 'adminJobCreate.json');
+      expect(spyer.mock.calls.length).toBe(1);
+    });
+  });
+
+  describe('validate', () => {
+    it('should validate job', async () => {
+      mockJobModel.findById.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Dev',
+        validated: false,
+        save: jest.fn().mockResolvedValueOnce(null),
+      });
+      const job = await service.validate('623aed68c5d45b6fbbaa7e60');
+      expect(job.validated).toBe(true);
+    });
+    it('should throw exception', async () => {
+      mockJobModel.findById.mockResolvedValueOnce(null);
+      try {
+        await service.validate('623aed68c5d45b6fbbaa7e60');
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Cannot validate job. It might have been already validate');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+  });
+
+  describe('mergeJob', () => {
+    it('should delete source job', async () => {
+      const reply = {
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e61'),
+        name: 'Dev 2',
+        validated: true,
+        hasPersonalOffer: false,
+      };
+      mockJobModel.findById
+        .mockResolvedValueOnce({
+          _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+          name: 'Dev',
+          validated: false,
+          hasPersonalOffer: false,
+        })
+        .mockResolvedValueOnce(reply);
+      jest.spyOn(service, 'deleteInvalidJob').mockRejectedValueOnce({});
+
+      expect(
+        await service.mergeJob({ sourceJobId: '623aed68c5d45b6fbbaa7e60', targetJobId: '623aed68c5d45b6fbbaa7e61' })
+      ).toEqual(reply);
+    });
+    it('should throw error if target job is not validated', async () => {
+      mockJobModel.findById
+        .mockResolvedValueOnce({
+          _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+          name: 'Dev',
+          validated: false,
+          hasPersonalOffer: false,
+        })
+        .mockResolvedValueOnce(null);
+      try {
+        await service.mergeJob({ sourceJobId: '623aed68c5d45b6fbbaa7e60', targetJobId: '623aed68c5d45b6fbbaa7e61' });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Cannot operate on job.');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+    it('should throw error if no source or target job', async () => {
+      mockJobModel.findById.mockResolvedValueOnce(null).mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Dev',
+        validated: false,
+        hasPersonalOffer: false,
+      });
+      try {
+        await service.mergeJob({ sourceJobId: '623aed68c5d45b6fbbaa7e60', targetJobId: '623aed68c5d45b6fbbaa7e61' });
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Cannot operate on job.');
+        expect(e.status).toBe(HttpStatus.NOT_FOUND);
+      }
+    });
+  });
+
+  it('deleteInvalidJob', async () => {
+    mockJobModel.deleteOne.mockResolvedValueOnce(null);
+    const spyer = jest.spyOn(service, 'deleteInvalidJob');
+    await service.deleteInvalidJob('623aed68c5d45b6fbbaa7e60');
+    expect(spyer.mock.calls.length).toEqual(1);
+  });
+
+  describe('deleteOneId', () => {
+    it('should delete ', async () => {
+      mockJobModel.findOne.mockResolvedValueOnce({
+        _id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
+        name: 'Dev',
+        validated: false,
+        deleteOne: jest.fn().mockResolvedValueOnce('toto'),
+      });
+      const reply = await service.deleteOneId('623aed68c5d45b6fbbaa7e60');
+      expect(reply).toBe('toto');
+    });
+    it('should delete ', async () => {
+      mockJobModel.findOne.mockResolvedValueOnce(null);
+      try {
+        await service.deleteOneId('623aed68c5d45b6fbbaa7e60');
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe('Invalid job id');
+        expect(e.status).toBe(HttpStatus.BAD_REQUEST);
+      }
+    });
+  });
+
+  describe('update', () => {
+    it('should update', async () => {
+      const newJobDto = {
+        name: 'CNFS',
+        hasPersonalOffer: true,
+      };
+      const newJob = {
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'CNFS',
+        validated: true,
+        hasPersonalOffer: true,
+      };
+      mockJobModel.findById.mockResolvedValue({
+        _id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
+        name: 'CNFS old',
+        validated: true,
+        hasPersonalOffer: false,
+        save: jest.fn().mockResolvedValueOnce(newJob),
+      });
+      const reply = await service.update('623aed68c5d45b6fbbaa7e60', newJobDto);
+      expect(reply.name).toBe('CNFS');
+      expect(reply.hasPersonalOffer).toBe(true);
+    });
+  });
+
+  it('should throw error', async () => {
+    const newJobDto = {
+      name: 'CNFS',
+      hasPersonalOffer: true,
+    };
+    mockJobModel.findById.mockResolvedValue(null);
+    try {
+      await service.update('623aed68c5d45b6fbbaa7e60', newJobDto);
+      expect(true).toBe(false);
+    } catch (e) {
+      expect(e.message).toBe('Cannot edit job. It was not found in database.');
+      expect(e.status).toBe(HttpStatus.NOT_FOUND);
+    }
+  });
 });
diff --git a/src/users/services/jobs.service.ts b/src/users/services/jobs.service.ts
index 43e77b4c6fc19ef73e7da020b31308a05aa2c6aa..56442b52db120566a7c8164df4d383cad4afcb3c 100644
--- a/src/users/services/jobs.service.ts
+++ b/src/users/services/jobs.service.ts
@@ -1,18 +1,27 @@
-import { Injectable, Logger } from '@nestjs/common';
+import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
 import { InjectModel } from '@nestjs/mongoose';
-import { Model } from 'mongoose';
+import * as ejs from 'ejs';
+import { Model, Query, Types } from 'mongoose';
+import { MergeJobDto } from '../../admin/dto/merge-job.dto';
+import { MailerService } from '../../mailer/mailer.service';
 import { CreateJobDto } from '../dto/create-job.dto';
+import { IJob } from '../interfaces/job.interface';
 import { Job, JobDocument } from '../schemas/job.schema';
+import { UsersService } from './users.service';
 
 @Injectable()
 export class JobsService {
   private readonly logger = new Logger(JobsService.name);
 
-  constructor(@InjectModel(Job.name) private jobModel: Model<JobDocument>) {}
+  constructor(
+    @InjectModel(Job.name) private jobModel: Model<JobDocument>,
+    private readonly userService: UsersService,
+    private readonly mailerService: MailerService
+  ) {}
 
-  public async findAll(filterValidetedJobs = true): Promise<Job[]> {
-    this.logger.debug(`findAll with filterValidetedJobs: ${filterValidetedJobs}`);
-    if (!filterValidetedJobs) {
+  public async findAll(filterValidatedJobs = true): Promise<IJob[]> {
+    this.logger.debug(`findAll with filterValidetedJobs: ${filterValidatedJobs}`);
+    if (!filterValidatedJobs) {
       return this.jobModel.find();
     } else {
       return this.jobModel.find({ validated: true });
@@ -24,8 +33,115 @@ export class JobsService {
     return this.jobModel.findOne({ name });
   }
 
-  public async create(job: CreateJobDto, validated = false, hasPersonalOffer = true): Promise<Job> {
-    this.logger.debug(`createJob: ${job.name}`);
-    return this.jobModel.create({ name: job.name, validated, hasPersonalOffer });
+  public async findOne(idParam: string): Promise<JobDocument> {
+    this.logger.debug('findOne');
+    return this.jobModel.findById(Types.ObjectId(idParam));
+  }
+
+  public async findAllUnvalidated(): Promise<IJob[]> {
+    this.logger.debug('findAllUnvalidated');
+    return this.jobModel.find({ validated: false });
+  }
+
+  public async create(
+    job: CreateJobDto,
+    validated = false,
+    hasPersonalOffer = false,
+    sendNotification = true
+  ): Promise<Job> {
+    this.logger.debug(`createJob: ${job.name} | notificationSending ${sendNotification}`);
+    const result = this.jobModel
+      .create({ name: job.name, validated, hasPersonalOffer })
+      .then(async (postCreate: JobDocument) => {
+        if (sendNotification) {
+          this.sendAdminCreateNotification(
+            postCreate,
+            this.mailerService.config.templates.adminJobCreate.ejs,
+            this.mailerService.config.templates.adminJobCreate.json
+          );
+        }
+        return postCreate;
+      });
+    return result;
+  }
+
+  public async sendAdminCreateNotification(
+    job: JobDocument,
+    templateLocation: any,
+    jsonConfigLocation: any
+  ): Promise<void> {
+    const config = this.mailerService.config;
+    const ejsPath = this.mailerService.getTemplateLocation(templateLocation);
+    const jsonConfig = this.mailerService.loadJsonConfig(jsonConfigLocation);
+    const html = await ejs.renderFile(ejsPath, {
+      config,
+      jobName: job ? job.name : '',
+    });
+    const admins = await this.userService.getAdmins();
+    admins.forEach((admin) => {
+      this.mailerService.send(admin.email, jsonConfig.subject, html);
+    });
+  }
+
+  public async validate(jobId: string): Promise<Job> {
+    this.logger.debug(`validateJob: ${jobId}`);
+    const job = await this.jobModel.findById(Types.ObjectId(jobId));
+    if (job) {
+      job.validated = true;
+      job.save();
+      return job;
+    } else {
+      throw new HttpException('Cannot validate job. It might have been already validate', HttpStatus.NOT_FOUND);
+    }
+  }
+
+  public async mergeJob({ sourceJobId, targetJobId }: MergeJobDto): Promise<Job | HttpException> {
+    this.logger.debug(`mergeJob: ${sourceJobId} into ${targetJobId}`);
+    const sourceJob = await this.jobModel.findById(Types.ObjectId(sourceJobId));
+    const targetJob = await this.jobModel.findById(Types.ObjectId(targetJobId));
+    if (targetJob && sourceJob) {
+      this.logger.debug(`Both jobs : ${sourceJob}, ${targetJob}`);
+      this.userService.replaceJobs(sourceJob, targetJob);
+      if (!sourceJob.validated) {
+        this.deleteInvalidJob(sourceJobId);
+      }
+      return targetJob;
+    } else {
+      throw new HttpException('Cannot operate on job.', HttpStatus.NOT_FOUND);
+    }
+  }
+
+  public async deleteInvalidJob(
+    id: string
+  ): Promise<
+    Query<{
+      ok?: number;
+      n?: number;
+      deletedCount?: number;
+    }>
+  > {
+    this.logger.debug(`deleteInvalidJob: ${id}`);
+    return this.jobModel.deleteOne({ _id: id });
+  }
+
+  public async deleteOneId(id: string): Promise<Job> {
+    const job = await this.jobModel.findOne({ _id: id });
+    if (!job) {
+      throw new HttpException('Invalid job id', HttpStatus.BAD_REQUEST);
+    }
+    return job.deleteOne();
+  }
+
+  public async update(jobId: string, newJob: CreateJobDto): Promise<Job> {
+    this.logger.debug(`editJob: ${jobId}`);
+    const job = await this.jobModel.findById(Types.ObjectId(jobId));
+    if (job) {
+      job.name = newJob.name;
+      job.hasPersonalOffer = newJob.hasPersonalOffer;
+      job.save();
+      return job;
+    } else {
+      throw new HttpException('Cannot edit job. It was not found in database.', HttpStatus.NOT_FOUND);
+    }
   }
 }
diff --git a/src/users/services/users.service.spec.ts b/src/users/services/users.service.spec.ts
index 2eaee5ce895a86269eed4f69716d3e4f561edd61..11079f622c9148565b967cb2c9acff4c5ec6ab00 100644
--- a/src/users/services/users.service.spec.ts
+++ b/src/users/services/users.service.spec.ts
@@ -7,6 +7,7 @@ import * as bcrypt from 'bcrypt';
 import { personalOffersDataMock } from '../../../test/mock/data/personalOffers.mock.data';
 import { PersonalOfferDocument } from '../../personal-offers/schemas/personal-offer.schema';
 import { usersMockData } from '../../../test/mock/data/users.mock.data';
+import { employersMockData } from '../../../test/mock/data/employers.mock.data';
 import { LoginDto } from '../../auth/login-dto';
 import { ConfigurationModule } from '../../configuration/configuration.module';
 import { MailerModule } from '../../mailer/mailer.module';
@@ -19,6 +20,17 @@ function hashPassword() {
   return bcrypt.hashSync(process.env.USER_PWD, process.env.SALT);
 }
 
+const mockUserModel = {
+  create: jest.fn(),
+  findOne: jest.fn(),
+  findById: jest.fn(),
+  deleteOne: jest.fn(),
+  updateMany: jest.fn(),
+  exec: jest.fn(),
+  find: jest.fn(() => mockUserModel),
+  sort: jest.fn(() => mockUserModel),
+};
+
 describe('UsersService', () => {
   let service: UsersService;
 
@@ -29,7 +41,7 @@ describe('UsersService', () => {
         UsersService,
         {
           provide: getModelToken('User'),
-          useValue: User,
+          useValue: mockUserModel,
         },
       ],
     }).compile();
@@ -405,4 +417,29 @@ describe('UsersService', () => {
       }
     });
   });
+
+  describe('user employer', () => {
+    it('should replace employer with a new one', async () => {
+      const spyer = jest.spyOn(mockUserModel, 'updateMany');
+
+      mockUserModel.updateMany.mockReturnThis();
+      mockUserModel.exec.mockResolvedValueOnce([usersMockData[0]]);
+      await service.replaceEmployers(employersMockData[0], employersMockData[1]);
+      expect(spyer).toBeCalledTimes(1);
+    });
+
+    it('should return true if a user is linked to a given employer', async () => {});
+    it('should fetch users attached to a given employer', async () => {});
+    it('should populate an employer with a list of attached users', async () => {});
+    it("should update user's employer ", async () => {});
+  });
+
+  describe('user job', () => {
+    it('should replace job with a new one', async () => {});
+
+    it('should return true if a user is linked to a given job', async () => {});
+    it('should fetch users attached to a given job', async () => {});
+    it('should populate an job with a list of attached users', async () => {});
+    it("should update user's job ", async () => {});
+  });
 });
diff --git a/src/users/services/users.service.ts b/src/users/services/users.service.ts
index fecd0be4252b9f10e519c2f4835408908e34dc32..676c6047162c2e60a0d8cab30124561f93d4ac58 100644
--- a/src/users/services/users.service.ts
+++ b/src/users/services/users.service.ts
@@ -14,8 +14,8 @@ import { PendingStructureDto } from '../../admin/dto/pending-structure.dto';
 import { OwnerDto } from '../dto/owner.dto';
 import { StructureDocument } from '../../structures/schemas/structure.schema';
 import { ConfigurationService } from '../../configuration/configuration.service';
-import { EmployerDocument } from '../schemas/employer.schema';
-import { JobDocument } from '../schemas/job.schema';
+import { Employer, EmployerDocument } from '../schemas/employer.schema';
+import { Job, JobDocument } from '../schemas/job.schema';
 import { PersonalOfferDocument } from '../../personal-offers/schemas/personal-offer.schema';
 
 @Injectable()
@@ -87,7 +87,7 @@ export class UsersService {
   }
 
   public findAll(): Promise<User[]> {
-    return this.userModel.find().exec();
+    return this.userModel.find().populate('employer').populate('job').select('-password').exec();
   }
 
   public findAllUnattached(): Promise<IUser[]> {
@@ -98,6 +98,9 @@ export class UsersService {
       .where('structuresLink')
       .size(0)
       .sort({ surname: 1 })
+      .populate('employer')
+      .populate('job')
+      .select('-password')
       .exec();
   }
 
@@ -107,18 +110,29 @@ export class UsersService {
       .where('emailVerified')
       .equals(true)
       .sort({ surname: 1 })
+      .populate('employer')
+      .populate('job')
+      .select('-password')
       .exec();
   }
 
   public findAllUnVerified(): Promise<IUser[]> {
-    return this.userModel.find().where('emailVerified').equals(false).sort({ surname: 1 }).exec();
+    return this.userModel
+      .find()
+      .where('emailVerified')
+      .equals(false)
+      .sort({ surname: 1 })
+      .populate('employer')
+      .populate('job')
+      .select('-password')
+      .exec();
   }
 
   public async findById(id: string, passwordQuery?: boolean): Promise<IUser | undefined> {
     if (passwordQuery) {
-      return this.userModel.findById(id).exec();
+      return this.userModel.findById(id).populate('employer').populate('job').exec();
     }
-    return this.userModel.findById(id).select('-password').exec();
+    return this.userModel.findById(id).populate('employer').populate('job').select('-password').exec();
   }
 
   public async removeStructureIdFromUsers(structureId: Types.ObjectId): Promise<IUser[] | undefined> {
@@ -127,6 +141,19 @@ export class UsersService {
       .exec();
   }
 
+  public async replaceEmployers(
+    sourceEmployer: EmployerDocument,
+    targetEmployer: EmployerDocument
+  ): Promise<IUser[] | undefined> {
+    return this.userModel
+      .updateMany({ employer: sourceEmployer._id }, { $set: { employer: targetEmployer._id } })
+      .exec();
+  }
+
+  public async replaceJobs(sourceJob: JobDocument, targetJob: JobDocument): Promise<IUser[] | undefined> {
+    return this.userModel.updateMany({ job: sourceJob._id }, { $set: { job: targetJob._id } }).exec();
+  }
+
   /**
    * Return a user after credential checking.
    * Use for login action
@@ -359,6 +386,63 @@ export class UsersService {
     return this.userModel.findOne({ structuresLink: Types.ObjectId(structureId) }).exec();
   }
 
+  public async isEmployerLinkedtoUser(id: string): Promise<boolean> {
+    const users = await this.userModel.find().exec();
+    let hasLinkedUser = false;
+    users.map((x) => {
+      if (String(x.employer) === id.toString()) {
+        hasLinkedUser = true;
+      }
+    });
+    return hasLinkedUser;
+  }
+
+  public async isJobLinkedtoUser(id: string): Promise<boolean> {
+    const users = await this.userModel.find().exec();
+    let hasLinkedUser = false;
+    users.map((x) => {
+      if (String(x.job) === id.toString()) {
+        hasLinkedUser = true;
+      }
+    });
+    return hasLinkedUser;
+  }
+
+  public getJobAttachedUsers(jobId: JobDocument): Promise<IUser[]> {
+    return this.userModel.find({ job: jobId._id }).select('-password -job').exec();
+  }
+
+  public getEmployerAttachedUsers(employerId: EmployerDocument): Promise<IUser[]> {
+    return this.userModel.find({ employer: employerId._id }).select('-password -employer').exec();
+  }
+
+  public async populateJobswithUsers(jobs: JobDocument[]): Promise<any[]> {
+    return Promise.all(
+      jobs.map(async (job) => {
+        return {
+          _id: job._id,
+          name: job.name,
+          validated: job.validated,
+          hasPersonalOffer: job.hasPersonalOffer,
+          users: await this.getJobAttachedUsers(job),
+        };
+      })
+    );
+  }
+
+  public async populateEmployerswithUsers(employers: EmployerDocument[]): Promise<any[]> {
+    return Promise.all(
+      employers.map(async (employer) => {
+        return {
+          _id: employer._id,
+          name: employer.name,
+          validated: employer.validated,
+          users: await this.getEmployerAttachedUsers(employer),
+        };
+      })
+    );
+  }
+
   public getStructureOwners(structureId: string): Promise<IUser[]> {
     return this.userModel.find({ structuresLink: Types.ObjectId(structureId) }).exec();
   }
@@ -529,7 +613,7 @@ export class UsersService {
       return this.getPendingStructures();
     } else {
       throw new HttpException(
-        'Cannot validate strucutre. It might have been already validate, or the structure does`nt belong to the user',
+        'Cannot validate strucutre. It might have been already validate, or the structure doesn`t belong to the user',
         HttpStatus.NOT_FOUND
       );
     }
@@ -608,6 +692,7 @@ export class UsersService {
   }
 
   /**
+   *
    * @param profile
    * @param userId
    */
@@ -615,4 +700,24 @@ export class UsersService {
     this.logger.debug(`updateUserProfile | ${userId}`);
     return this.userModel.updateOne({ _id: userId }, { $set: { employer: employer._id, job: job._id } });
   }
+
+  /**
+   *
+   * @param job
+   * @param userId
+   */
+  public async updateUserJob(userId: Types.ObjectId, job: JobDocument): Promise<any> {
+    this.logger.debug(`updateUserProfile - Job | ${userId}`);
+    return this.userModel.updateOne({ _id: userId }, { $set: { job: job._id } });
+  }
+
+  /**
+   *
+   * @param employer
+   * @param userId
+   */
+  public async updateUserEmployer(userId: Types.ObjectId, employer: EmployerDocument): Promise<any> {
+    this.logger.debug(`updateUserProfile - Employer | ${userId}`);
+    return this.userModel.updateOne({ _id: userId }, { $set: { employer: employer._id } });
+  }
 }
diff --git a/test/mock/data/employers.mock.data.ts b/test/mock/data/employers.mock.data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..073aa6d65c5cb07aee5b5590314a87ab76d3d1ac
--- /dev/null
+++ b/test/mock/data/employers.mock.data.ts
@@ -0,0 +1,14 @@
+import { IEmployer } from '../../../src/users/interfaces/employer.interface';
+
+export const employersMockData: IEmployer[] = [
+  {
+    _id: '6036721022462b001334c4ba',
+    name: 'Metro',
+    validated: true,
+  } as any,
+  {
+    _id: '6036721022462b001334c4bb',
+    name: 'Sopra',
+    validated: true,
+  } as any,
+] as IEmployer[];
diff --git a/test/mock/services/user.mock.service.ts b/test/mock/services/user.mock.service.ts
index e13d723466b5f39ee643c871367e8a36f8c4907f..1ef41de52cc36e0d195a566978e47bf21d772275 100644
--- a/test/mock/services/user.mock.service.ts
+++ b/test/mock/services/user.mock.service.ts
@@ -1,4 +1,5 @@
 import { HttpException, HttpStatus } from '@nestjs/common';
+import { isValidObjectId } from 'mongoose';
 import { PendingStructureDto } from '../../../src/admin/dto/pending-structure.dto';
 import { LoginDto } from '../../../src/auth/login-dto';
 import { PersonalOffer, PersonalOfferDocument } from '../../../src/personal-offers/schemas/personal-offer.schema';
@@ -66,17 +67,66 @@ export class UsersServiceMock {
     return user;
   }
 
+  findById(id: string) {
+    if (isValidObjectId(id)) {
+      return {
+        _id: id,
+        validationToken:
+          'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+        emailVerified: true,
+        email: 'pauline.dupont@mii.com',
+        password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+        role: 0,
+        name: 'DUPONT',
+        surname: 'Pauline',
+        personalOffers: [],
+      };
+    } else {
+      return null;
+    }
+  }
+
+  isEmployerLinkedtoUser(id: string) {
+    if (id == '6231aefe76598527c8d0b5bc') return true;
+    else {
+      return false;
+    }
+  }
+
+  isJobLinkedtoUser(id: string) {
+    if (id == '6231aefe76598527c8d0b5bc') return true;
+    else {
+      return false;
+    }
+  }
+  getAdmins() {
+    return {
+      _id: '6231aefe76598527c8d0b5bc',
+      validationToken:
+        'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
+      emailVerified: true,
+      email: 'admin@admin.com',
+      password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
+      role: 0,
+      name: 'admin',
+      surname: 'admin',
+      personalOffers: [],
+    };
+  }
+
   getPendingStructures() {
     return [
       {
         structureId: '6093ba0e2ab5775cfc01ed3e',
         structureName: 'a',
         userEmail: 'paula.dubois@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       },
       {
         structureId: '6903ba0e2ab5775cfc01ed4d',
         structureName: "L'Atelier Numérique",
         userEmail: 'jacques.dupont@mii.com',
+        updatedAt: '2021-03-02T10:07:48.000Z',
       },
     ];
   }
@@ -211,6 +261,18 @@ export class UsersServiceMock {
     return await [];
   }
 
+  async populateEmployerswithUsers(): Promise<User[]> {
+    return await [];
+  }
+
+  async populateJobswithUsers(): Promise<User[]> {
+    return await [];
+  }
+
+  replaceEmployers(source, tar): IUser[] {
+    return [];
+  }
+
   public async addPersonalOffer(userId: string, personalOfferDocument: PersonalOfferDocument): Promise<IUser> {
     if (userId === '6036721022462b001334c4bb') {
       const personalOffer: PersonalOffer = { ...personalOfferDocument } as PersonalOffer;
@@ -240,4 +302,12 @@ export class UsersServiceMock {
     }
     throw new HttpException('User not found for the personal offer attachment', HttpStatus.BAD_REQUEST);
   }
+
+  async updateUserJob() {
+    return await [];
+  }
+
+  async updateUserEmployer() {
+    return await [];
+  }
 }