]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Made the video channels limit (per user) server-wide configurable (#4491)
authorFlorian CUNY <poslovitch@bentobox.world>
Tue, 26 Oct 2021 14:42:10 +0000 (16:42 +0200)
committerGitHub <noreply@github.com>
Tue, 26 Oct 2021 14:42:10 +0000 (16:42 +0200)
* Made the video channels limit (per user) server-wide configurable

Implements https://github.com/Chocobozzz/PeerTube/issues/3092

Also added a "quota bar" in the account's settings page

* Fixed lint errors

* Another pass at fixing lint errors

* Applied code suggestions

* Removed 'video channels quota'

19 files changed:
client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
client/src/app/shared/form-validators/custom-config-validators.ts
client/src/app/shared/shared-main/shared-main.module.ts
config/default.yaml
config/production.yaml.example
server/controllers/api/config.ts
server/initializers/checker-before-init.ts
server/initializers/config.ts
server/initializers/constants.ts
server/lib/server-config-manager.ts
server/middlewares/validators/config.ts
server/middlewares/validators/videos/video-channels.ts
server/models/video/video-channel.ts
server/tests/api/check-params/config.ts
server/tests/api/server/config.ts
shared/extra-utils/server/config-command.ts
shared/models/server/custom-config.model.ts
shared/models/server/server-config.model.ts

index 537e06d4d3513a2b67e98dfeb125ed8cefe07145..318c8e2c28847d73b755e3d1b7ade4e13bef8268 100644 (file)
     </div>
   </div>
 
+  <div class="form-row mt-4"> <!-- video channels grid -->
+    <div class="form-group col-12 col-lg-4 col-xl-3">
+      <div i18n class="inner-form-title">VIDEO CHANNELS</div>
+    </div>
+    
+    <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+      <div class="form-group" formGroupName="videoChannels">
+        <label i18n for="videoChannelsMaxPerUser">Max video channels per user</label>
+
+        <div class="number-with-unit">
+          <input
+            type="number" min="1" id="videoChannelsMaxPerUser" class="form-control"
+            formControlName="maxPerUser" [ngClass]="{ 'input-error': formErrors['videoChannels.maxPerUser'] }"
+          >
+          <span i18n>{form.value['videoChannels']['maxPerUser'], plural, =1 {channel} other {channels}}</span>
+        </div>
+
+        <div *ngIf="formErrors.videoChannels.maxPerUser" class="form-error">{{ formErrors.videoChannels.maxPerUser }}</div>
+      </div>
+    </div>
+  </div>
+
   <div class="form-row mt-4"> <!-- search grid -->
     <div class="form-group col-12 col-lg-4 col-xl-3">
       <div i18n class="inner-form-title">SEARCH</div>
index 96c67fac7e02bec68dc0b6a8d7bfc582d8e812e2..fdb0a753270bce4c578bfdb523a1582c21b9c568 100644 (file)
@@ -22,7 +22,8 @@ import {
   SERVICES_TWITTER_USERNAME_VALIDATOR,
   SIGNUP_LIMIT_VALIDATOR,
   SIGNUP_MINIMUM_AGE_VALIDATOR,
-  TRANSCODING_THREADS_VALIDATOR
+  TRANSCODING_THREADS_VALIDATOR,
+  MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR
 } from '@app/shared/form-validators/custom-config-validators'
 import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
 import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
@@ -151,6 +152,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
         videoQuota: USER_VIDEO_QUOTA_VALIDATOR,
         videoQuotaDaily: USER_VIDEO_QUOTA_DAILY_VALIDATOR
       },
+      videoChannels: {
+        maxPerUser: MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR
+      },
       transcoding: {
         enabled: null,
         threads: TRANSCODING_THREADS_VALIDATOR,
index fbf423d08a4db6c6591301820c135484d7417eee..ba8512e9530761ee8783e9e21ab71c74912457bf 100644 (file)
@@ -98,6 +98,15 @@ export const MAX_USER_LIVES_VALIDATOR: BuildFormValidator = {
   }
 }
 
