diff --git a/src/app.module.ts b/src/app.module.ts
index e0aa57e2278e56f027bcfe0d0db969e5936708c8..467fe404c31f6fdeadc948aec96bdf136aa676f3 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -11,6 +11,7 @@ import { MailerModule } from './mailer/mailer.module';
 import { TclModule } from './tcl/tcl.module';
 import { AdminModule } from './admin/admin.module';
 import { PostsModule } from './posts/posts.module';
+import { TempUserModule } from './temp-user/temp-user.module';
 @Module({
   imports: [
     ConfigurationModule,
@@ -26,6 +27,7 @@ import { PostsModule } from './posts/posts.module';
     TclModule,
     AdminModule,
     PostsModule,
+    TempUserModule,
   ],
   controllers: [AppController],
 })
diff --git a/src/configuration/config.dev.ts b/src/configuration/config.dev.ts
index 30d4a3f124d3f64e1c4427164e985e193a07535f..90917c6903316ef855ee1e2d21e7b93dcb7aa76a 100644
--- a/src/configuration/config.dev.ts
+++ b/src/configuration/config.dev.ts
@@ -7,31 +7,4 @@ export const configDev = {
   from: 'inclusionnumerique@grandlyon.com',
   from_name: 'Réseau des acteurs de la médiation numérique',
   replyTo: 'inclusionnumerique@grandlyon.com',
-  templates: {
-    directory: './src/mailer/mail-templates',
-    verify: {
-      ejs: 'verify.ejs',
-      json: 'verify.json',
-    },
-    changeEmail: {
-      ejs: 'changeEmail.ejs',
-      json: 'changeEmail.json',
-    },
-    resetPassword: {
-      ejs: 'resetPassword.ejs',
-      json: 'resetPassword.json',
-    },
-    adminStructureClaim: {
-      ejs: 'adminStructureClaim.ejs',
-      json: 'adminStructureClaim.json',
-    },
-    structureClaimValidation: {
-      ejs: 'structureClaimValidation.ejs',
-      json: 'structureClaimValidation.json',
-    },
-    structureOutdatedInfo: {
-      ejs: 'structureOutdatedInfo.ejs',
-      json: 'structureOutdatedInfo.json',
-    },
-  },
 };
diff --git a/src/configuration/config.prod.ts b/src/configuration/config.prod.ts
index 19167f8c124329bc4acf99b1d1ce7c3dc84ed032..d9333dd6499c2498a7853abf5ad97b8e1a2c849c 100644
--- a/src/configuration/config.prod.ts
+++ b/src/configuration/config.prod.ts
@@ -7,31 +7,4 @@ export const configProd = {
   from: 'inclusionnumerique@grandlyon.com',
   from_name: 'Réseau des acteurs de la médiation numérique',
   replyTo: 'inclusionnumerique@grandlyon.com',
-  templates: {
-    directory: './src/mailer/mail-templates',
-    verify: {
-      ejs: 'verify.ejs',
-      json: 'verify.json',
-    },
-    changeEmail: {
-      ejs: 'changeEmail.ejs',
-      json: 'changeEmail.json',
-    },
-    resetPassword: {
-      ejs: 'resetPassword.ejs',
-      json: 'resetPassword.json',
-    },
-    adminStructureClaim: {
-      ejs: 'adminStructureClaim.ejs',
-      json: 'adminStructureClaim.json',
-    },
-    structureClaimValidation: {
-      ejs: 'structureClaimValidation.ejs',
-      json: 'structureClaimValidation.json',
-    },
-    structureOutdatedInfo: {
-      ejs: 'structureOutdatedInfo.ejs',
-      json: 'structureOutdatedInfo.json',
-    },
-  },
 };
diff --git a/src/configuration/config.ts b/src/configuration/config.ts
index 7bb9d6f5a8b02c9fc654caa84f5cb74a223c99e9..e9d940409b5b8b927e138bb8b33a9e2ff6935743 100644
--- a/src/configuration/config.ts
+++ b/src/configuration/config.ts
@@ -37,5 +37,13 @@ export const config = {
       ejs: 'apticStructureDuplication.ejs',
       json: 'apticStructureDuplication.json',
     },
