From bee0abffff73804d816b90c7fd599e0a51c09d61 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 28 Aug 2018 02:01:35 -0500 Subject: Implement daily upload limit (#956) * Implement daily upload limit (ref #652) * remove duplicate code * review fixes * fix tests? * whitespace fixes, finish leftover todo * fix tests * added some new tests * use different config value for tests * remove todo --- .../edit-custom-config.component.html | 14 +++++++++++++ .../edit-custom-config.component.ts | 24 +++++++++++++++++----- .../users/user-edit/user-edit.component.html | 9 ++++++++ client/src/app/+admin/users/user-edit/user-edit.ts | 17 +++++++-------- .../users/user-edit/user-update.component.ts | 9 +++++--- client/src/app/core/server/server.service.ts | 3 ++- .../form-validators/user-validators.service.ts | 8 ++++++++ client/src/app/shared/users/user.model.ts | 3 +++ .../video-add-components/video-upload.component.ts | 22 ++++++++++++++++++-- 9 files changed, 88 insertions(+), 21 deletions(-) (limited to 'client') diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 49b89cef4..ca7890d84 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html @@ -142,6 +142,20 @@ {{ formErrors.userVideoQuota }} + +
+ +
+ +
+
+ {{ formErrors.userVideoQuotaDaily }} +
+
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 fd6784415..3b6dabcb9 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 @@ -15,10 +15,7 @@ import { BuildFormDefaultValues, FormValidatorService } from '@app/shared/forms/ styleUrls: [ './edit-custom-config.component.scss' ] }) export class EditCustomConfigComponent extends FormReactive implements OnInit { - customConfig: CustomConfig - resolutions = [ '240p', '360p', '480p', '720p', '1080p' ] - - videoQuotaOptions = [ + static videoQuotaOptions = [ { value: -1, label: 'Unlimited' }, { value: 0, label: '0' }, { value: 100 * 1024 * 1024, label: '100MB' }, @@ -28,6 +25,20 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { { value: 20 * 1024 * 1024 * 1024, label: '20GB' }, { value: 50 * 1024 * 1024 * 1024, label: '50GB' } ] + static videoQuotaDailyOptions = [ + { value: -1, label: 'Unlimited' }, + { value: 0, label: '0' }, + { value: 10 * 1024 * 1024, label: '10MB' }, + { value: 50 * 1024 * 1024, label: '50MB' }, + { value: 100 * 1024 * 1024, label: '100MB' }, + { value: 500 * 1024 * 1024, label: '500MB' }, + { value: 2 * 1024 * 1024 * 1024, label: '2GB' }, + { value: 5 * 1024 * 1024 * 1024, label: '5GB' } + ] + + customConfig: CustomConfig + resolutions = [ '240p', '360p', '480p', '720p', '1080p' ] + transcodingThreadOptions = [ { value: 0, label: 'Auto (via ffmpeg)' }, { value: 1, label: '1' }, @@ -75,6 +86,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { importVideosTorrentEnabled: null, adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL, userVideoQuota: this.userValidatorsService.USER_VIDEO_QUOTA, + userVideoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY, transcodingThreads: this.customConfigValidatorsService.TRANSCODING_THREADS, transcodingEnabled: null, customizationJavascript: null, @@ -173,7 +185,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { email: this.form.value['adminEmail'] }, user: { - videoQuota: this.form.value['userVideoQuota'] + videoQuota: this.form.value['userVideoQuota'], + videoQuotaDaily: this.form.value['userVideoQuotaDaily'] }, transcoding: { enabled: this.form.value['transcodingEnabled'], @@ -231,6 +244,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { signupLimit: this.customConfig.signup.limit, adminEmail: this.customConfig.admin.email, userVideoQuota: this.customConfig.user.videoQuota, + userVideoQuotaDaily: this.customConfig.user.videoQuotaDaily, transcodingThreads: this.customConfig.transcoding.threads, transcodingEnabled: this.customConfig.transcoding.enabled, customizationJavascript: this.customConfig.instance.customizations.javascript, diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.html b/client/src/app/+admin/users/user-edit/user-edit.component.html index 4626a40c9..bb745d6aa 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.component.html +++ b/client/src/app/+admin/users/user-edit/user-edit.component.html @@ -61,6 +61,15 @@ + + +
+ +
Transcoding is enabled on server. The video quota only take in account original video.
diff --git a/client/src/app/+admin/users/user-edit/user-edit.ts b/client/src/app/+admin/users/user-edit/user-edit.ts index ea8c733c3..4e7ca8a1b 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/users/user-edit/user-edit.ts @@ -1,18 +1,15 @@ import { ServerService } from '../../../core' import { FormReactive } from '../../../shared' import { USER_ROLE_LABELS, VideoResolution } from '../../../../../../shared' +import { EditCustomConfigComponent } from '../../../+admin/config/edit-custom-config/' export abstract class UserEdit extends FormReactive { - videoQuotaOptions = [ - { value: -1, label: 'Unlimited' }, - { value: 0, label: '0' }, - { value: 100 * 1024 * 1024, label: '100MB' }, - { value: 500 * 1024 * 1024, label: '500MB' }, - { value: 1024 * 1024 * 1024, label: '1GB' }, - { value: 5 * 1024 * 1024 * 1024, label: '5GB' }, - { value: 20 * 1024 * 1024 * 1024, label: '20GB' }, - { value: 50 * 1024 * 1024 * 1024, label: '50GB' } - ].map(q => ({ value: q.value.toString(), label: q.label })) // Used by a HTML select, so convert key into strings + + // These are used by a HTML select, so convert key into strings + videoQuotaOptions = EditCustomConfigComponent.videoQuotaOptions + .map(q => ({ value: q.value.toString(), label: q.label })) + videoQuotaDailyOptions = EditCustomConfigComponent.videoQuotaDailyOptions + .map(q => ({ value: q.value.toString(), label: q.label })) roles = Object.keys(USER_ROLE_LABELS).map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) diff --git a/client/src/app/+admin/users/user-edit/user-update.component.ts b/client/src/app/+admin/users/user-edit/user-update.component.ts index 06bde582e..5821229b3 100644 --- a/client/src/app/+admin/users/user-edit/user-update.component.ts +++ b/client/src/app/+admin/users/user-edit/user-update.component.ts @@ -36,11 +36,12 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { } ngOnInit () { - const defaultValues = { videoQuota: '-1' } + const defaultValues = { videoQuota: '-1', videoQuotaDaily: '-1' } this.buildForm({ email: this.userValidatorsService.USER_EMAIL, role: this.userValidatorsService.USER_ROLE, - videoQuota: this.userValidatorsService.USER_VIDEO_QUOTA + videoQuota: this.userValidatorsService.USER_VIDEO_QUOTA, + videoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY }, defaultValues) this.paramsSub = this.route.params.subscribe(routeParams => { @@ -64,6 +65,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { // A select in HTML is always mapped as a string, we convert it to number userUpdate.videoQuota = parseInt(this.form.value['videoQuota'], 10) + userUpdate.videoQuotaDaily = parseInt(this.form.value['videoQuotaDaily'], 10) this.userService.updateUser(this.userId, userUpdate).subscribe( () => { @@ -93,7 +95,8 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { this.form.patchValue({ email: userJson.email, role: userJson.role, - videoQuota: userJson.videoQuota + videoQuota: userJson.videoQuota, + videoQuotaDaily: userJson.videoQuotaDaily }) } } diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 7823fa80e..a1ce12069 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -67,7 +67,8 @@ export class ServerService { } }, user: { - videoQuota: -1 + videoQuota: -1, + videoQuotaDaily: -1 }, import: { videos: { diff --git a/client/src/app/shared/forms/form-validators/user-validators.service.ts b/client/src/app/shared/forms/form-validators/user-validators.service.ts index ec9566ef3..424553d74 100644 --- a/client/src/app/shared/forms/form-validators/user-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/user-validators.service.ts @@ -9,6 +9,7 @@ export class UserValidatorsService { readonly USER_EMAIL: BuildFormValidator readonly USER_PASSWORD: BuildFormValidator readonly USER_VIDEO_QUOTA: BuildFormValidator + readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator readonly USER_ROLE: BuildFormValidator readonly USER_DISPLAY_NAME: BuildFormValidator readonly USER_DESCRIPTION: BuildFormValidator @@ -61,6 +62,13 @@ export class UserValidatorsService { 'min': this.i18n('Quota must be greater than -1.') } } + this.USER_VIDEO_QUOTA_DAILY = { + VALIDATORS: [ Validators.required, Validators.min(-1) ], + MESSAGES: { + 'required': this.i18n('Daily upload limit is required.'), + 'min': this.i18n('Daily upload limit must be greater than -1.') + } + } this.USER_ROLE = { VALIDATORS: [ Validators.required ], diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index 2748001d0..877f1bf3a 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts @@ -16,6 +16,7 @@ export type UserConstructorHash = { email: string, role: UserRole, videoQuota?: number, + videoQuotaDaily?: number, nsfwPolicy?: NSFWPolicyType, autoPlayVideo?: boolean, createdAt?: Date, @@ -33,6 +34,7 @@ export class User implements UserServerModel { nsfwPolicy: NSFWPolicyType autoPlayVideo: boolean videoQuota: number + videoQuotaDaily: number account: Account videoChannels: VideoChannel[] createdAt: Date @@ -48,6 +50,7 @@ export class User implements UserServerModel { this.videoChannels = hash.videoChannels this.videoQuota = hash.videoQuota + this.videoQuotaDaily = hash.videoQuotaDaily this.nsfwPolicy = hash.nsfwPolicy this.autoPlayVideo = hash.autoPlayVideo this.createdAt = hash.createdAt diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts index 3ec89ff62..c9ab35b1d 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts @@ -31,6 +31,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY userVideoQuotaUsed = 0 + userVideoQuotaUsedDaily = 0 isUploadingVideo = false isUpdatingVideo = false @@ -68,6 +69,9 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy this.userService.getMyVideoQuotaUsed() .subscribe(data => this.userVideoQuotaUsed = data.videoQuotaUsed) + + this.userService.getMyVideoQuotaUsed() + .subscribe(data => this.userVideoQuotaUsedDaily = data.videoQuotaUsedDaily) } ngOnDestroy () { @@ -115,10 +119,9 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy return } + const bytePipes = new BytesPipe() const videoQuota = this.authService.getUser().videoQuota if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) { - const bytePipes = new BytesPipe() - const msg = this.i18n( 'Your video quota is exceeded with this video (video size: {{ videoSize }}, used: {{ videoQuotaUsed }}, quota: {{ videoQuota }})', { @@ -131,6 +134,21 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy return } + const videoQuotaDaily = this.authService.getUser().videoQuotaDaily + if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) { + const msg = this.i18n( + 'Your daily video quota is exceeded with this video (video size: {{ videoSize }}, ' + + 'used: {{ videoQuotaUsedDaily }}, quota: {{ videoQuotaDaily }})', + { + videoSize: bytePipes.transform(videofile.size, 0), + videoQuotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0), + videoQuotaDaily: bytePipes.transform(videoQuotaDaily, 0) + } + ) + this.notificationsService.error(this.i18n('Error'), msg) + return + } + const nameWithoutExtension = videofile.name.replace(/\.[^/.]+$/, '') let name: string -- cgit v1.2.3