aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/users
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/shared/users')
-rw-r--r--client/src/app/shared/users/index.ts1
-rw-r--r--client/src/app/shared/users/user-history.service.ts45
-rw-r--r--client/src/app/shared/users/user-notification.model.ts155
-rw-r--r--client/src/app/shared/users/user-notification.service.ts86
-rw-r--r--client/src/app/shared/users/user-notifications.component.html101
-rw-r--r--client/src/app/shared/users/user-notifications.component.scss51
-rw-r--r--client/src/app/shared/users/user-notifications.component.ts87
-rw-r--r--client/src/app/shared/users/user.model.ts37
8 files changed, 536 insertions, 27 deletions
diff --git a/client/src/app/shared/users/index.ts b/client/src/app/shared/users/index.ts
index 7b5a67bc7..ebd715fb1 100644
--- a/client/src/app/shared/users/index.ts
+++ b/client/src/app/shared/users/index.ts
@@ -1,2 +1,3 @@
1export * from './user.model' 1export * from './user.model'
2export * from './user.service' 2export * from './user.service'
3export * from './user-notifications.component'
diff --git a/client/src/app/shared/users/user-history.service.ts b/client/src/app/shared/users/user-history.service.ts
new file mode 100644
index 000000000..9ed25bfc7
--- /dev/null
+++ b/client/src/app/shared/users/user-history.service.ts
@@ -0,0 +1,45 @@
1import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core'
3import { environment } from '../../../environments/environment'
4import { RestExtractor } from '../rest/rest-extractor.service'
5import { RestService } from '../rest/rest.service'
6import { Video } from '../video/video.model'
7import { catchError, map, switchMap } from 'rxjs/operators'
8import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
9import { VideoService } from '@app/shared/video/video.service'
10import { ResultList } from '../../../../../shared'
11
12@Injectable()
13export class UserHistoryService {
14 static BASE_USER_VIDEOS_HISTORY_URL = environment.apiUrl + '/api/v1/users/me/history/videos'
15
16 constructor (
17 private authHttp: HttpClient,
18 private restExtractor: RestExtractor,
19 private restService: RestService,
20 private videoService: VideoService
21 ) {}
22
23 getUserVideosHistory (historyPagination: ComponentPagination) {
24 const pagination = this.restService.componentPaginationToRestPagination(historyPagination)
25
26 let params = new HttpParams()
27 params = this.restService.addRestGetParams(params, pagination)
28
29 return this.authHttp
30 .get<ResultList<Video>>(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL, { params })
31 .pipe(
32 switchMap(res => this.videoService.extractVideos(res)),
33 catchError(err => this.restExtractor.handleError(err))
34 )
35 }
36
37 deleteUserVideosHistory () {
38 return this.authHttp
39 .post(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL + '/remove', {})
40 .pipe(
41 map(() => this.restExtractor.extractDataBool()),
42 catchError(err => this.restExtractor.handleError(err))
43 )
44 }
45}
diff --git a/client/src/app/shared/users/user-notification.model.ts b/client/src/app/shared/users/user-notification.model.ts
new file mode 100644
index 000000000..125d2120c
--- /dev/null
+++ b/client/src/app/shared/users/user-notification.model.ts
@@ -0,0 +1,155 @@
1import { UserNotification as UserNotificationServer, UserNotificationType, VideoInfo, ActorInfo } from '../../../../../shared'
2import { Actor } from '@app/shared/actor/actor.model'
3
4export class UserNotification implements UserNotificationServer {
5 id: number
6 type: UserNotificationType
7 read: boolean
8
9 video?: VideoInfo & {
10 channel: ActorInfo & { avatarUrl?: string }
11 }
12
13 videoImport?: {
14 id: number
15 video?: VideoInfo
16 torrentName?: string
17 magnetUri?: string
18 targetUrl?: string
19 }
20
21 comment?: {
22 id: number
23 threadId: number
24 account: ActorInfo & { avatarUrl?: string }
25 video: VideoInfo
26 }
27
28 videoAbuse?: {
29 id: number
30 video: VideoInfo
31 }
32
33 videoBlacklist?: {
34 id: number
35 video: VideoInfo
36 }
37
38 account?: ActorInfo & { avatarUrl?: string }
39
40 actorFollow?: {
41 id: number
42 follower: ActorInfo & { avatarUrl?: string }
43 following: {
44 type: 'account' | 'channel'
45 name: string
46 displayName: string
47 }
48 }
49
50 createdAt: string
51 updatedAt: string
52
53 // Additional fields
54 videoUrl?: string
55 commentUrl?: any[]
56 videoAbuseUrl?: string
57 accountUrl?: string
58 videoImportIdentifier?: string
59 videoImportUrl?: string
60
61 constructor (hash: UserNotificationServer) {
62 this.id = hash.id
63 this.type = hash.type
64 this.read = hash.read
65
66 this.video = hash.video
67 if (this.video) this.setAvatarUrl(this.video.channel)
68
69 this.videoImport = hash.videoImport
70
71 this.comment = hash.comment
72 if (this.comment) this.setAvatarUrl(this.comment.account)
73
74 this.videoAbuse = hash.videoAbuse
75
76 this.videoBlacklist = hash.videoBlacklist
77
78 this.account = hash.account
79 if (this.account) this.setAvatarUrl(this.account)
80
81 this.actorFollow = hash.actorFollow
82 if (this.actorFollow) this.setAvatarUrl(this.actorFollow.follower)
83
84 this.createdAt = hash.createdAt
85 this.updatedAt = hash.updatedAt
86
87 switch (this.type) {
88 case UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION:
89 this.videoUrl = this.buildVideoUrl(this.video)
90 break
91
92 case UserNotificationType.UNBLACKLIST_ON_MY_VIDEO:
93 this.videoUrl = this.buildVideoUrl(this.video)
94 break
95
96 case UserNotificationType.NEW_COMMENT_ON_MY_VIDEO:
97 case UserNotificationType.COMMENT_MENTION:
98 this.accountUrl = this.buildAccountUrl(this.comment.account)
99 this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ]
100 break
101
102 case UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS:
103 this.videoAbuseUrl = '/admin/moderation/video-abuses/list'
104 this.videoUrl = this.buildVideoUrl(this.videoAbuse.video)
105 break
106
107 case UserNotificationType.BLACKLIST_ON_MY_VIDEO:
108 this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video)
109 break
110
111 case UserNotificationType.MY_VIDEO_PUBLISHED:
112 this.videoUrl = this.buildVideoUrl(this.video)
113 break
114
115 case UserNotificationType.MY_VIDEO_IMPORT_SUCCESS:
116 this.videoImportUrl = this.buildVideoImportUrl()
117 this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport)
118 this.videoUrl = this.buildVideoUrl(this.videoImport.video)
119 break
120
121 case UserNotificationType.MY_VIDEO_IMPORT_ERROR:
122 this.videoImportUrl = this.buildVideoImportUrl()
123 this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport)
124 break
125
126 case UserNotificationType.NEW_USER_REGISTRATION:
127 this.accountUrl = this.buildAccountUrl(this.account)
128 break
129
130 case UserNotificationType.NEW_FOLLOW:
131 this.accountUrl = this.buildAccountUrl(this.actorFollow.follower)
132 break
133 }
134 }
135
136 private buildVideoUrl (video: { uuid: string }) {
137 return '/videos/watch/' + video.uuid
138 }
139
140 private buildAccountUrl (account: { name: string, host: string }) {
141 return '/accounts/' + Actor.CREATE_BY_STRING(account.name, account.host)
142 }
143
144 private buildVideoImportUrl () {
145 return '/my-account/video-imports'
146 }
147
148 private buildVideoImportIdentifier (videoImport: { targetUrl?: string, magnetUri?: string, torrentName?: string }) {
149 return videoImport.targetUrl || videoImport.magnetUri || videoImport.torrentName
150 }
151
152 private setAvatarUrl (actor: { avatarUrl?: string, avatar?: { path: string } }) {
153 actor.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(actor)
154 }
155}
diff --git a/client/src/app/shared/users/user-notification.service.ts b/client/src/app/shared/users/user-notification.service.ts
new file mode 100644
index 000000000..f8a30955d
--- /dev/null
+++ b/client/src/app/shared/users/user-notification.service.ts
@@ -0,0 +1,86 @@
1import { Injectable } from '@angular/core'
2import { HttpClient, HttpParams } from '@angular/common/http'
3import { RestExtractor, RestService } from '../rest'
4import { catchError, map, tap } from 'rxjs/operators'
5import { environment } from '../../../environments/environment'
6import { ResultList, UserNotification as UserNotificationServer, UserNotificationSetting } from '../../../../../shared'
7import { UserNotification } from './user-notification.model'
8import { AuthService } from '../../core'
9import { ComponentPagination } from '../rest/component-pagination.model'
10import { User } from '..'
11import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service'
12
13@Injectable()
14export class UserNotificationService {
15 static BASE_NOTIFICATIONS_URL = environment.apiUrl + '/api/v1/users/me/notifications'
16 static BASE_NOTIFICATION_SETTINGS = environment.apiUrl + '/api/v1/users/me/notification-settings'
17
18 constructor (
19 private auth: AuthService,
20 private authHttp: HttpClient,
21 private restExtractor: RestExtractor,
22 private restService: RestService,
23 private userNotificationSocket: UserNotificationSocket
24 ) {}
25
26 listMyNotifications (pagination: ComponentPagination, unread?: boolean, ignoreLoadingBar = false) {
27 let params = new HttpParams()
28 params = this.restService.addRestGetParams(params, this.restService.componentPaginationToRestPagination(pagination))
29
30 if (unread) params = params.append('unread', `${unread}`)
31
32 const headers = ignoreLoadingBar ? { ignoreLoadingBar: '' } : undefined
33
34 return this.authHttp.get<ResultList<UserNotification>>(UserNotificationService.BASE_NOTIFICATIONS_URL, { params, headers })
35 .pipe(
36 map(res => this.restExtractor.convertResultListDateToHuman(res)),
37 map(res => this.restExtractor.applyToResultListData(res, this.formatNotification.bind(this))),
38 catchError(err => this.restExtractor.handleError(err))
39 )
40 }
41
42 countUnreadNotifications () {
43 return this.listMyNotifications({ currentPage: 1, itemsPerPage: 0 }, true)
44 .pipe(map(n => n.total))
45 }
46
47 markAsRead (notification: UserNotification) {
48 const url = UserNotificationService.BASE_NOTIFICATIONS_URL + '/read'
49
50 const body = { ids: [ notification.id ] }
51 const headers = { ignoreLoadingBar: '' }
52
53 return this.authHttp.post(url, body, { headers })
54 .pipe(
55 map(this.restExtractor.extractDataBool),
56 tap(() => this.userNotificationSocket.dispatch('read')),
57 catchError(res => this.restExtractor.handleError(res))
58 )
59 }
60
61 markAllAsRead () {
62 const url = UserNotificationService.BASE_NOTIFICATIONS_URL + '/read-all'
63 const headers = { ignoreLoadingBar: '' }
64
65 return this.authHttp.post(url, {}, { headers })
66 .pipe(
67 map(this.restExtractor.extractDataBool),
68 tap(() => this.userNotificationSocket.dispatch('read-all')),
69 catchError(res => this.restExtractor.handleError(res))
70 )
71 }
72
73 updateNotificationSettings (user: User, settings: UserNotificationSetting) {
74 const url = UserNotificationService.BASE_NOTIFICATION_SETTINGS
75
76 return this.authHttp.put(url, settings)
77 .pipe(
78 map(this.restExtractor.extractDataBool),
79 catchError(res => this.restExtractor.handleError(res))
80 )
81 }
82
83 private formatNotification (notification: UserNotificationServer) {
84 return new UserNotification(notification)
85 }
86}
diff --git a/client/src/app/shared/users/user-notifications.component.html b/client/src/app/shared/users/user-notifications.component.html
new file mode 100644
index 000000000..0d69e0feb
--- /dev/null
+++ b/client/src/app/shared/users/user-notifications.component.html
@@ -0,0 +1,101 @@
1<div *ngIf="componentPagination.totalItems === 0" class="no-notification" i18n>You don't have notifications.</div>
2
3<div class="notifications" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
4 <div *ngFor="let notification of notifications" class="notification" [ngClass]="{ unread: !notification.read }" (click)="markAsRead(notification)">
5
6 <ng-container [ngSwitch]="notification.type">
7 <ng-container i18n *ngSwitchCase="UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION">
8 <img alt="" aria-labelledby="avatar" class="avatar" [src]="notification.video.channel.avatarUrl" />
9
10 <div class="message">
11 {{ notification.video.channel.displayName }} published a <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">new video</a>
12 </div>
13 </ng-container>
14
15 <ng-container i18n *ngSwitchCase="UserNotificationType.UNBLACKLIST_ON_MY_VIDEO">
16 <my-global-icon iconName="undo"></my-global-icon>
17
18 <div class="message">
19 Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been unblacklisted
20 </div>
21 </ng-container>
22
23 <ng-container i18n *ngSwitchCase="UserNotificationType.BLACKLIST_ON_MY_VIDEO">
24 <my-global-icon iconName="no"></my-global-icon>
25
26 <div class="message">
27 Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been blacklisted
28 </div>
29 </ng-container>
30
31 <ng-container i18n *ngSwitchCase="UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS">
32 <my-global-icon iconName="alert"></my-global-icon>
33
34 <div class="message">
35 <a (click)="markAsRead(notification)" [routerLink]="notification.videoAbuseUrl">A new video abuse</a> has been created on video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoAbuse.video.name }}</a>
36 </div>
37 </ng-container>
38
39 <ng-container i18n *ngSwitchCase="UserNotificationType.NEW_COMMENT_ON_MY_VIDEO">
40 <img alt="" aria-labelledby="avatar" class="avatar" [src]="notification.comment.account.avatarUrl" />
41
42 <div class="message">
43 <a (click)="markAsRead(notification)" [routerLink]="notification.accountUrl">{{ notification.comment.account.displayName }}</a> commented your video <a (click)="markAsRead(notification)" [routerLink]="notification.commentUrl">{{ notification.comment.video.name }}</a>
44 </div>
45 </ng-container>
46
47 <ng-container i18n *ngSwitchCase="UserNotificationType.MY_VIDEO_PUBLISHED">
48 <my-global-icon iconName="sparkle"></my-global-icon>
49
50 <div class="message">
51 Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been published
52 </div>
53 </ng-container>
54
55 <ng-container i18n *ngSwitchCase="UserNotificationType.MY_VIDEO_IMPORT_SUCCESS">
56 <my-global-icon iconName="cloud-download"></my-global-icon>
57
58 <div class="message">
59 <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">Your video import</a> {{ notification.videoImportIdentifier }} succeeded
60 </div>
61 </ng-container>
62
63 <ng-container i18n *ngSwitchCase="UserNotificationType.MY_VIDEO_IMPORT_ERROR">
64 <my-global-icon iconName="cloud-error"></my-global-icon>
65
66 <div class="message">
67 <a (click)="markAsRead(notification)" [routerLink]="notification.videoImportUrl">Your video import</a> {{ notification.videoImportIdentifier }} failed
68 </div>
69 </ng-container>
70
71 <ng-container i18n *ngSwitchCase="UserNotificationType.NEW_USER_REGISTRATION">
72 <my-global-icon iconName="user-add"></my-global-icon>
73
74 <div class="message">
75 User <a (click)="markAsRead(notification)" [routerLink]="notification.accountUrl">{{ notification.account.name }} registered</a> on your instance
76 </div>
77 </ng-container>
78
79 <ng-container i18n *ngSwitchCase="UserNotificationType.NEW_FOLLOW">
80 <img alt="" aria-labelledby="avatar" class="avatar" [src]="notification.actorFollow.follower.avatarUrl" />
81
82 <div class="message">
83 <a (click)="markAsRead(notification)" [routerLink]="notification.accountUrl">{{ notification.actorFollow.follower.displayName }}</a> is following
84
85 <ng-container *ngIf="notification.actorFollow.following.type === 'channel'">your channel {{ notification.actorFollow.following.displayName }}</ng-container>
86 <ng-container *ngIf="notification.actorFollow.following.type === 'account'">your account</ng-container>
87 </div>
88 </ng-container>
89
90 <ng-container i18n *ngSwitchCase="UserNotificationType.COMMENT_MENTION">
91 <img alt="" aria-labelledby="avatar" class="avatar" [src]="notification.comment.account.avatarUrl" />
92
93 <div class="message">
94 <a (click)="markAsRead(notification)" [routerLink]="notification.accountUrl">{{ notification.comment.account.displayName }}</a> mentioned you on <a (click)="markAsRead(notification)" [routerLink]="notification.commentUrl">video {{ notification.comment.video.name }}</a>
95 </div>
96 </ng-container>
97 </ng-container>
98
99 <div class="from-date">{{ notification.createdAt | myFromNow }}</div>
100 </div>
101</div>
diff --git a/client/src/app/shared/users/user-notifications.component.scss b/client/src/app/shared/users/user-notifications.component.scss
new file mode 100644
index 000000000..315d504c9
--- /dev/null
+++ b/client/src/app/shared/users/user-notifications.component.scss
@@ -0,0 +1,51 @@
1@import '_variables';
2@import '_mixins';
3
4.no-notification {
5 display: flex;
6 justify-content: center;
7 align-items: center;
8 padding: 20px 0;
9}
10
11.notification {
12 display: flex;
13 align-items: center;
14 font-size: inherit;
15 padding: 15px 5px 15px 10px;
16 border-bottom: 1px solid rgba(0, 0, 0, 0.10);
17
18 &.unread {
19 background-color: rgba(0, 0, 0, 0.05);
20 }
21
22 my-global-icon {
23 width: 24px;
24 margin-right: 11px;
25 margin-left: 3px;
26
27 @include apply-svg-color(#333);
28 }
29
30 .avatar {
31 @include avatar(30px);
32
33 margin-right: 10px;
34 }
35
36 .message {
37 flex-grow: 1;
38
39 a {
40 font-weight: $font-semibold;
41 }
42 }
43
44 .from-date {
45 font-size: 0.85em;
46 color: $grey-foreground-color;
47 padding-left: 5px;
48 min-width: 70px;
49 text-align: right;
50 }
51}
diff --git a/client/src/app/shared/users/user-notifications.component.ts b/client/src/app/shared/users/user-notifications.component.ts
new file mode 100644
index 000000000..b5f9fd399
--- /dev/null
+++ b/client/src/app/shared/users/user-notifications.component.ts
@@ -0,0 +1,87 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { UserNotificationService } from '@app/shared/users/user-notification.service'
3import { UserNotificationType } from '../../../../../shared'
4import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
5import { Notifier } from '@app/core'
6import { UserNotification } from '@app/shared/users/user-notification.model'
7
8@Component({
9 selector: 'my-user-notifications',
10 templateUrl: 'user-notifications.component.html',
11 styleUrls: [ 'user-notifications.component.scss' ]
12})
13export class UserNotificationsComponent implements OnInit {
14 @Input() ignoreLoadingBar = false
15 @Input() infiniteScroll = true
16 @Input() itemsPerPage = 20
17
18 notifications: UserNotification[] = []
19
20 // So we can access it in the template
21 UserNotificationType = UserNotificationType
22
23 componentPagination: ComponentPagination
24
25 constructor (
26 private userNotificationService: UserNotificationService,
27 private notifier: Notifier
28 ) { }
29
30 ngOnInit () {
31 this.componentPagination = {
32 currentPage: 1,
33 itemsPerPage: this.itemsPerPage, // Reset items per page, because of the @Input() variable
34 totalItems: null
35 }
36
37 this.loadMoreNotifications()
38 }
39
40 loadMoreNotifications () {
41 this.userNotificationService.listMyNotifications(this.componentPagination, undefined, this.ignoreLoadingBar)
42 .subscribe(
43 result => {
44 this.notifications = this.notifications.concat(result.data)
45 this.componentPagination.totalItems = result.total
46 },
47
48 err => this.notifier.error(err.message)
49 )
50 }
51
52 onNearOfBottom () {
53 if (this.infiniteScroll === false) return
54
55 this.componentPagination.currentPage++
56
57 if (hasMoreItems(this.componentPagination)) {
58 this.loadMoreNotifications()
59 }
60 }
61
62 markAsRead (notification: UserNotification) {
63 if (notification.read) return
64
65 this.userNotificationService.markAsRead(notification)
66 .subscribe(
67 () => {
68 notification.read = true
69 },
70
71 err => this.notifier.error(err.message)
72 )
73 }
74
75 markAllAsRead () {
76 this.userNotificationService.markAllAsRead()
77 .subscribe(
78 () => {
79 for (const notification of this.notifications) {
80 notification.read = true
81 }
82 },
83
84 err => this.notifier.error(err.message)
85 )
86 }
87}
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts
index 9819829fd..c15f1de8c 100644
--- a/client/src/app/shared/users/user.model.ts
+++ b/client/src/app/shared/users/user.model.ts
@@ -1,33 +1,8 @@
1import { 1import { hasUserRight, User as UserServerModel, UserNotificationSetting, UserRight, UserRole, VideoChannel } from '../../../../../shared'
2 Account as AccountServerModel,
3 hasUserRight,
4 User as UserServerModel,
5 UserRight,
6 UserRole,
7 VideoChannel
8} from '../../../../../shared'
9import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' 2import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type'
10import { Account } from '@app/shared/account/account.model' 3import { Account } from '@app/shared/account/account.model'
11import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 4import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
12 5
13export type UserConstructorHash = {
14 id: number,
15 username: string,
16 email: string,
17 role: UserRole,
18 emailVerified?: boolean,
19 videoQuota?: number,
20 videoQuotaDaily?: number,
21 nsfwPolicy?: NSFWPolicyType,
22 webTorrentEnabled?: boolean,
23 autoPlayVideo?: boolean,
24 createdAt?: Date,
25 account?: AccountServerModel,
26 videoChannels?: VideoChannel[]
27
28 blocked?: boolean
29 blockedReason?: string
30}
31export class User implements UserServerModel { 6export class User implements UserServerModel {
32 id: number 7 id: number
33 username: string 8 username: string
@@ -35,8 +10,11 @@ export class User implements UserServerModel {
35 emailVerified: boolean 10 emailVerified: boolean
36 role: UserRole 11 role: UserRole
37 nsfwPolicy: NSFWPolicyType 12 nsfwPolicy: NSFWPolicyType
13
38 webTorrentEnabled: boolean 14 webTorrentEnabled: boolean
39 autoPlayVideo: boolean 15 autoPlayVideo: boolean
16 videosHistoryEnabled: boolean
17
40 videoQuota: number 18 videoQuota: number
41 videoQuotaDaily: number 19 videoQuotaDaily: number
42 account: Account 20 account: Account
@@ -46,7 +24,9 @@ export class User implements UserServerModel {
46 blocked: boolean 24 blocked: boolean
47 blockedReason?: string 25 blockedReason?: string
48 26
49 constructor (hash: UserConstructorHash) { 27 notificationSettings?: UserNotificationSetting
28
29 constructor (hash: Partial<UserServerModel>) {
50 this.id = hash.id 30 this.id = hash.id
51 this.username = hash.username 31 this.username = hash.username
52 this.email = hash.email 32 this.email = hash.email
@@ -57,11 +37,14 @@ export class User implements UserServerModel {
57 this.videoQuotaDaily = hash.videoQuotaDaily 37 this.videoQuotaDaily = hash.videoQuotaDaily
58 this.nsfwPolicy = hash.nsfwPolicy 38 this.nsfwPolicy = hash.nsfwPolicy
59 this.webTorrentEnabled = hash.webTorrentEnabled 39 this.webTorrentEnabled = hash.webTorrentEnabled
40 this.videosHistoryEnabled = hash.videosHistoryEnabled
60 this.autoPlayVideo = hash.autoPlayVideo 41 this.autoPlayVideo = hash.autoPlayVideo
61 this.createdAt = hash.createdAt 42 this.createdAt = hash.createdAt
62 this.blocked = hash.blocked 43 this.blocked = hash.blocked
63 this.blockedReason = hash.blockedReason 44 this.blockedReason = hash.blockedReason
64 45
46 this.notificationSettings = hash.notificationSettings
47
65 if (hash.account !== undefined) { 48 if (hash.account !== undefined) {
66 this.account = new Account(hash.account) 49 this.account = new Account(hash.account)
67 } 50 }