Finish admin design

This commit is contained in:
Chocobozzz 2017-12-08 17:31:21 +01:00
parent e600e1fea2
commit f595d39477
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
19 changed files with 163 additions and 114 deletions

View File

@ -6,7 +6,7 @@
<p-column field="following.host" header="Host"></p-column>
<p-column field="state" header="State"></p-column>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
<p-column header="Unfollow" styleClass="action-cell">
<p-column styleClass="action-cell">
<ng-template pTemplate="body" let-following="rowData">
<my-delete-button (click)="removeFollowing(following)"></my-delete-button>
</ng-template>

View File

@ -8,7 +8,7 @@
>
<p-column field="id" header="ID" [style]="{ width: '40px' }"></p-column>
<p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column>
<p-column field="handlerName" header="Handler name" [style]="{ width: '150px' }"></p-column>
<p-column field="handlerName" header="Handler name" [style]="{ width: '200px' }"></p-column>
<p-column header="Input data">
<ng-template pTemplate="body" let-job="rowData">
<pre>{{ job.handlerInputData }}</pre>

View File

@ -1,24 +1,19 @@
<div class="row">
<div class="content-padding">
<div class="admin-sub-header">
<div class="admin-sub-title">Video abuses list</div>
</div>
<h3>Video abuses list</h3>
<p-dataTable
<p-dataTable
[value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="id" (onLazyLoad)="loadLazy($event)"
>
>
<p-column field="id" header="ID" [sortable]="true"></p-column>
<p-column field="reason" header="Reason"></p-column>
<p-column field="reporterServerHost" header="Reporter server host"></p-column>
<p-column field="reporterUsername" header="Reporter username"></p-column>
<p-column field="videoName" header="Video name"></p-column>
<p-column header="Video" styleClass="action-cell">
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
<p-column header="Video">
<ng-template pTemplate="body" let-videoAbuse="rowData">
<a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoId }}</a>
<a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoName }}</a>
</ng-template>
</p-column>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
</p-dataTable>
</div>
</div>
</p-dataTable>

View File

@ -0,0 +1,6 @@
/deep/ a {
&, &:hover, &:active, &:focus {
color: #000;
}
}

View File

