aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-12-08 17:31:21 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-12-08 17:31:21 +0100
commitf595d3947708114deeed4312cc5ffd285745b090 (patch)
treee2fef8fae4e9d9ee6039ea2ab53eb20d11002969
parente600e1fea275c12f4420e23624804617e61a082c (diff)
downloadPeerTube-f595d3947708114deeed4312cc5ffd285745b090.tar.gz
PeerTube-f595d3947708114deeed4312cc5ffd285745b090.tar.zst
PeerTube-f595d3947708114deeed4312cc5ffd285745b090.zip
Finish admin design
-rw-r--r--client/src/app/+admin/follows/following-list/following-list.component.html2
-rw-r--r--client/src/app/+admin/jobs/jobs-list/jobs-list.component.html2
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html41
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss6
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts3
-rw-r--r--client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html2
-rw-r--r--client/src/app/core/auth/auth.service.ts22
-rw-r--r--client/src/app/shared/video/abstract-video-list.ts6
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.html2
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.scss17
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.ts2
-rw-r--r--client/src/sass/application.scss21
-rw-r--r--server/controllers/api/videos/index.ts8
-rw-r--r--server/helpers/custom-validators/activitypub/videos.ts6
-rw-r--r--server/helpers/custom-validators/videos.ts9
-rw-r--r--server/lib/activitypub/process/misc.ts21
-rw-r--r--server/models/video/video.ts26
-rw-r--r--server/tests/api/multiple-servers.ts46
-rw-r--r--server/tests/api/single-server.ts37
19 files changed, 164 insertions, 115 deletions
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html
index 3e70b418c..2b6cc9113 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.html
+++ b/client/src/app/+admin/follows/following-list/following-list.component.html
@@ -6,7 +6,7 @@
6 <p-column field="following.host" header="Host"></p-column> 6 <p-column field="following.host" header="Host"></p-column>
7 <p-column field="state" header="State"></p-column> 7 <p-column field="state" header="State"></p-column>
8 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> 8 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
9 <p-column header="Unfollow" styleClass="action-cell"> 9 <p-column styleClass="action-cell">
10 <ng-template pTemplate="body" let-following="rowData"> 10 <ng-template pTemplate="body" let-following="rowData">
11 <my-delete-button (click)="removeFollowing(following)"></my-delete-button> 11 <my-delete-button (click)="removeFollowing(following)"></my-delete-button>
12 </ng-template> 12 </ng-template>
diff --git a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html
index 29103c06b..7aa5f4254 100644
--- a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html
+++ b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html
@@ -8,7 +8,7 @@
8> 8>
9 <p-column field="id" header="ID" [style]="{ width: '40px' }"></p-column> 9 <p-column field="id" header="ID" [style]="{ width: '40px' }"></p-column>
10 <p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column> 10 <p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column>
11 <p-column field="handlerName" header="Handler name" [style]="{ width: '150px' }"></p-column> 11 <p-column field="handlerName" header="Handler name" [style]="{ width: '200px' }"></p-column>
12 <p-column header="Input data"> 12 <p-column header="Input data">
13 <ng-template pTemplate="body" let-job="rowData"> 13 <ng-template pTemplate="body" let-job="rowData">
14 <pre>{{ job.handlerInputData }}</pre> 14 <pre>{{ job.handlerInputData }}</pre>
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
index ab0a9d99f..d655a5e9b 100644
--- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
+++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
@@ -1,24 +1,19 @@
1<div class="row"> 1<div class="admin-sub-header">
2 <div class="content-padding"> 2 <div class="admin-sub-title">Video abuses list</div>
3
4 <h3>Video abuses list</h3>
5
6 <p-dataTable
7 [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
8 sortField="id" (onLazyLoad)="loadLazy($event)"
9 >
10 <p-column field="id" header="ID" [sortable]="true"></p-column>
11 <p-column field="reason" header="Reason"></p-column>
12 <p-column field="reporterServerHost" header="Reporter server host"></p-column>
13 <p-column field="reporterUsername" header="Reporter username"></p-column>
14 <p-column field="videoName" header="Video name"></p-column>
15 <p-column header="Video" styleClass="action-cell">
16 <ng-template pTemplate="body" let-videoAbuse="rowData">
17 <a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoId }}</a>
18 </ng-template>
19 </p-column>
20 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
21 </p-dataTable>
22
23 </div>
24</div> 3</div>
4
5<p-dataTable
6 [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
7 sortField="id" (onLazyLoad)="loadLazy($event)"
8>
9 <p-column field="id" header="ID" [sortable]="true"></p-column>
10 <p-column field="reason" header="Reason"></p-column>
11 <p-column field="reporterServerHost" header="Reporter server host"></p-column>
12 <p-column field="reporterUsername" header="Reporter username"></p-column>
13 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
14 <p-column header="Video">
15 <ng-template pTemplate="body" let-videoAbuse="rowData">
16 <a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoName }}</a>
17 </ng-template>
18 </p-column>
19</p-dataTable>
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss
new file mode 100644
index 000000000..6a4762650
--- /dev/null
+++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss
@@ -0,0 +1,6 @@
1/deep/ a {
2
3 &, &:hover, &:active, &:focus {
4 color: #000;
5 }
6}
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts
index 654603d01..b4d3bbd24 100644
--- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts
+++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts
@@ -8,7 +8,8 @@ import { VideoAbuse } from '../../../../../../shared'
8 8
9@Component({ 9@Component({
10 selector: 'my-video-abuse-list', 10 selector: 'my-video-abuse-list',
11 templateUrl: './video-abuse-list.component.html' 11 templateUrl: './video-abuse-list.component.html',
12 styleUrls: [ './video-abuse-list.component.scss']
12}) 13})
13export class VideoAbuseListComponent extends RestTable implements OnInit { 14export class VideoAbuseListComponent extends RestTable implements OnInit {
14 videoAbuses: VideoAbuse[] = [] 15 videoAbuses: VideoAbuse[] = []
diff --git a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html
index 05d116798..1d813fa07 100644
--- a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html
+++ b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html
@@ -18,7 +18,7 @@
18 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> 18 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
19 <p-column header="Delete" styleClass="action-cell"> 19 <p-column header="Delete" styleClass="action-cell">
20 <ng-template pTemplate="body" let-entry="rowData"> 20 <ng-template pTemplate="body" let-entry="rowData">
21 <span (click)="removeVideoFromBlacklist(entry)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this video from blacklist"></span> 21 <my-delete-button (click)="removeVideoFromBlacklist(entry)"></my-delete-button>
22 </ng-template> 22 </ng-template>
23 </p-column> 23 </p-column>
24 </p-dataTable> 24 </p-dataTable>
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 0db197f02..e887dde1f 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -169,19 +169,15 @@ export class AuthService {
169 169
170 return this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers }) 170 return this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
171 .map(res => this.handleRefreshToken(res)) 171 .map(res => this.handleRefreshToken(res))
172 .catch(res => { 172 .catch(err => {
173 // The refresh token is invalid? 173 console.error(err)
174 if (res.status === 400 && res.error.error === 'invalid_grant') { 174 console.log('Cannot refresh token -> logout...')
175 console.error('Cannot refresh token -> logout...') 175 this.logout()
176 this.logout() 176 this.router.navigate(['/login'])
177 this.router.navigate(['/login']) 177
178 178 return Observable.throw({
179 return Observable.throw({ 179 error: 'You need to reconnect.'
180 error: 'You need to reconnect.' 180 })
181 })
182 }
183
184 return this.restExtractor.handleError(res)
185 }) 181 })
186 } 182 }
187 183
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index ee1ed2cb2..ba1635a18 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -62,7 +62,7 @@ export abstract class AbstractVideoList implements OnInit {
62 observable.subscribe( 62 observable.subscribe(
63 ({ videos, totalVideos }) => { 63 ({ videos, totalVideos }) => {
64 // Paging is too high, return to the first one 64 // Paging is too high, return to the first one
65 if (totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) { 65 if (this.pagination.currentPage > 1 && totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) {
66 this.pagination.currentPage = 1 66 this.pagination.currentPage = 1
67 this.setNewRouteParams() 67 this.setNewRouteParams()
68 return this.reloadVideos() 68 return this.reloadVideos()
@@ -82,6 +82,10 @@ export abstract class AbstractVideoList implements OnInit {
82 } 82 }
83 83
84 protected hasMoreVideos () { 84 protected hasMoreVideos () {
85 // No results
86 if (this.pagination.totalItems === 0) return false
87
88 // Not loaded yet
85 if (!this.pagination.totalItems) return true 89 if (!this.pagination.totalItems) return true
86 90
87 const maxPage = this.pagination.totalItems / this.pagination.itemsPerPage 91 const maxPage = this.pagination.totalItems / this.pagination.itemsPerPage
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.html b/client/src/app/videos/+video-edit/shared/video-description.component.html
index da66a9753..5d05467be 100644
--- a/client/src/app/videos/+video-edit/shared/video-description.component.html
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.html
@@ -1,6 +1,6 @@
1<textarea 1<textarea
2 [(ngModel)]="description" (ngModelChange)="onModelChange()" 2 [(ngModel)]="description" (ngModelChange)="onModelChange()"
3 id="description" placeholder="My super video"> 3 id="description" name="description">
4</textarea> 4</textarea>
5 5
6<tabset #staticTabs class="previews"> 6<tabset #staticTabs class="previews">
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.scss b/client/src/app/videos/+video-edit/shared/video-description.component.scss
index 8155cbca7..2a4c8d189 100644
--- a/client/src/app/videos/+video-edit/shared/video-description.component.scss
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.scss
@@ -4,4 +4,21 @@ textarea {
4 padding: 5px 15px; 4 padding: 5px 15px;
5 font-size: 15px; 5 font-size: 15px;
6 height: 150px; 6 height: 150px;
7 margin-bottom: 15px;
7} 8}
9
10/deep/ {
11 .nav-link {
12 display: flex !important;
13 align-items: center;
14 height: 30px !important;
15 padding: 0 15px !important;
16 }
17
18 .tab-content {
19 min-height: 75px;
20 padding: 15px;
21 font-size: 15px;
22 }
23}
24
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.ts b/client/src/app/videos/+video-edit/shared/video-description.component.ts
index 8dfb74b2a..9b77a27e6 100644
--- a/client/src/app/videos/+video-edit/shared/video-description.component.ts
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.ts
@@ -60,6 +60,8 @@ export class VideoDescriptionComponent implements ControlValueAccessor, OnInit {
60 } 60 }
61 61
62 private updateDescriptionPreviews () { 62 private updateDescriptionPreviews () {
63 if (!this.description) return
64
63 this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 })) 65 this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 }))
64 this.descriptionHTML = this.markdownService.markdownToHTML(this.description) 66 this.descriptionHTML = this.markdownService.markdownToHTML(this.description)
65 } 67 }
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index ecbb8dac5..5a4aa4cd9 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -165,7 +165,7 @@ p-datatable {
165 165
166 td { 166 td {
167 border: 1px solid #E5E5E5 !important; 167 border: 1px solid #E5E5E5 !important;
168 padding: 15px; 168 padding-left: 15px !important;
169 } 169 }
170 170
171 tr { 171 tr {
@@ -185,6 +185,10 @@ p-datatable {
185 &:first-child td { 185 &:first-child td {
186 border-top: none !important; 186 border-top: none !important;
187 } 187 }
188
189 &:last-child td {
190 border-bottom: none !important;
191 }
188 } 192 }
189 193
190 th { 194 th {
@@ -198,6 +202,7 @@ p-datatable {
198 &.ui-state-active, &.ui-sortable-column:hover { 202 &.ui-state-active, &.ui-sortable-column:hover {
199 background-color: #f0f0f0 !important; 203 background-color: #f0f0f0 !important;
200 border: 1px solid #f0f0f0 !important; 204 border: 1px solid #f0f0f0 !important;
205 border-width: 0 1px !important;
201 } 206 }
202 } 207 }
203 208
@@ -208,17 +213,10 @@ p-datatable {
208 } 213 }
209 214
210 p-paginator { 215 p-paginator {
211 overflow: hidden;
212 display: block;
213 padding-top: 2px;
214 border: 1px solid #f0f0f0 !important;
215 border-top: none !important;
216
217 .ui-paginator-bottom { 216 .ui-paginator-bottom {
218 position: relative; 217 position: relative;
219 border: none !important; 218 border: none !important;
220 border-top: 1px solid #f0f0f0 !important; 219 border: 1px solid #f0f0f0 !important;
221 box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.16);
222 height: 40px; 220 height: 40px;
223 display: flex; 221 display: flex;
224 justify-content: center; 222 justify-content: center;
@@ -298,11 +296,6 @@ p-datatable {
298 font-weight: $font-semibold !important; 296 font-weight: $font-semibold !important;
299 } 297 }
300 } 298 }
301
302 .tab-content {
303 min-height: 75px;
304 padding: 15px;
305 }
306} 299}
307 300
308 301
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 0f71a7f7f..63de662a7 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -280,7 +280,7 @@ async function updateVideo (req: express.Request, res: express.Response) {
280 if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence) 280 if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
281 if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language) 281 if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
282 if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw) 282 if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
283 if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', videoInfoToUpdate.privacy) 283 if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10))
284 if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description) 284 if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
285 285
286 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) 286 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
@@ -298,9 +298,9 @@ async function updateVideo (req: express.Request, res: express.Response) {
298 } 298 }
299 299
300 // Video is not private anymore, send a create action to remote servers 300 // Video is not private anymore, send a create action to remote servers
301 if (wasPrivateVideo === true && videoInstance.privacy !== VideoPrivacy.PRIVATE) { 301 if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) {
302 await sendAddVideo(videoInstance, t) 302 await sendAddVideo(videoInstanceUpdated, t)
303 await shareVideoByServer(videoInstance, t) 303 await shareVideoByServer(videoInstanceUpdated, t)
304 } 304 }
305 }) 305 })
306 306
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts
index 12c672fd2..2ed2988f5 100644
--- a/server/helpers/custom-validators/activitypub/videos.ts
+++ b/server/helpers/custom-validators/activitypub/videos.ts
@@ -49,14 +49,14 @@ function isVideoTorrentObjectValid (video: any) {
49 isActivityPubVideoDurationValid(video.duration) && 49 isActivityPubVideoDurationValid(video.duration) &&
50 isUUIDValid(video.uuid) && 50 isUUIDValid(video.uuid) &&
51 setValidRemoteTags(video) && 51 setValidRemoteTags(video) &&
52 isRemoteIdentifierValid(video.category) && 52 (!video.category || isRemoteIdentifierValid(video.category)) &&
53 isRemoteIdentifierValid(video.licence) && 53 (!video.licence || isRemoteIdentifierValid(video.licence)) &&
54 (!video.language || isRemoteIdentifierValid(video.language)) && 54 (!video.language || isRemoteIdentifierValid(video.language)) &&
55 isVideoViewsValid(video.views) && 55 isVideoViewsValid(video.views) &&
56 isVideoNSFWValid(video.nsfw) && 56 isVideoNSFWValid(video.nsfw) &&
57 isDateValid(video.published) && 57 isDateValid(video.published) &&
58 isDateValid(video.updated) && 58 isDateValid(video.updated) &&
59 isRemoteVideoContentValid(video.mediaType, video.content) && 59 (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) &&
60 isRemoteVideoIconValid(video.icon) && 60 isRemoteVideoIconValid(video.icon) &&
61 setValidRemoteVideoUrls(video) && 61 setValidRemoteVideoUrls(video) &&
62 video.url.length !== 0 62 video.url.length !== 0
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts
index f13178c54..4fc460699 100644
--- a/server/helpers/custom-validators/videos.ts
+++ b/server/helpers/custom-validators/videos.ts
@@ -9,16 +9,17 @@ import { VIDEO_PRIVACIES } from '../../initializers/constants'
9import { database as db } from '../../initializers/database' 9import { database as db } from '../../initializers/database'
10import { VideoInstance } from '../../models/video/video-interface' 10import { VideoInstance } from '../../models/video/video-interface'
11import { exists, isArray } from './misc' 11import { exists, isArray } from './misc'
12import isInt = require('validator/lib/isInt')
12 13
13const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS 14const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
14const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES 15const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
15 16
16function isVideoCategoryValid (value: number) { 17function isVideoCategoryValid (value: number) {
17 return VIDEO_CATEGORIES[value] !== undefined 18 return value === null || VIDEO_CATEGORIES[value] !== undefined
18} 19}
19 20
20function isVideoLicenceValid (value: number) { 21function isVideoLicenceValid (value: number) {
21 return VIDEO_LICENCES[value] !== undefined 22 return value === null || VIDEO_LICENCES[value] !== undefined
22} 23}
23 24
24function isVideoLanguageValid (value: number) { 25function isVideoLanguageValid (value: number) {
@@ -38,7 +39,7 @@ function isVideoTruncatedDescriptionValid (value: string) {
38} 39}
39 40
40function isVideoDescriptionValid (value: string) { 41function isVideoDescriptionValid (value: string) {
41 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION) 42 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
42} 43}
43 44
44function isVideoNameValid (value: string) { 45function isVideoNameValid (value: string) {
@@ -84,7 +85,7 @@ function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } |
84} 85}
85 86
86function isVideoPrivacyValid (value: string) { 87function isVideoPrivacyValid (value: string) {
87 return VIDEO_PRIVACIES[value] !== undefined 88 return validator.isInt(value + '') && VIDEO_PRIVACIES[value] !== undefined
88} 89}
89 90
90function isVideoFileInfoHashValid (value: string) { 91function isVideoFileInfoHashValid (value: string) {
diff --git a/server/lib/activitypub/process/misc.ts b/server/lib/activitypub/process/misc.ts
index f20e588ab..0baa22c26 100644
--- a/server/lib/activitypub/process/misc.ts
+++ b/server/lib/activitypub/process/misc.ts
@@ -41,15 +41,30 @@ async function videoActivityObjectToDBAttributes (
41 language = parseInt(videoObject.language.identifier, 10) 41 language = parseInt(videoObject.language.identifier, 10)
42 } 42 }
43 43
44 let category = null
45 if (videoObject.category) {
46 category = parseInt(videoObject.category.identifier, 10)
47 }
48
49 let licence = null
50 if (videoObject.licence) {
51 licence = parseInt(videoObject.licence.identifier, 10)
52 }
53
54 let description = null
55 if (videoObject.content) {
56 description = videoObject.content
57 }
58
44 const videoData: VideoAttributes = { 59 const videoData: VideoAttributes = {
45 name: videoObject.name, 60 name: videoObject.name,
46 uuid: videoObject.uuid, 61 uuid: videoObject.uuid,
47 url: videoObject.id, 62 url: videoObject.id,
48 category: parseInt(videoObject.category.identifier, 10), 63 category,
49 licence: parseInt(videoObject.licence.identifier, 10), 64 licence,
50 language, 65 language,
66 description,
51 nsfw: videoObject.nsfw, 67 nsfw: videoObject.nsfw,
52 description: videoObject.content,
53 channelId: videoChannel.id, 68 channelId: videoChannel.id,
54 duration: parseInt(duration, 10), 69 duration: parseInt(duration, 10),
55 createdAt: new Date(videoObject.published), 70 createdAt: new Date(videoObject.published),
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 8b1eb1f96..d46fdeebe 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -564,6 +564,22 @@ toActivityPubObject = function (this: VideoInstance) {
564 } 564 }
565 } 565 }
566 566
567 let category
568 if (this.category) {
569 category = {
570 identifier: this.category + '',
571 name: this.getCategoryLabel()
572 }
573 }
574
575 let licence
576 if (this.licence) {
577 licence = {
578 identifier: this.licence + '',
579 name: this.getLicenceLabel()
580 }
581 }
582
567 let likesObject 583 let likesObject
568 let dislikesObject 584 let dislikesObject
569 585
@@ -635,14 +651,8 @@ toActivityPubObject = function (this: VideoInstance) {
635 duration: 'PT' + this.duration + 'S', 651 duration: 'PT' + this.duration + 'S',
636 uuid: this.uuid, 652 uuid: this.uuid,
637 tag, 653 tag,
638 category: { 654 category,
639 identifier: this.category + '', 655 licence,
640 name: this.getCategoryLabel()
641 },
642 licence: {
643 identifier: this.licence + '',
644 name: this.getLicenceLabel()
645 },
646 language, 656 language,
647 views: this.views, 657 views: this.views,
648 nsfw: this.nsfw, 658 nsfw: this.nsfw,
diff --git a/server/tests/api/multiple-servers.ts b/server/tests/api/multiple-servers.ts
index c7f19f261..c9f74cc8c 100644
--- a/server/tests/api/multiple-servers.ts
+++ b/server/tests/api/multiple-servers.ts
@@ -2,6 +2,8 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { join } from "path"
6import * as request from 'supertest'
5 7
6import { 8import {
7 dateIsValid, 9 dateIsValid,
@@ -707,6 +709,50 @@ describe('Test multiple servers', function () {
707 }) 709 })
708 }) 710 })
709 711
712 describe('With minimum parameters', function () {
713 it('Should upload and propagate the video', async function () {
714 this.timeout(50000)
715
716 const path = '/api/v1/videos/upload'
717
718 const req = request(servers[1].url)
719 .post(path)
720 .set('Accept', 'application/json')
721 .set('Authorization', 'Bearer ' + servers[1].accessToken)
722 .field('name', 'minimum parameters')
723 .field('privacy', '1')
724 .field('nsfw', 'false')
725 .field('channelId', '1')
726
727 const filePath = join(__dirname, '..', 'api', 'fixtures', 'video_short.webm')
728
729 await req.attach('videofile', filePath)
730 .expect(200)
731
732 await wait(25000)
733
734 for (const server of servers) {
735 const res = await getVideosList(server.url)
736 const video = res.body.data.find(v => v.name === 'minimum parameters')
737
738 expect(video.name).to.equal('minimum parameters')
739 expect(video.category).to.equal(null)
740 expect(video.categoryLabel).to.equal('Misc')
741 expect(video.licence).to.equal(null)
742 expect(video.licenceLabel).to.equal('Unknown')
743 expect(video.language).to.equal(null)
744 expect(video.languageLabel).to.equal('Unknown')
745 expect(video.nsfw).to.not.be.ok
746 expect(video.description).to.equal(null)
747 expect(video.serverHost).to.equal('localhost:9002')
748 expect(video.accountName).to.equal('root')
749 expect(video.tags).to.deep.equal([ ])
750 expect(dateIsValid(video.createdAt)).to.be.true
751 expect(dateIsValid(video.updatedAt)).to.be.true
752 }
753 })
754 })
755
710 after(async function () { 756 after(async function () {
711 killallServers(servers) 757 killallServers(servers)
712 758
diff --git a/server/tests/api/single-server.ts b/server/tests/api/single-server.ts
index e99955ef4..91460c7ae 100644
--- a/server/tests/api/single-server.ts
+++ b/server/tests/api/single-server.ts
@@ -694,43 +694,6 @@ describe('Test a single server', function () {
694 expect(video.dislikes).to.equal(1) 694 expect(video.dislikes).to.equal(1)
695 }) 695 })
696 696
697 it('Should upload a video with minimum parameters', async function () {
698 const path = '/api/v1/videos/upload'
699
700 const req = request(server.url)
701 .post(path)
702 .set('Accept', 'application/json')
703 .set('Authorization', 'Bearer ' + server.accessToken)
704 .field('name', 'minimum parameters')
705 .field('privacy', '1')
706 .field('nsfw', 'false')
707 .field('channelId', '1')
708
709 const filePath = join(__dirname, '..', 'api', 'fixtures', 'video_short.webm')
710
711 await req.attach('videofile', filePath)
712 .expect(200)
713
714 const res = await getVideosList(server.url)
715 const video = res.body.data.find(v => v.name === 'minimum parameters')
716
717 expect(video.name).to.equal('minimum parameters')
718 expect(video.category).to.equal(null)
719 expect(video.categoryLabel).to.equal('Misc')
720 expect(video.licence).to.equal(null)
721 expect(video.licenceLabel).to.equal('Unknown')
722 expect(video.language).to.equal(null)
723 expect(video.languageLabel).to.equal('Unknown')
724 expect(video.nsfw).to.not.be.ok
725 expect(video.description).to.equal(null)
726 expect(video.serverHost).to.equal('localhost:9001')
727 expect(video.accountName).to.equal('root')
728 expect(video.isLocal).to.be.true
729 expect(video.tags).to.deep.equal([ ])
730 expect(dateIsValid(video.createdAt)).to.be.true
731 expect(dateIsValid(video.updatedAt)).to.be.true
732 })
733
734 after(async function () { 697 after(async function () {
735 killallServers([ server ]) 698 killallServers([ server ])
736 699