From: Chocobozzz Date: Mon, 11 Feb 2019 13:09:23 +0000 (+0100) Subject: Merge branch 'develop' into pr/1285 X-Git-Tag: v1.3.0-rc.1~205 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=b718fd22374d64534bcfe69932cf562894abed6a;hp=adb115f5522bea4d52456a9fc5eb4140bb064476;p=github%2FChocobozzz%2FPeerTube.git Merge branch 'develop' into pr/1285 --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b733e4b6..13bec7535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,99 @@ # Changelog +## v1.2.0 + +### BREAKING CHANGES + + * **Docker:** `PEERTUBE_TRUST_PROXY` env variable is now an array ([LecygneNoir](https://github.com/LecygneNoir)) + * **Docker:** Check you have all the storage fields in your `/config/production.yaml` file: https://github.com/Chocobozzz/PeerTube/blob/develop/support/docker/production/config/production.yaml#L34 + * **nginx:** Add redundancy endpoint in static file. **You should add it in your nginx configuration: https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/production.md#nginx** + * **nginx:** Add socket io endpoint. **You should add it in your nginx configuration: https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/production.md#nginx** + * Moderators can manage users now (add/delete/update/block) + * Add `tmp` and `redundancy` directories in configuration file. **You should configure them in your production.yaml** + +### Maintenance + + * Check free storage before upgrading in upgrade script ([@Nutomic](https://github.com/nutomic)) + * Explain that PeerTube must be stopped in prune storage script + * Add some security directives in the systemd unit configuration file ([@rigelk](https://github.com/rigelk) & [@mkoppmann](https://github.com/mkoppmann)) + * Update FreeBSD startup script ([@gegeweb](https://github.com/gegeweb)) + +### Docker + + * Patch docker entrypoint to speed up the chown at startup ([LecygneNoir](https://github.com/LecygneNoir)) + +### Features + + * Add Russian, Polish and Italian languages + * Add user notifications: + * Notification types: + * Comment on my video + * New video from my subscriptions + * New video abuses (for moderators) + * Blacklist/Unblacklist on my video + * Video import finished (error or success) + * Pending video published (after transcoding or a scheduled update) + * My account or one of my channel has a new follower + * Someone (except muted accounts) mentioned me in comments + * A user registered on the instance (for moderators) + * Notification actions: + * Add a web notification + * Send an english email + * Add contact form in about page (**enabled by default**) + * Add ability to unfederate a local video in blacklist modal (**checkbox checked by default**) + * Support additional video extensions if transcoding is enabled (**enabled by default**) + * Redirect to the last url on login + * Add ability to automatically set the video caption in URL. Example: https://peertube2.cpy.re/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d?subtitle=ru + * Automatically enable the last selected caption when watching a video + * Add ability to disable, clear and list user videos history + * Add a button to help to translate peertube + * Add text in the report modal to explain to whom the report will be sent + * Open my account menu entries on hover + * Explain what features are enabled on the instance in the about page + * Add an error message in the forgot password modal if the instance email system is not configured + * Add sitemap + * Add well known url to change password ([@rigelk](https://github.com/rigelk)) + * Remove 8GB video upload limit on client side. There may still be such limit depending on the reverse proxy configuration ([@scanlime](https://github.com/scanlime)) + * Add CSP ([@rigelk](https://github.com/rigelk) & [@Nutomic](https://github.com/nutomic)) + * Update title and description HTML tags when rendering video HTML page + * Add webfinger support for remote follows ([@acid-chicken](https://github.com/acid-chicken)) + * Add tooltip to explain how the trending algorithm works ([@auberanger](https://github.com/auberanger)) + * Warn users when they want to delete a channel because they will not be able to create another channel with the same name + * Warn users when they leave the video upload/update (on page refresh/tab close) + * Set max user name, user display name, channel name and channel display name lengths to 50 characters ([@McFlat](https://github.com/mcflat)) + * Increase video abuse length to 3000 characters + * Add totalLocalVideoFilesSize in the stats endpoint + +## Bug fixes + + * Fix the addition of captions to a video + * Fix federation of some videos + * Fix NSFW blur on search + * Add error message when trying to upload .ass subtitles + * Fix default homepage in the progressive web application + * Don't crash on queue error + * Fix EXDEV errors if you have multiple mount points + * Fix broken audio in transcoding with some videos + * Fix crash on getVideoFileStream issue + * Fix followers search + * Remove trailing `/` in CLI import script ([@HesioZ](https://github.com/HesioZ/)) + * Use origin video url in canonical tag + * Fix captions in HTTP fallback + * Automatically refresh remote actors to fix deleted remote actors that are still displayed on some instances + * Add missing translations in video embed page + * Fix some styling issues in dark mode + * Fix transcoding issues with some videos + * Fix Mac OS mkv/avi upload + * Fix menu overflow on mobile + * Fix ownership button icons ([@joshmorel](https://github.com/joshmorel)) + + ## v1.1.0 ***Since v1.0.1*** ### BREAKING CHANGES + * **Docker:** `PEERTUBE_TRUST_PROXY` env variable is now an array ([LecygneNoir](https://github.com/LecygneNoir)) ### Maintenance diff --git a/README.md b/README.md index 7b2460f1e..a9b4eb54a 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ You can also join the cheerful bunch that makes our community: * Chat: * IRC : **[#peertube on chat.freenode.net:6697](https://kiwiirc.com/client/irc.freenode.net/#peertube)** - * Matrix (bridged on the IRC channel) : **[#peertube:matrix.org](https://matrix.to/#/#peertube:matrix.org)** + * Matrix (bridged on IRC and [Discord](https://discord.gg/wj8DDUT)) : **[#peertube:matrix.org](https://matrix.to/#/#peertube:matrix.org)** * Forum: * Framacolibri: [https://framacolibri.org/c/peertube](https://framacolibri.org/c/peertube) diff --git a/client/package.json b/client/package.json index 5fe1f3d5f..3eea661f1 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "peertube-client", - "version": "1.1.0", + "version": "1.2.0", "private": true, "licence": "GPLv3", "author": { @@ -28,7 +28,8 @@ "resolutions": { "video.js": "^7", "webtorrent/create-torrent/junk": "^1", - "simple-get": "^2.8.1" + "simple-get": "^2.8.1", + "punycode": "^1.4.1" }, "jest": { "globals": { @@ -63,20 +64,20 @@ "setupTestFrameworkScriptFile": "/src/setupJest.ts" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.11.1", - "@angular/animations": "~7.1.1", - "@angular/cli": "~7.1.1", - "@angular/common": "~7.1.1", - "@angular/compiler": "~7.1.1", - "@angular/compiler-cli": "~7.1.1", - "@angular/core": "~7.1.1", - "@angular/forms": "~7.1.1", - "@angular/http": "~7.1.1", - "@angular/language-service": "~7.1.1", - "@angular/platform-browser": "~7.1.1", - "@angular/platform-browser-dynamic": "~7.1.1", - "@angular/router": "~7.1.1", - "@angular/service-worker": "~7.1.1", + "@angular-devkit/build-angular": "~0.13.1", + "@angular/animations": "~7.2.4", + "@angular/cli": "~7.3.1", + "@angular/common": "~7.2.4", + "@angular/compiler": "~7.2.4", + "@angular/compiler-cli": "~7.2.4", + "@angular/core": "~7.2.4", + "@angular/forms": "~7.2.4", + "@angular/http": "~7.2.4", + "@angular/language-service": "~7.2.4", + "@angular/platform-browser": "~7.2.4", + "@angular/platform-browser-dynamic": "~7.2.4", + "@angular/router": "~7.2.4", + "@angular/service-worker": "~7.2.4", "@angularclass/hmr": "^2.1.3", "@neos21/bootstrap3-glyphicons": "^1.0.1", "@ng-bootstrap/ng-bootstrap": "^4.0.0", @@ -85,7 +86,9 @@ "@ngx-loading-bar/router": "^3.0.0", "@ngx-meta/core": "^6.0.0-rc.1", "@ngx-translate/i18n-polyfill": "^1.0.0", + "@streamroot/videojs-hlsjs-plugin": "^1.0.7", "@types/core-js": "^2.5.0", + "@types/hls.js": "^0.12.0", "@types/jasmine": "^2.8.7", "@types/jasminewd2": "^2.0.3", "@types/jest": "^23.3.1", @@ -109,6 +112,7 @@ "extract-text-webpack-plugin": "4.0.0-beta.0", "file-loader": "^2.0.0", "focus-visible": "^4.1.5", + "hls.js": "^0.12.2", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "https-browserify": "^1.0.0", @@ -131,6 +135,7 @@ "ngx-qrcode2": "^0.0.9", "node-sass": "^4.9.3", "npm-font-source-sans-pro": "^1.0.2", + "p2p-media-loader-hlsjs": "^0.4.0", "path-browserify": "^1.0.0", "primeng": "^7.0.0", "process": "^0.11.10", @@ -152,9 +157,9 @@ "typescript": "3.1.6", "video.js": "^7", "videojs-contextmenu-ui": "^5.0.0", + "videojs-contrib-quality-levels": "^2.0.9", "videojs-dock": "^2.0.2", "videojs-hotkeys": "^0.2.21", - "webpack": "^4.17.1", "webpack-bundle-analyzer": "^3.0.2", "webpack-cli": "^3.0.8", "webtorrent": "https://github.com/webtorrent/webtorrent#e9b209c7970816fc29e0cc871157a4918d66001d", diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts index d3ee8a1e4..a1b30fa8c 100644 --- a/client/src/app/+about/about-instance/about-instance.component.ts +++ b/client/src/app/+about/about-instance/about-instance.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core' import { Notifier, ServerService } from '@app/core' -import { MarkdownService } from '@app/videos/shared' import { I18n } from '@ngx-translate/i18n-polyfill' import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' import { InstanceService } from '@app/shared/instance/instance.service' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-about-instance', diff --git a/client/src/app/+about/about-instance/contact-admin-modal.component.html b/client/src/app/+about/about-instance/contact-admin-modal.component.html index 2b3fb32f3..b2cbd0873 100644 --- a/client/src/app/+about/about-instance/contact-admin-modal.component.html +++ b/client/src/app/+about/about-instance/contact-admin-modal.component.html @@ -1,7 +1,7 @@ -
+
This comment can only be seen by you or the other moderators.
- Cancel + Cancel
- \ No newline at end of file + diff --git a/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.ts b/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.ts index bebcb4207..f915978ee 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.ts @@ -45,7 +45,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI }) } - hideModerationCommentModal () { + hide () { this.abuseToComment = undefined this.openedModal.close() this.form.reset() @@ -60,7 +60,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI this.notifier.success(this.i18n('Comment updated.')) this.commentUpdated.emit(moderationComment) - this.hideModerationCommentModal() + this.hide() }, err => this.notifier.error(err.message) diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index e862d5162..05b549de6 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html @@ -51,11 +51,11 @@
Reason: - {{ videoAbuse.reason }} +
Moderation comment: - {{ videoAbuse.moderationComment }} +
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts index f64234b74..00c871659 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts @@ -9,6 +9,7 @@ import { DropdownAction } from '../../../shared/buttons/action-dropdown.componen import { ConfirmService } from '../../../core/index' import { ModerationCommentModalComponent } from './moderation-comment-modal.component' import { Video } from '../../../shared/video/video.model' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-abuse-list', @@ -30,7 +31,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { private notifier: Notifier, private videoAbuseService: VideoAbuseService, private confirmService: ConfirmService, - private i18n: I18n + private i18n: I18n, + private markdownRenderer: MarkdownService ) { super() @@ -108,6 +110,10 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { } + toHtml (text: string) { + return this.markdownRenderer.textMarkdownToHTML(text) + } + protected loadData () { return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort) .subscribe( diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html index 7cef787d2..247f441c1 100644 --- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html +++ b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html @@ -7,6 +7,7 @@ Video name Sensitive + Unfederated Date @@ -26,7 +27,8 @@ - {{ videoBlacklist.video.nsfw }} + {{ booleanToText(videoBlacklist.video.nsfw) }} + {{ booleanToText(videoBlacklist.unfederated) }} {{ videoBlacklist.createdAt }} @@ -37,9 +39,9 @@ - + Blacklist reason: - {{ videoBlacklist.reason }} + diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts index a02e84f67..b27bbbfef 100644 --- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts +++ b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts @@ -7,6 +7,7 @@ import { VideoBlacklist } from '../../../../../../shared' import { I18n } from '@ngx-translate/i18n-polyfill' import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' import { Video } from '../../../shared/video/video.model' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-blacklist-list', @@ -26,6 +27,7 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { private notifier: Notifier, private confirmService: ConfirmService, private videoBlacklistService: VideoBlacklistService, + private markdownRenderer: MarkdownService, private i18n: I18n ) { super() @@ -46,6 +48,16 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { return Video.buildClientUrl(videoBlacklist.video.uuid) } + booleanToText (value: boolean) { + if (value === true) return this.i18n('yes') + + return this.i18n('no') + } + + toHtml (text: string) { + return this.markdownRenderer.textMarkdownToHTML(text) + } + async removeVideoFromBlacklist (entry: VideoBlacklist) { const confirmMessage = this.i18n( 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' diff --git a/client/src/app/+admin/users/user-edit/index.ts b/client/src/app/+admin/users/user-edit/index.ts index fd80a02e0..ec734ef92 100644 --- a/client/src/app/+admin/users/user-edit/index.ts +++ b/client/src/app/+admin/users/user-edit/index.ts @@ -1,2 +1,3 @@ export * from './user-create.component' export * from './user-update.component' +export * from './user-password.component' 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 56cf7d17d..c6566da24 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 @@ -81,3 +81,17 @@ + +
+ + +
+ + +
+ +
+ + +
+
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.scss b/client/src/app/+admin/users/user-edit/user-edit.component.scss index 6675f65cc..c1cc4ca45 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.component.scss +++ b/client/src/app/+admin/users/user-edit/user-edit.component.scss @@ -14,7 +14,7 @@ input:not([type=submit]) { @include peertube-select-container(340px); } -input[type=submit] { +input[type=submit], button { @include peertube-button; @include orange-button; @@ -25,3 +25,23 @@ input[type=submit] { margin-top: 5px; font-size: 11px; } + +.account-title { + @include in-content-small-title; + + margin-top: 55px; + margin-bottom: 30px; +} + +.danger-zone { + .reset-password-email { + margin-bottom: 30px; + padding-bottom: 30px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + + button { + display: block; + margin-top: 0; + } + } +} 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 0b3511e8e..649b35b0c 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/users/user-edit/user-edit.ts @@ -8,6 +8,7 @@ export abstract class UserEdit extends FormReactive { videoQuotaDailyOptions: { value: string, label: string }[] = [] roles = Object.keys(USER_ROLE_LABELS).map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) username: string + userId: number protected abstract serverService: ServerService protected abstract configService: ConfigService @@ -22,7 +23,9 @@ export abstract class UserEdit extends FormReactive { } computeQuotaWithTranscoding () { - const resolutions = this.serverService.getConfig().transcoding.enabledResolutions + const transcodingConfig = this.serverService.getConfig().transcoding + + const resolutions = transcodingConfig.enabledResolutions const higherResolution = VideoResolution.H_1080P let multiplier = 0 @@ -30,9 +33,15 @@ export abstract class UserEdit extends FormReactive { multiplier += resolution / higherResolution } + if (transcodingConfig.hls.enabled) multiplier *= 2 + return multiplier * parseInt(this.form.value['videoQuota'], 10) } + resetPassword () { + return + } + protected buildQuotaOptions () { // These are used by a HTML select, so convert key into strings this.videoQuotaOptions = this.configService diff --git a/client/src/app/+admin/users/user-edit/user-password.component.html b/client/src/app/+admin/users/user-edit/user-password.component.html new file mode 100644 index 000000000..a1e1f6216 --- /dev/null +++ b/client/src/app/+admin/users/user-edit/user-password.component.html @@ -0,0 +1,21 @@ +
+
+ +
+ +
+ +
+
+
+ {{ formErrors.password }} +
+
+ + +
diff --git a/client/src/app/+admin/users/user-edit/user-password.component.scss b/client/src/app/+admin/users/user-edit/user-password.component.scss new file mode 100644 index 000000000..217d585af --- /dev/null +++ b/client/src/app/+admin/users/user-edit/user-password.component.scss @@ -0,0 +1,22 @@ +@import '_variables'; +@import '_mixins'; + +input:not([type=submit]):not([type=checkbox]) { + @include peertube-input-text(340px); + + display: block; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; +} + +input[type=submit] { + @include peertube-button; + @include orange-button; + + margin-top: 10px; +} + +.input-group-append { + height: 30px; +} diff --git a/client/src/app/+admin/users/user-edit/user-password.component.ts b/client/src/app/+admin/users/user-edit/user-password.component.ts new file mode 100644 index 000000000..5b3040440 --- /dev/null +++ b/client/src/app/+admin/users/user-edit/user-password.component.ts @@ -0,0 +1,64 @@ +import { Component, Input, OnInit } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { UserService } from '@app/shared/users/user.service' +import { Notifier } from '../../../core' +import { User, UserUpdate } from '../../../../../../shared' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' +import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' +import { FormReactive } from '../../../shared' + +@Component({ + selector: 'my-user-password', + templateUrl: './user-password.component.html', + styleUrls: [ './user-password.component.scss' ] +}) +export class UserPasswordComponent extends FormReactive implements OnInit { + error: string + username: string + showPassword = false + + @Input() userId: number + + constructor ( + protected formValidatorService: FormValidatorService, + private userValidatorsService: UserValidatorsService, + private route: ActivatedRoute, + private router: Router, + private notifier: Notifier, + private userService: UserService, + private i18n: I18n + ) { + super() + } + + ngOnInit () { + this.buildForm({ + password: this.userValidatorsService.USER_PASSWORD + }) + } + + formValidated () { + this.error = undefined + + const userUpdate: UserUpdate = this.form.value + + this.userService.updateUser(this.userId, userUpdate).subscribe( + () => { + this.notifier.success( + this.i18n('Password changed for user {{username}}.', { username: this.username }) + ) + }, + + err => this.error = err.message + ) + } + + togglePasswordVisibility () { + this.showPassword = !this.showPassword + } + + getFormButtonTitle () { + return this.i18n('Update user password') + } +} 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 61e641823..94ef87b08 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 @@ -19,6 +19,7 @@ import { UserService } from '@app/shared' export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { error: string userId: number + userEmail: string username: string private paramsSub: Subscription @@ -89,9 +90,22 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { return this.i18n('Update user') } + resetPassword () { + this.userService.askResetPassword(this.userEmail).subscribe( + () => { + this.notifier.success( + this.i18n('An email asking for password reset has been sent to {{username}}.', { username: this.username }) + ) + }, + + err => this.error = err.message + ) + } + private onUserFetched (userJson: User) { this.userId = userJson.id this.username = userJson.username + this.userEmail = userJson.email this.form.patchValue({ email: userJson.email, diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index 556ab3c5d..69a4616a3 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html @@ -2,7 +2,7 @@
Users list
- + Create user
@@ -65,7 +65,9 @@ (banned) + {{ user.email }} + ? {{ user.email }} @@ -76,6 +78,7 @@
+ {{ user.videoQuotaUsed }} / {{ user.videoQuota }} {{ user.roleLabel }} {{ user.createdAt }} diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss index f235769f0..5274be01c 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/users/user-list/user-list.component.scss @@ -2,7 +2,7 @@ @import '_mixins'; .add-button { - @include create-button('../../../../assets/images/global/add.svg'); + @include create-button; } tr.banned { @@ -23,4 +23,4 @@ tr.banned { input { @include peertube-input-text(250px); } -} \ No newline at end of file +} diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.scss b/client/src/app/+my-account/my-account-history/my-account-history.component.scss index 82150cbe3..e7c6863f1 100644 --- a/client/src/app/+my-account/my-account-history/my-account-history.component.scss +++ b/client/src/app/+my-account/my-account-history/my-account-history.component.scss @@ -65,10 +65,10 @@ text-overflow: ellipsis; white-space: nowrap; font-size: 14px; - color: #585858; + color: $grey-foreground-color; &:hover { - color: #303030; + color: $grey-foreground-hover-color; } } } diff --git a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html index b98a1087e..d518b22ec 100644 --- a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html +++ b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html @@ -1,7 +1,13 @@
- Notification preferences + + + Notification preferences + - +
diff --git a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss index 86ac094c5..43d1f82ab 100644 --- a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss +++ b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss @@ -5,16 +5,18 @@ display: flex; justify-content: space-between; font-size: 15px; - margin-bottom: 10px; + margin-bottom: 20px; a { @include peertube-button-link; @include grey-button; + @include button-with-icon(18px, 3px, -1px); } button { @include peertube-button; @include grey-button; + @include button-with-icon(20px, 3px, -1px); } } diff --git a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html index fd7d7d23b..674a4e8a2 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html +++ b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.html @@ -1,7 +1,8 @@ @@ -45,7 +45,7 @@ @@ -53,4 +53,4 @@ - \ No newline at end of file + diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss index a735562f8..39d0cf2f7 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss @@ -23,14 +23,11 @@ .action-button-delete-selection { @include peertube-button; @include orange-button; - } - - .icon.icon-delete-white { - @include icon(21px); + @include button-with-icon(21px); - position: relative; - top: -2px; - background-image: url('../../../assets/images/global/delete-white.svg'); + my-global-icon { + @include apply-svg-color(#fff); + } } } } diff --git a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html index 7c0df850d..22f127904 100644 --- a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html +++ b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html @@ -1,7 +1,8 @@ + +
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 79ea32ced..eaa822e0f 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -3,12 +3,12 @@ import { catchError, map, mergeMap, share, tap } from 'rxjs/operators' import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { Router } from '@angular/router' -import { Notifier } from '@app/core/notification' +import { Notifier } from '@app/core/notification/notifier.service' import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared' import { User } from '../../../../../shared/models/users' import { UserLogin } from '../../../../../shared/models/users/user-login.model' import { environment } from '../../../environments/environment' -import { RestExtractor } from '../../shared/rest' +import { RestExtractor } from '../../shared/rest/rest-extractor.service' import { AuthStatus } from './auth-status.model' import { AuthUser } from './auth-user.model' import { objectToUrlEncoded } from '@app/shared/misc/utils' diff --git a/client/src/app/core/confirm/index.ts b/client/src/app/core/confirm/index.ts index 44aabfc13..aca591e1a 100644 --- a/client/src/app/core/confirm/index.ts +++ b/client/src/app/core/confirm/index.ts @@ -1,2 +1 @@ -export * from './confirm.component' export * from './confirm.service' diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 7c0d4ac8f..4ef3b1e73 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -8,7 +8,7 @@ import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' import { LoadingBarRouterModule } from '@ngx-loading-bar/router' import { AuthService } from './auth' -import { ConfirmComponent, ConfirmService } from './confirm' +import { ConfirmService } from './confirm' import { throwIfAlreadyLoaded } from './module-import-guard' import { LoginGuard, RedirectService, UserRightGuard } from './routing' import { ServerService } from './server' @@ -18,6 +18,7 @@ import { CheatSheetComponent } from './hotkeys' import { ToastModule } from 'primeng/toast' import { Notifier } from './notification' import { MessageService } from 'primeng/api' +import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' @NgModule({ imports: [ @@ -37,7 +38,6 @@ import { MessageService } from 'primeng/api' ], declarations: [ - ConfirmComponent, CheatSheetComponent ], @@ -47,7 +47,6 @@ import { MessageService } from 'primeng/api' ToastModule, - ConfirmComponent, CheatSheetComponent ], @@ -60,7 +59,8 @@ import { MessageService } from 'primeng/api' UserRightGuard, RedirectService, Notifier, - MessageService + MessageService, + UserNotificationSocket ] }) export class CoreModule { diff --git a/client/src/app/core/notification/index.ts b/client/src/app/core/notification/index.ts index 8b0cfde5f..3e8d9ea65 100644 --- a/client/src/app/core/notification/index.ts +++ b/client/src/app/core/notification/index.ts @@ -1 +1,2 @@ export * from './notifier.service' +export * from './user-notification-socket.service' diff --git a/client/src/app/core/notification/user-notification-socket.service.ts b/client/src/app/core/notification/user-notification-socket.service.ts new file mode 100644 index 000000000..f367d9ae4 --- /dev/null +++ b/client/src/app/core/notification/user-notification-socket.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core' +import { environment } from '../../../environments/environment' +import { UserNotification as UserNotificationServer } from '../../../../../shared' +import { Subject } from 'rxjs' +import * as io from 'socket.io-client' +import { AuthService } from '../auth' + +export type NotificationEvent = 'new' | 'read' | 'read-all' + +@Injectable() +export class UserNotificationSocket { + private notificationSubject = new Subject<{ type: NotificationEvent, notification?: UserNotificationServer }>() + + private socket: SocketIOClient.Socket + + constructor ( + private auth: AuthService + ) {} + + dispatch (type: NotificationEvent, notification?: UserNotificationServer) { + this.notificationSubject.next({ type, notification }) + } + + getMyNotificationsSocket () { + const socket = this.getSocket() + + socket.on('new-notification', (n: UserNotificationServer) => this.dispatch('new', n)) + + return this.notificationSubject.asObservable() + } + + private getSocket () { + if (this.socket) return this.socket + + this.socket = io(environment.apiUrl + '/user-notifications', { + query: { accessToken: this.auth.getAccessToken() } + }) + + return this.socket + } +} diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index f33e6f20c..c868ccdcc 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -51,7 +51,10 @@ export class ServerService { requiresEmailVerification: false }, transcoding: { - enabledResolutions: [] + enabledResolutions: [], + hls: { + enabled: false + } }, avatar: { file: { @@ -87,6 +90,11 @@ export class ServerService { enabled: false } } + }, + trending: { + videos: { + intervalDays: 0 + } } } private videoCategories: Array> = [] diff --git a/client/src/app/header/header.component.html b/client/src/app/header/header.component.html index c23e0c55d..46a87c79c 100644 --- a/client/src/app/header/header.component.html +++ b/client/src/app/header/header.component.html @@ -5,6 +5,6 @@ - + Upload diff --git a/client/src/app/header/header.component.scss b/client/src/app/header/header.component.scss index 2f9820665..cea415d9b 100644 --- a/client/src/app/header/header.component.scss +++ b/client/src/app/header/header.component.scss @@ -6,6 +6,7 @@ padding-left: 10px; margin-right: 15px; padding-right: 40px; // For the search icon + font-size: 14px; &::placeholder { color: var(--inputPlaceholderColor); @@ -40,6 +41,7 @@ .upload-button { @include peertube-button-link; @include orange-button; + @include button-with-icon(22px, 3px, -1px); margin-right: 25px; @@ -47,15 +49,6 @@ margin-right: 0; } - .icon.icon-upload { - @include icon(22px); - - background-image: url('../../assets/images/header/upload-white.svg'); - height: 24px; - vertical-align: middle; - margin-right: 6px; - } - @media screen and (max-width: 600px) { margin-right: 10px; padding: 0 10px; diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html index 9b8146624..4efe3fb22 100644 --- a/client/src/app/login/login.component.html +++ b/client/src/app/login/login.component.html @@ -55,7 +55,8 @@ - + See all your notifications diff --git a/client/src/app/menu/avatar-notification.component.scss b/client/src/app/menu/avatar-notification.component.scss index c86667469..e785db788 100644 --- a/client/src/app/menu/avatar-notification.component.scss +++ b/client/src/app/menu/avatar-notification.component.scss @@ -3,7 +3,7 @@ /deep/ { .popover-notifications.popover { - max-width: 400px; + max-width: none; .popover-body { padding: 0; @@ -11,6 +11,7 @@ font-family: $main-fonts; overflow-y: auto; max-height: 500px; + width: 400px; box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30); .notifications-header { @@ -40,7 +41,7 @@ justify-content: center; font-weight: $font-semibold; color: var(--mainForegroundColor); - height: 30px; + padding: 7px 0; } } } @@ -71,7 +72,7 @@ justify-content: center; background-color: var(--mainColor); - color: var(--mainBackgroundColor); + color: var(#fff); font-size: 10px; font-weight: $font-semibold; @@ -80,3 +81,11 @@ height: 15px; } } + +@media screen and (max-width: $mobile-view) { + /deep/ { + .popover-notifications.popover .popover-body { + width: 400px; + } + } +} diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts index 60e090726..f1af08096 100644 --- a/client/src/app/menu/avatar-notification.component.ts +++ b/client/src/app/menu/avatar-notification.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core' import { User } from '../shared/users/user.model' import { UserNotificationService } from '@app/shared/users/user-notification.service' import { Subscription } from 'rxjs' -import { Notifier } from '@app/core' +import { Notifier, UserNotificationSocket } from '@app/core' import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' import { NavigationEnd, Router } from '@angular/router' import { filter } from 'rxjs/operators' @@ -23,6 +23,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy { constructor ( private userNotificationService: UserNotificationService, + private userNotificationSocket: UserNotificationSocket, private notifier: Notifier, private router: Router ) {} @@ -53,7 +54,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy { } private subscribeToNotifications () { - this.notificationSub = this.userNotificationService.getMyNotificationsSocket() + this.notificationSub = this.userNotificationSocket.getMyNotificationsSocket() .subscribe(data => { if (data.type === 'new') return this.unreadNotifications++ if (data.type === 'read') return this.unreadNotifications-- diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html index c79609898..a62b33dda 100644 --- a/client/src/app/menu/language-chooser.component.html +++ b/client/src/app/menu/language-chooser.component.html @@ -1,7 +1,7 @@ diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index a4aaadc7f..f30b89413 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss @@ -16,7 +16,7 @@ menu { height: 100%; white-space: nowrap; text-overflow: ellipsis; - overflow: hidden; + overflow: auto; color: var(--menuForegroundColor); display: flex; flex-direction: column; @@ -243,7 +243,7 @@ menu { } } -@media screen and (max-width: 400px) { +@media screen and (max-width: $mobile-view) { .menu-wrapper { width: 100% !important; } diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html index 3a87ea1de..82a5f0f26 100644 --- a/client/src/app/search/search.component.html +++ b/client/src/app/search/search.component.html @@ -48,7 +48,7 @@
- +
{{ result.name }} diff --git a/client/src/app/search/search.component.scss b/client/src/app/search/search.component.scss index 3e074621b..6de13d276 100644 --- a/client/src/app/search/search.component.scss +++ b/client/src/app/search/search.component.scss @@ -87,10 +87,10 @@ text-overflow: ellipsis; white-space: nowrap; font-size: 14px; - color: #585858; + color: $grey-foreground-color; &:hover { - color: #303030; + color: $grey-foreground-hover-color; } } } diff --git a/client/src/app/search/search.component.ts b/client/src/app/search/search.component.ts index 474b72824..c4a4b1fde 100644 --- a/client/src/app/search/search.component.ts +++ b/client/src/app/search/search.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { AuthService, Notifier } from '@app/core' +import { AuthService, Notifier, ServerService } from '@app/core' import { forkJoin, Subscription } from 'rxjs' import { SearchService } from '@app/search/search.service' import { ComponentPagination } from '@app/shared/rest/component-pagination.model' @@ -41,7 +41,8 @@ export class SearchComponent implements OnInit, OnDestroy { private metaService: MetaService, private notifier: Notifier, private searchService: SearchService, - private authService: AuthService + private authService: AuthService, + private serverService: ServerService ) { } ngOnInit () { @@ -75,6 +76,10 @@ export class SearchComponent implements OnInit, OnDestroy { if (this.subActivatedRoute) this.subActivatedRoute.unsubscribe() } + isVideoBlur (video: Video) { + return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig()) + } + isVideoChannel (d: VideoChannel | Video): d is VideoChannel { return d instanceof VideoChannel } diff --git a/client/src/app/shared/actor/actor.model.ts b/client/src/app/shared/actor/actor.model.ts index 811afb449..adecec1fc 100644 --- a/client/src/app/shared/actor/actor.model.ts +++ b/client/src/app/shared/actor/actor.model.ts @@ -16,7 +16,7 @@ export abstract class Actor implements ActorServer { avatarUrl: string - static GET_ACTOR_AVATAR_URL (actor: { avatar: Avatar }) { + static GET_ACTOR_AVATAR_URL (actor: { avatar?: { path: string } }) { const absoluteAPIUrl = getAbsoluteAPIUrl() if (actor && actor.avatar) return absoluteAPIUrl + actor.avatar.path diff --git a/client/src/app/shared/buttons/action-dropdown.component.html b/client/src/app/shared/buttons/action-dropdown.component.html index 90651f217..114b1d71f 100644 --- a/client/src/app/shared/buttons/action-dropdown.component.html +++ b/client/src/app/shared/buttons/action-dropdown.component.html @@ -3,7 +3,7 @@ class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange' }" ngbDropdownToggle role="button" > - + {{ label }}
diff --git a/client/src/app/shared/buttons/action-dropdown.component.scss b/client/src/app/shared/buttons/action-dropdown.component.scss index a4fcceeee..985b2ca88 100644 --- a/client/src/app/shared/buttons/action-dropdown.component.scss +++ b/client/src/app/shared/buttons/action-dropdown.component.scss @@ -24,14 +24,11 @@ } &:hover, &:active, &:focus { - background-color: $grey-color; + background-color: $grey-background-color; } - .icon-action { - @include icon(21px); - - background-image: url('../../../assets/images/video/more.svg'); - top: -1px; + .more-icon { + width: 21px; } &.small { diff --git a/client/src/app/shared/buttons/button.component.html b/client/src/app/shared/buttons/button.component.html index 87a8daccf..b6df67102 100644 --- a/client/src/app/shared/buttons/button.component.html +++ b/client/src/app/shared/buttons/button.component.html @@ -1,4 +1,4 @@ - + {{ label }} diff --git a/client/src/app/shared/buttons/button.component.scss b/client/src/app/shared/buttons/button.component.scss index 168102f09..04199a2a9 100644 --- a/client/src/app/shared/buttons/button.component.scss +++ b/client/src/app/shared/buttons/button.component.scss @@ -3,41 +3,18 @@ .action-button { @include peertube-button-link; + @include button-with-icon(21px, 0, -2px); - font-size: 15px; font-weight: $font-semibold; - color: #585858; - background-color: #E5E5E5; + color: $grey-foreground-color; + background-color: $grey-background-color; &:hover { - background-color: #EFEFEF; + background-color: $grey-background-hover-color; } - .icon { - @include icon(21px); - - position: relative; - top: -2px; - - &.icon-edit { - background-image: url('../../../assets/images/global/edit-grey.svg'); - } - - &.icon-delete-grey { - background-image: url('../../../assets/images/global/delete-grey.svg'); - } - - &.icon-im-with-her { - background-image: url('../../../assets/images/global/im-with-her.svg'); - } - - &.icon-tick { - background-image: url('../../../assets/images/global/tick.svg'); - } - - &.icon-cross { - background-image: url('../../../assets/images/global/cross.svg'); - } + my-global-icon { + @include apply-svg-color($grey-foreground-color); } } diff --git a/client/src/app/shared/buttons/button.component.ts b/client/src/app/shared/buttons/button.component.ts index 1a1162f09..a91e9c7eb 100644 --- a/client/src/app/shared/buttons/button.component.ts +++ b/client/src/app/shared/buttons/button.component.ts @@ -1,4 +1,5 @@ import { Component, Input } from '@angular/core' +import { GlobalIconName } from '@app/shared/icons/global-icon.component' @Component({ selector: 'my-button', @@ -9,7 +10,7 @@ import { Component, Input } from '@angular/core' export class ButtonComponent { @Input() label = '' @Input() className: string = undefined - @Input() icon: string = undefined + @Input() icon: GlobalIconName = undefined @Input() title: string = undefined getTitle () { diff --git a/client/src/app/shared/buttons/delete-button.component.html b/client/src/app/shared/buttons/delete-button.component.html index 6c55d8104..4d12a84c0 100644 --- a/client/src/app/shared/buttons/delete-button.component.html +++ b/client/src/app/shared/buttons/delete-button.component.html @@ -1,5 +1,5 @@ - + {{ label }} Delete diff --git a/client/src/app/shared/buttons/edit-button.component.html b/client/src/app/shared/buttons/edit-button.component.html index cecb780f3..da3addbae 100644 --- a/client/src/app/shared/buttons/edit-button.component.html +++ b/client/src/app/shared/buttons/edit-button.component.html @@ -1,5 +1,5 @@ - + {{ label }} Edit diff --git a/client/src/app/core/confirm/confirm.component.html b/client/src/app/shared/confirm/confirm.component.html similarity index 87% rename from client/src/app/core/confirm/confirm.component.html rename to client/src/app/shared/confirm/confirm.component.html index 43f0c6190..65df1cd4d 100644 --- a/client/src/app/core/confirm/confirm.component.html +++ b/client/src/app/shared/confirm/confirm.component.html @@ -2,7 +2,8 @@