@ -8,7 +8,8 @@ import { VideoAbuse } from '../../../../../../shared'
@Component({
selector: 'my-video-abuse-list',
templateUrl: './video-abuse-list.component.html'
templateUrl: './video-abuse-list.component.html',
styleUrls: [ './video-abuse-list.component.scss']
})
export class VideoAbuseListComponent extends RestTable implements OnInit {
videoAbuses: VideoAbuse[] = []

View File

@ -18,7 +18,7 @@
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
<p-column header="Delete" styleClass="action-cell">
<ng-template pTemplate="body" let-entry="rowData">
<span (click)="removeVideoFromBlacklist(entry)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this video from blacklist"></span>
<my-delete-button (click)="removeVideoFromBlacklist(entry)"></my-delete-button>
</ng-template>
</p-column>
</p-dataTable>

View File

@ -169,19 +169,15 @@ export class AuthService {
return this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
.map(res => this.handleRefreshToken(res))
.catch(res => {
// The refresh token is invalid?
if (res.status === 400 && res.error.error === 'invalid_grant') {
console.error('Cannot refresh token -> logout...')
.catch(err => {
console.error(err)
console.log('Cannot refresh token -> logout...')
this.logout()
this.router.navigate(['/login'])
return Observable.throw({
error: 'You need to reconnect.'
})
}
return this.restExtractor.handleError(res)
})
}

View File

@ -62,7 +62,7 @@ export abstract class AbstractVideoList implements OnInit {
observable.subscribe(
({ videos, totalVideos }) => {
// Paging is too high, return to the first one
if (totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) {
if (this.pagination.currentPage > 1 && totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) {
this.pagination.currentPage = 1
this.setNewRouteParams()
return this.reloadVideos()
@ -82,6 +82,10 @@ export abstract class AbstractVideoList implements OnInit {
}
protected hasMoreVideos () {
// No results
if (this.pagination.totalItems === 0) return false
// Not loaded yet
if (!this.pagination.totalItems) return true
const maxPage = this.pagination.totalItems / this.pagination.itemsPerPage

View File

@ -1,6 +1,6 @@
<textarea
[(ngModel)]="description" (ngModelChange)="onModelChange()"
id="description" placeholder="My super video">
id="description" name="description">
</textarea>
<tabset #staticTabs class="previews">

View File

@ -4,4 +4,21 @@ textarea {
padding: 5px 15px;
font-size: 15px;
height: 150px;
margin-bottom: 15px;
}
/deep/ {
.nav-link {
display: flex !important;
align-items: center;
height: 30px !important;
padding: 0 15px !important;
}
.tab-content {
min-height: 75px;
padding: 15px;
font-size: 15px;
}
}

View File

@ -60,6 +60,8 @@ export class VideoDescriptionComponent implements ControlValueAccessor, OnInit {
}
private updateDescriptionPreviews () {
if (!this.description) return
this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 }))
this.descriptionHTML = this.markdownService.markdownToHTML(this.description)
}

View File

@ -165,7 +165,7 @@ p-datatable {
td {
border: 1px solid #E5E5E5 !important;
padding: 15px;
padding-left: 15px !important;
}
tr {
@ -185,6 +185,10 @@ p-datatable {
&:first-child td {
border-top: none !important;
}
&:last-child td {
border-bottom: none !important;
}
}
th {
@ -198,6 +202,7 @@ p-datatable {
&.ui-state-active, &.ui-sortable-column:hover {
background-color: #f0f0f0 !important;
border: 1px solid #f0f0f0 !important;
border-width: 0 1px !important;
}
}
@ -208,17 +213,10 @@ p-datatable {
}
p-paginator {
overflow: hidden;
display: block;
padding-top: 2px;
border: 1px solid #f0f0f0 !important;
border-top: none !important;
.ui-paginator-bottom {
position: relative;
border: none !important;
border-top: 1px solid #f0f0f0 !important;
box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.16);
border: 1px solid #f0f0f0 !important;
height: 40px;
display: flex;
justify-content: center;
@ -298,11 +296,6 @@ p-datatable {
font-weight: $font-semibold !important;
}
}
.tab-content {
min-height: 75px;
padding: 15px;
}
}

View File

@ -280,7 +280,7 @@ async function updateVideo (req: express.Request, res: express.Response) {
if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', videoInfoToUpdate.privacy)
if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10))
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
@ -298,9 +298,9 @@ async function updateVideo (req: express.Request, res: express.Response) {
}
// Video is not private anymore, send a create action to remote servers
if (wasPrivateVideo === true && videoInstance.privacy !== VideoPrivacy.PRIVATE) {
await sendAddVideo(videoInstance, t)
await shareVideoByServer(videoInstance, t)
if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) {
await sendAddVideo(videoInstanceUpdated, t)
await shareVideoByServer(videoInstanceUpdated, t)
}
})

View File

@ -49,14 +49,14 @@ function isVideoTorrentObjectValid (video: any) {
isActivityPubVideoDurationValid(video.duration) &&
isUUIDValid(video.uuid) &&
setValidRemoteTags(video) &&
isRemoteIdentifierValid(video.category) &&
isRemoteIdentifierValid(video.licence) &&
(!video.category || isRemoteIdentifierValid(video.category)) &&
(!video.licence || isRemoteIdentifierValid(video.licence)) &&
(!video.language || isRemoteIdentifierValid(video.language)) &&
isVideoViewsValid(video.views) &&
isVideoNSFWValid(video.nsfw) &&
isDateValid(video.published) &&
isDateValid(video.updated) &&
isRemoteVideoContentValid(video.mediaType, video.content) &&
(!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
isRemoteVideoIconValid(video.icon) &&
setValidRemoteVideoUrls(video) &&
video.url.length !== 0

View File

@ -9,16 +9,17 @@ import { VIDEO_PRIVACIES } from '../../initializers/constants'
import { database as db } from '../../initializers/database'
import { VideoInstance } from '../../models/video/video-interface'
import { exists, isArray } from './misc'
import isInt = require('validator/lib/isInt')
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
function isVideoCategoryValid (value: number) {
return VIDEO_CATEGORIES[value] !== undefined
return value === null || VIDEO_CATEGORIES[value] !== undefined
}
function isVideoLicenceValid (value: number) {
return VIDEO_LICENCES[value] !== undefined
return value === null || VIDEO_LICENCES[value] !== undefined
}
function isVideoLanguageValid (value: number) {
@ -38,7 +39,7 @@ function isVideoTruncatedDescriptionValid (value: string) {
}
function isVideoDescriptionValid (value: string) {
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
}
function isVideoNameValid (value: string) {
@ -84,7 +85,7 @@ function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } |
}
function isVideoPrivacyValid (value: string) {
return VIDEO_PRIVACIES[value] !== undefined
return validator.isInt(value + '') && VIDEO_PRIVACIES[value] !== undefined
}
function isVideoFileInfoHashValid (value: string) {

View File

@ -41,15 +41,30 @@ async function videoActivityObjectToDBAttributes (
language = parseInt(videoObject.language.identifier, 10)
}
let category = null
if (videoObject.category) {
category = parseInt(videoObject.category.identifier, 10)
}
let licence = null
if (videoObject.licence) {
licence = parseInt(videoObject.licence.identifier, 10)
}
let description = null
if (videoObject.content) {
description = videoObject.content
}
const videoData: VideoAttributes = {
name: videoObject.name,
uuid: videoObject.uuid,
url: videoObject.id,
category: parseInt(videoObject.category.identifier, 10),
licence: parseInt(videoObject.licence.identifier, 10),
category,
licence,
language,
description,
nsfw: videoObject.nsfw,
description: videoObject.content,
channelId: videoChannel.id,
duration: parseInt(duration, 10),
createdAt: new Date(videoObject.published),

View File

@ -564,6 +564,22 @@ toActivityPubObject = function (this: VideoInstance) {
}
}
let category
if (this.category) {
category = {
identifier: this.category + '',
name: this.getCategoryLabel()
}
}
let licence
if (this.licence) {
licence = {
identifier: this.licence + '',
name: this.getLicenceLabel()
}
}
let likesObject
let dislikesObject
@ -635,14 +651,8 @@ toActivityPubObject = function (this: VideoInstance) {
duration: 'PT' + this.duration + 'S',
uuid: this.uuid,
tag,
category: {
identifier: this.category + '',
name: this.getCategoryLabel()
},
licence: {
identifier: this.licence + '',
name: this.getLicenceLabel()
},
category,
licence,
language,
views: this.views,
nsfw: this.nsfw,

View File

@ -2,6 +2,8 @@
import 'mocha'
import * as chai from 'chai'
import { join } from "path"
import * as request from 'supertest'
import {
dateIsValid,
@ -707,6 +709,50 @@ describe('Test multiple servers', function () {
})
})
describe('With minimum parameters', function () {
it('Should upload and propagate the video', async function () {
this.timeout(50000)
const path = '/api/v1/videos/upload'
const req = request(servers[1].url)
.post(path)
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + servers[1].accessToken)
.field('name', 'minimum parameters')
.field('privacy', '1')
.field('nsfw', 'false')
.field('channelId', '1')
const filePath = join(__dirname, '..', 'api', 'fixtures', 'video_short.webm')
await req.attach('videofile', filePath)
.expect(200)
await wait(25000)
for (const server of servers) {
const res = await getVideosList(server.url)
const video = res.body.data.find(v => v.name === 'minimum parameters')
expect(video.name).to.equal('minimum parameters')
expect(video.category).to.equal(null)
expect(video.categoryLabel).to.equal('Misc')
expect(video.licence).to.equal(null)
expect(video.licenceLabel).to.equal('Unknown')
expect(video.language).to.equal(null)
expect(video.languageLabel).to.equal('Unknown')
expect(video.nsfw).to.not.be.ok
expect(video.description).to.equal(null)
expect(video.serverHost).to.equal('localhost:9002')
expect(video.accountName).to.equal('root')
expect(video.tags).to.deep.equal([ ])
expect(dateIsValid(video.createdAt)).to.be.true
expect(dateIsValid(video.updatedAt)).to.be.true
}
})
})
after(async function () {
killallServers(servers)

View File

@ -694,43 +694,6 @@ describe('Test a single server', function () {
expect(video.dislikes).to.equal(1)
})
it('Should upload a video with minimum parameters', async function () {
const path = '/api/v1/videos/upload'
const req = request(server.url)
.post(path)
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + server.accessToken)
.field('name', 'minimum parameters')
.field('privacy', '1')
.field('nsfw', 'false')
.field('channelId', '1')
const filePath = join(__dirname, '..', 'api', 'fixtures', 'video_short.webm')
await req.attach('videofile', filePath)
.expect(200)
const res = await getVideosList(server.url)
const video = res.body.data.find(v => v.name === 'minimum parameters')
expect(video.name).to.equal('minimum parameters')
expect(video.category).to.equal(null)
expect(video.categoryLabel).to.equal('Misc')
expect(video.licence).to.equal(null)
expect(video.licenceLabel).to.equal('Unknown')
expect(video.language).to.equal(null)
expect(video.languageLabel).to.equal('Unknown')
expect(video.nsfw).to.not.be.ok
expect(video.description).to.equal(null)
expect(video.serverHost).to.equal('localhost:9001')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ ])
expect(dateIsValid(video.createdAt)).to.be.true
expect(dateIsValid(video.updatedAt)).to.be.true
})
after(async function () {
killallServers([ server ])