aboutsummaryrefslogtreecommitdiffstats
path: root/app/Models/User.ts
blob: f7445880c2aa5550f7b82bf6cf71b3430c5b621e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { DateTime } from 'luxon';
import { BaseModel, beforeSave, column, hasMany } from '@adonisjs/lucid/orm';
import hash from '@adonisjs/core/services/hash';
import emitter from '@adonisjs/core/services/emitter';
import moment from 'moment';
import { Encryption } from '@adonisjs/core/encryption';
import randtoken from 'rand-token';
import Token from './Token.js';
import Workspace from './Workspace.js';
import Service from './Service.js';
import mail from '@adonisjs/mail/services/main';
import { url } from '#config/app';
import { mailFrom } from '#config/dashboard';
import { HasMany } from '@adonisjs/lucid/types/relations';

export default class User extends BaseModel {
  @column({ isPrimary: true })
  public id: number;

  @column()
  public email: string;

  @column()
  public username: string;

  @column()
  public password: string;

  @column()
  public lastname: string;

  // TODO: Type the settings object.
  @column()
  public settings: object;

  @column.dateTime({ autoCreate: true })
  public created_at: DateTime;

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  public updated_at: DateTime;

  @beforeSave()
  public static async hashPassword(user: User) {
    if (user.$dirty.password) {
      user.password = await hash.make(user.password);
    }
  }

  @hasMany(() => Token, {
    foreignKey: 'user_id',
  })
  public tokens: HasMany<typeof Token>;

  @hasMany(() => Service, {
    foreignKey: 'userId',
  })
  public services: HasMany<typeof Service>;

  @hasMany(() => Workspace, {
    foreignKey: 'userId',
  })
  public workspaces: HasMany<typeof Workspace>;

  public async forgotPassword(): Promise<void> {
    const token = await this.generateToken(this, 'forgot_password');

    await mail.send(message => {
      message
        .from(mailFrom)
        .to(this.email)
        .subject('[Ferdium] Password Recovery')
        .htmlView('emails/reset_password', {
          username: this.username,
          appUrl: url,
          token: token,
        });
    });

    await emitter.emit('forgot:password', {
      user: this,
      token,
    });
  }

  private async generateToken(user: User, type: string): Promise<string> {
    const query = user
      .related('tokens')
      .query()
      .where('type', type)
      .where('is_revoked', false)
      .where(
        'updated_at',
        '>=',
        moment().subtract(24, 'hours').format('YYYY-MM-DD HH:mm:ss'),
      );

    const row = await query.first();
    if (row) {
      return row.token;
    }

    const token = Encryption.encrypt(randtoken.generate(16));

    await user.related('tokens').create({ type, token });

    return token;
  }
}