Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alert and hide upload view when no upload is possible #2966

Merged
merged 9 commits into from
Jul 28, 2020
147 changes: 78 additions & 69 deletions client/src/app/+my-account/my-account.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core'
import { ServerService } from '@app/core'
import { AuthService, ServerService, AuthUser } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig } from '@shared/models'
import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdown.component'
Expand All @@ -11,11 +11,13 @@ import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdo
})
export class MyAccountComponent implements OnInit {
menuEntries: TopMenuDropdownParam[] = []
user: AuthUser

private serverConfig: ServerConfig

constructor (
private serverService: ServerService,
private authService: AuthService,
private i18n: I18n
) { }

Expand All @@ -24,84 +26,91 @@ export class MyAccountComponent implements OnInit {
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)

const libraryEntries: TopMenuDropdownParam = {
label: this.i18n('My library'),
children: [
{
label: this.i18n('My channels'),
routerLink: '/my-account/video-channels',
iconName: 'channel'
},
{
label: this.i18n('My videos'),
routerLink: '/my-account/videos',
iconName: 'videos'
},
{
label: this.i18n('My playlists'),
routerLink: '/my-account/video-playlists',
iconName: 'playlists'
},
{
label: this.i18n('My subscriptions'),
routerLink: '/my-account/subscriptions',
iconName: 'subscriptions'
},
{
label: this.i18n('My history'),
routerLink: '/my-account/history/videos',
iconName: 'history'
this.user = this.authService.getUser()

this.authService.userInformationLoaded.subscribe(
() => {
const libraryEntries: TopMenuDropdownParam = {
label: this.i18n('My library'),
children: [
{
label: this.i18n('My channels'),
routerLink: '/my-account/video-channels',
iconName: 'channel'
},
{
label: this.i18n('My videos'),
routerLink: '/my-account/videos',
iconName: 'videos',
isHidden: !this.user.canSeeVideosLink()
},
{
label: this.i18n('My playlists'),
routerLink: '/my-account/video-playlists',
iconName: 'playlists'
},
{
label: this.i18n('My subscriptions'),
routerLink: '/my-account/subscriptions',
iconName: 'inbox-full'
},
{
label: this.i18n('My history'),
routerLink: '/my-account/history/videos',
iconName: 'history'
}
]
}
]
}

if (this.isVideoImportEnabled()) {
libraryEntries.children.push({
label: 'My imports',
routerLink: '/my-account/video-imports',
iconName: 'cloud-download'
})
}
if (this.isVideoImportEnabled()) {
libraryEntries.children.push({
label: 'My imports',
routerLink: '/my-account/video-imports',
iconName: 'cloud-download',
isHidden: !this.user.canSeeVideosLink()
})
}

const miscEntries: TopMenuDropdownParam = {
label: this.i18n('Misc'),
children: [
{
label: this.i18n('Muted accounts'),
routerLink: '/my-account/blocklist/accounts',
iconName: 'user-x'
},
{
label: this.i18n('Muted servers'),
routerLink: '/my-account/blocklist/servers',
iconName: 'peertube-x'
},
{
label: this.i18n('Ownership changes'),
routerLink: '/my-account/ownership',
iconName: 'download'
const miscEntries: TopMenuDropdownParam = {
label: this.i18n('Misc'),
children: [
{
label: this.i18n('Muted accounts'),
routerLink: '/my-account/blocklist/accounts',
iconName: 'user-x'
},
{
label: this.i18n('Muted servers'),
routerLink: '/my-account/blocklist/servers',
iconName: 'peertube-x'
},
{
label: this.i18n('Ownership changes'),
routerLink: '/my-account/ownership',
iconName: 'download'
}
]
}
]
}

this.menuEntries = [
{
label: this.i18n('My settings'),
routerLink: '/my-account/settings'
},
{
label: this.i18n('My notifications'),
routerLink: '/my-account/notifications'
},
libraryEntries,
miscEntries
]
this.menuEntries = [
{
label: this.i18n('My settings'),
routerLink: '/my-account/settings'
},
{
label: this.i18n('My notifications'),
routerLink: '/my-account/notifications'
},
libraryEntries,
miscEntries
]
}
)
}

isVideoImportEnabled () {
const importConfig = this.serverConfig.import.videos

return importConfig.http.enabled || importConfig.torrent.enabled
}

}
12 changes: 10 additions & 2 deletions client/src/app/+videos/+video-edit/video-add.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<div class="margin-content">
<div *ngIf="user.isUploadDisabled()" class="no-upload">
<div class="alert alert-warning">
<div i18n>Sorry, the upload feature is disabled for your account. If you want to add videos, an admin must unlock your quota.</div>
<a i18n routerLink="/about/instance" class="about-link">Read instance rules for help</a>
</div>
<img src="/client/assets/images/mascot/defeated.svg" alt="defeated mascot">
</div>

<div *ngIf="!user.isUploadDisabled()" class="margin-content">
<div class="alert alert-warning" *ngIf="isRootUser()" i18n>
We recommend you to not use the <strong>root</strong> user to publish your videos, since it's the super-admin account of your instance.
<br />
Expand Down Expand Up @@ -45,4 +53,4 @@
</div>

<div [ngbNavOutlet]="nav"></div>
</div>
</div>
28 changes: 28 additions & 0 deletions client/src/app/+videos/+video-edit/video-add.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@ $border-type: solid;
$border-color: #EAEAEA;
$nav-link-height: 40px;

.no-upload {
height: 100%;
width: 100%;
text-align: center;

.about-link {
@include peertube-button-link;
@include orange-button;

height: fit-content;
margin-top: 10px;
}

img {
margin-top: 10px;
margin-bottom: 75px;
width: 220px;
height: auto;
}

@media screen and (max-height: 600px) {
img {
margin-top: 5px;
width: 160px;
}
}
}

.margin-content {
padding-top: 20px;
}
Expand Down
8 changes: 5 additions & 3 deletions client/src/app/+videos/+video-edit/video-add.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { AuthService, CanComponentDeactivate, ServerService, User } from '@app/core'
import { AuthService, AuthUser, CanComponentDeactivate, ServerService } from '@app/core'
import { ServerConfig } from '@shared/models'
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
Expand All @@ -15,7 +15,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
@ViewChild('videoImportUrl') videoImportUrl: VideoImportUrlComponent
@ViewChild('videoImportTorrent') videoImportTorrent: VideoImportTorrentComponent

user: User = null
user: AuthUser = null

secondStepType: 'upload' | 'import-url' | 'import-torrent'
videoName: string
Expand All @@ -37,6 +37,8 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {

this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)

this.user = this.auth.getUser()
}