+    tempUserRegistration: {
+      ejs: 'tempUserRegistration.ejs',
+      json: 'tempUserRegistration.json',
+    },
+    structureJoinRequest: {
+      ejs: 'structureJoinRequest.ejs',
+      json: 'structureJoinRequest.json',
+    },
   },
 };
diff --git a/src/configuration/configuration.service.ts b/src/configuration/configuration.service.ts
index 13b4f5e4d827e55bc85ba4cacb6dc54ada5c887c..ca6f9e6c44a78e2259c3b3e70c8a5168d3d30d95 100644
--- a/src/configuration/configuration.service.ts
+++ b/src/configuration/configuration.service.ts
@@ -10,9 +10,11 @@ export class ConfigurationService {
     // Initializing conf with values from var env
     if (process.env.NODE_ENV && process.env.NODE_ENV === 'production') {
       this._config = configProd;
+      this._config.templates = config.templates; // Add mail templates
       Logger.log('App started with production conf', 'ConfigurationService');
     } else if (process.env.NODE_ENV && process.env.NODE_ENV === 'dev') {
       this._config = configDev;
+      this._config.templates = config.templates; // Add mail templates
       Logger.log('App started with dev conf', 'ConfigurationService');
     } else {
       this._config = config;
diff --git a/src/mailer/mail-templates/structureJoinRequest.ejs b/src/mailer/mail-templates/structureJoinRequest.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..550665e04bb48c9f796a21b97fef4dfc11407107
--- /dev/null
+++ b/src/mailer/mail-templates/structureJoinRequest.ejs
@@ -0,0 +1,21 @@
+Bonjour<br />
+<br />
+Vous recevez ce message car <strong><%= surname %></strong> <strong><%= name %></strong> demande a rejoindre votre
+stucture <strong><%= structureName %></strong> sur RES'in, le réseau des acteurs de l'inclusion numérique de la
+Métropole de Lyon. Vous pouvez dès maintenant valider la demande en
+<a
+  href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/join?id=<%= id %>&userId=<%= userId %>&status=true"
+  >cliquant ici</a
+>
+ou refuser la demande
+<a
+  href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/join?id=<%= id %>&userId=<%= userId %>&status=false"
+  >cliquant ici</a
+>.
+<br />
+Cordialement,
+<br />
+L'équipe RES'in
+<br />
+<br />
+Ce mail est un mail automatique. Merci de ne pas y répondre.
diff --git a/src/mailer/mail-templates/structureJoinRequest.json b/src/mailer/mail-templates/structureJoinRequest.json
new file mode 100644
index 0000000000000000000000000000000000000000..8b756e80dda646b74494d044a1c027c48294ac34
--- /dev/null
+++ b/src/mailer/mail-templates/structureJoinRequest.json
@@ -0,0 +1,3 @@
+{
+  "subject": "Un acteur demande a rejoindre votre structure, Réseau des Acteurs de la Médiation Numérique de la Métropole de Lyon"
+}
diff --git a/src/mailer/mail-templates/tempUserRegistration.ejs b/src/mailer/mail-templates/tempUserRegistration.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..8422b7dbefde902844d6970d16a0b19282321a92
--- /dev/null
+++ b/src/mailer/mail-templates/tempUserRegistration.ejs
@@ -0,0 +1,15 @@
+Bonjour<br />
+<br />
+Vous recevez ce message car vous avez été relié a la stucture <strong><%= name %></strong> sur RES'in, le réseau des
+acteurs de l'inclusion numérique de la Métropole de Lyon. Vous pouvez dès maitenant vous créer un compte sur la
+plateforme pour accéder a votre structure en
+<a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/register?id=<%= id %>"
+  >cliquant ici</a
+>.
+<br />
+Cordialement,
+<br />
+L'équipe RES'in
+<br />
+<br />
+Ce mail est un mail automatique. Merci de ne pas y répondre.
diff --git a/src/mailer/mail-templates/tempUserRegistration.json b/src/mailer/mail-templates/tempUserRegistration.json
new file mode 100644
index 0000000000000000000000000000000000000000..b344e7953f3643b216eec56a385e464f4d6a0de6
--- /dev/null
+++ b/src/mailer/mail-templates/tempUserRegistration.json
@@ -0,0 +1,3 @@
+{
+  "subject": "Un compte a été créé pour vous sur le Réseau des Acteurs de la Médiation Numérique de la Métropole de Lyon"
+}
diff --git a/src/structures/services/structures.service.ts b/src/structures/services/structures.service.ts
index 934ff6e620d4402e2e4f08291ee5c75566095bb2..4f9a8b7fdcacd65080b8b2157859b62adfb9c1d2 100644
--- a/src/structures/services/structures.service.ts
+++ b/src/structures/services/structures.service.ts
@@ -11,7 +11,9 @@ import { User } from '../../users/schemas/user.schema';
 import { MailerService } from '../../mailer/mailer.service';
 import { Cron, CronExpression } from '@nestjs/schedule';
 import { DateTime } from 'luxon';
+import { IUser } from '../../users/interfaces/user.interface';
 import * as _ from 'lodash';
+
 @Injectable()
 export class StructuresService {
   constructor(
@@ -117,7 +119,7 @@ export class StructuresService {
     return this.findOne(idStructure);
   }
 
-  public async findOne(idParam: string): Promise<Structure> {
+  public async findOne(idParam: string): Promise<StructureDocument> {
     return await this.structureModel.findById(Types.ObjectId(idParam)).exec();
   }
   /**
@@ -288,7 +290,7 @@ export class StructuresService {
   }
 
   /**
-   * Generate activation token and send it to user by email, in order to validate
+   * Send an email to prevent outdated
    * a new account.
    * @param user User
    */
@@ -305,6 +307,34 @@ export class StructuresService {
     this.mailerService.send(userEmail, jsonConfig.subject, html);
   }
 
+  /**
+   * Send an email to structure owner's in order to accept or decline a join request
+   * @param user User
+   */
+  public async sendStructureJoinRequest(user: IUser, structure: StructureDocument): Promise<void> {
+    const config = this.mailerService.config;
+    const ejsPath = this.mailerService.getTemplateLocation(config.templates.structureJoinRequest.ejs);
+    const jsonConfig = this.mailerService.loadJsonConfig(config.templates.structureJoinRequest.json);
+
+    const html = await ejs.renderFile(ejsPath, {
+      config,
+      structureName: structure.structureName,
+      name: user.name,
+      surname: user.surname,
+      id: structure._id,
+      userId: user._id,
+    });
+    const owners = await this.getOwners(structure._id);
+    owners.forEach((owner) => {
+      this.mailerService.send(owner.email, jsonConfig.subject, html);
+    });
+  }
+
+  private async getOwners(structureId: string): Promise<IUser[]> {
+    // Get owners of outdated structures
+    return this.userService.getStructureOwners(structureId);
+  }
+
   public async updateAccountVerified(idStructure: string, emailUser: string): Promise<Structure> {
     const user = await this.userService.findOne(emailUser);
     const structureLinked = await this.findOne(user.structuresLink[0].toHexString());
diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts
index 428154b072e576d954680a236fc6040498354a2a..5b1dde3eeed6c27796b31bedf03c57d0671325ec 100644
--- a/src/structures/structures.controller.ts
+++ b/src/structures/structures.controller.ts
@@ -1,7 +1,23 @@
-import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Query, UseGuards } from '@nestjs/common';
+import {
+  Body,
+  Controller,
+  Delete,
+  Get,
+  HttpException,
+  HttpStatus,
+  Param,
+  ParseIntPipe,
+  Post,
+  Put,
+  Query,
+  UseGuards,
+} from '@nestjs/common';
 import { ApiParam } from '@nestjs/swagger';
 import { Types } from 'mongoose';
 import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
+import { CreateTempUserDto } from '../temp-user/dto/create-temp-user.dto';
+import { TempUser } from '../temp-user/temp-user.schema';
+import { TempUserService } from '../temp-user/temp-user.service';
 import { Roles } from '../users/decorators/roles.decorator';
 import { IsStructureOwnerGuard } from '../users/guards/isStructureOwner.guard';
 import { RolesGuard } from '../users/guards/roles.guard';
@@ -15,7 +31,11 @@ import { StructuresService } from './services/structures.service';
 
 @Controller('structures')
 export class StructuresController {
-  constructor(private readonly structureService: StructuresService, private readonly userService: UsersService) {}
+  constructor(
+    private readonly structureService: StructuresService,
+    private readonly userService: UsersService,
+    private readonly tempUserService: TempUserService
+  ) {}
 
   @Post()
   public async create(@Body() createStructureDto: CreateStructureDto): Promise<Structure> {
@@ -54,7 +74,7 @@ export class StructuresController {
 
   @Post(':id/claim')
   public async claim(@Param('id') idStructure: string, @Body() user: User): Promise<Types.ObjectId[]> {
-    return this.userService.updateStructureLinked(user.email, idStructure);
+    return this.userService.updateStructureLinkedClaim(user.email, idStructure);
   }
 
   @Get('count')
@@ -100,4 +120,104 @@ export class StructuresController {
   public async delete(@Param('id') id: string) {
     return this.structureService.deleteOne(id);
   }
+
+  @Post(':id/addOwner')
+  @UseGuards(JwtAuthGuard, IsStructureOwnerGuard)
+  @Roles('admin')
+  @ApiParam({ name: 'id', type: String, required: true })
+  public async addOwner(@Param('id') id: string, @Body() user: CreateTempUserDto): Promise<any> {
+    // Get structure name
+    const structure = await this.structureService.findOne(id);
+    if (!structure) {
+      throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND);
+    }
+    user.pendingStructuresLink = [Types.ObjectId(id)];
+    // If user already exist, use created account
+    if (await this.userService.verifyUserExist(user.email)) {
+      return this.userService.updateStructureLinked(user.email, id);
+    }
+    // If temp user exist, update it
+    if (await this.tempUserService.findOne(user.email)) {
+      return this.tempUserService.updateStructureLinked(user);
+    }
+    // If not, create
+    return this.tempUserService.create(user, structure.structureName);
+  }
+
+  @Post(':id/join')
+  @ApiParam({ name: 'id', type: String, required: true })
+  public async join(@Param('id') id: string, @Body() user: User): Promise<void> {
+    // Get structure name
+    const structure = await this.structureService.findOne(id);
+    if (!structure) {
+      throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND);
+    }
+    // Get user and add pending structure
+    const userFromDb = await this.userService.findOne(user.email);
+    if (!userFromDb) {
+      throw new HttpException('Invalid User', HttpStatus.NOT_FOUND);
+    }
+    // If user has not already request it, send owner's validation email
+    if (!userFromDb.pendingStructuresLink.includes(Types.ObjectId(id))) {
+      userFromDb.pendingStructuresLink.push(Types.ObjectId(id));
+      userFromDb.save();
+      // Send structure owner's an email
+      this.structureService.sendStructureJoinRequest(userFromDb, structure);
+    }
+  }
+
+  @Post(':id/join/:userId/:status')
+  @UseGuards(JwtAuthGuard, IsStructureOwnerGuard)
+  @ApiParam({ name: 'id', type: String, required: true })
+  @ApiParam({ name: 'userId', type: String, required: true })
+  @ApiParam({ name: 'status', type: String, required: true })
+  public async joinValidation(
+    @Param('id') id: string,
+    @Param('status') status: string,
+    @Param('userId') userId: string
+  ): Promise<any> {
+    // Get structure name
+    const structure = await this.structureService.findOne(id);
+    if (!structure) {
+      throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND);
+    }
+
+    // Get user and add pending structure
+    const userFromDb = await this.userService.findById(userId);
+    if (!userFromDb) {
+      throw new HttpException('Invalid User', HttpStatus.NOT_FOUND);
+    }
+
+    if (!userFromDb.pendingStructuresLink.includes(Types.ObjectId(id))) {
+      throw new HttpException('User not linked to structure', HttpStatus.NOT_FOUND);
+    }
+
+    if (status === 'true') {
+      // Accept
+      await this.userService.updateStructureLinked(userFromDb.email, id);
+      await this.userService.removeFromPendingStructureLinked(userFromDb.email, id);
+    } else {
+      // Refuse
+      this.userService.removeFromPendingStructureLinked(userFromDb.email, id);
+    }
+  }
+
+  @Delete(':id/owner/:userId')
+  @UseGuards(JwtAuthGuard, IsStructureOwnerGuard)
+  @Roles('admin')
+  @ApiParam({ name: 'id', type: String, required: true })
+  @ApiParam({ name: 'userId', type: String, required: true })
+  public async removeOwner(@Param('id') id: string, @Param('userId') userId: string): Promise<void> {
+    // Get structure
+    const structure = await this.structureService.findOne(id);
+    if (!structure) {
+      throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND);
+    }
+    // Get user
+    const userFromDb = await this.userService.findById(userId);
+    if (!userFromDb || !userFromDb.structuresLink.includes(Types.ObjectId(id))) {
+      throw new HttpException('Invalid User', HttpStatus.NOT_FOUND);
+    }
+    this.userService.removeFromStructureLinked(userFromDb.email, id);
+  }
 }
diff --git a/src/structures/structures.module.ts b/src/structures/structures.module.ts
index 6494ea3a5eed4386ed251679c6e5b45a66e88804..0ec48d708808d0a1a3fdf495a037c99ba14bb9cf 100644
--- a/src/structures/structures.module.ts
+++ b/src/structures/structures.module.ts
@@ -1,5 +1,6 @@
 import { HttpModule, Module } from '@nestjs/common';
 import { MongooseModule } from '@nestjs/mongoose';
+import { TempUserModule } from '../temp-user/temp-user.module';
 import { MailerModule } from '../mailer/mailer.module';
 import { UsersModule } from '../users/users.module';
 import { Structure, StructureSchema } from './schemas/structure.schema';
@@ -19,6 +20,7 @@ import { StructureType, StructureTypeSchema } from './structure-type/structure-t
     HttpModule,
     MailerModule,
     UsersModule,
+    TempUserModule,
   ],
   controllers: [StructuresController, StructureTypeController],
   exports: [StructuresService, StructureTypeService],
diff --git a/src/temp-user/dto/create-temp-user.dto.ts b/src/temp-user/dto/create-temp-user.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..892eb6fca9e723f5b3be341d7e3c4cc90cc009de
--- /dev/null
+++ b/src/temp-user/dto/create-temp-user.dto.ts
@@ -0,0 +1,22 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsArray, IsEmail, IsNotEmpty, IsOptional } from 'class-validator';
+import { Types } from 'mongoose';
+
+export class CreateTempUserDto {
+  @IsNotEmpty()
+  @IsEmail()
+  @ApiProperty({ type: String })
+  email: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  name: string;
+
+  @IsNotEmpty()
+  @ApiProperty({ type: String })
+  surname: string;
+
+  @IsArray()
+  @IsOptional()
+  pendingStructuresLink?: Types.ObjectId[];
+}
diff --git a/src/temp-user/dto/temp-user-delete.dto.ts b/src/temp-user/dto/temp-user-delete.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ac6149d3d67d378dc0fd6641652a636148f1782c
--- /dev/null
+++ b/src/temp-user/dto/temp-user-delete.dto.ts
@@ -0,0 +1,9 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsEmail, IsNotEmpty } from 'class-validator';
+
+export class DeleteTempUserDto {
+  @IsNotEmpty()
+  @IsEmail()
+  @ApiProperty({ type: String })
+  email: string;
+}
diff --git a/src/temp-user/temp-user.controller.ts b/src/temp-user/temp-user.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9dc21a559e179a4ba1fc59f6c70ff7b6e9a7dc01
--- /dev/null
+++ b/src/temp-user/temp-user.controller.ts
@@ -0,0 +1,19 @@
+import { Controller, Get, HttpException, HttpStatus, Param } from '@nestjs/common';
+import { ApiParam } from '@nestjs/swagger';
+import { TempUser } from './temp-user.schema';
+import { TempUserService } from './temp-user.service';
+
+@Controller('temp-user')
+export class TempUserController {
+  constructor(private readonly tempUserSercice: TempUserService) {}
+
+  @Get(':id')
+  @ApiParam({ name: 'id', type: String, required: true })
+  public async getTempUser(@Param('id') id: string): Promise<TempUser> {
+    const user = await this.tempUserSercice.findById(id);
+    if (!user) {
+      throw new HttpException('User does not exists', HttpStatus.BAD_REQUEST);
+    }
+    return user;
+  }
+}
diff --git a/src/temp-user/temp-user.interface.ts b/src/temp-user/temp-user.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b802cf3dd6c66a907bf923f9eaa678c15e7e9d81
--- /dev/null
+++ b/src/temp-user/temp-user.interface.ts
@@ -0,0 +1,9 @@
+import { Document, Types } from 'mongoose';
+
+export interface ITempUser extends Document {
+  readonly _id: string;
+  email: string;
+  name: string;
+  surname: string;
+  pendingStructuresLink: Types.ObjectId[];
+}
diff --git a/src/temp-user/temp-user.module.ts b/src/temp-user/temp-user.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9b55281e49839559323398587a13a487cb462ea6
--- /dev/null
+++ b/src/temp-user/temp-user.module.ts
@@ -0,0 +1,14 @@
+import { HttpModule, Module } from '@nestjs/common';
+import { MongooseModule } from '@nestjs/mongoose';
+import { TempUser, TempUserSchema } from './temp-user.schema';
+import { TempUserService } from './temp-user.service';
+import { TempUserController } from './temp-user.controller';
+import { MailerModule } from '../mailer/mailer.module';
+
+@Module({
+  imports: [MongooseModule.forFeature([{ name: TempUser.name, schema: TempUserSchema }]), HttpModule, MailerModule],
+  providers: [TempUserService],
+  exports: [TempUserService],
+  controllers: [TempUserController],
+})
+export class TempUserModule {}
diff --git a/src/temp-user/temp-user.schema.ts b/src/temp-user/temp-user.schema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c8777e3ef81fba888fc2185c754bcdf8d9a435b2
--- /dev/null
+++ b/src/temp-user/temp-user.schema.ts
@@ -0,0 +1,21 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document, Types } from 'mongoose';
+
+export type TempUserDocument = TempUser & Document;
+
+@Schema({ timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } })
+export class TempUser {
+  @Prop({ required: true })
+  email: string;
+
+  @Prop({ required: true })
+  name: string;
+
+  @Prop({ required: true })
+  surname: string;
+
+  @Prop({ default: null })
+  pendingStructuresLink: Types.ObjectId[];
+}
+
+export const TempUserSchema = SchemaFactory.createForClass(TempUser);
diff --git a/src/temp-user/temp-user.service.ts b/src/temp-user/temp-user.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8d3eba3993df83ff996aa597ea74637907975623
--- /dev/null
+++ b/src/temp-user/temp-user.service.ts
@@ -0,0 +1,87 @@
+import { HttpException, HttpService, HttpStatus, Injectable } from '@nestjs/common';
+import { InjectModel } from '@nestjs/mongoose';
+import { Model, Types } from 'mongoose';
+import { MailerService } from '../mailer/mailer.service';
+import { CreateTempUserDto } from './dto/create-temp-user.dto';
+import { TempUser, TempUserDocument } from './temp-user.schema';
+import * as ejs from 'ejs';
+import { ITempUser } from './temp-user.interface';
+
+@Injectable()
+export class TempUserService {
+  constructor(
+    private readonly httpService: HttpService,
+    private readonly mailerService: MailerService,
+    @InjectModel(TempUser.name) private tempUserModel: Model<ITempUser>
+  ) {}
+
+  public async create(createTempUser: CreateTempUserDto, structureName: string): Promise<TempUser> {
+    const userInDb = await this.findOne(createTempUser.email);
+    if (userInDb) {
+      throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
+    }
+    const createUser = new this.tempUserModel(createTempUser);
+    // Send email
+    this.sendUserMail(createUser, structureName);
+    createUser.save();
+    return await this.findOne(createTempUser.email);
+  }
+
+  public async findOne(mail: string): Promise<TempUser | undefined> {
+    return this.tempUserModel.findOne({ email: mail }).exec();
+  }
+
+  public async findById(id: string): Promise<TempUser | undefined> {
+    return this.tempUserModel.findById(Types.ObjectId(id)).exec();
+  }
+
+  public async delete(mail: string): Promise<TempUser> {
+    const userInDb = await this.findOne(mail);
+    if (!userInDb) {
+      throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
+    }
+    this.tempUserModel.deleteOne({ email: mail }).exec();
+    return userInDb;
+  }
+
+  public async updateStructureLinked(createTempUser: CreateTempUserDto): Promise<TempUser> {
+    const userInDb = await this.tempUserModel
+      .find({
+        $and: [
+          {
+            email: createTempUser.email,
+          },
+          {
+            pendingStructuresLink: { $in: [createTempUser.pendingStructuresLink[0]] },
+          },
+        ],
+      })
+      .exec();
+    if (userInDb.length > 0) {
+      throw new HttpException('User already linked', HttpStatus.UNPROCESSABLE_ENTITY);
+    }
+    return this.tempUserModel
+      .updateOne(
+        { email: createTempUser.email },
+        { $push: { pendingStructuresLink: createTempUser.pendingStructuresLink[0] } }
+      )
+      .exec();
+  }
+
+  /**
+   * Send email in order to tell the user that an account is alreday fill with his structure info.
+   * @param user User
+   */
+  private async sendUserMail(user: ITempUser, structureName: string): Promise<any> {
+    const config = this.mailerService.config;
+    const ejsPath = this.mailerService.getTemplateLocation(config.templates.tempUserRegistration.ejs);
+    const jsonConfig = this.mailerService.loadJsonConfig(config.templates.tempUserRegistration.json);
+
+    const html = await ejs.renderFile(ejsPath, {
+      config,
+      id: user._id,
+      name: structureName,
+    });
+    this.mailerService.send(user.email, jsonConfig.subject, html);
+  }
+}
diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts
index a3d450e51a4c4fdc4bbb6bce6e46234165bf65a8..a16fca1915a89d913e885dd7772e321040f75ff9 100644
--- a/src/users/users.controller.ts
+++ b/src/users/users.controller.ts
@@ -7,10 +7,11 @@ import { CreateUserDto } from './dto/create-user.dto';
 import { PasswordResetApplyDto } from './dto/reset-password-apply.dto';
 import { PasswordResetDto } from './dto/reset-password.dto';
 import { UsersService } from './users.service';
