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 3229571e1..5e5f97fc9 100644
--- a/client/src/app/+videos/+video-edit/video-add.component.scss
+++ b/client/src/app/+videos/+video-edit/video-add.component.scss
@@ -8,23 +8,14 @@ $border-color: #EAEAEA;
$nav-link-height: 40px;
.upload-message {
+ display: block;
width: 100%;
text-align: center;
margin-bottom: 0;
- border-radius: 0;
&:last-child {
margin-bottom: 1rem;
}
-
- .about-link,
- .contact-link {
- height: fit-content;
- margin-top: 10px;
-
- @include peertube-button-link;
- @include orange-button;
- }
}
.upload-image {
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 772f48e67..6f63fadfb 100644
--- a/client/src/app/+videos/+video-edit/video-add.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add.component.ts
@@ -1,3 +1,4 @@
+import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import {
@@ -8,16 +9,16 @@ import {
ServerService,
UserService
} from '@app/core'
+import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
+import { NgbNav, NgbNavContent, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap'
import { HTMLServerConfig } from '@peertube/peertube-models'
+import { ChannelsSetupMessageComponent } from '../../shared/shared-main/channel/channels-setup-message.component'
+import { UserQuotaComponent } from '../../shared/shared-main/users/user-quota.component'
import { VideoEditType } from './shared/video-edit.type'
import { VideoGoLiveComponent } from './video-add-components/video-go-live.component'
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
import { VideoUploadComponent } from './video-add-components/video-upload.component'
-import { NgbNav, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavContent, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap'
-import { ChannelsSetupMessageComponent } from '../../shared/shared-main/channel/channels-setup-message.component'
-import { UserQuotaComponent } from '../../shared/shared-main/users/user-quota.component'
-import { NgIf, NgTemplateOutlet, NgClass } from '@angular/common'
@Component({
selector: 'my-videos-add',
@@ -40,7 +41,8 @@ import { NgIf, NgTemplateOutlet, NgClass } from '@angular/common'
VideoImportUrlComponent,
VideoImportTorrentComponent,
VideoGoLiveComponent,
- NgbNavOutlet
+ NgbNavOutlet,
+ AlertComponent
]
})
export class VideoAddComponent implements OnInit, CanComponentDeactivate {
diff --git a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
index ca4ed1a94..fc5c92cee 100644
--- a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
+++ b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
@@ -1,28 +1,28 @@
-
+
This video will be published on {{ video.scheduledUpdate.updateAt | date: 'full' }}.
-
+
-
+
This live is not currently streaming.
-
+
-
+
This live has ended.
-
+
-
+
{{ getAlertWarning() }}
-
+
-
+
There are no videos available in this playlist.
-
+
-
+
This video is blocked.
{{ video.blacklistedReason }}
-
+
-
+
This video is password protected.
-
+
diff --git a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.scss b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.scss
deleted file mode 100644
index 7b8a876ab..000000000
--- a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-@use '_variables' as *;
-@use '_mixins' as *;
-
-.alert {
- text-align: center;
- border-radius: 0;
-}
diff --git a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
index a350075f4..b41192fce 100644
--- a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
@@ -1,15 +1,16 @@
+import { DatePipe, NgIf } from '@angular/common'
import { Component, Input } from '@angular/core'
import { AuthUser } from '@app/core'
+import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoDetails } from '@app/shared/shared-main/video/video-details.model'
import { VideoPrivacy, VideoState } from '@peertube/peertube-models'
-import { NgIf, DatePipe } from '@angular/common'
@Component({
selector: 'my-video-alert',
templateUrl: './video-alert.component.html',
- styleUrls: [ './video-alert.component.scss' ],
standalone: true,
- imports: [ NgIf, DatePipe ]
+ styles: `my-alert { text-align: center }`,
+ imports: [ NgIf, DatePipe, AlertComponent ]
})
export class VideoAlertComponent {
@Input() user: AuthUser
diff --git a/client/src/app/menu/quick-settings-modal.component.html b/client/src/app/menu/quick-settings-modal.component.html
index 9db3117a9..3ae275b28 100644
--- a/client/src/app/menu/quick-settings-modal.component.html
+++ b/client/src/app/menu/quick-settings-modal.component.html
@@ -7,7 +7,7 @@
-
These settings apply only to your session on this instance.
+
These settings apply only to your session on this instance.
Videos
diff --git a/client/src/app/menu/quick-settings-modal.component.ts b/client/src/app/menu/quick-settings-modal.component.ts
index d5e06b6b9..a25a95465 100644
--- a/client/src/app/menu/quick-settings-modal.component.ts
+++ b/client/src/app/menu/quick-settings-modal.component.ts
@@ -1,20 +1,21 @@
-import { ReplaySubject, Subscription } from 'rxjs'
-import { filter } from 'rxjs/operators'
+import { CommonModule } from '@angular/common'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, AuthStatus, LocalStorageService, User, UserService } from '@app/core'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
-import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
-import { CommonModule } from '@angular/common'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
+import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { UserInterfaceSettingsComponent } from '@app/shared/shared-user-settings/user-interface-settings.component'
import { UserVideoSettingsComponent } from '@app/shared/shared-user-settings/user-video-settings.component'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
+import { ReplaySubject, Subscription } from 'rxjs'
+import { filter } from 'rxjs/operators'
@Component({
selector: 'my-quick-settings',
templateUrl: './quick-settings-modal.component.html',
standalone: true,
- imports: [ CommonModule, GlobalIconComponent, UserVideoSettingsComponent, UserInterfaceSettingsComponent ]
+ imports: [ CommonModule, GlobalIconComponent, UserVideoSettingsComponent, UserInterfaceSettingsComponent, AlertComponent ]
})
export class QuickSettingsModalComponent implements OnInit, OnDestroy {
private static readonly QUERY_MODAL_NAME = 'quick-settings'
diff --git a/client/src/app/shared/shared-main/channel/channels-setup-message.component.html b/client/src/app/shared/shared-main/channel/channels-setup-message.component.html
index 55b5ca732..c8d5ab88a 100644
--- a/client/src/app/shared/shared-main/channel/channels-setup-message.component.html
+++ b/client/src/app/shared/shared-main/channel/channels-setup-message.component.html
@@ -1,7 +1,7 @@
-
+
Some of your channels are not fully set up. Make them welcoming and explicit about what you publish by adding a banner, an avatar and a description.
Set up my channels
-
+
diff --git a/client/src/app/shared/shared-main/channel/channels-setup-message.component.scss b/client/src/app/shared/shared-main/channel/channels-setup-message.component.scss
index beb49864b..7df835c16 100644
--- a/client/src/app/shared/shared-main/channel/channels-setup-message.component.scss
+++ b/client/src/app/shared/shared-main/channel/channels-setup-message.component.scss
@@ -1,10 +1,6 @@
@use '_variables' as *;
@use '_mixins' as *;
-.pt-alert-primary {
- text-align: center;
-}
-
my-global-icon {
width: 32px;
display: inline-block;
diff --git a/client/src/app/shared/shared-main/channel/channels-setup-message.component.ts b/client/src/app/shared/shared-main/channel/channels-setup-message.component.ts
index a87c8b88b..18e455d30 100644
--- a/client/src/app/shared/shared-main/channel/channels-setup-message.component.ts
+++ b/client/src/app/shared/shared-main/channel/channels-setup-message.component.ts
@@ -1,8 +1,9 @@
-import { Component, Input, OnInit } from '@angular/core'
-import { AuthService, User } from '@app/core'
-import { RouterLink } from '@angular/router'
-import { GlobalIconComponent } from '../../shared-icons/global-icon.component'
import { NgIf } from '@angular/common'
+import { Component, Input, OnInit } from '@angular/core'
+import { RouterLink } from '@angular/router'
+import { AuthService, User } from '@app/core'
+import { GlobalIconComponent } from '../../shared-icons/global-icon.component'
+import { AlertComponent } from '../common/alert.component'
import { VideoChannel } from './video-channel.model'
@Component({
@@ -10,7 +11,7 @@ import { VideoChannel } from './video-channel.model'
templateUrl: './channels-setup-message.component.html',
styleUrls: [ './channels-setup-message.component.scss' ],
standalone: true,
- imports: [ NgIf, GlobalIconComponent, RouterLink ]
+ imports: [ NgIf, GlobalIconComponent, RouterLink, AlertComponent ]
})
export class ChannelsSetupMessageComponent implements OnInit {
@Input() hideLink = false
diff --git a/client/src/app/shared/shared-main/common/alert.component.html b/client/src/app/shared/shared-main/common/alert.component.html
new file mode 100644
index 000000000..576afd69f
--- /dev/null
+++ b/client/src/app/shared/shared-main/common/alert.component.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/client/src/app/shared/shared-main/common/alert.component.scss b/client/src/app/shared/shared-main/common/alert.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/client/src/app/shared/shared-main/common/alert.component.ts b/client/src/app/shared/shared-main/common/alert.component.ts
new file mode 100644
index 000000000..49d43dfe5
--- /dev/null
+++ b/client/src/app/shared/shared-main/common/alert.component.ts
@@ -0,0 +1,41 @@
+import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
+import { booleanAttribute, Component, Input, OnChanges, OnInit } from '@angular/core'
+import { RouterLink } from '@angular/router'
+
+export type AlertType = 'success' | 'info' | 'warning' | 'danger' | 'primary'
+
+@Component({
+ selector: 'my-alert',
+ styleUrls: [ './alert.component.scss' ],
+ templateUrl: './alert.component.html',
+ standalone: true,
+ imports: [ NgIf, RouterLink, NgClass, NgTemplateOutlet ]
+})
+export class AlertComponent implements OnInit, OnChanges {
+ @Input({ required: true }) type: AlertType
+ @Input({ transform: booleanAttribute }) rounded = true
+
+ builtClasses = ''
+
+ ngOnInit () {
+ this.buildClasses()
+ }
+
+ ngOnChanges () {
+ this.buildClasses()
+ }
+
+ private buildClasses () {
+ this.builtClasses = 'alert'
+
+ if (this.type === 'primary') {
+ this.builtClasses += ' pt-alert-primary'
+ } else {
+ this.builtClasses += ' alert-' + this.type
+ }
+
+ if (this.rounded !== true) {
+ this.builtClasses += ' rounded-0'
+ }
+ }
+}
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.html b/client/src/app/shared/shared-share-modal/video-share.component.html
index cb4f207d8..f0181e994 100644
--- a/client/src/app/shared/shared-share-modal/video-share.component.html
+++ b/client/src/app/shared/shared-share-modal/video-share.component.html
@@ -13,13 +13,13 @@
Share the playlist
-
+
@@ -57,9 +57,9 @@
[withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"
>
-
+
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
-
+
@@ -103,17 +103,17 @@
Share the video
-
+
-
+
This video is password protected, please note that recipients will require the corresponding password to access the content.
-
+
@@ -151,9 +151,9 @@
[withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"
>
-
+
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
-
+
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts
index 170abf286..7e297cc07 100644
--- a/client/src/app/shared/shared-share-modal/video-share.component.ts
+++ b/client/src/app/shared/shared-share-modal/video-share.component.ts
@@ -1,29 +1,30 @@
+import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
+import { FormsModule } from '@angular/forms'
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
+import { RouterLink } from '@angular/router'
import { HooksService, ServerService } from '@app/core'
import { VideoDetails } from '@app/shared/shared-main/video/video-details.model'
import {
+ NgbCollapse,
NgbModal,
NgbNav,
+ NgbNavContent,
NgbNavItem,
NgbNavLink,
NgbNavLinkBase,
- NgbNavContent,
- NgbNavOutlet,
- NgbCollapse
+ NgbNavOutlet
} from '@ng-bootstrap/ng-bootstrap'
-import { buildVideoOrPlaylistEmbed } from '@root-helpers/video'
import { buildPlaylistLink, buildVideoLink, decoratePlaylistLink, decorateVideoLink } from '@peertube/peertube-core-utils'
import { VideoCaption, VideoPlaylistPrivacy, VideoPrivacy } from '@peertube/peertube-models'
-import { TimestampInputComponent } from '../shared-forms/timestamp-input.component'
-import { PluginPlaceholderComponent } from '../shared-main/plugins/plugin-placeholder.component'
-import { FormsModule } from '@angular/forms'
-import { PeertubeCheckboxComponent } from '../shared-forms/peertube-checkbox.component'
+import { buildVideoOrPlaylistEmbed } from '@root-helpers/video'
import { QRCodeModule } from 'angularx-qrcode'
import { InputTextComponent } from '../shared-forms/input-text.component'
-import { RouterLink } from '@angular/router'
-import { NgIf, NgClass, NgFor } from '@angular/common'
+import { PeertubeCheckboxComponent } from '../shared-forms/peertube-checkbox.component'
+import { TimestampInputComponent } from '../shared-forms/timestamp-input.component'
import { GlobalIconComponent } from '../shared-icons/global-icon.component'
+import { AlertComponent } from '../shared-main/common/alert.component'
+import { PluginPlaceholderComponent } from '../shared-main/plugins/plugin-placeholder.component'
import { VideoPlaylist } from '../shared-video-playlist/video-playlist.model'
type Customizations = {
@@ -77,7 +78,8 @@ type TabId = 'url' | 'qrcode' | 'embed'
TimestampInputComponent,
NgClass,
NgFor,
- NgbCollapse
+ NgbCollapse,
+ AlertComponent
]
})
export class VideoShareComponent {
diff --git a/client/src/app/shared/shared-video-live/live-stream-information.component.html b/client/src/app/shared/shared-video-live/live-stream-information.component.html
index 5f574844f..325a6e44a 100644
--- a/client/src/app/shared/shared-video-live/live-stream-information.component.html
+++ b/client/src/app/shared/shared-video-live/live-stream-information.component.html
@@ -13,9 +13,9 @@
Replay will be saved
-
+
-
+
diff --git a/client/src/app/shared/shared-video-live/live-stream-information.component.scss b/client/src/app/shared/shared-video-live/live-stream-information.component.scss
index 09209f3fe..ba352d045 100644
--- a/client/src/app/shared/shared-video-live/live-stream-information.component.scss
+++ b/client/src/app/shared/shared-video-live/live-stream-information.component.scss
@@ -9,7 +9,8 @@ p-autocomplete {
margin: 20px 0;
}
-.pt-alert-primary {
+my-alert {
+ display: block;
margin: 1rem 0;
}
diff --git a/client/src/app/shared/shared-video-live/live-stream-information.component.ts b/client/src/app/shared/shared-video-live/live-stream-information.component.ts
index b04191641..77cdd6ba4 100644
--- a/client/src/app/shared/shared-video-live/live-stream-information.component.ts
+++ b/client/src/app/shared/shared-video-live/live-stream-information.component.ts
@@ -1,14 +1,15 @@
+import { DatePipe, NgFor, NgIf } from '@angular/common'
import { Component, ElementRef, ViewChild } from '@angular/core'
+import { RouterLink } from '@angular/router'
import { Video } from '@app/shared/shared-main/video/video.model'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { LiveVideo, LiveVideoError, LiveVideoErrorType, LiveVideoSession } from '@peertube/peertube-models'
-import { LiveVideoService } from './live-video.service'
-import { EditButtonComponent } from '../shared-main/buttons/edit-button.component'
-import { RouterLink } from '@angular/router'
import { InputTextComponent } from '../shared-forms/input-text.component'
-import { LiveDocumentationLinkComponent } from './live-documentation-link.component'
-import { NgIf, NgFor, DatePipe } from '@angular/common'
import { GlobalIconComponent } from '../shared-icons/global-icon.component'
+import { EditButtonComponent } from '../shared-main/buttons/edit-button.component'
+import { AlertComponent } from '../shared-main/common/alert.component'
+import { LiveDocumentationLinkComponent } from './live-documentation-link.component'
+import { LiveVideoService } from './live-video.service'
@Component({
selector: 'my-live-stream-information',
@@ -23,7 +24,8 @@ import { GlobalIconComponent } from '../shared-icons/global-icon.component'
NgFor,
RouterLink,
EditButtonComponent,
- DatePipe
+ DatePipe,
+ AlertComponent
],
providers: [ LiveVideoService ]
})
diff --git a/client/src/app/shared/shared-video-miniature/download/video-files-download.component.html b/client/src/app/shared/shared-video-miniature/download/video-files-download.component.html
index 53cbd2201..ec3c77aa4 100644
--- a/client/src/app/shared/shared-video-miniature/download/video-files-download.component.html
+++ b/client/src/app/shared/shared-video-miniature/download/video-files-download.component.html
@@ -1,6 +1,6 @@
-
+
The following link contains a private token and should not be shared with anyone.
-
+
diff --git a/client/src/app/shared/shared-video-miniature/download/video-files-download.component.ts b/client/src/app/shared/shared-video-miniature/download/video-files-download.component.ts
index 10022b90e..ac9d3ce38 100644
--- a/client/src/app/shared/shared-video-miniature/download/video-files-download.component.ts
+++ b/client/src/app/shared/shared-video-miniature/download/video-files-download.component.ts
@@ -1,6 +1,7 @@
import { KeyValuePipe, NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, EventEmitter, Inject, Input, LOCALE_ID, OnInit, Output } from '@angular/core'
import { FormsModule } from '@angular/forms'
+import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import {
NgbCollapse,
NgbNav,
@@ -48,7 +49,8 @@ type FileMetadata = { [key: string]: { label: string, value: string | number } }
KeyValuePipe,
NgbTooltip,
NgTemplateOutlet,
- NgClass
+ NgClass,
+ AlertComponent
]
})
export class VideoFilesDownloadComponent implements OnInit {
diff --git a/client/src/app/shared/standalone-upload/upload-progress.component.html b/client/src/app/shared/standalone-upload/upload-progress.component.html
index 836c4c437..0c55d1e9f 100644
--- a/client/src/app/shared/standalone-upload/upload-progress.component.html
+++ b/client/src/app/shared/standalone-upload/upload-progress.component.html
@@ -23,7 +23,7 @@
-
+
Sorry, but something went wrong
{{ error }}
-
+
diff --git a/client/src/app/shared/standalone-upload/upload-progress.component.ts b/client/src/app/shared/standalone-upload/upload-progress.component.ts
index ec82d0fbe..b2736a8da 100644
--- a/client/src/app/shared/standalone-upload/upload-progress.component.ts
+++ b/client/src/app/shared/standalone-upload/upload-progress.component.ts
@@ -1,12 +1,13 @@
import { CommonModule } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core'
+import { AlertComponent } from '../shared-main/common/alert.component'
import { ProgressBarComponent } from '../shared-main/common/progress-bar.component'
@Component({
selector: 'my-upload-progress',
templateUrl: './upload-progress.component.html',
styleUrls: [ './upload-progress.component.scss' ],
- imports: [ CommonModule, ProgressBarComponent ],
+ imports: [ CommonModule, ProgressBarComponent, AlertComponent ],
standalone: true
})
export class UploadProgressComponent {
diff --git a/server/core/lib/auth/oauth-model.ts b/server/core/lib/auth/oauth-model.ts
index 47362931f..e801b678b 100644
--- a/server/core/lib/auth/oauth-model.ts
+++ b/server/core/lib/auth/oauth-model.ts
@@ -130,6 +130,8 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
checkUserValidityOrThrow(user)
if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION && user.emailVerified === false) {
+ // Keep this message sync with the client
+ // TODO: use custom server code
throw new AccessDeniedError('User email is not verified.')
}