Merge branch 'release/2.2.0' into develop

pull/2780/head
Chocobozzz 2020-05-20 13:53:51 +02:00
commit 745437e3ab
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
24 changed files with 92 additions and 47 deletions

View File

@ -23,7 +23,7 @@
<th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
<th style="width: 100px;" i18n pSortableColumn="score">Score <p-sortIcon field="score"></p-sortIcon></th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 100px;"></th>
<th style="width: 150px;"></th>
</tr>
</ng-template>

View File

@ -22,7 +22,7 @@
<th style="width: 160px;" i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th>
<th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th >
<th style="width: 100px;" i18n *ngIf="isDisplayingRemoteVideos()">Total size</th>
<th style="width: 80px;"></th>
<th style="width: 150px;"></th>
</tr>
</ng-template>

View File

@ -21,7 +21,7 @@
<tr>
<th style="width: 100%;" i18n>Account</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 100px;"></th> <!-- column for action buttons -->
<th style="width: 150px;"></th> <!-- column for action buttons -->
</tr>
</ng-template>

View File

@ -25,7 +25,7 @@
<tr>
<th style="width: 100%;" i18n>Instance</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 100px;"></th> <!-- column for action buttons -->
<th style="width: 150px;"></th> <!-- column for action buttons -->
</tr>
</ng-template>

View File

@ -41,7 +41,7 @@
<th i18n>Video</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th>
<th style="width: 120px;"></th>
<th style="width: 150px;"></th>
</tr>
</ng-template>

View File

@ -25,7 +25,7 @@
<th style="width: 100px;" i18n>Sensitive</th>
<th style="width: 120px;" i18n>Unfederated</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 120px;"></th>
<th style="width: 150px;"></th>
</tr>
</ng-template>

View File

@ -9,7 +9,7 @@
<span class="email">{{ user.pendingEmail }}</span> is awaiting email verification
</div>
<form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form">
<form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form" *ngIf="user.pluginAuth === null">
<div class="form-group">
<label i18n for="new-email">New email</label>
@ -23,6 +23,7 @@
</div>
<div class="form-group">
<label i18n for="new-email">Your current password</label>
<input
type="password" id="password" i18n-placeholder placeholder="Your password" autocomplete="off"
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" class="form-control"

View File

@ -58,7 +58,7 @@
</div>
</div>
<div class="form-row mt-5"> <!-- password grid -->
<div class="form-row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid -->
<div class="form-group col-12 col-lg-4 col-xl-3">
<div i18n class="account-title">PASSWORD</div>
</div>

View File

