diff options
Diffstat (limited to 'server/models/account')
-rw-r--r-- | server/models/account/account.ts | 5 | ||||
-rw-r--r-- | server/models/account/actor-image.ts | 100 | ||||
-rw-r--r-- | server/models/account/user-notification-setting.ts | 26 | ||||
-rw-r--r-- | server/models/account/user-notification.ts | 98 | ||||
-rw-r--r-- | server/models/account/user.ts | 20 |
5 files changed, 228 insertions, 21 deletions
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index c72f9c63d..312451abe 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -33,7 +33,7 @@ import { | |||
33 | import { ActorModel } from '../activitypub/actor' | 33 | import { ActorModel } from '../activitypub/actor' |
34 | import { ActorFollowModel } from '../activitypub/actor-follow' | 34 | import { ActorFollowModel } from '../activitypub/actor-follow' |
35 | import { ApplicationModel } from '../application/application' | 35 | import { ApplicationModel } from '../application/application' |
36 | import { AvatarModel } from '../avatar/avatar' | 36 | import { ActorImageModel } from './actor-image' |
37 | import { ServerModel } from '../server/server' | 37 | import { ServerModel } from '../server/server' |
38 | import { ServerBlocklistModel } from '../server/server-blocklist' | 38 | import { ServerBlocklistModel } from '../server/server-blocklist' |
39 | import { getSort, throwIfNotValid } from '../utils' | 39 | import { getSort, throwIfNotValid } from '../utils' |
@@ -82,7 +82,8 @@ export type SummaryOptions = { | |||
82 | serverInclude, | 82 | serverInclude, |
83 | 83 | ||
84 | { | 84 | { |
85 | model: AvatarModel.unscoped(), | 85 | model: ActorImageModel.unscoped(), |
86 | as: 'Avatar', | ||
86 | required: false | 87 | required: false |
87 | } | 88 | } |
88 | ] | 89 | ] |
diff --git a/server/models/account/actor-image.ts b/server/models/account/actor-image.ts new file mode 100644 index 000000000..ae05b4969 --- /dev/null +++ b/server/models/account/actor-image.ts | |||
@@ -0,0 +1,100 @@ | |||
1 | import { remove } from 'fs-extra' | ||
2 | import { join } from 'path' | ||
3 | import { AfterDestroy, AllowNull, Column, CreatedAt, Default, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | ||
4 | import { MActorImageFormattable } from '@server/types/models' | ||
5 | import { ActorImageType } from '@shared/models' | ||
6 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' | ||
7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | ||
8 | import { logger } from '../../helpers/logger' | ||
9 | import { CONFIG } from '../../initializers/config' | ||
10 | import { LAZY_STATIC_PATHS } from '../../initializers/constants' | ||
11 | import { throwIfNotValid } from '../utils' | ||
12 | |||
13 | @Table({ | ||
14 | tableName: 'actorImage', | ||
15 | indexes: [ | ||
16 | { | ||
17 | fields: [ 'filename' ], | ||
18 | unique: true | ||
19 | } | ||
20 | ] | ||
21 | }) | ||
22 | export class ActorImageModel extends Model { | ||
23 | |||
24 | @AllowNull(false) | ||
25 | @Column | ||
26 | filename: string | ||
27 | |||
28 | @AllowNull(true) | ||
29 | @Default(null) | ||
30 | @Column | ||
31 | height: number | ||
32 | |||
33 | @AllowNull(true) | ||
34 | @Default(null) | ||
35 | @Column | ||
36 | width: number | ||
37 | |||
38 | @AllowNull(true) | ||
39 | @Is('ActorImageFileUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'fileUrl', true)) | ||
40 | @Column | ||
41 | fileUrl: string | ||
42 | |||
43 | @AllowNull(false) | ||
44 | @Column | ||
45 | onDisk: boolean | ||
46 | |||
47 | @AllowNull(false) | ||
48 | @Column | ||
49 | type: ActorImageType | ||
50 | |||
51 | @CreatedAt | ||
52 | createdAt: Date | ||
53 | |||
54 | @UpdatedAt | ||
55 | updatedAt: Date | ||
56 | |||
57 | @AfterDestroy | ||
58 | static removeFilesAndSendDelete (instance: ActorImageModel) { | ||
59 | logger.info('Removing actor image file %s.', instance.filename) | ||
60 | |||
61 | // Don't block the transaction | ||
62 | instance.removeImage() | ||
63 | .catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, err)) | ||
64 | } | ||
65 | |||
66 | static loadByName (filename: string) { | ||
67 | const query = { | ||
68 | where: { | ||
69 | filename | ||
70 | } | ||
71 | } | ||
72 | |||
73 | return ActorImageModel.findOne(query) | ||
74 | } | ||
75 | |||
76 | toFormattedJSON (this: MActorImageFormattable): ActorImage { | ||
77 | return { | ||
78 | path: this.getStaticPath(), | ||
79 | createdAt: this.createdAt, | ||
80 | updatedAt: this.updatedAt | ||
81 | } | ||
82 | } | ||
83 | |||
84 | getStaticPath () { | ||
85 | if (this.type === ActorImageType.AVATAR) { | ||
86 | return join(LAZY_STATIC_PATHS.AVATARS, this.filename) | ||
87 | } | ||
88 | |||
89 | return join(LAZY_STATIC_PATHS.BANNERS, this.filename) | ||
90 | } | ||
91 | |||
92 | getPath () { | ||
93 | return join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename) | ||
94 | } | ||
95 | |||
96 | removeImage () { | ||
97 | const imagePath = join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename) | ||
98 | return remove(imagePath) | ||
99 | } | ||
100 | } | ||
diff --git a/server/models/account/user-notification-setting.ts b/server/models/account/user-notification-setting.ts index ebab8b6d2..138051528 100644 --- a/server/models/account/user-notification-setting.ts +++ b/server/models/account/user-notification-setting.ts | |||
@@ -12,10 +12,10 @@ import { | |||
12 | Table, | 12 | Table, |
13 | UpdatedAt | 13 | UpdatedAt |
14 | } from 'sequelize-typescript' | 14 | } from 'sequelize-typescript' |
15 | import { TokensCache } from '@server/lib/auth/tokens-cache' | ||
15 | import { MNotificationSettingFormattable } from '@server/types/models' | 16 | import { MNotificationSettingFormattable } from '@server/types/models' |
16 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' | 17 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' |
17 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' | 18 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' |
18 | import { clearCacheByUserId } from '../../lib/oauth-model' | ||
19 | import { throwIfNotValid } from '../utils' | 19 | import { throwIfNotValid } from '../utils' |
20 | import { UserModel } from './user' | 20 | import { UserModel } from './user' |
21 | 21 | ||
@@ -156,6 +156,24 @@ export class UserNotificationSettingModel extends Model { | |||
156 | @Column | 156 | @Column |
157 | abuseNewMessage: UserNotificationSettingValue | 157 | abuseNewMessage: UserNotificationSettingValue |
158 | 158 | ||
159 | @AllowNull(false) | ||
160 | @Default(null) | ||
161 | @Is( | ||
162 | 'UserNotificationSettingNewPeerTubeVersion', | ||
163 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'newPeerTubeVersion') | ||
164 | ) | ||
165 | @Column | ||
166 | newPeerTubeVersion: UserNotificationSettingValue | ||
167 | |||
168 | @AllowNull(false) | ||
169 | @Default(null) | ||
170 | @Is( | ||
171 | 'UserNotificationSettingNewPeerPluginVersion', | ||
172 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'newPluginVersion') | ||
173 | ) | ||
174 | @Column | ||
175 | newPluginVersion: UserNotificationSettingValue | ||
176 | |||
159 | @ForeignKey(() => UserModel) | 177 | @ForeignKey(() => UserModel) |
160 | @Column | 178 | @Column |
161 | userId: number | 179 | userId: number |
@@ -177,7 +195,7 @@ export class UserNotificationSettingModel extends Model { | |||
177 | @AfterUpdate | 195 | @AfterUpdate |
178 | @AfterDestroy | 196 | @AfterDestroy |
179 | static removeTokenCache (instance: UserNotificationSettingModel) { | 197 | static removeTokenCache (instance: UserNotificationSettingModel) { |
180 | return clearCacheByUserId(instance.userId) | 198 | return TokensCache.Instance.clearCacheByUserId(instance.userId) |
181 | } | 199 | } |
182 | 200 | ||
183 | toFormattedJSON (this: MNotificationSettingFormattable): UserNotificationSetting { | 201 | toFormattedJSON (this: MNotificationSettingFormattable): UserNotificationSetting { |
@@ -195,7 +213,9 @@ export class UserNotificationSettingModel extends Model { | |||
195 | newInstanceFollower: this.newInstanceFollower, | 213 | newInstanceFollower: this.newInstanceFollower, |
196 | autoInstanceFollowing: this.autoInstanceFollowing, | 214 | autoInstanceFollowing: this.autoInstanceFollowing, |
197 | abuseNewMessage: this.abuseNewMessage, | 215 | abuseNewMessage: this.abuseNewMessage, |
198 | abuseStateChange: this.abuseStateChange | 216 | abuseStateChange: this.abuseStateChange, |
217 | newPeerTubeVersion: this.newPeerTubeVersion, | ||
218 | newPluginVersion: this.newPluginVersion | ||
199 | } | 219 | } |
200 | } | 220 | } |
201 | } | 221 | } |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index add129644..805095002 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -9,7 +9,8 @@ import { VideoAbuseModel } from '../abuse/video-abuse' | |||
9 | import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' | 9 | import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' |
10 | import { ActorModel } from '../activitypub/actor' | 10 | import { ActorModel } from '../activitypub/actor' |
11 | import { ActorFollowModel } from '../activitypub/actor-follow' | 11 | import { ActorFollowModel } from '../activitypub/actor-follow' |
12 | import { AvatarModel } from '../avatar/avatar' | 12 | import { ApplicationModel } from '../application/application' |
13 | import { PluginModel } from '../server/plugin' | ||
13 | import { ServerModel } from '../server/server' | 14 | import { ServerModel } from '../server/server' |
14 | import { getSort, throwIfNotValid } from '../utils' | 15 | import { getSort, throwIfNotValid } from '../utils' |
15 | import { VideoModel } from '../video/video' | 16 | import { VideoModel } from '../video/video' |
@@ -18,6 +19,7 @@ import { VideoChannelModel } from '../video/video-channel' | |||
18 | import { VideoCommentModel } from '../video/video-comment' | 19 | import { VideoCommentModel } from '../video/video-comment' |
19 | import { VideoImportModel } from '../video/video-import' | 20 | import { VideoImportModel } from '../video/video-import' |
20 | import { AccountModel } from './account' | 21 | import { AccountModel } from './account' |
22 | import { ActorImageModel } from './actor-image' | ||
21 | import { UserModel } from './user' | 23 | import { UserModel } from './user' |
22 | 24 | ||
23 | enum ScopeNames { | 25 | enum ScopeNames { |
@@ -32,7 +34,8 @@ function buildActorWithAvatarInclude () { | |||
32 | include: [ | 34 | include: [ |
33 | { | 35 | { |
34 | attributes: [ 'filename' ], | 36 | attributes: [ 'filename' ], |
35 | model: AvatarModel.unscoped(), | 37 | as: 'Avatar', |
38 | model: ActorImageModel.unscoped(), | ||
36 | required: false | 39 | required: false |
37 | }, | 40 | }, |
38 | { | 41 | { |
@@ -96,7 +99,7 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
96 | attributes: [ 'id' ], | 99 | attributes: [ 'id' ], |
97 | model: VideoAbuseModel.unscoped(), | 100 | model: VideoAbuseModel.unscoped(), |
98 | required: false, | 101 | required: false, |
99 | include: [ buildVideoInclude(true) ] | 102 | include: [ buildVideoInclude(false) ] |
100 | }, | 103 | }, |
101 | { | 104 | { |
102 | attributes: [ 'id' ], | 105 | attributes: [ 'id' ], |
@@ -106,12 +109,12 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
106 | { | 109 | { |
107 | attributes: [ 'id', 'originCommentId' ], | 110 | attributes: [ 'id', 'originCommentId' ], |
108 | model: VideoCommentModel.unscoped(), | 111 | model: VideoCommentModel.unscoped(), |
109 | required: true, | 112 | required: false, |
110 | include: [ | 113 | include: [ |
111 | { | 114 | { |
112 | attributes: [ 'id', 'name', 'uuid' ], | 115 | attributes: [ 'id', 'name', 'uuid' ], |
113 | model: VideoModel.unscoped(), | 116 | model: VideoModel.unscoped(), |
114 | required: true | 117 | required: false |
115 | } | 118 | } |
116 | ] | 119 | ] |
117 | } | 120 | } |
@@ -120,7 +123,7 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
120 | { | 123 | { |
121 | model: AccountModel, | 124 | model: AccountModel, |
122 | as: 'FlaggedAccount', | 125 | as: 'FlaggedAccount', |
123 | required: true, | 126 | required: false, |
124 | include: [ buildActorWithAvatarInclude() ] | 127 | include: [ buildActorWithAvatarInclude() ] |
125 | } | 128 | } |
126 | ] | 129 | ] |
@@ -141,6 +144,18 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
141 | }, | 144 | }, |
142 | 145 | ||
143 | { | 146 | { |
147 | attributes: [ 'id', 'name', 'type', 'latestVersion' ], | ||
148 | model: PluginModel.unscoped(), | ||
149 | required: false | ||
150 | }, | ||
151 | |||
152 | { | ||
153 | attributes: [ 'id', 'latestPeerTubeVersion' ], | ||
154 | model: ApplicationModel.unscoped(), | ||
155 | required: false | ||
156 | }, | ||
157 | |||
158 | { | ||
144 | attributes: [ 'id', 'state' ], | 159 | attributes: [ 'id', 'state' ], |
145 | model: ActorFollowModel.unscoped(), | 160 | model: ActorFollowModel.unscoped(), |
146 | required: false, | 161 | required: false, |
@@ -158,7 +173,8 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
158 | }, | 173 | }, |
159 | { | 174 | { |
160 | attributes: [ 'filename' ], | 175 | attributes: [ 'filename' ], |
161 | model: AvatarModel.unscoped(), | 176 | as: 'Avatar', |
177 | model: ActorImageModel.unscoped(), | ||
162 | required: false | 178 | required: false |
163 | }, | 179 | }, |
164 | { | 180 | { |
@@ -251,6 +267,22 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
251 | [Op.ne]: null | 267 | [Op.ne]: null |
252 | } | 268 | } |
253 | } | 269 | } |
270 | }, | ||
271 | { | ||
272 | fields: [ 'pluginId' ], | ||
273 | where: { | ||
274 | pluginId: { | ||
275 | [Op.ne]: null | ||
276 | } | ||
277 | } | ||
278 | }, | ||
279 | { | ||
280 | fields: [ 'applicationId' ], | ||
281 | where: { | ||
282 | applicationId: { | ||
283 | [Op.ne]: null | ||
284 | } | ||
285 | } | ||
254 | } | 286 | } |
255 | ] as (ModelIndexesOptions & { where?: WhereOptions })[] | 287 | ] as (ModelIndexesOptions & { where?: WhereOptions })[] |
256 | }) | 288 | }) |
@@ -370,6 +402,30 @@ export class UserNotificationModel extends Model { | |||
370 | }) | 402 | }) |
371 | ActorFollow: ActorFollowModel | 403 | ActorFollow: ActorFollowModel |
372 | 404 | ||
405 | @ForeignKey(() => PluginModel) | ||
406 | @Column | ||
407 | pluginId: number | ||
408 | |||
409 | @BelongsTo(() => PluginModel, { | ||
410 | foreignKey: { | ||
411 | allowNull: true | ||
412 | }, | ||
413 | onDelete: 'cascade' | ||
414 | }) | ||
415 | Plugin: PluginModel | ||
416 | |||
417 | @ForeignKey(() => ApplicationModel) | ||
418 | @Column | ||
419 | applicationId: number | ||
420 | |||
421 | @BelongsTo(() => ApplicationModel, { | ||
422 | foreignKey: { | ||
423 | allowNull: true | ||
424 | }, | ||
425 | onDelete: 'cascade' | ||
426 | }) | ||
427 | Application: ApplicationModel | ||
428 | |||
373 | static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { | 429 | static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { |
374 | const where = { userId } | 430 | const where = { userId } |
375 | 431 | ||
@@ -524,6 +580,18 @@ export class UserNotificationModel extends Model { | |||
524 | } | 580 | } |
525 | : undefined | 581 | : undefined |
526 | 582 | ||
583 | const plugin = this.Plugin | ||
584 | ? { | ||
585 | name: this.Plugin.name, | ||
586 | type: this.Plugin.type, | ||
587 | latestVersion: this.Plugin.latestVersion | ||
588 | } | ||
589 | : undefined | ||
590 | |||
591 | const peertube = this.Application | ||
592 | ? { latestVersion: this.Application.latestPeerTubeVersion } | ||
593 | : undefined | ||
594 | |||
527 | return { | 595 | return { |
528 | id: this.id, | 596 | id: this.id, |
529 | type: this.type, | 597 | type: this.type, |
@@ -535,6 +603,8 @@ export class UserNotificationModel extends Model { | |||
535 | videoBlacklist, | 603 | videoBlacklist, |
536 | account, | 604 | account, |
537 | actorFollow, | 605 | actorFollow, |
606 | plugin, | ||
607 | peertube, | ||
538 | createdAt: this.createdAt.toISOString(), | 608 | createdAt: this.createdAt.toISOString(), |
539 | updatedAt: this.updatedAt.toISOString() | 609 | updatedAt: this.updatedAt.toISOString() |
540 | } | 610 | } |
@@ -553,17 +623,19 @@ export class UserNotificationModel extends Model { | |||
553 | ? { | 623 | ? { |
554 | threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), | 624 | threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), |
555 | 625 | ||
556 | video: { | 626 | video: abuse.VideoCommentAbuse.VideoComment.Video |
557 | id: abuse.VideoCommentAbuse.VideoComment.Video.id, | 627 | ? { |
558 | name: abuse.VideoCommentAbuse.VideoComment.Video.name, | 628 | id: abuse.VideoCommentAbuse.VideoComment.Video.id, |
559 | uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid | 629 | name: abuse.VideoCommentAbuse.VideoComment.Video.name, |
560 | } | 630 | uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid |
631 | } | ||
632 | : undefined | ||
561 | } | 633 | } |
562 | : undefined | 634 | : undefined |
563 | 635 | ||
564 | const videoAbuse = abuse.VideoAbuse?.Video ? this.formatVideo(abuse.VideoAbuse.Video) : undefined | 636 | const videoAbuse = abuse.VideoAbuse?.Video ? this.formatVideo(abuse.VideoAbuse.Video) : undefined |
565 | 637 | ||
566 | const accountAbuse = (!commentAbuse && !videoAbuse) ? this.formatActor(abuse.FlaggedAccount) : undefined | 638 | const accountAbuse = (!commentAbuse && !videoAbuse && abuse.FlaggedAccount) ? this.formatActor(abuse.FlaggedAccount) : undefined |
567 | 639 | ||
568 | return { | 640 | return { |
569 | id: abuse.id, | 641 | id: abuse.id, |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index c1f22b76a..00c6d73aa 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -21,6 +21,7 @@ import { | |||
21 | Table, | 21 | Table, |
22 | UpdatedAt | 22 | UpdatedAt |
23 | } from 'sequelize-typescript' | 23 | } from 'sequelize-typescript' |
24 | import { TokensCache } from '@server/lib/auth/tokens-cache' | ||
24 | import { | 25 | import { |
25 | MMyUserFormattable, | 26 | MMyUserFormattable, |
26 | MUser, | 27 | MUser, |
@@ -58,7 +59,6 @@ import { | |||
58 | } from '../../helpers/custom-validators/users' | 59 | } from '../../helpers/custom-validators/users' |
59 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' | 60 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' |
60 | import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' | 61 | import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' |
61 | import { clearCacheByUserId } from '../../lib/oauth-model' | ||
62 | import { getThemeOrDefault } from '../../lib/plugins/theme-utils' | 62 | import { getThemeOrDefault } from '../../lib/plugins/theme-utils' |
63 | import { ActorModel } from '../activitypub/actor' | 63 | import { ActorModel } from '../activitypub/actor' |
64 | import { ActorFollowModel } from '../activitypub/actor-follow' | 64 | import { ActorFollowModel } from '../activitypub/actor-follow' |
@@ -71,6 +71,7 @@ import { VideoLiveModel } from '../video/video-live' | |||
71 | import { VideoPlaylistModel } from '../video/video-playlist' | 71 | import { VideoPlaylistModel } from '../video/video-playlist' |
72 | import { AccountModel } from './account' | 72 | import { AccountModel } from './account' |
73 | import { UserNotificationSettingModel } from './user-notification-setting' | 73 | import { UserNotificationSettingModel } from './user-notification-setting' |
74 | import { ActorImageModel } from './actor-image' | ||
74 | 75 | ||
75 | enum ScopeNames { | 76 | enum ScopeNames { |
76 | FOR_ME_API = 'FOR_ME_API', | 77 | FOR_ME_API = 'FOR_ME_API', |
@@ -97,7 +98,20 @@ enum ScopeNames { | |||
97 | model: AccountModel, | 98 | model: AccountModel, |
98 | include: [ | 99 | include: [ |
99 | { | 100 | { |
100 | model: VideoChannelModel | 101 | model: VideoChannelModel.unscoped(), |
102 | include: [ | ||
103 | { | ||
104 | model: ActorModel, | ||
105 | required: true, | ||
106 | include: [ | ||
107 | { | ||
108 | model: ActorImageModel, | ||
109 | as: 'Banner', | ||
110 | required: false | ||
111 | } | ||
112 | ] | ||
113 | } | ||
114 | ] | ||
101 | }, | 115 | }, |
102 | { | 116 | { |
103 | attributes: [ 'id', 'name', 'type' ], | 117 | attributes: [ 'id', 'name', 'type' ], |
@@ -411,7 +425,7 @@ export class UserModel extends Model { | |||
411 | @AfterUpdate | 425 | @AfterUpdate |
412 | @AfterDestroy | 426 | @AfterDestroy |
413 | static removeTokenCache (instance: UserModel) { | 427 | static removeTokenCache (instance: UserModel) { |
414 | return clearCacheByUserId(instance.id) | 428 | return TokensCache.Instance.clearCacheByUserId(instance.id) |
415 | } | 429 | } |
416 | 430 | ||
417 | static countTotal () { | 431 | static countTotal () { |