+export const MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR: BuildFormValidator = {
+  VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
+  MESSAGES: {
+    required: $localize`Max video channels per user is required.`,
+    min: $localize`Max video channels per user must be greater or equal to 1.`,
+    pattern: $localize`Max video channels per user must be a number.`
+  }
+}
+
 export const CONCURRENCY_VALIDATOR: BuildFormValidator = {
   VALIDATORS: [ Validators.required, Validators.min(1) ],
   MESSAGES: {
index 80d0a84f32f8e53d1f7859a41ea03c372277d27a..93989780d447938ea81abc8ea34f5d91af589207 100644 (file)
@@ -43,7 +43,12 @@ import {
 } from './misc'
 import { PluginPlaceholderComponent } from './plugins'
 import { ActorRedirectGuard } from './router'
-import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
+import {
+  UserHistoryService,
+  UserNotificationsComponent,
+  UserNotificationService,
+  UserQuotaComponent
+} from './users'
 import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
 import { VideoCaptionService } from './video-caption'
 import { VideoChannelService } from './video-channel'
index f545382c8a065498b618495d87ac6e3dbb3bfa68..cf9d69a621150562b8c5d7786a795a971f2ca584 100644 (file)
@@ -296,6 +296,9 @@ user:
   video_quota: -1
   video_quota_daily: -1
 
+video_channels:
+  max_per_user: 20 # Allows each user to create up to 20 video channels.
+
 # If enabled, the video will be transcoded to mp4 (x264) with `faststart` flag
 # In addition, if some resolutions are enabled the mp4 video file will be transcoded to these new resolutions
 # Please, do not disable transcoding since many uploaded videos will not work
index 2e0d029ceb1cd78e40f9defb69fe6bc5f3203193..70993bf57a30126279b916f2ce8b32f42bd691ce 100644 (file)
@@ -306,6 +306,9 @@ user:
   video_quota: -1
   video_quota_daily: -1
 
+video_channels:
+  max_per_user: 20 # Allows each user to create up to 20 video channels.
+
 # If enabled, the video will be transcoded to mp4 (x264) with `faststart` flag
 # In addition, if some resolutions are enabled the mp4 video file will be transcoded to these new resolutions
 # Please, do not disable transcoding since many uploaded videos will not work
index 5ea1f67c99103a9f8e24dddc53294f18c8ff05c8..8965cacc9b4a66f1260db783e0be0b1322f5f8af 100644 (file)
@@ -196,6 +196,9 @@ function customConfig (): CustomConfig {
       videoQuota: CONFIG.USER.VIDEO_QUOTA,
       videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
     },
+    videoChannels: {
+      maxPerUser: CONFIG.VIDEO_CHANNELS.MAX_PER_USER
+    },
     transcoding: {
       enabled: CONFIG.TRANSCODING.ENABLED,
       allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS,
index 16dc137c0e68436d0d58d5e8fedd2d2da60d7571..72acdd422f94dc96b36791f8fdc8699042e5f217 100644 (file)
@@ -19,6 +19,7 @@ function checkMissedConfig () {
     'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', 'storage.plugins',
     'log.level',
     'user.video_quota', 'user.video_quota_daily',
+    'video_channels.max_per_user',
     'csp.enabled', 'csp.report_only', 'csp.report_uri',
     'security.frameguard.enabled',
     'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled',
index cab60a61fa78028363bbc2679fd492c397d52eb0..8375bf4304cda5e3794bf79871596de32f316f50 100644 (file)
@@ -233,6 +233,9 @@ const CONFIG = {
     get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
     get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) }
   },
+  VIDEO_CHANNELS: {
+    get MAX_PER_USER () { return config.get<number>('video_channels.max_per_user') }
+  },
   TRANSCODING: {
     get ENABLED () { return config.get<boolean>('transcoding.enabled') },
     get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
index f6c19dab4197fa3f1837c06273d514c070099845..3781f9508b58222c9e4b8d8367a81c524df28d1b 100644 (file)
@@ -512,10 +512,6 @@ const OVERVIEWS = {
   }
 }
 
-const VIDEO_CHANNELS = {
-  MAX_PER_USER: 20
-}
-
 // ---------------------------------------------------------------------------
 
 const SERVER_ACTOR_NAME = 'peertube'
@@ -897,7 +893,6 @@ export {
   VIDEO_TRANSCODING_FPS,
   FFMPEG_NICE,
   ABUSE_STATES,
-  VIDEO_CHANNELS,
   LRU_CACHE,
   REQUEST_TIMEOUT,
   USER_PASSWORD_RESET_LIFETIME,
index b78251e8ce64853f739b91580a841011ac724f3b..bdf6492f98b3b540bbd19371cc6c96466a81915a 100644 (file)
@@ -184,6 +184,9 @@ class ServerConfigManager {
         videoQuota: CONFIG.USER.VIDEO_QUOTA,
         videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
       },
+      videoChannels: {
+        maxPerUser: CONFIG.VIDEO_CHANNELS.MAX_PER_USER
+      },
       trending: {
         videos: {
           intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
index f0385ab44bd9dfc24e1897d1079215c0a0ab8eed..da52b14bab09cb1c27a4e2102641e2e482f17245 100644 (file)
@@ -38,6 +38,8 @@ const customConfigUpdateValidator = [
   body('user.videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid video quota'),
   body('user.videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily video quota'),
 
+  body('videoChannels.maxPerUser').isInt().withMessage("Should have a valid maximum amount of video channels per user"),
+
   body('transcoding.enabled').isBoolean().withMessage('Should have a valid transcoding enabled boolean'),
   body('transcoding.allowAdditionalExtensions').isBoolean().withMessage('Should have a valid additional extensions boolean'),
   body('transcoding.threads').isInt().withMessage('Should have a valid transcoding threads number'),
index c4705192a042a403f4a4755a13341b5bd25320b7..edce48c7f76b4df23dbd1f5e7318b022122455a3 100644 (file)
@@ -1,6 +1,5 @@
 import express from 'express'
 import { body, param, query } from 'express-validator'
-import { VIDEO_CHANNELS } from '@server/initializers/constants'
 import { MChannelAccountDefault, MUser } from '@server/types/models'
 import { UserRight } from '../../../../shared'
 import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes'
@@ -15,6 +14,7 @@ import { logger } from '../../../helpers/logger'
 import { ActorModel } from '../../../models/actor/actor'
 import { VideoChannelModel } from '../../../models/video/video-channel'
 import { areValidationErrors, doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../shared'
+import { CONFIG } from '@server/initializers/config'
 
 const videoChannelsAddValidator = [
   body('name').custom(isVideoChannelUsernameValid).withMessage('Should have a valid channel name'),
@@ -37,8 +37,8 @@ const videoChannelsAddValidator = [
     }
 
     const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id)
-    if (count >= VIDEO_CHANNELS.MAX_PER_USER) {
-      res.fail({ message: `You cannot create more than ${VIDEO_CHANNELS.MAX_PER_USER} channels` })
+    if (count >= CONFIG.VIDEO_CHANNELS.MAX_PER_USER) {
+      res.fail({ message: `You cannot create more than ${CONFIG.VIDEO_CHANNELS.MAX_PER_USER} channels` })
       return false
     }
 
index 4151dc5b533ce5ff78d32d8f72c024653643d0fb..b652d8531aab6a60a9dfe1379827e0e040346c37 100644 (file)
@@ -26,7 +26,7 @@ import {
   isVideoChannelDisplayNameValid,
   isVideoChannelSupportValid
 } from '../../helpers/custom-validators/video-channels'
-import { CONSTRAINTS_FIELDS, VIDEO_CHANNELS, WEBSERVER } from '../../initializers/constants'
+import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
 import { sendDeleteActor } from '../../lib/activitypub/send'
 import {
   MChannelActor,
@@ -44,6 +44,7 @@ import { setAsUpdated } from '../shared'
 import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils'
 import { VideoModel } from './video'
 import { VideoPlaylistModel } from './video-playlist'
+import { CONFIG } from '@server/initializers/config'
 
 export enum ScopeNames {
   FOR_API = 'FOR_API',
@@ -584,7 +585,7 @@ ON              "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
 
   static listAllByAccount (accountId: number) {
     const query = {
-      limit: VIDEO_CHANNELS.MAX_PER_USER,
+      limit: CONFIG.VIDEO_CHANNELS.MAX_PER_USER,
       include: [
         {
           attributes: [],
index 87cb2287e8bf16cd49fc74ac97044dacc36edd96..273b1f71841294b9af725883547c064fa25254ec 100644 (file)
@@ -81,6 +81,9 @@ describe('Test config API validators', function () {
       videoQuota: 5242881,
       videoQuotaDaily: 318742
     },
+    videoChannels: {
+      maxPerUser: 20
+    },
     transcoding: {
       enabled: true,
       allowAdditionalExtensions: true,
index 1d996d4541c2806b3517b26bfdc0f4ebe3caa222..8d5b3ac7fb509010e78aead99026cc788fc7db45 100644 (file)
@@ -58,6 +58,8 @@ function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) {
   expect(data.user.videoQuota).to.equal(5242880)
   expect(data.user.videoQuotaDaily).to.equal(-1)
 
+  expect(data.videoChannels.maxPerUser).to.equal(20)
+
   expect(data.transcoding.enabled).to.be.false
   expect(data.transcoding.allowAdditionalExtensions).to.be.false
   expect(data.transcoding.allowAudioFiles).to.be.false
@@ -153,6 +155,8 @@ function checkUpdatedConfig (data: CustomConfig) {
   expect(data.user.videoQuota).to.equal(5242881)
   expect(data.user.videoQuotaDaily).to.equal(318742)
 
+  expect(data.videoChannels.maxPerUser).to.equal(24)
+
   expect(data.transcoding.enabled).to.be.true
   expect(data.transcoding.threads).to.equal(1)
   expect(data.transcoding.concurrency).to.equal(3)
@@ -265,6 +269,9 @@ const newCustomConfig: CustomConfig = {
     videoQuota: 5242881,
     videoQuotaDaily: 318742
   },
+  videoChannels: {
+    maxPerUser: 24
+  },
   transcoding: {
     enabled: true,
     allowAdditionalExtensions: true,
index 51d04fa63891a05a5ed9e0a4b7f7c69bf4467f70..2746e9ac407f0823f35538f58ef6dfaee7d889d4 100644 (file)
@@ -220,6 +220,9 @@ export class ConfigCommand extends AbstractCommand {
         videoQuota: 5242881,
         videoQuotaDaily: 318742
       },
+      videoChannels: {
+        maxPerUser: 20
+      },
       transcoding: {
         enabled: true,
         allowAdditionalExtensions: true,
index 75d04423ada0be2d8035d49850107fd67e46d09c..322fbb797ba1e424433d570ae4a8c446c0d5012d 100644 (file)
@@ -85,6 +85,10 @@ export interface CustomConfig {
     videoQuotaDaily: number
   }
 
+  videoChannels: {
+    maxPerUser: number
+  }
+
   transcoding: {
     enabled: boolean
 
index a0313b8da3290e7685750c2dccfe77612fc95fdd..e75eefd47b05922f3d9e3e0e1b9c786e439adb81 100644 (file)
@@ -203,6 +203,10 @@ export interface ServerConfig {
     videoQuotaDaily: number
   }
 
+  videoChannels: {
+    maxPerUser: number
+  }
+
   trending: {
     videos: {
       intervalDays: number