Users

In this chapter, we will go through the Users Module and give you an overview of how module works

Users module path

├── node_modules
├── mail-templates
├── migrations
├── src
│   ├── configs
│   ├── domains
│   │   ├── users             # Users module

User entity

@Entity()
export class User extends BaseEntity {
  // before insert and update hooks
  @BeforeInsert()
  @BeforeUpdate()
  async hashPassword() {
    if (!!this.password) {
      if (!this.password.includes('$2b$10')) {
        this.password = bcrypt.hashSync(this.password, 10);
      }
    }
  }

  @BeforeInsert()
  @BeforeUpdate()
  lowerCaseEmail() {
    this.email = this.email.toLowerCase();
  }

  @PrimaryGeneratedColumn()
  id: number;

  @Column({ default: false })
  isAdmin: boolean;

  @Column({ nullable: true })
  firstName: string;

  @Column({ nullable: true })
  lastName: string;

  @Index({ unique: true })
  @Column()
  email: string;

  @Column({ nullable: true })
  password: string;

  @Column({ default: null })
  resetPasswordToken: string;

  @Column({ default: false })
  confirmPayment: boolean;

  @Column({ default: false })
  errorPayment: boolean;

  @Column({ nullable: true })
  customerStripeId: string;

  @Column({ nullable: true })
  @IsOptional()
  endSubscription: Date;

  @Column({ default: false })
  canceledSubscription: boolean;

  @Column({ nullable: true})
  magicToken: string;

  @Column({ nullable: true })
  planId: number;

  @ManyToOne(() => Plan, plan => plan.users)
  @JoinColumn()
  plan: Plan;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}


export function password(length): string {
    let pass = '';
    for (let l=0; l < length; l++) {
        const rand = Math.random() * (126 - 33) + 33;
        pass += String.fromCharCode(~~rand);
    }
    return pass;
}

Users routes

@Controller('users')
export class UsersController implements CrudController<User> {
  private readonly logger = new Logger(UsersController.name);

  constructor(
    public service: UsersService,
    private readonly shared: SharedService,
    private readonly authService: AuthService,
  ) {}

  @Delete('/:id')
  @ApiOperation({
    operationId: 'Deactivate user',
    description: 'Deactivate an existing user',
  })
  @UseGuards(AdminGuard)
  async softDelete(@Param('id') id) {
    await this.service.softDelete(id);
    return null;
  }

  @Get('list')
  @UseGuards(AdminGuard)
  async getList(@Query('page') page: number, @Query('limit') limit: number, @Query('nameOrEmail') nameOrEmail: string = null) {
     return await this.service.getUsers(page, limit, nameOrEmail);
  }

  @Get('/me')
  @ApiOperation({
    operationId: 'Get current user',
    description: 'Get user information for logged user',
  })
  @ApiOkResponse({ type: UserResponse })
  @UseGuards(ConnectedUserGuard)
  async getCurrentUser(
    @CurrentUser() userPayload: TokenPayload,
  ): Promise<UserResponse> {
    const user = await this.service.findOne({ where: { id: userPayload.id }});
    delete user.password;
    delete user.resetPasswordToken;
    return user;
  }

  @Get('stats') 
  @UseGuards(AdminGuard)
  async getStats(@Query('from') from: Date, @Query('to') to: Date) {
      return await this.service.getStats(from, to);
  }

  @Put('/me')
  @ApiOperation({
    operationId: 'Update current user',
    description: 'Update user information for logged user',
  })
  @ApiOkResponse({ type: UserResponse })
  @UseGuards(ConnectedUserGuard)
  async updateCurrentUser(
    @Body() updatedUserInfo: UserUpdateRequest,
    @CurrentUser() userPayload: TokenPayload
  ) {
    const user = await this.service.findOne({ where: {id: userPayload.id }});
    let paymentUrl = null;

    if (typeof updatedUserInfo.canceledSubscription !== 'undefined') {
      if (updatedUserInfo.canceledSubscription) {
        // cancel subscription
        await this.shared.cancelSubscription(user.customerStripeId);
      } else {
        // reactivate subscription
        paymentUrl = await this.shared.getSubscriptionUrl(user, false, user.subscriptionId);
        updatedUserInfo.canceledSubscription = true;
      }
    }

    const resp = await this.service.repo.update({id: userPayload.id}, updatedUserInfo);

    // changer de plan
    if (!!updatedUserInfo.subscriptionId) {
      const subscription: Subscription = await this.service.repoSubscription.findOne({where: {id: updatedUserInfo.subscriptionId}});
      const subscriptions = await this.shared.getSubscriptions(user.customerStripeId);
      await this.shared.updateSubscription(subscriptions[subscriptions.length - 1].id, subscription.stripePlanId);
    }

    if (!resp) {
      throw new Error('Error updating user');
    }

    if (paymentUrl) {
      return {resp, paymentUrl};
    } else {
      return resp;
    }
  }


  @Put('/password')
  @ApiOperation({
    operationId: 'Update current user',
    description: 'Update user information for logged user',
  })
  @ApiOkResponse({ type: UserResponse })
  @UseGuards(ConnectedUserGuard)
  async updateUserPassword(
    @Body() updatedUserInfo: UserUpdateRequest,
    @CurrentUser() userPayload: TokenPayload
  ) {
    const validate = await this.authService.validateUser(userPayload.email, updatedUserInfo.oldPassword);
    if (!validate) {
      throw new Error('Incorrect Old Password');
    }
    return await this.service.repo.update({ id: userPayload.id }, { password: updatedUserInfo.password });
  }

}

Last updated