onFirstStepDone (type: 'upload' | 'import-url' | 'import-torrent', videoName: string) {
Expand Down Expand Up @@ -80,6 +82,6 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
}

isRootUser () {
return this.auth.getUser().username === 'root'
return this.user.username === 'root'
}
}
17 changes: 17 additions & 0 deletions client/src/app/core/users/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,21 @@ export class User implements UserServerModel {
updateAccountAvatar (newAccountAvatar: Avatar) {
this.account.updateAvatar(newAccountAvatar)
}

isUploadDisabled (): boolean {
return (this.videoQuota === 0 || this.videoQuotaDaily === 0)
}

canSeeVideosLink (): boolean {
if (!this.isUploadDisabled()) {
return true
}

// cannot upload but has already some videos
if (this.videosCount > 0) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chocobozzz we have an issue here, it seems videosCount is always undefined in this context

Copy link
Owner

@Chocobozzz Chocobozzz Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we don't compute videosCount in the /me endpoint. I'll update this PR

return true
}
kimsible marked this conversation as resolved.
Show resolved Hide resolved

return false
}
}
2 changes: 1 addition & 1 deletion client/src/app/menu/menu.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<div *ngIf="isLoggedIn" class="panel-block">
<div i18n class="block-title">MY LIBRARY</div>

<a routerLink="/my-account/videos" routerLinkActive="active">
<a *ngIf="user.canSeeVideosLink()" routerLink="/my-account/videos" routerLinkActive="active">
<my-global-icon iconName="videos" aria-hidden="true"></my-global-icon>
<ng-container i18n>Videos</ng-container>
</a>
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/menu/menu.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HotkeysService } from 'angular2-hotkeys'
import { Component, OnInit, ViewChild } from '@angular/core'
import { AuthService, AuthStatus, RedirectService, ScreenService, ServerService, User, UserService } from '@app/core'
import { AuthService, AuthStatus, RedirectService, ScreenService, ServerService, AuthUser, UserService } from '@app/core'
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
import { I18n } from '@ngx-translate/i18n-polyfill'
Expand All @@ -15,7 +15,7 @@ export class MenuComponent implements OnInit {
@ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
@ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent

user: User
user: AuthUser
isLoggedIn: boolean

userHasAdminAccess = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="sub-menu" [ngClass]="{ 'no-scroll': isModalOpened }">
<ng-container *ngFor="let menuEntry of menuEntries; index as id">

<a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
<a *ngIf="menuEntry.routerLink && !menuEntry.isHidden" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>

<div *ngIf="!menuEntry.routerLink" ngbDropdown class="parent-entry"
#dropdown="ngbDropdown" autoClose="outside">
Expand All @@ -25,11 +25,15 @@
</span>

<div ngbDropdownMenu>
<a *ngFor="let menuChild of menuEntry.children" class="dropdown-item" [ngClass]="{ icon: hasIcons, active: suffixLabels[menuEntry.label] === menuChild.label }" [routerLink]="menuChild.routerLink">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
<ng-container *ngFor="let menuChild of menuEntry.children">
<a *ngIf="!menuChild.isHidden" class="dropdown-item"
[ngClass]="{ icon: hasIcons, active: suffixLabels[menuEntry.label] === menuChild.label }"
[routerLink]="menuChild.routerLink">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>

{{ menuChild.label }}
</a>
{{ menuChild.label }}
</a>
</ng-container>
</div>
</div>
</ng-container>
Expand All @@ -39,13 +43,15 @@
<div class="modal-body">
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
<div [ngClass]="{ hidden: id !== currentMenuEntryIndex }">
<a *ngFor="let menuChild of menuEntry.children"
[ngClass]="{ icon: hasIcons }"
[routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
<ng-container *ngFor="let menuChild of menuEntry.children">
<a *ngIf="!menuChild.isHidden"
[ngClass]="{ icon: hasIcons }"
[routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>

{{ menuChild.label }}
</a>
{{ menuChild.label }}
</a>
</ng-container>
</div>
</ng-container>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
export type TopMenuDropdownParam = {
label: string
routerLink?: string
isHidden?: boolean
kimsible marked this conversation as resolved.
Show resolved Hide resolved

children?: {
label: string
routerLink: string

isHidden?: boolean
iconName?: GlobalIconName
}[]
}
Expand Down