+import { TempUserService } from '../temp-user/temp-user.service';
 
 @Controller('users')
 export class UsersController {
-  constructor(private usersService: UsersService) {}
+  constructor(private usersService: UsersService, private tempUserService: TempUserService) {}
 
   @UseGuards(JwtAuthGuard)
   @ApiBearerAuth('JWT')
@@ -33,7 +34,12 @@ export class UsersController {
     }
     const user = await this.usersService.create(createUserDto);
     if (structureId) {
-      this.usersService.updateStructureLinked(createUserDto.email, structureId);
+      this.usersService.updateStructureLinkedClaim(createUserDto.email, structureId);
+    }
+    // Remove temp user if exist
+    const tempUser = await this.tempUserService.findOne(createUserDto.email);
+    if (tempUser) {
+      this.tempUserService.delete(createUserDto.email);
     }
     return user;
   }
diff --git a/src/users/users.module.ts b/src/users/users.module.ts
index ae73bfe01263691656b98892941287ea85642e23..2741bbd41a798f060a82c203249b9064dabbaa9b 100644
--- a/src/users/users.module.ts
+++ b/src/users/users.module.ts
@@ -1,12 +1,18 @@
-import { Module } from '@nestjs/common';
+import { HttpModule, Module } from '@nestjs/common';
 import { MongooseModule } from '@nestjs/mongoose';
 import { UsersService } from './users.service';
 import { UsersController } from './users.controller';
 import { User, UserSchema } from './schemas/user.schema';
 import { MailerModule } from '../mailer/mailer.module';
