Finish admin design
This commit is contained in:
parent
e600e1fea2
commit
f595d39477
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
<div class="row">
|
||||
<div class="content-padding">
|
||||
|
||||
<h3>Video abuses list</h3>
|
||||
|
||||
<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">
|
||||
<ng-template pTemplate="body" let-videoAbuse="rowData">
|
||||
<a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoId }}</a>
|
||||
</ng-template>
|
||||
</p-column>
|
||||
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
||||
</p-dataTable>
|
||||
|
||||
</div>
|
||||
<div class="admin-sub-header">
|
||||
<div class="admin-sub-title">Video abuses list</div>
|
||||
</div>
|
||||
|
||||
<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="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.videoName }}</a>
|
||||
</ng-template>
|
||||
</p-column>
|
||||
</p-dataTable>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/deep/ a {
|
||||
|
||||
&, &:hover, &:active, &:focus {
|
||||
color: #000;
|
||||
}
|
||||
}
|
|
@ -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[] = []
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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...')
|
||||
this.logout()
|
||||
this.router.navigate(['/login'])
|
||||
.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)
|
||||
return Observable.throw({
|
||||
error: 'You need to reconnect.'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<textarea
|
||||
[(ngModel)]="description" (ngModelChange)="onModelChange()"
|
||||
id="description" placeholder="My super video">
|
||||
id="description" name="description">
|
||||
</textarea>
|
||||
|
||||
<tabset #staticTabs class="previews">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 ])
|
||||
|
||||
|
|
Loading…
Reference in New Issue