diff --git a/client/src/app/+videos/+video-edit/video-add.component.scss b/client/src/app/+videos/+video-edit/video-add.component.scss
index dea6fde36..26be86d29 100644
--- a/client/src/app/+videos/+video-edit/video-add.component.scss
+++ b/client/src/app/+videos/+video-edit/video-add.component.scss
@@ -6,18 +6,29 @@ $border-type: solid;
$border-color: #EAEAEA;
$nav-link-height: 40px;
-.no-upload {
- height: 100%;
+.upload-message {
width: 100%;
text-align: center;
+ font-size: 15px;
+ margin-bottom: 0;
- .about-link {
+ &:last-child {
+ margin-bottom: 1rem;
+ }
+
+ .about-link,
+ .contact-link {
@include peertube-button-link;
@include orange-button;
height: fit-content;
margin-top: 10px;
}
+}
+
+.upload-image {
+ width: 100%;
+ text-align: center;
img {
margin-top: 10px;
@@ -38,10 +49,6 @@ $nav-link-height: 40px;
padding-top: 20px;
}
-.alert {
- font-size: 15px;
-}
-
::ng-deep .video-add-nav {
border-bottom: $border-width $border-type $border-color;
margin: 20px 0 0 !important;
diff --git a/client/src/app/+videos/+video-edit/video-add.component.ts b/client/src/app/+videos/+video-edit/video-add.component.ts
index 8606b8222..1443c64af 100644
--- a/client/src/app/+videos/+video-edit/video-add.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add.component.ts
@@ -1,6 +1,6 @@
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
-import { AuthService, AuthUser, CanComponentDeactivate, ServerService } from '@app/core'
+import { AuthService, AuthUser, CanComponentDeactivate, HooksService, ServerService } from '@app/core'
import { HTMLServerConfig } from '@shared/models'
import { VideoEditType } from './shared/video-edit.type'
import { VideoGoLiveComponent } from './video-add-components/video-go-live.component'
@@ -26,15 +26,27 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
activeNav: string
+ uploadMessages: {
+ noQuota: string
+ autoBlock: string
+ quotaLeftDaily: string
+ quotaLeft: string
+ }
+
private serverConfig: HTMLServerConfig
constructor (
private auth: AuthService,
+ private hooks: HooksService,
private serverService: ServerService,
private route: ActivatedRoute,
private router: Router
) {}
+ get isContactFormEnabled () {
+ return this.serverConfig.email.enabled && this.serverConfig.contactForm.enabled
+ }
+
get userInformationLoaded () {
return this.auth.userInformationLoaded
}
@@ -49,6 +61,28 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
if (this.route.snapshot.fragment) {
this.onNavChange(this.route.snapshot.fragment)
}
+
+ this.buildUploadMessages()
+ }
+
+ private async buildUploadMessages () {
+ // eslint-disable-next-line max-len
+ const noQuota = $localize`Sorry, the upload feature is disabled for your account. If you want to add videos, an admin must unlock your quota.`
+ // eslint-disable-next-line max-len
+ const autoBlock = $localize`Uploaded videos are reviewed before publishing for your account. If you want to add videos without moderation review, an admin must turn off your videos auto-block.`
+ // eslint-disable-next-line max-len
+ const quotaLeftDaily = $localize`Your daily video quota is insufficient. If you want to add more videos, you must wait for 24 hours or an admin must increase your daily quota.`
+ // eslint-disable-next-line max-len
+ const quotaLeft = $localize`Your video quota is insufficient. If you want to add more videos, an admin must increase your quota.`
+
+ const uploadMessages = {
+ noQuota,
+ autoBlock,
+ quotaLeftDaily,
+ quotaLeft
+ }
+
+ this.uploadMessages = await this.hooks.wrapObject(uploadMessages, 'common', 'filter:upload-page.alert-messages.edit.result')
}
onNavChange (newActiveNav: string) {
diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts
index 7d03e1c40..5e1fb1c8d 100644
--- a/client/src/app/core/users/user.model.ts
+++ b/client/src/app/core/users/user.model.ts
@@ -133,4 +133,30 @@ export class User implements UserServerModel {
isUploadDisabled () {
return this.videoQuota === 0 || this.videoQuotaDaily === 0
}
+
+ isAutoBlocked () {
+ return this.role === UserRole.USER && this.adminFlags !== UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST
+ }
+
+ hasNoQuotaLeft () {
+ // unlimited videoQuota
+ if (this.videoQuota === -1) return false
+
+ // no more videoQuota
+ if (!this.videoQuotaUsed) return true
+
+ // videoQuota left lower than 10%
+ return this.videoQuotaUsed > this.videoQuota * 0.9
+ }
+
+ hasNoQuotaLeftDaily () {
+ // unlimited videoQuotaDaily
+ if (this.videoQuotaDaily === -1) return false
+
+ // no more videoQuotaDaily
+ if (!this.videoQuotaUsedDaily) return true
+
+ // videoQuotaDaily left lower than 10%
+ return this.videoQuotaUsedDaily > this.videoQuotaDaily * 0.9
+ }
}
diff --git a/server/models/user/user.ts b/server/models/user/user.ts
index 20696b1f4..069d7266e 100644
--- a/server/models/user/user.ts
+++ b/server/models/user/user.ts
@@ -958,7 +958,7 @@ export class UserModel extends Model
>> {
}
toMeFormattedJSON (this: MMyUserFormattable): MyUser {
- const formatted = this.toFormattedJSON()
+ const formatted = this.toFormattedJSON({ withAdminFlags: true })
const specialPlaylists = this.Account.VideoPlaylists
.map(p => ({ id: p.id, name: p.name, type: p.type }))
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index 1419ae820..318ff832a 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -290,7 +290,7 @@ describe('Test users', function () {
expect(user.account.description).to.be.null
}
- expect(userMe.adminFlags).to.be.undefined
+ expect(userMe.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST)
expect(userGet.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST)
expect(userMe.specialPlaylists).to.have.lengthOf(1)
diff --git a/shared/models/plugins/client/client-hook.model.ts b/shared/models/plugins/client/client-hook.model.ts
index cedd1be61..aafc8c72b 100644
--- a/shared/models/plugins/client/client-hook.model.ts
+++ b/shared/models/plugins/client/client-hook.model.ts
@@ -58,6 +58,9 @@ export const clientFilterHookObject = {
// Filter left menu links
'filter:left-menu.links.create.result': true,
+ // Filter upload page alert messages
+ 'filter:upload-page.alert-messages.edit.result': true,
+
// Filter videojs options built for PeerTube player
'filter:internal.player.videojs.options.result': true
}