Browse Source

Merge pull request #461 from Lezek123/media-schemas-and-links-fix

Media schemas and links fix
Mokhtar Naamani 4 years ago
parent
commit
9dd4478ad8

+ 2 - 2
packages/joy-media/src/schemas/general/FeaturedContent.ts

@@ -69,7 +69,7 @@ export const FeaturedContentClass: FeaturedContentClassType = {
     "name": "Featured Videos",
     "description": "Videos featured in the Video tab.",
     "type": "InternalVec",
-    "maxItems": 6,
+    "maxItems": 12,
     "classId": "Video"
   },
   featuredAlbums: {
@@ -77,7 +77,7 @@ export const FeaturedContentClass: FeaturedContentClassType = {
     "name": "Featured Albums",
     "description": "Music albums featured in the Music tab.",
     "type": "InternalVec",
-    "maxItems": 6,
+    "maxItems": 12,
     "classId": "Music Album"
   }
 };

+ 9 - 9
packages/joy-media/src/schemas/music/MusicAlbum.ts

@@ -51,7 +51,7 @@ export type MusicAlbumFormValues = {
   theme: number
   tracks: number[]
   language: number
-  link: string[]
+  links: string[]
   lyrics: string
   composerOrSongwriter: string
   reviews: string[]
@@ -77,7 +77,7 @@ export type MusicAlbumType = {
   theme?: MusicThemeType
   tracks?: MusicTrackType[]
   language?: LanguageType
-  link?: string[]
+  links?: string[]
   lyrics?: string
   composerOrSongwriter?: string
   reviews?: string[]
@@ -104,7 +104,7 @@ export function MusicAlbumToFormValues(entity?: MusicAlbumType): MusicAlbumFormV
     theme: entity && entity.theme?.id || 0,
     tracks: entity && entity.tracks?.map(x => x.id) || [],
     language: entity && entity.language?.id || 0,
-    link: entity && entity.link || [],
+    links: entity && entity.links || [],
     lyrics: entity && entity.lyrics || '',
     composerOrSongwriter: entity && entity.composerOrSongwriter || '',
     reviews: entity && entity.reviews || [],
@@ -128,7 +128,7 @@ export type MusicAlbumPropId =
   'theme' |
   'tracks' |
   'language' |
-  'link' |
+  'links' |
   'lyrics' |
   'composerOrSongwriter' |
   'reviews' |
@@ -232,10 +232,10 @@ export const MusicAlbumClass: MusicAlbumClassType = {
     "type": "Internal",
     "classId": "Language"
   },
-  link: {
-    "id": "link",
-    "name": "Link",
-    "description": "Links to the artist or album site or social media pages.",
+  links: {
+    "id": "links",
+    "name": "Links",
+    "description": "Links to the artist or album site, or social media pages.",
     "type": "TextVec",
     "maxItems": 5,
     "maxTextLength": 255
@@ -302,7 +302,7 @@ export const MusicAlbumClass: MusicAlbumClassType = {
   channelId: {
     "id": "channelId",
     "name": "Channel Id",
-    "description": "Id of the channel this music album is published to.",
+    "description": "Id of the channel this album is published under.",
     "type": "Uint64"
   }
 };

+ 9 - 9
packages/joy-media/src/schemas/music/MusicTrack.ts

@@ -49,7 +49,7 @@ export type MusicTrackFormValues = {
   genre: number
   mood: number
   theme: number
-  link: string[]
+  links: string[]
   composerOrSongwriter: string
   lyrics: string
   object: number
@@ -74,7 +74,7 @@ export type MusicTrackType = {
   genre?: MusicGenreType
   mood?: MusicMoodType
   theme?: MusicThemeType
-  link?: string[]
+  links?: string[]
   composerOrSongwriter?: string
   lyrics?: string
   object?: MediaObjectType
@@ -100,7 +100,7 @@ export function MusicTrackToFormValues(entity?: MusicTrackType): MusicTrackFormV
     genre: entity && entity.genre?.id || 0,
     mood: entity && entity.mood?.id || 0,
     theme: entity && entity.theme?.id || 0,
-    link: entity && entity.link || [],
+    links: entity && entity.links || [],
     composerOrSongwriter: entity && entity.composerOrSongwriter || '',
     lyrics: entity && entity.lyrics || '',
     object: entity && entity.object?.id || 0,
@@ -123,7 +123,7 @@ export type MusicTrackPropId =
   'genre' |
   'mood' |
   'theme' |
-  'link' |
+  'links' |
   'composerOrSongwriter' |
   'lyrics' |
   'object' |
@@ -217,10 +217,10 @@ export const MusicTrackClass: MusicTrackClassType = {
     "type": "Internal",
     "classId": "Music Theme"
   },
-  link: {
-    "id": "link",
-    "name": "Link",
-    "description": "A link to the artist page.",
+  links: {
+    "id": "links",
+    "name": "Links",
+    "description": "Links to the artist site or social media pages.",
     "type": "TextVec",
     "maxItems": 5,
     "maxTextLength": 255
@@ -286,7 +286,7 @@ export const MusicTrackClass: MusicTrackClassType = {
   channelId: {
     "id": "channelId",
     "name": "Channel Id",
-    "description": "Id of the channel this music track is published to.",
+    "description": "Id of the channel this track is published under.",
     "type": "Uint64"
   }
 };

+ 230 - 230
packages/joy-media/src/schemas/video/Video.ts

@@ -1,230 +1,230 @@
-
-/** This file is generated based on JSON schema. Do not modify. */
-
-import * as Yup from 'yup';
-import { EntityCodec } from '@joystream/types/versioned-store/EntityCodec';
-import moment from 'moment';
-import { LanguageType } from '../general/Language';
-import { VideoCategoryType } from './VideoCategory';
-import { MediaObjectType } from '../general/MediaObject';
-import { PublicationStatusType } from '../general/PublicationStatus';
-import { CurationStatusType } from '../general/CurationStatus';
-import { ContentLicenseType } from '../general/ContentLicense';
-import { ChannelEntity } from '@polkadot/joy-media/entities/ChannelEntity';
-
-export const VideoValidationSchema = Yup.object().shape({
-  title: Yup.string()
-    .required('This field is required')
-    .max(255, 'Text is too long. Maximum length is 255 chars.'),
-  thumbnail: Yup.string()
-    .required('This field is required')
-    .max(255, 'Text is too long. Maximum length is 255 chars.'),
-  description: Yup.string()
-    .required('This field is required')
-    .max(4000, 'Text is too long. Maximum length is 4000 chars.'),
-  firstReleased: Yup.string()
-    .required('This field is required')
-    .test('valid-date', 'Invalid date. Valid date formats are yyyy-mm-dd or yyyy-mm or yyyy.', (val?: any) => {
-      return moment(val as any).isValid();
-    }),
-  attribution: Yup.string()
-    .max(255, 'Text is too long. Maximum length is 255 chars.')
-});
-
-export type VideoFormValues = {
-  title: string
-  thumbnail: string
-  description: string
-  language: number
-  firstReleased: string
-  category: number
-  link: string[]
-  object: number
-  publicationStatus: number
-  curationStatus: number
-  explicit: boolean
-  license: number
-  attribution: string
-  channelId: number
-};
-
-export type VideoType = {
-  classId: number
-  inClassSchemaIndexes: number[]
-  id: number
-  title: string
-  thumbnail: string
-  description: string
-  language: LanguageType
-  firstReleased: number
-  category?: VideoCategoryType
-  link?: string[]
-  object?: MediaObjectType
-  publicationStatus: PublicationStatusType
-  curationStatus?: CurationStatusType
-  explicit: boolean
-  license: ContentLicenseType
-  attribution?: string
-  channelId?: number
-  channel?: ChannelEntity
-};
-
-export class VideoCodec extends EntityCodec<VideoType> { }
-
-export function VideoToFormValues(entity?: VideoType): VideoFormValues {
-  return {
-    title: entity && entity.title || '',
-    thumbnail: entity && entity.thumbnail || '',
-    description: entity && entity.description || '',
-    language: entity && entity.language?.id || 0,
-    firstReleased: entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD') || '',
-    category: entity && entity.category?.id || 0,
-    link: entity && entity.link || [],
-    object: entity && entity.object?.id || 0,
-    publicationStatus: entity && entity.publicationStatus?.id || 0,
-    curationStatus: entity && entity.curationStatus?.id || 0,
-    explicit: entity && entity.explicit || false,
-    license: entity && entity.license?.id || 0,
-    attribution: entity && entity.attribution || '',
-    channelId: entity && entity.channelId || 0
-  }
-}
-
-export type VideoPropId =
-  'title' |
-  'thumbnail' |
-  'description' |
-  'language' |
-  'firstReleased' |
-  'category' |
-  'link' |
-  'object' |
-  'publicationStatus' |
-  'curationStatus' |
-  'explicit' |
-  'license' |
-  'attribution' |
-  'channelId'
-  ;
-
-export type VideoGenericProp = {
-  id: VideoPropId,
-  type: string,
-  name: string,
-  description?: string,
-  required?: boolean,
-  maxItems?: number,
-  maxTextLength?: number,
-  classId?: any
-};
-
-type VideoClassType = {
-  [id in VideoPropId]: VideoGenericProp
-};
-
-export const VideoClass: VideoClassType = {
-  title: {
-    "id": "title",
-    "name": "Title",
-    "description": "The title of the video",
-    "type": "Text",
-    "required": true,
-    "maxTextLength": 255
-  },
-  thumbnail: {
-    "id": "thumbnail",
-    "name": "Thumbnail",
-    "description": "URL to video thumbnail: NOTE: Should be an https link to an image of ratio 16:9, ideally 1280 pixels wide by 720 pixels tall, with a minimum width of 640 pixels, in JPEG or PNG format.",
-    "required": true,
-    "type": "Text",
-    "maxTextLength": 255
-  },
-  description: {
-    "id": "description",
-    "name": "Description",
-    "description": "Information about the video.",
-    "required": true,
-    "type": "Text",
-    "maxTextLength": 4000
-  },
-  language: {
-    "id": "language",
-    "name": "Language",
-    "description": "The main language used in the video.",
-    "required": true,
-    "type": "Internal",
-    "classId": "Language"
-  },
-  firstReleased: {
-    "id": "firstReleased",
-    "name": "First Released",
-    "description": "When the video was first released",
-    "required": true,
-    "type": "Int64"
-  },
-  category: {
-    "id": "category",
-    "name": "Category",
-    "description": "The category of the video.",
-    "type": "Internal",
-    "classId": "Video Category"
-  },
-  link: {
-    "id": "link",
-    "name": "Link",
-    "description": "A link to the creators page.",
-    "type": "TextVec",
-    "maxItems": 5,
-    "maxTextLength": 255
-  },
-  object: {
-    "id": "object",
-    "name": "Object",
-    "description": "The entityId of the object in the data directory.",
-    "type": "Internal",
-    "classId": "Media Object"
-  },
-  publicationStatus: {
-    "id": "publicationStatus",
-    "name": "Publication Status",
-    "description": "The publication status of the video.",
-    "required": true,
-    "type": "Internal",
-    "classId": "Publication Status"
-  },
-  curationStatus: {
-    "id": "curationStatus",
-    "name": "Curation Status",
-    "description": "The publication status of the video set by the a content curator on the platform.",
-    "type": "Internal",
-    "classId": "Curation Status"
-  },
-  explicit: {
-    "id": "explicit",
-    "name": "Explicit",
-    "description": "Indicates whether the video contains explicit material.",
-    "required": true,
-    "type": "Bool"
-  },
-  license: {
-    "id": "license",
-    "name": "License",
-    "description": "The license of which the video is released under.",
-    "required": true,
-    "type": "Internal",
-    "classId": "Content License"
-  },
-  attribution: {
-    "id": "attribution",
-    "name": "Attribution",
-    "description": "If the License requires attribution, add this here.",
-    "type": "Text",
-    "maxTextLength": 255
-  },
-  channelId: {
-    "id": "channelId",
-    "name": "Channel Id",
-    "description": "Id of the channel this video is published to.",
-    "type": "Uint64"
-  }
-};
+
+/** This file is generated based on JSON schema. Do not modify. */
+
+import * as Yup from 'yup';
+import { EntityCodec } from '@joystream/types/versioned-store/EntityCodec';
+import moment from 'moment';
+import { LanguageType } from '../general/Language';
+import { VideoCategoryType } from './VideoCategory';
+import { MediaObjectType } from '../general/MediaObject';
+import { PublicationStatusType } from '../general/PublicationStatus';
+import { CurationStatusType } from '../general/CurationStatus';
+import { ContentLicenseType } from '../general/ContentLicense';
+import { ChannelEntity } from '@polkadot/joy-media/entities/ChannelEntity';
+
+export const VideoValidationSchema = Yup.object().shape({
+  title: Yup.string()
+    .required('This field is required')
+    .max(255, 'Text is too long. Maximum length is 255 chars.'),
+  thumbnail: Yup.string()
+    .required('This field is required')
+    .max(255, 'Text is too long. Maximum length is 255 chars.'),
+  description: Yup.string()
+    .required('This field is required')
+    .max(4000, 'Text is too long. Maximum length is 4000 chars.'),
+  firstReleased: Yup.string()
+    .required('This field is required')
+    .test('valid-date', 'Invalid date. Valid date formats are yyyy-mm-dd or yyyy-mm or yyyy.', (val?: any) => {
+      return moment(val as any).isValid();
+    }),
+  attribution: Yup.string()
+    .max(255, 'Text is too long. Maximum length is 255 chars.')
+});
+
+export type VideoFormValues = {
+  title: string
+  thumbnail: string
+  description: string
+  language: number
+  firstReleased: string
+  category: number
+  links: string[]
+  object: number
+  publicationStatus: number
+  curationStatus: number
+  explicit: boolean
+  license: number
+  attribution: string
+  channelId: number
+};
+
+export type VideoType = {
+  classId: number
+  inClassSchemaIndexes: number[]
+  id: number
+  title: string
+  thumbnail: string
+  description: string
+  language: LanguageType
+  firstReleased: number
+  category?: VideoCategoryType
+  links?: string[]
+  object?: MediaObjectType
+  publicationStatus: PublicationStatusType
+  curationStatus?: CurationStatusType
+  explicit: boolean
+  license: ContentLicenseType
+  attribution?: string
+  channelId?: number
+  channel?: ChannelEntity
+};
+
+export class VideoCodec extends EntityCodec<VideoType> { }
+
+export function VideoToFormValues(entity?: VideoType): VideoFormValues {
+  return {
+    title: entity && entity.title || '',
+    thumbnail: entity && entity.thumbnail || '',
+    description: entity && entity.description || '',
+    language: entity && entity.language?.id || 0,
+    firstReleased: entity && moment(entity.firstReleased * 1000).format('YYYY-MM-DD') || '',
+    category: entity && entity.category?.id || 0,
+    links: entity && entity.links || [],
+    object: entity && entity.object?.id || 0,
+    publicationStatus: entity && entity.publicationStatus?.id || 0,
+    curationStatus: entity && entity.curationStatus?.id || 0,
+    explicit: entity && entity.explicit || false,
+    license: entity && entity.license?.id || 0,
+    attribution: entity && entity.attribution || '',
+    channelId: entity && entity.channelId || 0
+  }
+}
+
+export type VideoPropId =
+  'title' |
+  'thumbnail' |
+  'description' |
+  'language' |
+  'firstReleased' |
+  'category' |
+  'links' |
+  'object' |
+  'publicationStatus' |
+  'curationStatus' |
+  'explicit' |
+  'license' |
+  'attribution' |
+  'channelId'
+  ;
+
+export type VideoGenericProp = {
+  id: VideoPropId,
+  type: string,
+  name: string,
+  description?: string,
+  required?: boolean,
+  maxItems?: number,
+  maxTextLength?: number,
+  classId?: any
+};
+
+type VideoClassType = {
+  [id in VideoPropId]: VideoGenericProp
+};
+
+export const VideoClass: VideoClassType = {
+  title: {
+    "id": "title",
+    "name": "Title",
+    "description": "The title of the video",
+    "type": "Text",
+    "required": true,
+    "maxTextLength": 255
+  },
+  thumbnail: {
+    "id": "thumbnail",
+    "name": "Thumbnail",
+    "description": "URL to video thumbnail: NOTE: Should be an https link to an image of ratio 16:9, ideally 1280 pixels wide by 720 pixels tall, with a minimum width of 640 pixels, in JPEG or PNG format.",
+    "required": true,
+    "type": "Text",
+    "maxTextLength": 255
+  },
+  description: {
+    "id": "description",
+    "name": "Description",
+    "description": "Information about the video.",
+    "required": true,
+    "type": "Text",
+    "maxTextLength": 4000
+  },
+  language: {
+    "id": "language",
+    "name": "Language",
+    "description": "The main language used in the video.",
+    "required": true,
+    "type": "Internal",
+    "classId": "Language"
+  },
+  firstReleased: {
+    "id": "firstReleased",
+    "name": "First Released",
+    "description": "When the video was first released",
+    "required": true,
+    "type": "Int64"
+  },
+  category: {
+    "id": "category",
+    "name": "Category",
+    "description": "The category of the video.",
+    "type": "Internal",
+    "classId": "Video Category"
+  },
+  links: {
+    "id": "links",
+    "name": "Link",
+    "description": "A link to the creators page.",
+    "type": "TextVec",
+    "maxItems": 5,
+    "maxTextLength": 255
+  },
+  object: {
+    "id": "object",
+    "name": "Object",
+    "description": "The entityId of the object in the data directory.",
+    "type": "Internal",
+    "classId": "Media Object"
+  },
+  publicationStatus: {
+    "id": "publicationStatus",
+    "name": "Publication Status",
+    "description": "The publication status of the video.",
+    "required": true,
+    "type": "Internal",
+    "classId": "Publication Status"
+  },
+  curationStatus: {
+    "id": "curationStatus",
+    "name": "Curation Status",
+    "description": "The publication status of the video set by the a content curator on the platform.",
+    "type": "Internal",
+    "classId": "Curation Status"
+  },
+  explicit: {
+    "id": "explicit",
+    "name": "Explicit",
+    "description": "Indicates whether the video contains explicit material.",
+    "required": true,
+    "type": "Bool"
+  },
+  license: {
+    "id": "license",
+    "name": "License",
+    "description": "The license of which the video is released under.",
+    "required": true,
+    "type": "Internal",
+    "classId": "Content License"
+  },
+  attribution: {
+    "id": "attribution",
+    "name": "Attribution",
+    "description": "If the License requires attribution, add this here.",
+    "type": "Text",
+    "maxTextLength": 255
+  },
+  channelId: {
+    "id": "channelId",
+    "name": "Channel Id",
+    "description": "Id of the channel this video is published under.",
+    "type": "Uint64"
+  }
+};

+ 2 - 2
packages/joy-media/src/upload/UploadVideo.tsx

@@ -336,7 +336,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
 
   const additionalTab = () => <Tab.Pane as='div'>
     <MediaDropdown field={Fields.category} options={opts.videoCategoryOptions} {...props} />
-    <MediaText field={Fields.link} {...props} />
+    <MediaText field={Fields.links} {...props} />
     <MediaText field={Fields.attribution} {...props} />
   </Tab.Pane>
 
@@ -360,7 +360,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
       render: additionalTab,
       fields: [
         Fields.category,
-        Fields.link,
+        Fields.links,
         Fields.attribution,
       ]
     }

+ 1 - 1
packages/joy-media/src/video/PlayVideo.tsx

@@ -71,7 +71,7 @@ export function PlayVideo (props: PlayVideoProps) {
         {metaField(Fields.category, video.category?.value)}
         {metaField(Fields.license, video.license?.value)}
         {metaField(Fields.attribution, video.attribution)}
-        {metaField(Fields.link, printLinks(video.link))}
+        {metaField(Fields.links, printLinks(video.links))}
         {metaField(Fields.curationStatus, video.curationStatus?.value)}
       </Table.Body>
     </Table>

+ 28 - 16
packages/joy-types/src/versioned-store/EntityCodec.ts

@@ -32,12 +32,12 @@ function substrateToPlain<T> (x: Codec): T | undefined {
 }
 
 /**
- * Convert a plain JavaScript value of such type as string, number, boolean 
+ * Convert a plain JavaScript value of such type as string, number, boolean
  * to Substrate equivalent in Versioned Store module.
- * 
+ *
  * Based on code of transformPropertyValue from another Joystream repo:
  * /versioned-store-js/src/transformPropertyValue.ts
- * 
+ *
  * @throws Error
  */
 function plainToSubstrate(propType: string, value: any): PropertyValue {
@@ -60,8 +60,20 @@ function plainToSubstrate(propType: string, value: any): PropertyValue {
     }
   }
 
+  const valueAsArr = (): any[] => {
+    if (Array.isArray(value)) {
+      return value as any[]
+    }
+
+    return typeof value === undefined ? [] : [ value ]
+  }
+
   const valueAsBoolArr = (): boolean[] => {
-    return (value as []).map(valueAsBool)
+    return valueAsArr().map(valueAsBool)
+  }
+
+  const valueAsStrArr = (): string[] => {
+    return valueAsArr() as string[]
   }
 
   switch (propType) {
@@ -82,14 +94,14 @@ function plainToSubstrate(propType: string, value: any): PropertyValue {
     // Vectors:
 
     case 'BoolVec':     return ok(new PV.BoolVec(valueAsBoolArr()))
-    case 'Uint16Vec':   return ok(new PV.Uint16Vec(value as string[]))
-    case 'Uint32Vec':   return ok(new PV.Uint32Vec(value as string[]))
-    case 'Uint64Vec':   return ok(new PV.Uint64Vec(value as string[]))
-    case 'Int16Vec':    return ok(new PV.Int16Vec(value as string[]))
-    case 'Int32Vec':    return ok(new PV.Int32Vec(value as string[]))
-    case 'Int64Vec':    return ok(new PV.Int64Vec(value as string[]))
-    case 'TextVec':     return ok(new PV.TextVec(value as string[]))
-    case 'InternalVec': return ok(new PV.InternalVec(value as string[]))
+    case 'Uint16Vec':   return ok(new PV.Uint16Vec(valueAsStrArr()))
+    case 'Uint32Vec':   return ok(new PV.Uint32Vec(valueAsStrArr()))
+    case 'Uint64Vec':   return ok(new PV.Uint64Vec(valueAsStrArr()))
+    case 'Int16Vec':    return ok(new PV.Int16Vec(valueAsStrArr()))
+    case 'Int32Vec':    return ok(new PV.Int32Vec(valueAsStrArr()))
+    case 'Int64Vec':    return ok(new PV.Int64Vec(valueAsStrArr()))
+    case 'TextVec':     return ok(new PV.TextVec(valueAsStrArr()))
+    case 'InternalVec': return ok(new PV.InternalVec(valueAsArr()))
 
     default: {
       throw new Error(`Unknown property type name: ${propType}`)
@@ -154,10 +166,10 @@ export interface ToPlainObjectProps {
 }
 
 export abstract class EntityCodec<T extends PlainEntity> {
-  
+
   private propNameToMetaMap: Map<string, PropMeta> = new Map()
   private propIndexToNameMap: Map<number, string> = new Map()
-  
+
   public constructor (entityClass: Class) {
     entityClass.properties.map((p, index) => {
       const propName = unifyPropName(p.name.toString());
@@ -199,7 +211,7 @@ export abstract class EntityCodec<T extends PlainEntity> {
         // Load a referred internal entity:
         if (loadInternals) {
           if (
-            propValue instanceof PV.Internal && 
+            propValue instanceof PV.Internal &&
             typeof loadEntityById === 'function'
           ) {
             convertedValue = await loadEntityById(propValue as EntityId)
@@ -241,7 +253,7 @@ export abstract class EntityCodec<T extends PlainEntity> {
       if (meta) {
         const propType = meta.type as PropertyTypeName;
         const plainValue = (updatedProps as any)[propName];
-  
+
         let codecValue: PropertyValue | undefined
         try {
           codecValue = plainToSubstrate(propType, plainValue)