diff options
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 | }) |
13 | export class VideoAbuseListComponent extends RestTable implements OnInit { | 14 | export 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' | |||
9 | import { database as db } from '../../initializers/database' | 9 | import { database as db } from '../../initializers/database' |
10 | import { VideoInstance } from '../../models/video/video-interface' | 10 | import { VideoInstance } from '../../models/video/video-interface' |
11 | import { exists, isArray } from './misc' | 11 | import { exists, isArray } from './misc' |
12 | import isInt = require('validator/lib/isInt') | ||
12 | 13 | ||
13 | const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS | 14 | const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS |
14 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES | 15 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES |
15 | 16 | ||
16 | function isVideoCategoryValid (value: number) { | 17 | function isVideoCategoryValid (value: number) { |
17 | return VIDEO_CATEGORIES[value] !== undefined | 18 | return value === null || VIDEO_CATEGORIES[value] !== undefined |
18 | } | 19 | } |
19 | 20 | ||
20 | function isVideoLicenceValid (value: number) { | 21 | function isVideoLicenceValid (value: number) { |
21 | return VIDEO_LICENCES[value] !== undefined | 22 | return value === null || VIDEO_LICENCES[value] !== undefined |
22 | } | 23 | } |
23 | 24 | ||
24 | function isVideoLanguageValid (value: number) { | 25 | function isVideoLanguageValid (value: number) { |
@@ -38,7 +39,7 @@ function isVideoTruncatedDescriptionValid (value: string) { | |||
38 | } | 39 | } |
39 | 40 | ||
40 | function isVideoDescriptionValid (value: string) { | 41 | function 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 | ||
44 | function isVideoNameValid (value: string) { | 45 | function isVideoNameValid (value: string) { |
@@ -84,7 +85,7 @@ function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | | |||
84 | } | 85 | } |
85 | 86 | ||
86 | function isVideoPrivacyValid (value: string) { | 87 | function isVideoPrivacyValid (value: string) { |
87 | return VIDEO_PRIVACIES[value] !== undefined | 88 | return validator.isInt(value + '') && VIDEO_PRIVACIES[value] !== undefined |
88 | } | 89 | } |
89 | 90 | ||
90 | function isVideoFileInfoHashValid (value: string) { | 91 | function 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 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { join } from "path" | ||
6 | import * as request from 'supertest' | ||
5 | 7 | ||
6 | import { | 8 | import { |
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 | ||