@ -10,7 +10,6 @@ my-search-typeahead {
@include orange-button;
@include button-with-icon(22px, 3px, -1px);
color: var(--mainBackgroundColor) !important;
margin-right: 25px;
@media screen and (max-width: 600px) {

View File

@ -14,7 +14,8 @@ $input-border-radius: 3px;
textarea {
@include peertube-textarea(100%, 150px);
background-color: var(--textareaBackgroundColor);
background-color: var(--markdownTextareaBackgroundColor);
font-family: monospace;
font-size: 13px;
border-bottom: none;

View File

@ -47,26 +47,32 @@ try {
peertubeLocalStorage = localStorage
peertubeSessionStorage = sessionStorage
} catch (err) {
const instance = new MemoryStorage()
const instanceLocalStorage = new MemoryStorage()
const instanceSessionStorage = new MemoryStorage()
peertubeLocalStorage = sessionStorage = new Proxy(instance, {
set: function (obj, prop: string | number, value) {
if (MemoryStorage.prototype.hasOwnProperty(prop)) {
instance[prop] = value
} else {
instance.setItem(prop, value)
function proxify (instance: MemoryStorage) {
return new Proxy(instance, {
set: function (obj, prop: string | number, value) {
if (MemoryStorage.prototype.hasOwnProperty(prop)) {
instance[prop] = value
} else {
instance.setItem(prop, value)
}
return true
},
get: function (target, name: string | number) {
if (MemoryStorage.prototype.hasOwnProperty(name)) {
return instance[name]
}
if (valuesMap.has(name)) {
return instance.getItem(name)
}
}
return true
},
get: function (target, name: string | number) {
if (MemoryStorage.prototype.hasOwnProperty(name)) {
return instance[name]
}
if (valuesMap.has(name)) {
return instance.getItem(name)
}
}
})
})
}
peertubeLocalStorage = proxify(instanceLocalStorage)
peertubeSessionStorage = proxify(instanceSessionStorage)
}
export {

View File

@ -12,10 +12,10 @@
<my-feed [syndicationItems]="syndicationItems"></my-feed>
<div ngbDropdown class="d-inline-block ml-4">
<button class="btn btn-sm btn-outline-secondary" id="dropdownSortComments" ngbDropdownToggle i18n>
<button class="btn btn-sm btn-outline-secondary" id="dropdown-sort-comments" ngbDropdownToggle i18n>
SORT BY
</button>
<div ngbDropdownMenu aria-labelledby="dropdownSortComments">
<div ngbDropdownMenu aria-labelledby="dropdown-sort-comments">
<button (click)="handleSortChange('-createdAt')" ngbDropdownItem i18n>Most recent first (default)</button>
<button (click)="handleSortChange('-totalReplies')" ngbDropdownItem i18n>Most replies first</button>
</div>
@ -72,7 +72,7 @@
>
<div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2">
<span class="glyphicon glyphicon-menu-down"></span>
<ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container>
<ng-template #hasAuthorComments>
<ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n>
@ -83,7 +83,7 @@
</ng-template>
</ng-template>
<ng-template i18n #noAuthorComments>View {{ comment.totalReplies }} replies</ng-template>
<my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader>
</div>
</my-video-comment>

View File

@ -21,7 +21,7 @@
.title-page {
margin-right: 0;
}
my-feed {
display: inline-block;
margin-left: 5px;
@ -33,7 +33,7 @@
}
}
#dropdownSortComments {
#dropdown-sort-comments {
font-weight: 600;
text-transform: uppercase;
border: none;

View File

@ -35,10 +35,13 @@ body {
--menuForegroundColor: #{$menu-color};
--submenuColor: #{$sub-menu-color};
--inputForegroundColor: #{$input-foreground-color};
--inputBackgroundColor: #{$input-background-color};
--inputPlaceholderColor: #{$input-placeholder-color};
--textareaForegroundColor: #{$textarea-foreground-color};
--textareaBackgroundColor: #{$textarea-background-color};
--markdownTextareaBackgroundColor: #{$markdown-textarea-background-color};
--actionButtonColor: #{$grey-foreground-color};
--supportButtonBackgroundColor: #{transparent};

View File

@ -37,6 +37,8 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
}
.dropdown-menu {
z-index: z(dropdown) + 1 !important;
border-radius: 3px;
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);
font-size: 15px;

View File

@ -90,7 +90,8 @@
display: inline-block;
height: $button-height;
width: $width;
background: var(--inputBackgroundColor);
color: var(--inputForegroundColor);
background-color: var(--inputBackgroundColor);
border: 1px solid #C6C6C6;
border-radius: 3px;
padding-left: 15px;
@ -121,6 +122,8 @@
@mixin peertube-textarea ($width, $height) {
@include peertube-input-text($width);
color: var(--textareaForegroundColor);
background-color: var(--textareaBackgroundColor);
height: $height;
padding: 5px 15px;
font-size: 15px;
@ -280,6 +283,7 @@
margin: 0;
width: $width;
border-radius: 3px;
color: var(--inputForegroundColor);
background: var(--inputBackgroundColor);
position: relative;
font-size: 15px;

View File

@ -63,10 +63,13 @@ $video-thumbnail-ratio: $video-thumbnail-width / $video-thumbnail-height;
$theater-bottom-space: 115px;
$input-foreground-color: $fg-color;
$input-background-color: $bg-color;
$input-placeholder-color: #898989;
$textarea-background-color: $grey-background-hover-color;
$textarea-foreground-color: $fg-color;
$textarea-background-color: $bg-color;
$markdown-textarea-background-color: $grey-background-hover-color;
$sub-menu-margin-bottom: 30px;
$sub-menu-margin-bottom-small-view: 10px;
@ -92,10 +95,13 @@ $variables: (
--menuForegroundColor: var(--menuForegroundColor),
--submenuColor: var(--submenuColor),
--inputForegroundColor: var(--inputForegroundColor),
--inputBackgroundColor: var(--inputBackgroundColor),
--inputPlaceholderColor: var(--inputPlaceholderColor),
--textareaForegroundColor: var(--textareaForegroundColor),
--textareaBackgroundColor: var(--textareaBackgroundColor),
--markdownTextareaBackgroundColor: var(--markdownTextareaBackgroundColor),
--actionButtonColor: var(--actionButtonColor),
--supportButtonColor: var(--supportButtonColor),

View File

@ -140,13 +140,13 @@ p-table {
font-size: 11px !important;
top: 0 !important;
&.pi-sort-up {
&.pi-sort-amount-up-alt {
@extend .glyphicon-triangle-top;
color: var(--mainForegroundColor) !important;
}
&.pi-sort-down {
&.pi-sort-amount-down {
@extend .glyphicon-triangle-bottom;
color: var(--mainForegroundColor) !important;
@ -302,12 +302,12 @@ p-table {
@if $mobile-paginator {
p-paginator .ui-paginator-bottom {
display: block;
.ui-paginator-current {
position: relative;
display: block;
}
a, .ui-paginator-pages {
vertical-align: middle;
}
@ -345,7 +345,7 @@ p-multiselect {
}
}
.pi.pi-chevron-down{
.pi.pi-chevron-down {
margin-left: 0 !important;
&::after {

View File

@ -14,6 +14,7 @@ import { UserAdminFlag } from '@shared/models/users/user-flag.model'
import { createUserAccountAndChannelAndPlaylist } from './user'
import { UserRole } from '@shared/models/users/user-role'
import { PluginManager } from '@server/lib/plugins/plugin-manager'
import { ActorModel } from '@server/models/activitypub/actor'
type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date }
@ -109,6 +110,9 @@ async function getUser (usernameOrEmail?: string, password?: string) {
let user = await UserModel.loadByEmail(obj.user.email)
if (!user) user = await createUserFromExternal(obj.pluginName, obj.user)
// Cannot create a user
if (!user) throw new AccessDeniedError('Cannot create such user: an actor with that name already exists.')
// If the user does not belongs to a plugin, it was created before its installation
// Then we just go through a regular login process
if (user.pluginAuth !== null) {
@ -208,6 +212,10 @@ async function createUserFromExternal (pluginAuth: string, options: {
role: UserRole
displayName: string
}) {
// Check an actor does not already exists with that name (removed user)
const actor = await ActorModel.loadLocalByName(options.username)
if (actor) return null
const userToCreate = new UserModel({
username: options.username,
password: null,

View File

@ -234,14 +234,19 @@ const usersUpdateMeValidator = [
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') })
const user = res.locals.oauth.token.User
if (req.body.password || req.body.email) {
if (user.pluginAuth !== null) {
return res.status(400)
.json({ error: 'You cannot update your email or password that is associated with an external auth system.' })
}
if (!req.body.currentPassword) {
return res.status(400)
.json({ error: 'currentPassword parameter is missing.' })
.end()
}
const user = res.locals.oauth.token.User
if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
return res.status(401)
.json({ error: 'currentPassword is invalid.' })

View File

@ -1044,7 +1044,7 @@ describe('Test users API validators', function () {
}
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getYoutubeVideoUrl() }))
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' }))
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any }))
await waitJobs([ server ])

View File

@ -175,7 +175,7 @@ Ajouter un sous-titre est vraiment facile`)
{
const attributes = immutableAssign(baseAttributes, {
torrentfile: 'video-720p.torrent',
torrentfile: 'video-720p.torrent' as any,
description: 'this is a super torrent description',
tags: [ 'tag_torrent1', 'tag_torrent2' ]
})

View File

@ -255,6 +255,16 @@ describe('Test external auth plugins', function () {
expect(body.role).to.equal(UserRole.USER)
})
it('Should not update an external auth email', async function () {
await updateMyUser({
url: server.url,
accessToken: cyanAccessToken,
email: 'toto@example.com',
currentPassword: 'toto',
statusCodeExpected: 400
})
})
it('Should reject token of Kefka by the plugin hook', async function () {
this.timeout(10000)

View File

@ -216,7 +216,7 @@ function unblockUser (url: string, userId: number | string, accessToken: string,
.expect(expectedStatus)
}
function updateMyUser (options: { url: string, accessToken: string } & UserUpdateMe) {
function updateMyUser (options: { url: string, accessToken: string, statusCodeExpected?: number } & UserUpdateMe) {
const path = '/api/v1/users/me'
const toSend: UserUpdateMe = omit(options, 'url', 'accessToken')
@ -226,7 +226,7 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat
path,
token: options.accessToken,
fields: toSend,
statusCodeExpected: 204
statusCodeExpected: options.statusCodeExpected || 204
})
}