From: Chocobozzz Date: Mon, 11 Feb 2019 13:09:23 +0000 (+0100) Subject: Merge branch 'develop' into pr/1285 X-Git-Tag: v1.3.0-rc.1~205 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=b718fd22374d64534bcfe69932cf562894abed6a;hp=501e961199578129629cf0567033d13efced9904;p=github%2FChocobozzz%2FPeerTube.git Merge branch 'develop' into pr/1285 --- diff --git a/client/src/app/shared/forms/form-validators/video-validators.service.ts b/client/src/app/shared/forms/form-validators/video-validators.service.ts index 81ed0666f..e3f7a0969 100644 --- a/client/src/app/shared/forms/form-validators/video-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/video-validators.service.ts @@ -16,6 +16,7 @@ export class VideoValidatorsService { readonly VIDEO_TAGS: BuildFormValidator readonly VIDEO_SUPPORT: BuildFormValidator readonly VIDEO_SCHEDULE_PUBLICATION_AT: BuildFormValidator + readonly VIDEO_ORIGINALLY_PUBLISHED_AT: BuildFormValidator constructor (private i18n: I18n) { @@ -92,5 +93,10 @@ export class VideoValidatorsService { 'required': this.i18n('A date is required to schedule video update.') } } + + this.VIDEO_ORIGINALLY_PUBLISHED_AT = { + VALIDATORS: [ ], + MESSAGES: {} + } } } diff --git a/client/src/app/shared/video-import/video-import.service.ts b/client/src/app/shared/video-import/video-import.service.ts index 2163eb905..7ae13154d 100644 --- a/client/src/app/shared/video-import/video-import.service.ts +++ b/client/src/app/shared/video-import/video-import.service.ts @@ -67,6 +67,7 @@ export class VideoImportService { const description = video.description || null const support = video.support || null const scheduleUpdate = video.scheduleUpdate || null + const originallyPublishedAt = video.originallyPublishedAt || null return { name: video.name, @@ -84,7 +85,8 @@ export class VideoImportService { downloadEnabled: video.downloadEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, - scheduleUpdate + scheduleUpdate, + originallyPublishedAt } } diff --git a/client/src/app/shared/video/video-edit.model.ts b/client/src/app/shared/video/video-edit.model.ts index 18c62a1f9..c5d5bb406 100644 --- a/client/src/app/shared/video/video-edit.model.ts +++ b/client/src/app/shared/video/video-edit.model.ts @@ -26,6 +26,7 @@ export class VideoEdit implements VideoUpdate { uuid?: string id?: number scheduleUpdate?: VideoScheduleUpdate + originallyPublishedAt?: Date | string constructor ( video?: Video & { @@ -56,6 +57,7 @@ export class VideoEdit implements VideoUpdate { this.previewUrl = video.previewUrl this.scheduleUpdate = video.scheduledUpdate + this.originallyPublishedAt = new Date(video.originallyPublishedAt) } } @@ -77,6 +79,12 @@ export class VideoEdit implements VideoUpdate { } else { this.scheduleUpdate = null } + + // Convert originallyPublishedAt to string so that function objectToFormData() works correctly + if (this.originallyPublishedAt) { + const originallyPublishedAt = new Date(values['originallyPublishedAt']) + this.originallyPublishedAt = originallyPublishedAt.toISOString() + } } toFormPatch () { @@ -93,7 +101,8 @@ export class VideoEdit implements VideoUpdate { downloadEnabled: this.downloadEnabled, waitTranscoding: this.waitTranscoding, channelId: this.channelId, - privacy: this.privacy + privacy: this.privacy, + originallyPublishedAt: this.originallyPublishedAt } // Special case if we scheduled an update diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts index 6ea83d13b..460c09258 100644 --- a/client/src/app/shared/video/video.model.ts +++ b/client/src/app/shared/video/video.model.ts @@ -17,6 +17,7 @@ export class Video implements VideoServerModel { createdAt: Date updatedAt: Date publishedAt: Date + originallyPublishedAt: Date | string category: VideoConstant licence: VideoConstant language: VideoConstant @@ -116,6 +117,9 @@ export class Video implements VideoServerModel { this.privacy.label = peertubeTranslate(this.privacy.label, translations) this.scheduledUpdate = hash.scheduledUpdate + this.originallyPublishedAt = hash.originallyPublishedAt ? + new Date(hash.originallyPublishedAt.toString()) + : null if (this.state) this.state.label = peertubeTranslate(this.state.label, translations) this.blacklisted = hash.blacklisted diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index 565aad93b..960846e21 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -81,6 +81,7 @@ export class VideoService implements VideosProvider { const description = video.description || null const support = video.support || null const scheduleUpdate = video.scheduleUpdate || null + const originallyPublishedAt = video.originallyPublishedAt || null const body: VideoUpdate = { name: video.name, @@ -98,7 +99,8 @@ export class VideoService implements VideosProvider { downloadEnabled: video.downloadEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, - scheduleUpdate + scheduleUpdate, + originallyPublishedAt } const data = objectToFormData(body) diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html index 59ba15b53..2fb540170 100644 --- a/client/src/app/videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html @@ -114,6 +114,20 @@ +
+ + + + + +
+ {{ formErrors.originallyPublishedAt }} +
+
+

{{ video.name }}

-
Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views
@@ -162,6 +161,11 @@ {{ video.privacy.label }}
+
+ Originally published + {{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }} +
+
Category {{ video.category.label }} diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index b03ed197d..cfe3533b6 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss @@ -286,7 +286,7 @@ $other-videos-width: 260px; margin-bottom: 12px; .video-attribute-label { - min-width: 91px; + min-width: 142px; padding-right: 5px; display: inline-block; color: $grey-foreground-color; diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 76a318d13..6ac13e6a4 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -190,7 +190,8 @@ async function addVideo (req: express.Request, res: express.Response) { support: videoInfo.support, privacy: videoInfo.privacy, duration: videoPhysicalFile['duration'], // duration was added by a previous middleware - channelId: res.locals.videoChannel.id + channelId: res.locals.videoChannel.id, + originallyPublishedAt: videoInfo.originallyPublishedAt } const video = new VideoModel(videoData) video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object @@ -328,6 +329,11 @@ async function updateVideo (req: express.Request, res: express.Response) { if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description) if (videoInfoToUpdate.commentsEnabled !== undefined) videoInstance.set('commentsEnabled', videoInfoToUpdate.commentsEnabled) if (videoInfoToUpdate.downloadEnabled !== undefined) videoInstance.set('downloadEnabled', videoInfoToUpdate.downloadEnabled) + + if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) { + videoInstance.set('originallyPublishedAt', videoInfoToUpdate.originallyPublishedAt) + } + if (videoInfoToUpdate.privacy !== undefined) { const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) videoInstance.set('privacy', newPrivacy) diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 95e256b8f..dd04aa5f6 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -13,7 +13,7 @@ import { VIDEO_STATES } from '../../initializers' import { VideoModel } from '../../models/video/video' -import { exists, isArray, isFileValid } from './misc' +import { exists, isArray, isDateValid, isFileValid } from './misc' import { VideoChannelModel } from '../../models/video/video-channel' import { UserModel } from '../../models/account/user' import * as magnetUtil from 'magnet-uri' @@ -115,6 +115,10 @@ function isScheduleVideoUpdatePrivacyValid (value: number) { ) } +function isVideoOriginallyPublishedAtValid (value: string | null) { + return value === null || isDateValid(value) +} + function isVideoFileInfoHashValid (value: string | null | undefined) { return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH) } @@ -220,6 +224,7 @@ export { isVideoTagsValid, isVideoFPSResolutionValid, isScheduleVideoUpdatePrivacyValid, + isVideoOriginallyPublishedAtValid, isVideoFile, isVideoMagnetUriValid, isVideoStateValid, diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 639493d73..3656a23f9 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -16,7 +16,7 @@ let config: IConfig = require('config') // --------------------------------------------------------------------------- -const LAST_MIGRATION_VERSION = 335 +const LAST_MIGRATION_VERSION = 340 // --------------------------------------------------------------------------- diff --git a/server/initializers/migrations/0340-add-originally-published-at.ts b/server/initializers/migrations/0340-add-originally-published-at.ts new file mode 100644 index 000000000..ab8d66854 --- /dev/null +++ b/server/initializers/migrations/0340-add-originally-published-at.ts @@ -0,0 +1,31 @@ +import * as Sequelize from 'sequelize' + +async function up (utils: { + transaction: Sequelize.Transaction, + queryInterface: Sequelize.QueryInterface, + sequelize: Sequelize.Sequelize +}): Promise { + + { + const data = { + type: Sequelize.DATE, + allowNull: true, + defaultValue: Sequelize.NOW + } + await utils.queryInterface.addColumn('video', 'originallyPublishedAt', data) + } + + { + const query = 'UPDATE video SET "originallyPublishedAt" = video."publishedAt"' + await utils.sequelize.query(query) + } +} + +function down (options) { + throw new Error('Not implemented.') +} + +export { + up, + down +} diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index d9626929c..159727e28 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -14,6 +14,7 @@ import { } from '../../../helpers/custom-validators/misc' import { checkUserCanManageVideo, + isVideoOriginallyPublishedAtValid, isScheduleVideoUpdatePrivacyValid, isVideoCategoryValid, isVideoChannelOfAccountExist, @@ -344,7 +345,10 @@ function getCommonVideoAttributes () { .optional() .toBoolean() .custom(isBooleanValid).withMessage('Should have downloading enabled boolean'), - + body('originallyPublishedAt') + .optional() + .customSanitizer(toValueOrNull) + .custom(isVideoOriginallyPublishedAtValid).withMessage('Should have a valid original publication date'), body('scheduleUpdate') .optional() .customSanitizer(toValueOrNull), diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index 76d0445d4..c63285e25 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts @@ -67,6 +67,7 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting createdAt: video.createdAt, updatedAt: video.updatedAt, publishedAt: video.publishedAt, + originallyPublishedAt: video.originallyPublishedAt, account: { id: formattedAccount.id, uuid: formattedAccount.uuid, @@ -323,6 +324,9 @@ function videoModelToActivityPubObject (video: VideoModel): VideoTorrentObject { commentsEnabled: video.commentsEnabled, downloadEnabled: video.downloadEnabled, published: video.publishedAt.toISOString(), + originallyPublishedAt: video.originallyPublishedAt ? + video.originallyPublishedAt.toISOString() : + null, updated: video.updatedAt.toISOString(), mediaType: 'text/markdown', content: video.getTruncatedDescription(), diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 0feeed4f8..73626b6a0 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -103,6 +103,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [ { fields: [ 'createdAt' ] }, { fields: [ 'publishedAt' ] }, + { fields: [ 'originallyPublishedAt' ] }, { fields: [ 'duration' ] }, { fields: [ 'views' ] }, { fields: [ 'channelId' ] }, @@ -740,6 +741,9 @@ export class VideoModel extends Model { @Column publishedAt: Date + @Column + originallyPublishedAt: Date + @ForeignKey(() => VideoChannelModel) @Column channelId: number diff --git a/shared/models/activitypub/objects/video-torrent-object.ts b/shared/models/activitypub/objects/video-torrent-object.ts index 4231fbb68..239822bc4 100644 --- a/shared/models/activitypub/objects/video-torrent-object.ts +++ b/shared/models/activitypub/objects/video-torrent-object.ts @@ -25,6 +25,7 @@ export interface VideoTorrentObject { waitTranscoding: boolean state: VideoState published: string + originallyPublishedAt: string updated: string mediaType: 'text/markdown' content: string diff --git a/shared/models/videos/video-create.model.ts b/shared/models/videos/video-create.model.ts index f153a1d00..53631bf79 100644 --- a/shared/models/videos/video-create.model.ts +++ b/shared/models/videos/video-create.model.ts @@ -16,4 +16,5 @@ export interface VideoCreate { downloadEnabled?: boolean privacy: VideoPrivacy scheduleUpdate?: VideoScheduleUpdate + originallyPublishedAt: Date | string } diff --git a/shared/models/videos/video-update.model.ts b/shared/models/videos/video-update.model.ts index 6f96633ae..4ef904156 100644 --- a/shared/models/videos/video-update.model.ts +++ b/shared/models/videos/video-update.model.ts @@ -18,4 +18,5 @@ export interface VideoUpdate { thumbnailfile?: Blob previewfile?: Blob scheduleUpdate?: VideoScheduleUpdate + originallyPublishedAt?: Date | string } diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts index 891831a9e..df800461c 100644 --- a/shared/models/videos/video.model.ts +++ b/shared/models/videos/video.model.ts @@ -44,6 +44,7 @@ export interface Video { createdAt: Date | string updatedAt: Date | string publishedAt: Date | string + originallyPublishedAt: Date | string category: VideoConstant licence: VideoConstant language: VideoConstant