+import { TempUserModule } from '../temp-user/temp-user.module';
 
 @Module({
-  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), MailerModule],
+  imports: [
+    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
+    MailerModule,
+    HttpModule,
+    TempUserModule,
+  ],
   providers: [UsersService],
   exports: [UsersService],
   controllers: [UsersController],
diff --git a/src/users/users.service.ts b/src/users/users.service.ts
index 6cb1ca3c38118ced008f183126491bf9af615e93..7aa2e1c552ed0fae2879dfe0fce22ae53ec879be 100644
--- a/src/users/users.service.ts
+++ b/src/users/users.service.ts
@@ -312,6 +312,10 @@ export class UsersService {
     return this.userModel.findOne({ structuresLink: Types.ObjectId(structureId) }).exec();
   }
 
+  public getStructureOwners(structureId: string): Promise<IUser[]> {
+    return this.userModel.find({ structuresLink: Types.ObjectId(structureId) }).exec();
+  }
+
   public async isUserAlreadyClaimedStructure(structureId: string, userEmail: string): Promise<boolean> {
     const user = await this.findOne(userEmail, true);
     if (user) {
@@ -320,13 +324,18 @@ export class UsersService {
     return false;
   }
 
-  public async updateStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
+  public async updateStructureLinkedClaim(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
+    const stucturesLinked = this.updatePendingStructureLinked(userEmail, idStructure);
+    this.sendAdminStructureValidationMail();
+    return stucturesLinked;
+  }
+
+  public async updatePendingStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
     const user = await this.findOne(userEmail, true);
     if (user) {
       if (!user.pendingStructuresLink.includes(Types.ObjectId(idStructure))) {
         user.pendingStructuresLink.push(Types.ObjectId(idStructure));
-        user.save();
-        this.sendAdminStructureValidationMail();
+        await user.save();
         return user.pendingStructuresLink;
       }
       throw new HttpException('User already claimed this structure', HttpStatus.NOT_FOUND);
@@ -334,6 +343,49 @@ export class UsersService {
     throw new HttpException('Invalid user', HttpStatus.NOT_FOUND);
   }
 
+  public async removeFromPendingStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
+    const user = await this.findOne(userEmail, true);
+    if (user) {
+      if (user.pendingStructuresLink.includes(Types.ObjectId(idStructure))) {
+        user.pendingStructuresLink = user.pendingStructuresLink.filter((structureId) => {
+          return structureId === Types.ObjectId(idStructure);
+        });
+        await user.save();
+        return user.pendingStructuresLink;
+      }
+      throw new HttpException('User already belong to this structure', HttpStatus.NOT_FOUND);
+    }
+    throw new HttpException('Invalid user', HttpStatus.NOT_FOUND);
+  }
+
+  public async updateStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
+    const user = await this.findOne(userEmail, true);
+    if (user) {
+      if (!user.structuresLink.includes(Types.ObjectId(idStructure))) {
+        user.structuresLink.push(Types.ObjectId(idStructure));
+        await user.save();
+        return user.structuresLink;
+      }
+      throw new HttpException('User already belong to this structure', HttpStatus.NOT_FOUND);
+    }
+    throw new HttpException('Invalid user', HttpStatus.NOT_FOUND);
+  }
+
+  public async removeFromStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> {
+    const user = await this.findOne(userEmail, true);
+    if (user) {
+      if (user.structuresLink.includes(Types.ObjectId(idStructure))) {
+        user.structuresLink = user.structuresLink.filter((structureId) => {
+          return structureId == Types.ObjectId(idStructure);
+        });
+        await user.save();
+        return user.structuresLink;
+      }
+      throw new HttpException('User already belong to this structure', HttpStatus.NOT_FOUND);
+    }
+    throw new HttpException('Invalid user', HttpStatus.NOT_FOUND);
+  }
+
   /**
    * Return all pending attachments of all profiles
    */