diff options
Diffstat (limited to 'client/src/app/+admin')
25 files changed, 175 insertions, 67 deletions
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 366e29883..f01967ea6 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -49,6 +49,7 @@ import { | |||
49 | PluginSearchComponent, | 49 | PluginSearchComponent, |
50 | PluginShowInstalledComponent | 50 | PluginShowInstalledComponent |
51 | } from './plugins' | 51 | } from './plugins' |
52 | import { SharedAdminModule } from './shared' | ||
52 | import { JobService, LogsComponent, LogsService } from './system' | 53 | import { JobService, LogsComponent, LogsService } from './system' |
53 | import { DebugComponent, DebugService } from './system/debug' | 54 | import { DebugComponent, DebugService } from './system/debug' |
54 | import { JobsComponent } from './system/jobs/jobs.component' | 55 | import { JobsComponent } from './system/jobs/jobs.component' |
@@ -69,6 +70,7 @@ import { JobsComponent } from './system/jobs/jobs.component' | |||
69 | SharedVideoMiniatureModule, | 70 | SharedVideoMiniatureModule, |
70 | SharedTablesModule, | 71 | SharedTablesModule, |
71 | SharedUsersModule, | 72 | SharedUsersModule, |
73 | SharedAdminModule, | ||
72 | 74 | ||
73 | TableModule, | 75 | TableModule, |
74 | ChartModule | 76 | ChartModule |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html index 929ea3a90..43f1438e0 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html | |||
@@ -218,6 +218,8 @@ | |||
218 | [clearable]="false" | 218 | [clearable]="false" |
219 | ></my-select-custom-value> | 219 | ></my-select-custom-value> |
220 | 220 | ||
221 | <my-user-real-quota-info [videoQuota]="getUserVideoQuota()"></my-user-real-quota-info> | ||
222 | |||
221 | <div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div> | 223 | <div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div> |
222 | </div> | 224 | </div> |
223 | 225 | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts index 90ed58c99..2122e67b2 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts | |||
@@ -60,6 +60,10 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges { | |||
60 | return !!enabled.find((e: string) => e === algorithm) | 60 | return !!enabled.find((e: string) => e === algorithm) |
61 | } | 61 | } |
62 | 62 | ||
63 | getUserVideoQuota () { | ||
64 | return this.form.value['user']['videoQuota'] | ||
65 | } | ||
66 | |||
63 | isSignupEnabled () { | 67 | isSignupEnabled () { |
64 | return this.form.value['signup']['enabled'] === true | 68 | return this.form.value['signup']['enabled'] === true |
65 | } | 69 | } |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss index dda5d0b5e..764e626ec 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss | |||
@@ -150,3 +150,9 @@ ngb-tabset:not(.previews) ::ng-deep { | |||
150 | padding: 0 .3em; | 150 | padding: 0 .3em; |
151 | } | 151 | } |
152 | } | 152 | } |
153 | |||
154 | my-user-real-quota-info { | ||
155 | display: block; | ||
156 | margin-top: 5px; | ||
157 | font-size: 11px; | ||
158 | } | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index 545e37857..168f4702c 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -18,15 +18,15 @@ import { | |||
18 | MAX_INSTANCE_LIVES_VALIDATOR, | 18 | MAX_INSTANCE_LIVES_VALIDATOR, |
19 | MAX_LIVE_DURATION_VALIDATOR, | 19 | MAX_LIVE_DURATION_VALIDATOR, |
20 | MAX_USER_LIVES_VALIDATOR, | 20 | MAX_USER_LIVES_VALIDATOR, |
21 | MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR, | ||
21 | SEARCH_INDEX_URL_VALIDATOR, | 22 | SEARCH_INDEX_URL_VALIDATOR, |
22 | SERVICES_TWITTER_USERNAME_VALIDATOR, | 23 | SERVICES_TWITTER_USERNAME_VALIDATOR, |
23 | SIGNUP_LIMIT_VALIDATOR, | 24 | SIGNUP_LIMIT_VALIDATOR, |
24 | SIGNUP_MINIMUM_AGE_VALIDATOR, | 25 | SIGNUP_MINIMUM_AGE_VALIDATOR, |
25 | TRANSCODING_THREADS_VALIDATOR, | 26 | TRANSCODING_THREADS_VALIDATOR |
26 | MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR | ||
27 | } from '@app/shared/form-validators/custom-config-validators' | 27 | } from '@app/shared/form-validators/custom-config-validators' |
28 | import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators' | 28 | import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators' |
29 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 29 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
30 | import { CustomPageService } from '@app/shared/shared-main/custom-page' | 30 | import { CustomPageService } from '@app/shared/shared-main/custom-page' |
31 | import { CustomConfig, CustomPage, HTMLServerConfig } from '@shared/models' | 31 | import { CustomConfig, CustomPage, HTMLServerConfig } from '@shared/models' |
32 | import { EditConfigurationService } from './edit-configuration.service' | 32 | import { EditConfigurationService } from './edit-configuration.service' |
@@ -52,9 +52,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
52 | categoryItems: SelectOptionsItem[] = [] | 52 | categoryItems: SelectOptionsItem[] = [] |
53 | 53 | ||
54 | constructor ( | 54 | constructor ( |
55 | protected formReactiveService: FormReactiveService, | ||
55 | private router: Router, | 56 | private router: Router, |
56 | private route: ActivatedRoute, | 57 | private route: ActivatedRoute, |
57 | protected formValidatorService: FormValidatorService, | ||
58 | private notifier: Notifier, | 58 | private notifier: Notifier, |
59 | private configService: ConfigService, | 59 | private configService: ConfigService, |
60 | private customPage: CustomPageService, | 60 | private customPage: CustomPageService, |
diff --git a/client/src/app/+admin/follows/following-list/follow-modal.component.ts b/client/src/app/+admin/follows/following-list/follow-modal.component.ts index 07cc75d77..8f74e82a6 100644 --- a/client/src/app/+admin/follows/following-list/follow-modal.component.ts +++ b/client/src/app/+admin/follows/following-list/follow-modal.component.ts | |||
@@ -2,7 +2,7 @@ import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/cor | |||
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { prepareIcu } from '@app/helpers' | 3 | import { prepareIcu } from '@app/helpers' |
4 | import { splitAndGetNotEmpty, UNIQUE_HOSTS_OR_HANDLE_VALIDATOR } from '@app/shared/form-validators/host-validators' | 4 | import { splitAndGetNotEmpty, UNIQUE_HOSTS_OR_HANDLE_VALIDATOR } from '@app/shared/form-validators/host-validators' |
5 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
6 | import { InstanceFollowService } from '@app/shared/shared-instance' | 6 | import { InstanceFollowService } from '@app/shared/shared-instance' |
7 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 7 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
8 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | 8 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' |
@@ -22,7 +22,7 @@ export class FollowModalComponent extends FormReactive implements OnInit { | |||
22 | private openedModal: NgbModalRef | 22 | private openedModal: NgbModalRef |
23 | 23 | ||
24 | constructor ( | 24 | constructor ( |
25 | protected formValidatorService: FormValidatorService, | 25 | protected formReactiveService: FormReactiveService, |
26 | private modalService: NgbModal, | 26 | private modalService: NgbModal, |
27 | private followService: InstanceFollowService, | 27 | private followService: InstanceFollowService, |
28 | private notifier: Notifier | 28 | private notifier: Notifier |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index 8d67e9beb..efd99e52b 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts | |||
@@ -98,7 +98,10 @@ export class VideoBlockListComponent extends RestTable implements OnInit { | |||
98 | 98 | ||
99 | this.videoService.removeVideo(videoBlock.video.id) | 99 | this.videoService.removeVideo(videoBlock.video.id) |
100 | .subscribe({ | 100 | .subscribe({ |
101 | next: () => this.notifier.success($localize`Video deleted.`), | 101 | next: () => { |
102 | this.notifier.success($localize`Video deleted.`) | ||
103 | this.reloadData() | ||
104 | }, | ||
102 | 105 | ||
103 | error: err => this.notifier.error(err.message) | 106 | error: err => this.notifier.error(err.message) |
104 | }) | 107 | }) |
@@ -124,7 +127,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit { | |||
124 | } | 127 | } |
125 | 128 | ||
126 | toHtml (text: string) { | 129 | toHtml (text: string) { |
127 | return this.markdownRenderer.textMarkdownToHTML(text) | 130 | return this.markdownRenderer.textMarkdownToHTML({ markdown: text }) |
128 | } | 131 | } |
129 | 132 | ||
130 | async unblockVideo (entry: VideoBlacklist) { | 133 | async unblockVideo (entry: VideoBlacklist) { |
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.ts b/client/src/app/+admin/overview/comments/video-comment-list.component.ts index cfe40b92a..c95d2ffeb 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.ts +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.ts | |||
@@ -115,7 +115,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
115 | } | 115 | } |
116 | 116 | ||
117 | toHtml (text: string) { | 117 | toHtml (text: string) { |
118 | return this.markdownRenderer.textMarkdownToHTML(text, true, true) | 118 | return this.markdownRenderer.textMarkdownToHTML({ markdown: text, withHtml: true, withEmoji: true }) |
119 | } | 119 | } |
120 | 120 | ||
121 | isInSelectionMode () { | 121 | isInSelectionMode () { |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-create.component.ts b/client/src/app/+admin/overview/users/user-edit/user-create.component.ts index 1713e06ce..0627aa887 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-create.component.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-create.component.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | USER_VIDEO_QUOTA_DAILY_VALIDATOR, | 12 | USER_VIDEO_QUOTA_DAILY_VALIDATOR, |
13 | USER_VIDEO_QUOTA_VALIDATOR | 13 | USER_VIDEO_QUOTA_VALIDATOR |
14 | } from '@app/shared/form-validators/user-validators' | 14 | } from '@app/shared/form-validators/user-validators' |
15 | import { FormValidatorService } from '@app/shared/shared-forms' | 15 | import { FormReactiveService } from '@app/shared/shared-forms' |
16 | import { UserAdminService } from '@app/shared/shared-users' | 16 | import { UserAdminService } from '@app/shared/shared-users' |
17 | import { UserCreate, UserRole } from '@shared/models' | 17 | import { UserCreate, UserRole } from '@shared/models' |
18 | import { UserEdit } from './user-edit' | 18 | import { UserEdit } from './user-edit' |
@@ -27,7 +27,7 @@ export class UserCreateComponent extends UserEdit implements OnInit { | |||
27 | 27 | ||
28 | constructor ( | 28 | constructor ( |
29 | protected serverService: ServerService, | 29 | protected serverService: ServerService, |
30 | protected formValidatorService: FormValidatorService, | 30 | protected formReactiveService: FormReactiveService, |
31 | protected configService: ConfigService, | 31 | protected configService: ConfigService, |
32 | protected screenService: ScreenService, | 32 | protected screenService: ScreenService, |
33 | protected auth: AuthService, | 33 | protected auth: AuthService, |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.component.html b/client/src/app/+admin/overview/users/user-edit/user-edit.component.html index e484ab8b0..e51ccf808 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.component.html +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.component.html | |||
@@ -152,10 +152,7 @@ | |||
152 | [clearable]="false" | 152 | [clearable]="false" |
153 | ></my-select-custom-value> | 153 | ></my-select-custom-value> |
154 | 154 | ||
155 | <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> | 155 | <my-user-real-quota-info [videoQuota]="getUserVideoQuota()"></my-user-real-quota-info> |
156 | Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br /> | ||
157 | At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}. | ||
158 | </div> | ||
159 | 156 | ||
160 | <div *ngIf="formErrors.videoQuota" class="form-error"> | 157 | <div *ngIf="formErrors.videoQuota" class="form-error"> |
161 | {{ formErrors.videoQuota }} | 158 | {{ formErrors.videoQuota }} |
@@ -207,7 +204,7 @@ | |||
207 | </div> | 204 | </div> |
208 | 205 | ||
209 | 206 | ||
210 | <div *ngIf="!isCreation() && user && user.pluginAuth === null" class="row mt-4"> <!-- danger zone grid --> | 207 | <div *ngIf="displayDangerZone()" class="row mt-4"> <!-- danger zone grid --> |
211 | <div class="col-12 col-lg-4 col-xl-3"> | 208 | <div class="col-12 col-lg-4 col-xl-3"> |
212 | <div class="anchor" id="danger"></div> <!-- danger zone anchor --> | 209 | <div class="anchor" id="danger"></div> <!-- danger zone anchor --> |
213 | <div i18n class="account-title account-title-danger">DANGER ZONE</div> | 210 | <div i18n class="account-title account-title-danger">DANGER ZONE</div> |
@@ -216,7 +213,7 @@ | |||
216 | <div class="col-12 col-lg-8 col-xl-9"> | 213 | <div class="col-12 col-lg-8 col-xl-9"> |
217 | 214 | ||
218 | <div class="danger-zone"> | 215 | <div class="danger-zone"> |
219 | <div class="form-group reset-password-email"> | 216 | <div class="form-group"> |
220 | <label i18n>Send a link to reset the password by email to the user</label> | 217 | <label i18n>Send a link to reset the password by email to the user</label> |
221 | <button (click)="resetPassword()" i18n>Ask for new password</button> | 218 | <button (click)="resetPassword()" i18n>Ask for new password</button> |
222 | </div> | 219 | </div> |
@@ -225,6 +222,11 @@ | |||
225 | <label i18n>Manually set the user password</label> | 222 | <label i18n>Manually set the user password</label> |
226 | <my-user-password [userId]="user.id"></my-user-password> | 223 | <my-user-password [userId]="user.id"></my-user-password> |
227 | </div> | 224 | </div> |
225 | |||
226 | <div *ngIf="user.twoFactorEnabled" class="form-group"> | ||
227 | <label i18n>This user has two factor authentication enabled</label> | ||
228 | <button (click)="disableTwoFactorAuth()" i18n>Disable two factor authentication</button> | ||
229 | </div> | ||
228 | </div> | 230 | </div> |
229 | 231 | ||
230 | </div> | 232 | </div> |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.component.scss b/client/src/app/+admin/overview/users/user-edit/user-edit.component.scss index 254286ae3..698628149 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.component.scss +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.component.scss | |||
@@ -41,23 +41,20 @@ button { | |||
41 | margin-top: 10px; | 41 | margin-top: 10px; |
42 | } | 42 | } |
43 | 43 | ||
44 | .transcoding-information { | 44 | my-user-real-quota-info { |
45 | display: block; | ||
45 | margin-top: 5px; | 46 | margin-top: 5px; |
46 | font-size: 11px; | 47 | font-size: 11px; |
47 | } | 48 | } |
48 | 49 | ||
49 | .danger-zone { | 50 | .danger-zone { |
50 | .reset-password-email { | 51 | button { |
51 | margin-bottom: 30px; | 52 | @include peertube-button; |
52 | 53 | @include danger-button; | |
53 | button { | 54 | @include disable-outline; |
54 | @include peertube-button; | ||
55 | @include danger-button; | ||
56 | @include disable-outline; | ||
57 | 55 | ||
58 | display: block; | 56 | display: block; |
59 | margin-top: 0; | 57 | margin-top: 0; |
60 | } | ||
61 | } | 58 | } |
62 | } | 59 | } |
63 | 60 | ||
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.ts b/client/src/app/+admin/overview/users/user-edit/user-edit.ts index 395d07423..1edca7fbf 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.ts | |||
@@ -3,7 +3,7 @@ import { ConfigService } from '@app/+admin/config/shared/config.service' | |||
3 | import { AuthService, ScreenService, ServerService, User } from '@app/core' | 3 | import { AuthService, ScreenService, ServerService, User } from '@app/core' |
4 | import { FormReactive } from '@app/shared/shared-forms' | 4 | import { FormReactive } from '@app/shared/shared-forms' |
5 | import { USER_ROLE_LABELS } from '@shared/core-utils/users' | 5 | import { USER_ROLE_LABELS } from '@shared/core-utils/users' |
6 | import { HTMLServerConfig, UserAdminFlag, UserRole, VideoResolution } from '@shared/models' | 6 | import { HTMLServerConfig, UserAdminFlag, UserRole } from '@shared/models' |
7 | import { SelectOptionsItem } from '../../../../../types/select-options-item.model' | 7 | import { SelectOptionsItem } from '../../../../../types/select-options-item.model' |
8 | 8 | ||
9 | @Directive() | 9 | @Directive() |
@@ -49,7 +49,7 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
49 | buildRoles () { | 49 | buildRoles () { |
50 | const authUser = this.auth.getUser() | 50 | const authUser = this.auth.getUser() |
51 | 51 | ||
52 | if (authUser.role === UserRole.ADMINISTRATOR) { | 52 | if (authUser.role.id === UserRole.ADMINISTRATOR) { |
53 | this.roles = Object.keys(USER_ROLE_LABELS) | 53 | this.roles = Object.keys(USER_ROLE_LABELS) |
54 | .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) | 54 | .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) |
55 | return | 55 | return |
@@ -60,33 +60,27 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
60 | ] | 60 | ] |
61 | } | 61 | } |
62 | 62 | ||
63 | isTranscodingInformationDisplayed () { | 63 | displayDangerZone () { |
64 | const formVideoQuota = parseInt(this.form.value['videoQuota'], 10) | 64 | if (this.isCreation()) return false |
65 | if (!this.user) return false | ||
66 | if (this.user.pluginAuth) return false | ||
67 | if (this.auth.getUser().id === this.user.id) return false | ||
65 | 68 | ||
66 | return this.serverConfig.transcoding.enabledResolutions.length !== 0 && | 69 | return true |
67 | formVideoQuota > 0 | ||
68 | } | 70 | } |
69 | 71 | ||
70 | computeQuotaWithTranscoding () { | 72 | resetPassword () { |
71 | const transcodingConfig = this.serverConfig.transcoding | 73 | return |
72 | |||
73 | const resolutions = transcodingConfig.enabledResolutions | ||
74 | const higherResolution = VideoResolution.H_4K | ||
75 | let multiplier = 0 | ||
76 | |||
77 | for (const resolution of resolutions) { | ||
78 | multiplier += resolution / higherResolution | ||
79 | } | ||
80 | |||
81 | if (transcodingConfig.hls.enabled) multiplier *= 2 | ||
82 | |||
83 | return multiplier * parseInt(this.form.value['videoQuota'], 10) | ||
84 | } | 74 | } |
85 | 75 | ||
86 | resetPassword () { | 76 | disableTwoFactorAuth () { |
87 | return | 77 | return |
88 | } | 78 | } |
89 | 79 | ||
80 | getUserVideoQuota () { | ||
81 | return this.form.value['videoQuota'] | ||
82 | } | ||
83 | |||
90 | protected buildAdminFlags (formValue: any) { | 84 | protected buildAdminFlags (formValue: any) { |
91 | return formValue.byPassAutoBlock ? UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST : UserAdminFlag.NONE | 85 | return formValue.byPassAutoBlock ? UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST : UserAdminFlag.NONE |
92 | } | 86 | } |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-password.component.html b/client/src/app/+admin/overview/users/user-edit/user-password.component.html index 13f57024b..173825957 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-password.component.html +++ b/client/src/app/+admin/overview/users/user-edit/user-password.component.html | |||
@@ -1,8 +1,10 @@ | |||
1 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> | 1 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> |
2 | 2 | ||
3 | <div class="input-group"> | 3 | <div class="input-group"> |
4 | <input id="password" [attr.type]="showPassword ? 'text' : 'password'" class="form-control" | 4 | <input id="password" |
5 | [attr.type]="showPassword ? 'text' : 'password'" class="form-control" | ||
5 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" | 6 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" |
7 | autocomplete="new-password" | ||
6 | > | 8 | > |
7 | <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button"> | 9 | <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button"> |
8 | <ng-container *ngIf="!showPassword" i18n>Show</ng-container> | 10 | <ng-container *ngIf="!showPassword" i18n>Show</ng-container> |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-password.component.ts b/client/src/app/+admin/overview/users/user-edit/user-password.component.ts index 8999d1f00..d6616e077 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-password.component.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-password.component.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | 1 | import { Component, Input, OnInit } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' | 3 | import { USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' |
4 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 4 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
5 | import { UserAdminService } from '@app/shared/shared-users' | 5 | import { UserAdminService } from '@app/shared/shared-users' |
6 | import { UserUpdate } from '@shared/models' | 6 | import { UserUpdate } from '@shared/models' |
7 | 7 | ||
@@ -18,7 +18,7 @@ export class UserPasswordComponent extends FormReactive implements OnInit { | |||
18 | @Input() userId: number | 18 | @Input() userId: number |
19 | 19 | ||
20 | constructor ( | 20 | constructor ( |
21 | protected formValidatorService: FormValidatorService, | 21 | protected formReactiveService: FormReactiveService, |
22 | private notifier: Notifier, | 22 | private notifier: Notifier, |
23 | private userAdminService: UserAdminService | 23 | private userAdminService: UserAdminService |
24 | ) { | 24 | ) { |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-update.component.ts b/client/src/app/+admin/overview/users/user-edit/user-update.component.ts index bab288a67..25d02f000 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-update.component.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-update.component.ts | |||
@@ -9,8 +9,8 @@ import { | |||
9 | USER_VIDEO_QUOTA_DAILY_VALIDATOR, | 9 | USER_VIDEO_QUOTA_DAILY_VALIDATOR, |
10 | USER_VIDEO_QUOTA_VALIDATOR | 10 | USER_VIDEO_QUOTA_VALIDATOR |
11 | } from '@app/shared/form-validators/user-validators' | 11 | } from '@app/shared/form-validators/user-validators' |
12 | import { FormValidatorService } from '@app/shared/shared-forms' | 12 | import { FormReactiveService } from '@app/shared/shared-forms' |
13 | import { UserAdminService } from '@app/shared/shared-users' | 13 | import { TwoFactorService, UserAdminService } from '@app/shared/shared-users' |
14 | import { User as UserType, UserAdminFlag, UserRole, UserUpdate } from '@shared/models' | 14 | import { User as UserType, UserAdminFlag, UserRole, UserUpdate } from '@shared/models' |
15 | import { UserEdit } from './user-edit' | 15 | import { UserEdit } from './user-edit' |
16 | 16 | ||
@@ -25,7 +25,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
25 | private paramsSub: Subscription | 25 | private paramsSub: Subscription |
26 | 26 | ||
27 | constructor ( | 27 | constructor ( |
28 | protected formValidatorService: FormValidatorService, | 28 | protected formReactiveService: FormReactiveService, |
29 | protected serverService: ServerService, | 29 | protected serverService: ServerService, |
30 | protected configService: ConfigService, | 30 | protected configService: ConfigService, |
31 | protected screenService: ScreenService, | 31 | protected screenService: ScreenService, |
@@ -34,6 +34,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
34 | private router: Router, | 34 | private router: Router, |
35 | private notifier: Notifier, | 35 | private notifier: Notifier, |
36 | private userService: UserService, | 36 | private userService: UserService, |
37 | private twoFactorService: TwoFactorService, | ||
37 | private userAdminService: UserAdminService | 38 | private userAdminService: UserAdminService |
38 | ) { | 39 | ) { |
39 | super() | 40 | super() |
@@ -120,10 +121,22 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
120 | this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`) | 121 | this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`) |
121 | }, | 122 | }, |
122 | 123 | ||
123 | error: err => { | 124 | error: err => this.notifier.error(err.message) |
124 | this.error = err.message | 125 | }) |
125 | } | 126 | } |
127 | |||
128 | disableTwoFactorAuth () { | ||
129 | this.twoFactorService.disableTwoFactor({ userId: this.user.id }) | ||
130 | .subscribe({ | ||
131 | next: () => { | ||
132 | this.user.twoFactorEnabled = false | ||
133 | |||
134 | this.notifier.success($localize`Two factor authentication of ${this.user.username} disabled.`) | ||
135 | }, | ||
136 | |||
137 | error: err => this.notifier.error(err.message) | ||
126 | }) | 138 | }) |
139 | |||
127 | } | 140 | } |
128 | 141 | ||
129 | private onUserFetched (userJson: UserType) { | 142 | private onUserFetched (userJson: UserType) { |
@@ -131,7 +144,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
131 | 144 | ||
132 | this.form.patchValue({ | 145 | this.form.patchValue({ |
133 | email: userJson.email, | 146 | email: userJson.email, |
134 | role: userJson.role.toString(), | 147 | role: userJson.role.id.toString(), |
135 | videoQuota: userJson.videoQuota, | 148 | videoQuota: userJson.videoQuota, |
136 | videoQuotaDaily: userJson.videoQuotaDaily, | 149 | videoQuotaDaily: userJson.videoQuotaDaily, |
137 | pluginAuth: userJson.pluginAuth, | 150 | pluginAuth: userJson.pluginAuth, |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index c7af7dfae..a96ce561c 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html | |||
@@ -106,8 +106,8 @@ | |||
106 | </td> | 106 | </td> |
107 | 107 | ||
108 | <td *ngIf="isSelected('role')"> | 108 | <td *ngIf="isSelected('role')"> |
109 | <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> | 109 | <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.role.label }}</span> |
110 | <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> | 110 | <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role.id)">{{ user.role.label }}</span> |
111 | </td> | 111 | </td> |
112 | 112 | ||
113 | <td *ngIf="isSelected('email')" [title]="user.email"> | 113 | <td *ngIf="isSelected('email')" [title]="user.email"> |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.scss b/client/src/app/+admin/overview/users/user-list/user-list.component.scss index 3c775cac5..23e0d29ee 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.scss | |||
@@ -1,6 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | @use '~bootstrap/scss/functions' as *; | 3 | @use 'bootstrap/scss/functions' as *; |
4 | 4 | ||
5 | .add-button { | 5 | .add-button { |
6 | @include create-button; | 6 | @include create-button; |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index 14bbb55e9..a6cd2e257 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -85,7 +85,8 @@ | |||
85 | <td> | 85 | <td> |
86 | <span *ngIf="isHLS(video)" class="pt-badge badge-blue">HLS</span> | 86 | <span *ngIf="isHLS(video)" class="pt-badge badge-blue">HLS</span> |
87 | <span *ngIf="isWebTorrent(video)" class="pt-badge badge-blue">WebTorrent ({{ video.files.length }})</span> | 87 | <span *ngIf="isWebTorrent(video)" class="pt-badge badge-blue">WebTorrent ({{ video.files.length }})</span> |
88 | <span *ngIf="video.isLive" class="pt-badge badge-blue">Live</span> | 88 | <span i18n *ngIf="video.isLive" class="pt-badge badge-blue">Live</span> |
89 | <span i18n *ngIf="hasObjectStorage(video)" class="pt-badge badge-purple">Object storage</span> | ||
89 | 90 | ||
90 | <span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span> | 91 | <span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span> |
91 | </td> | 92 | </td> |
@@ -106,7 +107,7 @@ | |||
106 | 107 | ||
107 | <ul> | 108 | <ul> |
108 | <li *ngFor="let file of video.files"> | 109 | <li *ngFor="let file of video.files"> |
109 | {{ file.resolution.label }}: {{ file.size | bytes: 1 }} | 110 | <a target="_blank" rel="noopener noreferrer" [href]="file.fileUrl">{{ file.resolution.label }}</a>: {{ file.size | bytes: 1 }} |
110 | 111 | ||
111 | <my-global-icon | 112 | <my-global-icon |
112 | *ngIf="canRemoveOneFile(video)" | 113 | *ngIf="canRemoveOneFile(video)" |
@@ -122,7 +123,7 @@ | |||
122 | 123 | ||
123 | <ul> | 124 | <ul> |
124 | <li *ngFor="let file of video.streamingPlaylists[0].files"> | 125 | <li *ngFor="let file of video.streamingPlaylists[0].files"> |
125 | {{ file.resolution.label }}: {{ file.size | bytes: 1 }} | 126 | <a target="_blank" rel="noopener noreferrer" [href]="file.fileUrl">{{ file.resolution.label }}</a>: {{ file.size | bytes: 1 }} |
126 | 127 | ||
127 | <my-global-icon | 128 | <my-global-icon |
128 | *ngIf="canRemoveOneFile(video)" | 129 | *ngIf="canRemoveOneFile(video)" |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index cb693ce12..4d3e9873c 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -8,6 +8,7 @@ import { AdvancedInputFilter } from '@app/shared/shared-forms' | |||
8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
9 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' | 9 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' |
10 | import { VideoActionsDisplayType } from '@app/shared/shared-video-miniature' | 10 | import { VideoActionsDisplayType } from '@app/shared/shared-video-miniature' |
11 | import { getAllFiles } from '@shared/core-utils' | ||
11 | import { UserRight, VideoFile, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' | 12 | import { UserRight, VideoFile, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' |
12 | import { VideoAdminService } from './video-admin.service' | 13 | import { VideoAdminService } from './video-admin.service' |
13 | 14 | ||
@@ -166,6 +167,14 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
166 | return video.files.length !== 0 | 167 | return video.files.length !== 0 |
167 | } | 168 | } |
168 | 169 | ||
170 | hasObjectStorage (video: Video) { | ||
171 | if (!video.isLocal) return false | ||
172 | |||
173 | const files = getAllFiles(video) | ||
174 | |||
175 | return files.some(f => !f.fileUrl.startsWith(window.location.origin)) | ||
176 | } | ||
177 | |||
169 | canRemoveOneFile (video: Video) { | 178 | canRemoveOneFile (video: Video) { |
170 | return video.canRemoveOneFile(this.authUser) | 179 | return video.canRemoveOneFile(this.authUser) |
171 | } | 180 | } |
diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts index ec02cfcd9..b1a41567e 100644 --- a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts +++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts | |||
@@ -4,7 +4,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core' | |||
4 | import { ActivatedRoute } from '@angular/router' | 4 | import { ActivatedRoute } from '@angular/router' |
5 | import { HooksService, Notifier, PluginService } from '@app/core' | 5 | import { HooksService, Notifier, PluginService } from '@app/core' |
6 | import { BuildFormArgument } from '@app/shared/form-validators' | 6 | import { BuildFormArgument } from '@app/shared/form-validators' |
7 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 7 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
8 | import { PeerTubePlugin, RegisterServerSettingOptions } from '@shared/models' | 8 | import { PeerTubePlugin, RegisterServerSettingOptions } from '@shared/models' |
9 | import { PluginApiService } from '../shared/plugin-api.service' | 9 | import { PluginApiService } from '../shared/plugin-api.service' |
10 | 10 | ||
@@ -22,7 +22,7 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit | |||
22 | private npmName: string | 22 | private npmName: string |
23 | 23 | ||
24 | constructor ( | 24 | constructor ( |
25 | protected formValidatorService: FormValidatorService, | 25 | protected formReactiveService: FormReactiveService, |
26 | private pluginService: PluginService, | 26 | private pluginService: PluginService, |
27 | private pluginAPIService: PluginApiService, | 27 | private pluginAPIService: PluginApiService, |
28 | private notifier: Notifier, | 28 | private notifier: Notifier, |
diff --git a/client/src/app/+admin/shared/index.ts b/client/src/app/+admin/shared/index.ts new file mode 100644 index 000000000..9e3834aae --- /dev/null +++ b/client/src/app/+admin/shared/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './user-real-quota-info.component' | ||
2 | |||
3 | export * from './shared-admin.module' | ||
diff --git a/client/src/app/+admin/shared/shared-admin.module.ts b/client/src/app/+admin/shared/shared-admin.module.ts new file mode 100644 index 000000000..bef7d54ef --- /dev/null +++ b/client/src/app/+admin/shared/shared-admin.module.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { SharedMainModule } from '../../shared/shared-main/shared-main.module' | ||
3 | import { UserRealQuotaInfoComponent } from './user-real-quota-info.component' | ||
4 | |||
5 | @NgModule({ | ||
6 | imports: [ | ||
7 | SharedMainModule | ||
8 | ], | ||
9 | |||
10 | declarations: [ | ||
11 | UserRealQuotaInfoComponent | ||
12 | ], | ||
13 | |||
14 | exports: [ | ||
15 | UserRealQuotaInfoComponent | ||
16 | ], | ||
17 | |||
18 | providers: [] | ||
19 | }) | ||
20 | export class SharedAdminModule { } | ||
diff --git a/client/src/app/+admin/shared/user-real-quota-info.component.html b/client/src/app/+admin/shared/user-real-quota-info.component.html new file mode 100644 index 000000000..b975ab17f --- /dev/null +++ b/client/src/app/+admin/shared/user-real-quota-info.component.html | |||
@@ -0,0 +1,4 @@ | |||
1 | <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> | ||
2 | The video quota only takes into account <strong>original</strong> video size. <br /> | ||
3 | Since transcoding is enabled, videos size can be at most ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}. | ||
4 | </div> | ||
diff --git a/client/src/app/+admin/shared/user-real-quota-info.component.scss b/client/src/app/+admin/shared/user-real-quota-info.component.scss new file mode 100644 index 000000000..40083bed3 --- /dev/null +++ b/client/src/app/+admin/shared/user-real-quota-info.component.scss | |||
@@ -0,0 +1,2 @@ | |||
1 | @use '_variables' as *; | ||
2 | @use '_mixins' as *; | ||
diff --git a/client/src/app/+admin/shared/user-real-quota-info.component.ts b/client/src/app/+admin/shared/user-real-quota-info.component.ts new file mode 100644 index 000000000..069eeba12 --- /dev/null +++ b/client/src/app/+admin/shared/user-real-quota-info.component.ts | |||
@@ -0,0 +1,44 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { ServerService } from '@app/core' | ||
3 | import { HTMLServerConfig, VideoResolution } from '@shared/models/index' | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-user-real-quota-info', | ||
7 | templateUrl: './user-real-quota-info.component.html', | ||
8 | styleUrls: [ './user-real-quota-info.component.scss' ] | ||
9 | }) | ||
10 | export class UserRealQuotaInfoComponent implements OnInit { | ||
11 | @Input() videoQuota: number | string | ||
12 | |||
13 | private serverConfig: HTMLServerConfig | ||
14 | |||
15 | constructor (private server: ServerService) { } | ||
16 | |||
17 | ngOnInit () { | ||
18 | this.serverConfig = this.server.getHTMLConfig() | ||
19 | } | ||
20 | |||
21 | isTranscodingInformationDisplayed () { | ||
22 | return this.serverConfig.transcoding.enabledResolutions.length !== 0 && this.getQuotaAsNumber() > 0 | ||
23 | } | ||
24 | |||
25 | computeQuotaWithTranscoding () { | ||
26 | const transcodingConfig = this.serverConfig.transcoding | ||
27 | |||
28 | const resolutions = transcodingConfig.enabledResolutions | ||
29 | const higherResolution = VideoResolution.H_4K | ||
30 | let multiplier = 0 | ||
31 | |||
32 | for (const resolution of resolutions) { | ||
33 | multiplier += resolution / higherResolution | ||
34 | } | ||
35 | |||
36 | if (transcodingConfig.hls.enabled) multiplier *= 2 | ||
37 | |||
38 | return multiplier * this.getQuotaAsNumber() | ||
39 | } | ||
40 | |||
41 | private getQuotaAsNumber () { | ||
42 | return parseInt(this.videoQuota + '', 10) | ||
43 | } | ||
44 | } | ||