aboutsummaryrefslogtreecommitdiffstats
path: root/app/Models/User.ts
blob: cc2c55348929f6d51865f13b456495d514ff7375 (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
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 '@ioc:Adonis/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
  }
}