diff options
24 files changed, 92 insertions, 47 deletions
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 93378a533..298871fce 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -23,7 +23,7 @@ | |||
23 | <th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> | 23 | <th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> |
24 | <th style="width: 100px;" i18n pSortableColumn="score">Score <p-sortIcon field="score"></p-sortIcon></th> | 24 | <th style="width: 100px;" i18n pSortableColumn="score">Score <p-sortIcon field="score"></p-sortIcon></th> |
25 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | 25 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
26 | <th style="width: 100px;"></th> | 26 | <th style="width: 150px;"></th> |
27 | </tr> | 27 | </tr> |
28 | </ng-template> | 28 | </ng-template> |
29 | 29 | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html index 28d57f83c..c08154bcd 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html | |||
@@ -22,7 +22,7 @@ | |||
22 | <th style="width: 160px;" i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th> | 22 | <th style="width: 160px;" i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th> |
23 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th > | 23 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th > |
24 | <th style="width: 100px;" i18n *ngIf="isDisplayingRemoteVideos()">Total size</th> | 24 | <th style="width: 100px;" i18n *ngIf="isDisplayingRemoteVideos()">Total size</th> |
25 | <th style="width: 80px;"></th> | 25 | <th style="width: 150px;"></th> |
26 | </tr> | 26 | </tr> |
27 | </ng-template> | 27 | </ng-template> |
28 | 28 | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index a4ab2a58c..b7d40be60 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | <tr> | 21 | <tr> |
22 | <th style="width: 100%;" i18n>Account</th> | 22 | <th style="width: 100%;" i18n>Account</th> |
23 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 23 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
24 | <th style="width: 100px;"></th> <!-- column for action buttons --> | 24 | <th style="width: 150px;"></th> <!-- column for action buttons --> |
25 | </tr> | 25 | </tr> |
26 | </ng-template> | 26 | </ng-template> |
27 | 27 | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html index dab068dd6..589a11b7b 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html | |||
@@ -25,7 +25,7 @@ | |||
25 | <tr> | 25 | <tr> |
26 | <th style="width: 100%;" i18n>Instance</th> | 26 | <th style="width: 100%;" i18n>Instance</th> |
27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
28 | <th style="width: 100px;"></th> <!-- column for action buttons --> | 28 | <th style="width: 150px;"></th> <!-- column for action buttons --> |
29 | </tr> | 29 | </tr> |
30 | </ng-template> | 30 | </ng-template> |
31 | 31 | ||
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 1c9530152..d30475794 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 | |||
@@ -41,7 +41,7 @@ | |||
41 | <th i18n>Video</th> | 41 | <th i18n>Video</th> |
42 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | 42 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
43 | <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th> | 43 | <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th> |
44 | <th style="width: 120px;"></th> | 44 | <th style="width: 150px;"></th> |
45 | </tr> | 45 | </tr> |
46 | </ng-template> | 46 | </ng-template> |
47 | 47 | ||
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 c4c4e765a..cfa04514f 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 | |||
@@ -25,7 +25,7 @@ | |||
25 | <th style="width: 100px;" i18n>Sensitive</th> | 25 | <th style="width: 100px;" i18n>Sensitive</th> |
26 | <th style="width: 120px;" i18n>Unfederated</th> | 26 | <th style="width: 120px;" i18n>Unfederated</th> |
27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> | 27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> |
28 | <th style="width: 120px;"></th> | 28 | <th style="width: 150px;"></th> |
29 | </tr> | 29 | </tr> |
30 | </ng-template> | 30 | </ng-template> |
31 | 31 | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html index f39f66696..ce176d682 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html | |||
@@ -9,7 +9,7 @@ | |||
9 | <span class="email">{{ user.pendingEmail }}</span> is awaiting email verification | 9 | <span class="email">{{ user.pendingEmail }}</span> is awaiting email verification |
10 | </div> | 10 | </div> |
11 | 11 | ||
12 | <form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form"> | 12 | <form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form" *ngIf="user.pluginAuth === null"> |
13 | 13 | ||
14 | <div class="form-group"> | 14 | <div class="form-group"> |
15 | <label i18n for="new-email">New email</label> | 15 | <label i18n for="new-email">New email</label> |
@@ -23,6 +23,7 @@ | |||
23 | </div> | 23 | </div> |
24 | 24 | ||
25 | <div class="form-group"> | 25 | <div class="form-group"> |
26 | <label i18n for="new-email">Your current password</label> | ||
26 | <input | 27 | <input |
27 | type="password" id="password" i18n-placeholder placeholder="Your password" autocomplete="off" | 28 | type="password" id="password" i18n-placeholder placeholder="Your password" autocomplete="off" |
28 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" class="form-control" | 29 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" class="form-control" |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index f1c466545..b4e4d29f0 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html | |||
@@ -58,7 +58,7 @@ | |||
58 | </div> | 58 | </div> |
59 | </div> | 59 | </div> |
60 | 60 | ||
61 | <div class="form-row mt-5"> <!-- password grid --> | 61 | <div class="form-row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid --> |
62 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 62 | <div class="form-group col-12 col-lg-4 col-xl-3"> |
63 | <div i18n class="account-title">PASSWORD</div> | 63 | <div i18n class="account-title">PASSWORD</div> |
64 | </div> | 64 | </div> |
diff --git a/client/src/app/header/header.component.scss b/client/src/app/header/header.component.scss index 91b390773..1e4ce2c56 100644 --- a/client/src/app/header/header.component.scss +++ b/client/src/app/header/header.component.scss | |||
@@ -10,7 +10,6 @@ my-search-typeahead { | |||
10 | @include orange-button; | 10 | @include orange-button; |
11 | @include button-with-icon(22px, 3px, -1px); | 11 | @include button-with-icon(22px, 3px, -1px); |
12 | 12 | ||
13 | color: var(--mainBackgroundColor) !important; | ||
14 | margin-right: 25px; | 13 | margin-right: 25px; |
15 | 14 | ||
16 | @media screen and (max-width: 600px) { | 15 | @media screen and (max-width: 600px) { |
diff --git a/client/src/app/shared/forms/markdown-textarea.component.scss b/client/src/app/shared/forms/markdown-textarea.component.scss index 8e5739e45..16f319587 100644 --- a/client/src/app/shared/forms/markdown-textarea.component.scss +++ b/client/src/app/shared/forms/markdown-textarea.component.scss | |||
@@ -14,7 +14,8 @@ $input-border-radius: 3px; | |||
14 | textarea { | 14 | textarea { |
15 | @include peertube-textarea(100%, 150px); | 15 | @include peertube-textarea(100%, 150px); |
16 | 16 | ||
17 | background-color: var(--textareaBackgroundColor); | 17 | background-color: var(--markdownTextareaBackgroundColor); |
18 | |||
18 | font-family: monospace; | 19 | font-family: monospace; |
19 | font-size: 13px; | 20 | font-size: 13px; |
20 | border-bottom: none; | 21 | border-bottom: none; |
diff --git a/client/src/app/shared/misc/peertube-web-storage.ts b/client/src/app/shared/misc/peertube-web-storage.ts index fff209678..6a152dd98 100644 --- a/client/src/app/shared/misc/peertube-web-storage.ts +++ b/client/src/app/shared/misc/peertube-web-storage.ts | |||
@@ -47,26 +47,32 @@ try { | |||
47 | peertubeLocalStorage = localStorage | 47 | peertubeLocalStorage = localStorage |
48 | peertubeSessionStorage = sessionStorage | 48 | peertubeSessionStorage = sessionStorage |
49 | } catch (err) { | 49 | } catch (err) { |
50 | const instance = new MemoryStorage() | 50 | const instanceLocalStorage = new MemoryStorage() |
51 | const instanceSessionStorage = new MemoryStorage() | ||
51 | 52 | ||
52 | peertubeLocalStorage = sessionStorage = new Proxy(instance, { | 53 | function proxify (instance: MemoryStorage) { |
53 | set: function (obj, prop: string | number, value) { | 54 | return new Proxy(instance, { |
54 | if (MemoryStorage.prototype.hasOwnProperty(prop)) { | 55 | set: function (obj, prop: string | number, value) { |
55 | instance[prop] = value | 56 | if (MemoryStorage.prototype.hasOwnProperty(prop)) { |
56 | } else { | 57 | instance[prop] = value |
57 | instance.setItem(prop, value) | 58 | } else { |
59 | instance.setItem(prop, value) | ||
60 | } | ||
61 | return true | ||
62 | }, | ||
63 | get: function (target, name: string | number) { | ||
64 | if (MemoryStorage.prototype.hasOwnProperty(name)) { | ||
65 | return instance[name] | ||
66 | } | ||
67 | if (valuesMap.has(name)) { | ||
68 | return instance.getItem(name) | ||
69 | } | ||
58 | } | 70 | } |
59 | return true | 71 | }) |
60 | }, | 72 | } |
61 | get: function (target, name: string | number) { | 73 | |
62 | if (MemoryStorage.prototype.hasOwnProperty(name)) { | 74 | peertubeLocalStorage = proxify(instanceLocalStorage) |
63 | return instance[name] | 75 | peertubeSessionStorage = proxify(instanceSessionStorage) |
64 | } | ||
65 | if (valuesMap.has(name)) { | ||
66 | return instance.getItem(name) | ||
67 | } | ||
68 | } | ||
69 | }) | ||
70 | } | 76 | } |
71 | 77 | ||
72 | export { | 78 | export { |
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.html b/client/src/app/videos/+video-watch/comment/video-comments.component.html index a21042f09..affbd4793 100644 --- a/client/src/app/videos/+video-watch/comment/video-comments.component.html +++ b/client/src/app/videos/+video-watch/comment/video-comments.component.html | |||
@@ -12,10 +12,10 @@ | |||
12 | <my-feed [syndicationItems]="syndicationItems"></my-feed> | 12 | <my-feed [syndicationItems]="syndicationItems"></my-feed> |
13 | 13 | ||
14 | <div ngbDropdown class="d-inline-block ml-4"> | 14 | <div ngbDropdown class="d-inline-block ml-4"> |
15 | <button class="btn btn-sm btn-outline-secondary" id="dropdownSortComments" ngbDropdownToggle i18n> | 15 | <button class="btn btn-sm btn-outline-secondary" id="dropdown-sort-comments" ngbDropdownToggle i18n> |
16 | SORT BY | 16 | SORT BY |
17 | </button> | 17 | </button> |
18 | <div ngbDropdownMenu aria-labelledby="dropdownSortComments"> | 18 | <div ngbDropdownMenu aria-labelledby="dropdown-sort-comments"> |
19 | <button (click)="handleSortChange('-createdAt')" ngbDropdownItem i18n>Most recent first (default)</button> | 19 | <button (click)="handleSortChange('-createdAt')" ngbDropdownItem i18n>Most recent first (default)</button> |
20 | <button (click)="handleSortChange('-totalReplies')" ngbDropdownItem i18n>Most replies first</button> | 20 | <button (click)="handleSortChange('-totalReplies')" ngbDropdownItem i18n>Most replies first</button> |
21 | </div> | 21 | </div> |
@@ -72,7 +72,7 @@ | |||
72 | > | 72 | > |
73 | <div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2"> | 73 | <div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2"> |
74 | <span class="glyphicon glyphicon-menu-down"></span> | 74 | <span class="glyphicon glyphicon-menu-down"></span> |
75 | 75 | ||
76 | <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container> | 76 | <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container> |
77 | <ng-template #hasAuthorComments> | 77 | <ng-template #hasAuthorComments> |
78 | <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n> | 78 | <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n> |
@@ -83,7 +83,7 @@ | |||
83 | </ng-template> | 83 | </ng-template> |
84 | </ng-template> | 84 | </ng-template> |
85 | <ng-template i18n #noAuthorComments>View {{ comment.totalReplies }} replies</ng-template> | 85 | <ng-template i18n #noAuthorComments>View {{ comment.totalReplies }} replies</ng-template> |
86 | 86 | ||
87 | <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> | 87 | <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> |
88 | </div> | 88 | </div> |
89 | </my-video-comment> | 89 | </my-video-comment> |
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.scss b/client/src/app/videos/+video-watch/comment/video-comments.component.scss index 5ed1ac629..df42fae73 100644 --- a/client/src/app/videos/+video-watch/comment/video-comments.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comments.component.scss | |||
@@ -21,7 +21,7 @@ | |||
21 | .title-page { | 21 | .title-page { |
22 | margin-right: 0; | 22 | margin-right: 0; |
23 | } | 23 | } |
24 | 24 | ||
25 | my-feed { | 25 | my-feed { |
26 | display: inline-block; | 26 | display: inline-block; |
27 | margin-left: 5px; | 27 | margin-left: 5px; |
@@ -33,7 +33,7 @@ | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | #dropdownSortComments { | 36 | #dropdown-sort-comments { |
37 | font-weight: 600; | 37 | font-weight: 600; |
38 | text-transform: uppercase; | 38 | text-transform: uppercase; |
39 | border: none; | 39 | border: none; |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index d637c94d9..17ed5c8f8 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -35,10 +35,13 @@ body { | |||
35 | --menuForegroundColor: #{$menu-color}; | 35 | --menuForegroundColor: #{$menu-color}; |
36 | --submenuColor: #{$sub-menu-color}; | 36 | --submenuColor: #{$sub-menu-color}; |
37 | 37 | ||
38 | --inputForegroundColor: #{$input-foreground-color}; | ||
38 | --inputBackgroundColor: #{$input-background-color}; | 39 | --inputBackgroundColor: #{$input-background-color}; |
39 | --inputPlaceholderColor: #{$input-placeholder-color}; | 40 | --inputPlaceholderColor: #{$input-placeholder-color}; |
40 | 41 | ||
42 | --textareaForegroundColor: #{$textarea-foreground-color}; | ||
41 | --textareaBackgroundColor: #{$textarea-background-color}; | 43 | --textareaBackgroundColor: #{$textarea-background-color}; |
44 | --markdownTextareaBackgroundColor: #{$markdown-textarea-background-color}; | ||
42 | 45 | ||
43 | --actionButtonColor: #{$grey-foreground-color}; | 46 | --actionButtonColor: #{$grey-foreground-color}; |
44 | --supportButtonBackgroundColor: #{transparent}; | 47 | --supportButtonBackgroundColor: #{transparent}; |
diff --git a/client/src/sass/bootstrap.scss b/client/src/sass/bootstrap.scss index cb266cc68..7985472ed 100644 --- a/client/src/sass/bootstrap.scss +++ b/client/src/sass/bootstrap.scss | |||
@@ -37,6 +37,8 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
37 | } | 37 | } |
38 | 38 | ||
39 | .dropdown-menu { | 39 | .dropdown-menu { |
40 | z-index: z(dropdown) + 1 !important; | ||
41 | |||
40 | border-radius: 3px; | 42 | border-radius: 3px; |
41 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); | 43 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); |
42 | font-size: 15px; | 44 | font-size: 15px; |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index f157ded5e..99ca25f9c 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -90,7 +90,8 @@ | |||
90 | display: inline-block; | 90 | display: inline-block; |
91 | height: $button-height; | 91 | height: $button-height; |
92 | width: $width; | 92 | width: $width; |
93 | background: var(--inputBackgroundColor); | 93 | color: var(--inputForegroundColor); |
94 | background-color: var(--inputBackgroundColor); | ||
94 | border: 1px solid #C6C6C6; | 95 | border: 1px solid #C6C6C6; |
95 | border-radius: 3px; | 96 | border-radius: 3px; |
96 | padding-left: 15px; | 97 | padding-left: 15px; |
@@ -121,6 +122,8 @@ | |||
121 | @mixin peertube-textarea ($width, $height) { | 122 | @mixin peertube-textarea ($width, $height) { |
122 | @include peertube-input-text($width); | 123 | @include peertube-input-text($width); |
123 | 124 | ||
125 | color: var(--textareaForegroundColor); | ||
126 | background-color: var(--textareaBackgroundColor); | ||
124 | height: $height; | 127 | height: $height; |
125 | padding: 5px 15px; | 128 | padding: 5px 15px; |
126 | font-size: 15px; | 129 | font-size: 15px; |
@@ -280,6 +283,7 @@ | |||
280 | margin: 0; | 283 | margin: 0; |
281 | width: $width; | 284 | width: $width; |
282 | border-radius: 3px; | 285 | border-radius: 3px; |
286 | color: var(--inputForegroundColor); | ||
283 | background: var(--inputBackgroundColor); | 287 | background: var(--inputBackgroundColor); |
284 | position: relative; | 288 | position: relative; |
285 | font-size: 15px; | 289 | font-size: 15px; |
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index 46f1e99f7..cdac8ae6f 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -63,10 +63,13 @@ $video-thumbnail-ratio: $video-thumbnail-width / $video-thumbnail-height; | |||
63 | 63 | ||
64 | $theater-bottom-space: 115px; | 64 | $theater-bottom-space: 115px; |
65 | 65 | ||
66 | $input-foreground-color: $fg-color; | ||
66 | $input-background-color: $bg-color; | 67 | $input-background-color: $bg-color; |
67 | $input-placeholder-color: #898989; | 68 | $input-placeholder-color: #898989; |
68 | 69 | ||
69 | $textarea-background-color: $grey-background-hover-color; | 70 | $textarea-foreground-color: $fg-color; |
71 | $textarea-background-color: $bg-color; | ||
72 | $markdown-textarea-background-color: $grey-background-hover-color; | ||
70 | 73 | ||
71 | $sub-menu-margin-bottom: 30px; | 74 | $sub-menu-margin-bottom: 30px; |
72 | $sub-menu-margin-bottom-small-view: 10px; | 75 | $sub-menu-margin-bottom-small-view: 10px; |
@@ -92,10 +95,13 @@ $variables: ( | |||
92 | --menuForegroundColor: var(--menuForegroundColor), | 95 | --menuForegroundColor: var(--menuForegroundColor), |
93 | --submenuColor: var(--submenuColor), | 96 | --submenuColor: var(--submenuColor), |
94 | 97 | ||
98 | --inputForegroundColor: var(--inputForegroundColor), | ||
95 | --inputBackgroundColor: var(--inputBackgroundColor), | 99 | --inputBackgroundColor: var(--inputBackgroundColor), |
96 | --inputPlaceholderColor: var(--inputPlaceholderColor), | 100 | --inputPlaceholderColor: var(--inputPlaceholderColor), |
97 | 101 | ||
102 | --textareaForegroundColor: var(--textareaForegroundColor), | ||
98 | --textareaBackgroundColor: var(--textareaBackgroundColor), | 103 | --textareaBackgroundColor: var(--textareaBackgroundColor), |
104 | --markdownTextareaBackgroundColor: var(--markdownTextareaBackgroundColor), | ||
99 | 105 | ||
100 | --actionButtonColor: var(--actionButtonColor), | 106 | --actionButtonColor: var(--actionButtonColor), |
101 | --supportButtonColor: var(--supportButtonColor), | 107 | --supportButtonColor: var(--supportButtonColor), |
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss index d48f2dfc4..33483533e 100644 --- a/client/src/sass/primeng-custom.scss +++ b/client/src/sass/primeng-custom.scss | |||
@@ -140,13 +140,13 @@ p-table { | |||
140 | font-size: 11px !important; | 140 | font-size: 11px !important; |
141 | top: 0 !important; | 141 | top: 0 !important; |
142 | 142 | ||
143 | &.pi-sort-up { | 143 | &.pi-sort-amount-up-alt { |
144 | @extend .glyphicon-triangle-top; | 144 | @extend .glyphicon-triangle-top; |
145 | 145 | ||
146 | color: var(--mainForegroundColor) !important; | 146 | color: var(--mainForegroundColor) !important; |
147 | } | 147 | } |
148 | 148 | ||
149 | &.pi-sort-down { | 149 | &.pi-sort-amount-down { |
150 | @extend .glyphicon-triangle-bottom; | 150 | @extend .glyphicon-triangle-bottom; |
151 | 151 | ||
152 | color: var(--mainForegroundColor) !important; | 152 | color: var(--mainForegroundColor) !important; |
@@ -302,12 +302,12 @@ p-table { | |||
302 | @if $mobile-paginator { | 302 | @if $mobile-paginator { |
303 | p-paginator .ui-paginator-bottom { | 303 | p-paginator .ui-paginator-bottom { |
304 | display: block; | 304 | display: block; |
305 | 305 | ||
306 | .ui-paginator-current { | 306 | .ui-paginator-current { |
307 | position: relative; | 307 | position: relative; |
308 | display: block; | 308 | display: block; |
309 | } | 309 | } |
310 | 310 | ||
311 | a, .ui-paginator-pages { | 311 | a, .ui-paginator-pages { |
312 | vertical-align: middle; | 312 | vertical-align: middle; |
313 | } | 313 | } |
@@ -345,7 +345,7 @@ p-multiselect { | |||
345 | } | 345 | } |
346 | } | 346 | } |
347 | 347 | ||
348 | .pi.pi-chevron-down{ | 348 | .pi.pi-chevron-down { |
349 | margin-left: 0 !important; | 349 | margin-left: 0 !important; |
350 | 350 | ||
351 | &::after { | 351 | &::after { |
diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts index e5ea4636e..db546efb1 100644 --- a/server/lib/oauth-model.ts +++ b/server/lib/oauth-model.ts | |||
@@ -14,6 +14,7 @@ import { UserAdminFlag } from '@shared/models/users/user-flag.model' | |||
14 | import { createUserAccountAndChannelAndPlaylist } from './user' | 14 | import { createUserAccountAndChannelAndPlaylist } from './user' |
15 | import { UserRole } from '@shared/models/users/user-role' | 15 | import { UserRole } from '@shared/models/users/user-role' |
16 | import { PluginManager } from '@server/lib/plugins/plugin-manager' | 16 | import { PluginManager } from '@server/lib/plugins/plugin-manager' |
17 | import { ActorModel } from '@server/models/activitypub/actor' | ||
17 | 18 | ||
18 | type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date } | 19 | type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date } |
19 | 20 | ||
@@ -109,6 +110,9 @@ async function getUser (usernameOrEmail?: string, password?: string) { | |||
109 | let user = await UserModel.loadByEmail(obj.user.email) | 110 | let user = await UserModel.loadByEmail(obj.user.email) |
110 | if (!user) user = await createUserFromExternal(obj.pluginName, obj.user) | 111 | if (!user) user = await createUserFromExternal(obj.pluginName, obj.user) |
111 | 112 | ||
113 | // Cannot create a user | ||
114 | if (!user) throw new AccessDeniedError('Cannot create such user: an actor with that name already exists.') | ||
115 | |||
112 | // If the user does not belongs to a plugin, it was created before its installation | 116 | // If the user does not belongs to a plugin, it was created before its installation |
113 | // Then we just go through a regular login process | 117 | // Then we just go through a regular login process |
114 | if (user.pluginAuth !== null) { | 118 | if (user.pluginAuth !== null) { |
@@ -208,6 +212,10 @@ async function createUserFromExternal (pluginAuth: string, options: { | |||
208 | role: UserRole | 212 | role: UserRole |
209 | displayName: string | 213 | displayName: string |
210 | }) { | 214 | }) { |
215 | // Check an actor does not already exists with that name (removed user) | ||
216 | const actor = await ActorModel.loadLocalByName(options.username) | ||
217 | if (actor) return null | ||
218 | |||
211 | const userToCreate = new UserModel({ | 219 | const userToCreate = new UserModel({ |
212 | username: options.username, | 220 | username: options.username, |
213 | password: null, | 221 | password: null, |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 840b9fc74..3bdbcdf6a 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -234,14 +234,19 @@ const usersUpdateMeValidator = [ | |||
234 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 234 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
235 | logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) | 235 | logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) |
236 | 236 | ||
237 | const user = res.locals.oauth.token.User | ||
238 | |||
237 | if (req.body.password || req.body.email) { | 239 | if (req.body.password || req.body.email) { |
240 | if (user.pluginAuth !== null) { | ||
241 | return res.status(400) | ||
242 | .json({ error: 'You cannot update your email or password that is associated with an external auth system.' }) | ||
243 | } | ||
244 | |||
238 | if (!req.body.currentPassword) { | 245 | if (!req.body.currentPassword) { |
239 | return res.status(400) | 246 | return res.status(400) |
240 | .json({ error: 'currentPassword parameter is missing.' }) | 247 | .json({ error: 'currentPassword parameter is missing.' }) |
241 | .end() | ||
242 | } | 248 | } |
243 | 249 | ||
244 | const user = res.locals.oauth.token.User | ||
245 | if (await user.isPasswordMatch(req.body.currentPassword) !== true) { | 250 | if (await user.isPasswordMatch(req.body.currentPassword) !== true) { |
246 | return res.status(401) | 251 | return res.status(401) |
247 | .json({ error: 'currentPassword is invalid.' }) | 252 | .json({ error: 'currentPassword is invalid.' }) |
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 4d597f0a3..6e737af15 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -1044,7 +1044,7 @@ describe('Test users API validators', function () { | |||
1044 | } | 1044 | } |
1045 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getYoutubeVideoUrl() })) | 1045 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getYoutubeVideoUrl() })) |
1046 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() })) | 1046 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() })) |
1047 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' })) | 1047 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any })) |
1048 | 1048 | ||
1049 | await waitJobs([ server ]) | 1049 | await waitJobs([ server ]) |
1050 | 1050 | ||
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts index 4d5989f43..d211859e4 100644 --- a/server/tests/api/videos/video-imports.ts +++ b/server/tests/api/videos/video-imports.ts | |||
@@ -175,7 +175,7 @@ Ajouter un sous-titre est vraiment facile`) | |||
175 | 175 | ||
176 | { | 176 | { |
177 | const attributes = immutableAssign(baseAttributes, { | 177 | const attributes = immutableAssign(baseAttributes, { |
178 | torrentfile: 'video-720p.torrent', | 178 | torrentfile: 'video-720p.torrent' as any, |
179 | description: 'this is a super torrent description', | 179 | description: 'this is a super torrent description', |
180 | tags: [ 'tag_torrent1', 'tag_torrent2' ] | 180 | tags: [ 'tag_torrent1', 'tag_torrent2' ] |
181 | }) | 181 | }) |
diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts index a85672782..57361be05 100644 --- a/server/tests/plugins/external-auth.ts +++ b/server/tests/plugins/external-auth.ts | |||
@@ -255,6 +255,16 @@ describe('Test external auth plugins', function () { | |||
255 | expect(body.role).to.equal(UserRole.USER) | 255 | expect(body.role).to.equal(UserRole.USER) |
256 | }) | 256 | }) |
257 | 257 | ||
258 | it('Should not update an external auth email', async function () { | ||
259 | await updateMyUser({ | ||
260 | url: server.url, | ||
261 | accessToken: cyanAccessToken, | ||
262 | email: 'toto@example.com', | ||
263 | currentPassword: 'toto', | ||
264 | statusCodeExpected: 400 | ||
265 | }) | ||
266 | }) | ||
267 | |||
258 | it('Should reject token of Kefka by the plugin hook', async function () { | 268 | it('Should reject token of Kefka by the plugin hook', async function () { |
259 | this.timeout(10000) | 269 | this.timeout(10000) |
260 | 270 | ||
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts index 54b506bce..08b7743a6 100644 --- a/shared/extra-utils/users/users.ts +++ b/shared/extra-utils/users/users.ts | |||
@@ -216,7 +216,7 @@ function unblockUser (url: string, userId: number | string, accessToken: string, | |||
216 | .expect(expectedStatus) | 216 | .expect(expectedStatus) |
217 | } | 217 | } |
218 | 218 | ||
219 | function updateMyUser (options: { url: string, accessToken: string } & UserUpdateMe) { | 219 | function updateMyUser (options: { url: string, accessToken: string, statusCodeExpected?: number } & UserUpdateMe) { |
220 | const path = '/api/v1/users/me' | 220 | const path = '/api/v1/users/me' |
221 | 221 | ||
222 | const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') | 222 | const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') |
@@ -226,7 +226,7 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat | |||
226 | path, | 226 | path, |
227 | token: options.accessToken, | 227 | token: options.accessToken, |
228 | fields: toSend, | 228 | fields: toSend, |
229 | statusCodeExpected: 204 | 229 | statusCodeExpected: options.statusCodeExpected || 204 |
230 | }) | 230 | }) |
231 | } | 231 | } |
232 | 232 | ||