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;
}
}
|