Commit 3b59a22a authored by Nicolas Castejon's avatar Nicolas Castejon
Browse files

Merge branch 'development' into 'master'

Version 3.0.0

See merge request refonte-data/service-organizations!8
parents bf6b6f78 b7068992
Pipeline #2349 passed with stage
in 5 seconds
FROM node:8
FROM node:12.13-slim
# Create app directory
WORKDIR /app
......@@ -15,6 +15,8 @@ RUN npm install
# Bundle app source
COPY . .
CMD ["sh","-c", "npm run typeorm:migrate-ci && npm run start:prod"]
# MIGRATING variable is needed to be able to use a different user depending on the context. Admin user for migration
# simple user to run the application
CMD ["sh","-c", "export MIGRATING=1 && npm run typeorm:migrate-ci && export MIGRATING=0 && npm run start:prod"]
EXPOSE 3000
......@@ -10,6 +10,7 @@ services:
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_ADMIN_PASSWORD: ${POSTGRES_ADMIN_PASSWORD}
POSTGRES_DB: postgres
POSTGRES_HOST: database-organizations
POSTGRES_PORT: 5432
......@@ -24,6 +25,7 @@ services:
POSTGRESQL_USERNAME: user
POSTGRESQL_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRESQL_DATABASE: postgres
POSTGRESQL_POSTGRES_PASSWORD : ${POSTGRES_ADMIN_PASSWORD}
restart: unless-stopped
ports:
- ${POSTGRES_PORT}:5432
......
......@@ -14,8 +14,8 @@ const ormConfig = {
type: 'postgres',
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT,
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
username: process.env.MIGRATING === '1' ? 'postgres' : process.env.POSTGRES_USER,
password: process.env.MIGRATING === '1' ? process.env.POSTGRES_ADMIN_PASSWORD : process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
entities: [`${root}/**/**.entity{.ts,.js}`],
synchronize: false,
......
This diff is collapsed.
{
"name": "service-organizations",
"version": "2.1.0",
"version": "3.0.0",
"description": "description",
"author": "",
"license": "MIT",
......@@ -43,9 +43,8 @@
"reflect-metadata": "^0.1.12",
"rxjs": "^6.2.2",
"serve-favicon": "^2.5.0",
"typeorm": "^0.2.7",
"typescript": "^3.0.1",
"uuid": "^3.3.2"
"typeorm": "^0.2.20",
"typescript": "^3.0.1"
},
"devDependencies": {
"@nestjs/testing": "^5.4.0",
......@@ -82,4 +81,4 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
}
\ No newline at end of file
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { OrganizationsModule } from './organizations/organizations.module';
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LinksModule } from './links/links.module';
import { HealthModule } from './health/health.module';
import { AppLogger } from './app-logger';
import { ConfigModule } from './configuration/config.module';
import { APP_GUARD } from '@nestjs/core';
import { GroupsGuard } from './guards/groups.guards';
import { AppLogger } from './app-logger';
import { HealthModule } from './health/health.module';
import { LinksModule } from './links/links.module';
import { VerifyXsrfTokenAndDecodeJWTPayloadMiddleware } from './middlewares/decode-jwt-payload.middleware';
import { OrganizationsModule } from './organizations/organizations.module';
@Module({
imports: [
......
import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, MaxLength } from 'class-validator';
export class Link {
@ApiModelPropertyOptional()
@IsOptional()
@MaxLength(100)
@IsString()
name?: string;
@ApiModelProperty()
@MaxLength(300)
@IsString()
url: string;
@ApiModelProperty()
organizationId?: string;
}
\ No newline at end of file
import { Entity, PrimaryColumn, Column, ManyToOne, JoinColumn, BeforeInsert } from 'typeorm';
import { IsString, IsOptional } from 'class-validator';
import { Organization } from '../organizations/organization.entity';
import { ApiModelProperty } from '@nestjs/swagger';
import * as uuidv4 from 'uuid/v4';
import { IsOptional, IsString } from 'class-validator';
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Organization } from '../organizations/organization.entity';
@Entity('link')
export class LinkEntity {
@PrimaryColumn('text')
@IsString()
@PrimaryGeneratedColumn()
@ApiModelProperty()
id: string;
id: number;
@IsString()
@IsOptional()
......@@ -24,9 +22,8 @@ export class LinkEntity {
url: string;
@Column({ nullable: true })
@IsOptional()
@ApiModelProperty()
organizationId: string;
organizationId: number;
@ManyToOne(type => Organization, organization => organization.links, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'organizationId' })
......
import { Controller, Get, Body, Post, Param, Delete, Put, Query, Response } from '@nestjs/common';
import { LinksService } from './links.service';
import { LinkEntity } from './link.entity';
import { ApiUseTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Link } from './link.dto';
import { Groups } from '../decorators/groups.decorators';
@ApiUseTags('links')
@Controller('links')
export class LinksController {
constructor(
private linksService: LinksService,
) { }
@ApiOperation({ title: 'Get all links' })
@ApiResponse({ status: 200, description: 'Return all links.' })
@Get()
async findAll(@Query() query, @Response() res): Promise<LinkEntity[]> {
const { links, linksCount } = await this.linksService.findAll(query);
res.append('Content-range', linksCount);
res.send(links);
return;
}
@ApiOperation({ title: 'Get one link' })
@Get(':id')
findOne(@Param('id') id: number) {
return this.linksService.findOne(id);
}
@ApiOperation({ title: 'Create one link' })
@ApiResponse({ status: 201, description: 'The record has been successfully created.' })
@ApiResponse({ status: 403, description: 'User does not have sufficient rights.' })
@Post()
@Groups('admin')
async create(@Body() linkDTo: Link) {
return this.linksService.create(linkDTo);
}
@ApiOperation({ title: 'Update one link' })
@ApiResponse({ status: 201, description: 'The record has been successfully updated.' })
@ApiResponse({ status: 403, description: 'User does not have sufficient rights.' })
@Put(':id')
@Groups('admin')
async update(@Param('id') id: number, @Body() link: Link) {
return this.linksService.update(id, link);
}
@ApiOperation({ title: 'Delete one link' })
@ApiResponse({ status: 403, description: 'User does not have sufficient rights.' })
@Delete(':id')
@Groups('admin')
delete(@Param('id') id: number) {
return this.linksService.delete(id);
}
}
import { Module } from '@nestjs/common';
import { LinksController } from './links.controller';
import { LinksService } from './links.service';
import { LinkEntity } from './link.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LinkEntity } from './link.entity';
import { LinksService } from './links.service';
@Module({
imports: [TypeOrmModule.forFeature([LinkEntity])],
controllers: [LinksController],
providers: [LinksService],
})
export class LinksModule {}
export class LinksModule { }
import { Injectable, Logger, InternalServerErrorException, NotFoundException } from '@nestjs/common';
import { LinkEntity, LinksRO } from './link.entity';
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Link } from './link.dto';
import { LinkEntity, LinksRO } from './link.entity';
import { LinkRepository } from './link.repository';
import * as uuidv4 from 'uuid/v4';
@Injectable()
export class LinksService {
......@@ -57,75 +55,6 @@ export class LinksService {
}
}
async findOne(id) {
try {
this.logger.log('Entering function', `${LinksService.name} - ${this.findOne.name}`);
return await this.linkRepository.findOne(id).catch((error) => {
this.logger.error(`Error while looking for the link with id ${id}.`, `${error}`, `${LinksService.name} - ${this.findOne.name}`);
throw new InternalServerErrorException({ error, message: 'Error while looking for the link with id ${id}.' });
});
} catch (error) {
throw error;
}
}
async create(link: Link) {
try {
this.logger.log('Entering function', `${LinksService.name} - ${this.create.name}`);
// cf https://github.com/typeorm/typeorm/issues/2924#issuecomment-430265476
const linkEntity = Object.assign(new LinkEntity(), link);
linkEntity.id = uuidv4();
return await this.linkRepository.save(linkEntity).catch((error) => {
this.logger.error(`Error saving the link into the database.`, `${error}`, `${LinksService.name} - ${this.create.name}`);
throw new InternalServerErrorException({ error, message: 'Error saving the link into the database.' });
});
} catch (error) {
throw error;
}
}
async update(id, link: Link) {
try {
this.logger.log('Entering function', `${LinksService.name} - ${this.update.name}`);
const toUpdate = await this.linkRepository.findOne(id).catch((error) => {
this.logger.error(`Error while looking for the link with the id ${id}.`, `${error}`, `${LinksService.name} - ${this.update.name}`);
throw new InternalServerErrorException({ error, message: 'Error while looking for the link.' });
});
const updated = Object.assign(toUpdate, link);
return await this.linkRepository.save(updated).catch((error) => {
this.logger.error(`Error while updating the resource.`, `${error}`, `${LinksService.name} - ${this.update.name}`);
throw new InternalServerErrorException({ error, message: 'Error while updating the link.' });
});
} catch (error) {
throw error;
}
}
async delete(id) {
try {
this.logger.log('Entering function', `${LinksService.name} - ${this.delete.name}`);
const toDelete = await this.linkRepository.findOne(id);
if (!toDelete) {
throw new NotFoundException({ message: 'No link exists with the given id' });
}
return await this.linkRepository.delete(id).catch((error) => {
this.logger.error(`Error while deleting the link with id ${id}.`, `${error}`, `${LinksService.name} - ${this.delete.name}`);
throw new InternalServerErrorException({ error, message: `Error while deleting the link with id ${id}.` });
});
} catch (error) {
throw error;
}
}
async deleteOrphans() {
try {
this.logger.log('Entering function', `${LinksService.name} - ${this.deleteOrphans.name}`);
......
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';
import * as favicon from 'serve-favicon';
import * as path from 'path';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as cookieParser from 'cookie-parser';
import * as path from 'path';
import * as favicon from 'serve-favicon';
import { AppLogger } from './app-logger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
......@@ -28,7 +28,7 @@ async function bootstrap() {
// Set endpoint serving the swagger documentation
SwaggerModule.setup('api-doc', app, document);
app.useGlobalPipes(new ValidationPipe());
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
await app.listen(3000);
}
......
import {MigrationInterface, QueryRunner} from "typeorm";
import { MigrationInterface, QueryRunner } from "typeorm";
export class initSchema1563573591949 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "organization" ("id" text NOT NULL, "name" character varying(200) NOT NULL, "elasticSearchName" character varying(100), "description" text NOT NULL, "logo" text, CONSTRAINT "PK_472c1f99a32def1b0abb219cd67" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "link" ("id" text NOT NULL, "name" character varying(100), "url" character varying(300) NOT NULL, "organizationId" text, CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "FK_afeaa57181e374e281c9a647eda" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE`);
}
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "organization" ("id" text NOT NULL, "name" character varying(200) NOT NULL, "elasticSearchName" character varying(100), "description" text NOT NULL, "logo" text, CONSTRAINT "PK_472c1f99a32def1b0abb219cd67" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "link" ("id" text NOT NULL, "name" character varying(100), "url" character varying(300) NOT NULL, "organizationId" text, CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "FK_afeaa57181e374e281c9a647eda" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "FK_afeaa57181e374e281c9a647eda"`);
await queryRunner.query(`DROP TABLE "link"`);
await queryRunner.query(`DROP TABLE "organization"`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "FK_afeaa57181e374e281c9a647eda"`);
await queryRunner.query(`DROP TABLE "link"`);
await queryRunner.query(`DROP TABLE "organization"`);
}
}
import {MigrationInterface, QueryRunner} from "typeorm";
export class MakeIDAutogeneratedAndAddUuidOnOrganization1574756164879 implements MigrationInterface {
name = 'MakeIDAutogeneratedAndAddUuidOnOrganization1574756164879'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "organization" ADD "uuid" text NOT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ADD CONSTRAINT "UQ_59f940b5775a9ccf5c2f094c8af" UNIQUE ("uuid")`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "FK_afeaa57181e374e281c9a647eda"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP CONSTRAINT "PK_472c1f99a32def1b0abb219cd67"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP COLUMN "id"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ADD "id" SERIAL NOT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ADD CONSTRAINT "PK_472c1f99a32def1b0abb219cd67" PRIMARY KEY ("id")`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9"`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP COLUMN "id"`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD "id" SERIAL NOT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9" PRIMARY KEY ("id")`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP COLUMN "organizationId"`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD "organizationId" integer`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "FK_afeaa57181e374e281c9a647eda" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "FK_afeaa57181e374e281c9a647eda"`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP COLUMN "organizationId"`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD "organizationId" text`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9"`, undefined);
await queryRunner.query(`ALTER TABLE "link" DROP COLUMN "id"`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD "id" text NOT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "PK_26206fb7186da72fbb9eaa3fac9" PRIMARY KEY ("id")`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP CONSTRAINT "PK_472c1f99a32def1b0abb219cd67"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP COLUMN "id"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ADD "id" text NOT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ADD CONSTRAINT "PK_472c1f99a32def1b0abb219cd67" PRIMARY KEY ("id")`, undefined);
await queryRunner.query(`ALTER TABLE "link" ADD CONSTRAINT "FK_afeaa57181e374e281c9a647eda" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP CONSTRAINT "UQ_59f940b5775a9ccf5c2f094c8af"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" DROP COLUMN "uuid"`, undefined);
}
}
import { MigrationInterface, QueryRunner } from "typeorm";
export class PutUUIDByDefaultInOrganizationModel1574772582441 implements MigrationInterface {
name = 'PutUUIDByDefaultInOrganizationModel1574772582441'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`create extension "pgcrypto"`, undefined);
await queryRunner.query(`ALTER TABLE "organization" ALTER COLUMN "uuid" SET DEFAULT gen_random_uuid()`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "organization" ALTER COLUMN "uuid" DROP DEFAULT`, undefined);
}
}
import { MigrationInterface, QueryRunner } from "typeorm";
export class GrantAccessTuUser1574849918251 implements MigrationInterface {
name = 'GrantAccessTuUser1574849918251';
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "user";`, undefined);
await queryRunner.query(`GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO "user";`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
}
}
import { Organization } from './organization.entity';
import { Link } from '../links/link.dto';
import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger';
import { IsString, IsOptional, IsArray, MaxLength, IsBoolean } from 'class-validator';
import { Type } from 'class-transformer';
import { IsArray, IsBoolean, IsOptional, IsString, MaxLength, ValidateNested } from 'class-validator';
import { Link } from '../links/link.dto';
import { Organization } from './organization.entity';
export class OrganizationDTO {
@ApiModelPropertyOptional()
@IsOptional()
@IsString()
uuid?: string;
@ApiModelProperty()
@IsString()
@MaxLength(200)
......@@ -23,10 +30,12 @@ export class OrganizationDTO {
@IsString()
logo?: string;
@ApiModelPropertyOptional({ type: [Link] })
@ApiModelPropertyOptional({ type: Link, isArray: true })
@IsOptional()
@IsArray()
links?: [Link];
@ValidateNested({ each: true })
@Type(() => Link)
links?: Link[];
@ApiModelProperty()
@IsBoolean()
......
import { Entity, PrimaryColumn, Column, OneToMany, Generated, BeforeInsert, BeforeUpdate } from 'typeorm';
import { LinkEntity } from '../links/link.entity';
import { ApiModelProperty } from '@nestjs/swagger';
import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger';
import { IsBoolean } from 'class-validator';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { LinkEntity } from '../links/link.entity';
@Entity('organization')
export class Organization {
@PrimaryColumn('text')
@PrimaryGeneratedColumn()
@ApiModelProperty()
id: string;
id: number;
@Column('text', { unique: true, nullable: false, default: () => 'gen_random_uuid()' })
@ApiModelProperty()
uuid: string;
@Column({ length: 200 })
@ApiModelProperty()
......@@ -26,7 +30,7 @@ export class Organization {
eager: true,
cascade: true,
})
@ApiModelProperty()
@ApiModelPropertyOptional()
links: LinkEntity[];
@Column('text', { nullable: true })
......
import { Controller, Get, Body, Post, Param, Delete, Put, Query, Response, UploadedFile, HttpCode, Req } from '@nestjs/common';
import { OrganizationsService } from './organizations.service';
import { ApiUseTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Body, Controller, Delete, Get, HttpCode, Param, Post, Put, Query, Req, Response } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiUseTags } from '@nestjs/swagger';
import { ConfigService } from '../configuration/config.service';
import { Groups } from '../decorators/groups.decorators';
import { LinkEntity } from '../links/link.entity';
import { OrganizationDTO } from './organization.dto';
import { Organization } from './organization.entity';
import { LinkEntity } from '../links/link.entity';
import { Groups } from '../decorators/groups.decorators';
import { ConfigService } from '../configuration/config.service';
import { OrganizationsService } from './organizations.service';
@ApiUseTags('organizations')
@Controller('organizations')
......
import { Injectable, Logger, InternalServerErrorException, NotFoundException, ForbiddenException } from '@nestjs/common';
import { Organization } from './organization.entity';
import { ForbiddenException, Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ConfigService } from '../configuration/config.service';
import { LinksService } from '../links/links.service';
import { OrganizationsRO, OrganizationDTO } from './organization.dto';
import { OrganizationDTO, OrganizationsRO } from './organization.dto';
import { Organization } from './organization.entity';
import { OrganizationRepository } from './organization.repository';
import * as uuidv4 from 'uuid/v4';
import { ConfigService } from '../configuration/config.service';
@Injectable()
export class OrganizationsService {
......@@ -130,13 +129,6 @@ export class OrganizationsService {
// cf https://github.com/typeorm/typeorm/issues/2924#issuecomment-430265476
const organizationEntity = Object.assign(new Organization(), organization);
organizationEntity.id = uuidv4();
organizationEntity.links.forEach((link) => {
if (!link.id) {
link.id = uuidv4();
}
});
const organizationCreated = await this.organizationRepository.save(organizationEntity).catch((error) => {
this.logger.error(`Error saving the organization into the database.`, `${error}`, `${OrganizationsService.name} - ${this.create.name}`);
......@@ -171,11 +163,6 @@ export class OrganizationsService {
}
const updated = Object.assign(toUpdate, organization);
updated.links.forEach((link) => {
if (!link.id) {
link.id = uuidv4();
}
});
const saved = await this.organizationRepository.save(updated).catch((error) => {
this.logger.error(`Error while updating the organization.`, `${error}`, `${OrganizationsService.name} - ${this.update.name}`);
......