Przeglądaj źródła

New schemas, improved tooling, initialization scripts

Leszek Wiesner 4 lat temu
rodzic
commit
cfe77cea87
96 zmienionych plików z 2977 dodań i 262 usunięć
  1. 1 0
      content-directory-schemas/.gitignore
  2. 3 4
      content-directory-schemas/README.md
  3. 3 1
      content-directory-schemas/inputs/classes/10_LicenseClass.json
  4. 6 0
      content-directory-schemas/inputs/classes/11_VideoMediaClass.json
  5. 6 0
      content-directory-schemas/inputs/classes/12_VideoClass.json
  6. 3 1
      content-directory-schemas/inputs/classes/1_LanguageClass.json
  7. 3 1
      content-directory-schemas/inputs/classes/2_HttpMediaLocationClass.json
  8. 3 1
      content-directory-schemas/inputs/classes/3_JoystreamMediaLocationClass.json
  9. 3 1
      content-directory-schemas/inputs/classes/4_MediaLocationClass.json
  10. 3 1
      content-directory-schemas/inputs/classes/5_ContentCategoryClass.json
  11. 3 1
      content-directory-schemas/inputs/classes/6_ChannelClass.json
  12. 3 1
      content-directory-schemas/inputs/classes/7_VideoMediaEncodingClass.json
  13. 3 1
      content-directory-schemas/inputs/classes/8_KnownLicenseClass.json
  14. 3 1
      content-directory-schemas/inputs/classes/9_UserDefinedLicenseClass.json
  15. 62 0
      content-directory-schemas/inputs/entityBatches/12_VideoBatch.json
  16. 5 0
      content-directory-schemas/inputs/entityBatches/1_LanguageBatch.json
  17. 4 0
      content-directory-schemas/inputs/entityBatches/5_ContentCategoryBatch.json
  18. 11 0
      content-directory-schemas/inputs/entityBatches/6_ChannelBatch.json
  19. 3 0
      content-directory-schemas/inputs/entityBatches/7_VideoMediaEncodingBatch.json
  20. 8 0
      content-directory-schemas/inputs/entityBatches/8_KnownLicenseBatch.json
  21. 2 2
      content-directory-schemas/inputs/schemas/10_LicenseSchema.json
  22. 35 0
      content-directory-schemas/inputs/schemas/11_VideoMediaSchema.json
  23. 97 0
      content-directory-schemas/inputs/schemas/12_VideoSchema.json
  24. 1 1
      content-directory-schemas/inputs/schemas/1_LanguageSchema.json
  25. 1 1
      content-directory-schemas/inputs/schemas/3_JoystreamMediaLocationSchema.json
  26. 2 2
      content-directory-schemas/inputs/schemas/4_MediaLocationSchema.json
  27. 1 1
      content-directory-schemas/inputs/schemas/6_ChannelSchema.json
  28. 0 0
      content-directory-schemas/inputs/schemas/7_VideoMediaEncodingSchema.json
  29. 1 1
      content-directory-schemas/inputs/schemas/9_UserDefinedLicenseSchema.json
  30. 13 3
      content-directory-schemas/package.json
  31. 75 0
      content-directory-schemas/schemas/entities/ChannelEntity.schema.json
  32. 23 0
      content-directory-schemas/schemas/entities/ContentCategoryEntity.schema.json
  33. 24 0
      content-directory-schemas/schemas/entities/HttpMediaLocationEntity.schema.json
  34. 18 0
      content-directory-schemas/schemas/entities/JoystreamMediaLocationEntity.schema.json
  35. 33 0
      content-directory-schemas/schemas/entities/KnownLicenseEntity.schema.json
  36. 24 0
      content-directory-schemas/schemas/entities/LanguageEntity.schema.json
  37. 69 0
      content-directory-schemas/schemas/entities/LicenseEntity.schema.json
  38. 69 0
      content-directory-schemas/schemas/entities/MediaLocationEntity.schema.json
  39. 18 0
      content-directory-schemas/schemas/entities/UserDefinedLicenseEntity.schema.json
  40. 217 0
      content-directory-schemas/schemas/entities/VideoEntity.schema.json
  41. 18 0
      content-directory-schemas/schemas/entities/VideoMediaEncodingEntity.schema.json
  42. 91 0
      content-directory-schemas/schemas/entities/VideoMediaEntity.schema.json
  43. 10 0
      content-directory-schemas/schemas/entityBatches/ChannelBatch.schema.json
  44. 10 0
      content-directory-schemas/schemas/entityBatches/ContentCategoryBatch.schema.json
  45. 10 0
      content-directory-schemas/schemas/entityBatches/HttpMediaLocationBatch.schema.json
  46. 10 0
      content-directory-schemas/schemas/entityBatches/JoystreamMediaLocationBatch.schema.json
  47. 10 0
      content-directory-schemas/schemas/entityBatches/KnownLicenseBatch.schema.json
  48. 10 0
      content-directory-schemas/schemas/entityBatches/LanguageBatch.schema.json
  49. 10 0
      content-directory-schemas/schemas/entityBatches/LicenseBatch.schema.json
  50. 10 0
      content-directory-schemas/schemas/entityBatches/MediaLocationBatch.schema.json
  51. 10 0
      content-directory-schemas/schemas/entityBatches/UserDefinedLicenseBatch.schema.json
  52. 10 0
      content-directory-schemas/schemas/entityBatches/VideoBatch.schema.json
  53. 10 0
      content-directory-schemas/schemas/entityBatches/VideoMediaBatch.schema.json
  54. 10 0
      content-directory-schemas/schemas/entityBatches/VideoMediaEncodingBatch.schema.json
  55. 26 0
      content-directory-schemas/schemas/entityReferences/ChannelRef.schema.json
  56. 26 0
      content-directory-schemas/schemas/entityReferences/ContentCategoryRef.schema.json
  57. 12 0
      content-directory-schemas/schemas/entityReferences/HttpMediaLocationRef.schema.json
  58. 26 0
      content-directory-schemas/schemas/entityReferences/JoystreamMediaLocationRef.schema.json
  59. 26 0
      content-directory-schemas/schemas/entityReferences/KnownLicenseRef.schema.json
  60. 26 0
      content-directory-schemas/schemas/entityReferences/LanguageRef.schema.json
  61. 12 0
      content-directory-schemas/schemas/entityReferences/LicenseRef.schema.json
  62. 12 0
      content-directory-schemas/schemas/entityReferences/MediaLocationRef.schema.json
  63. 12 0
      content-directory-schemas/schemas/entityReferences/UserDefinedLicenseRef.schema.json
  64. 26 0
      content-directory-schemas/schemas/entityReferences/VideoMediaEncodingRef.schema.json
  65. 12 0
      content-directory-schemas/schemas/entityReferences/VideoMediaRef.schema.json
  66. 12 0
      content-directory-schemas/schemas/entityReferences/VideoRef.schema.json
  67. 9 14
      content-directory-schemas/schemas/extrinsics/AddClassSchema.schema.json
  68. 7 3
      content-directory-schemas/schemas/extrinsics/CreateClass.schema.json
  69. 38 0
      content-directory-schemas/schemas/propertyValidationDefs.schema.json
  70. 81 0
      content-directory-schemas/scripts/devInitAliceLead.ts
  71. 141 0
      content-directory-schemas/scripts/helpers/EntityBatchParser.ts
  72. 15 0
      content-directory-schemas/scripts/helpers/entitySchemas.ts
  73. 26 0
      content-directory-schemas/scripts/helpers/inputs.ts
  74. 93 0
      content-directory-schemas/scripts/initializeContentDir.ts
  75. 145 0
      content-directory-schemas/scripts/inputSchemasToEntitySchemas.ts
  76. 41 0
      content-directory-schemas/scripts/schemasToTS.ts
  77. 11 26
      content-directory-schemas/scripts/validate.ts
  78. 9 3
      content-directory-schemas/tsconfig.json
  79. 71 0
      content-directory-schemas/types/entities/ChannelEntity.d.ts
  80. 20 0
      content-directory-schemas/types/entities/ContentCategoryEntity.d.ts
  81. 20 0
      content-directory-schemas/types/entities/HttpMediaLocationEntity.d.ts
  82. 16 0
      content-directory-schemas/types/entities/JoystreamMediaLocationEntity.d.ts
  83. 28 0
      content-directory-schemas/types/entities/KnownLicenseEntity.d.ts
  84. 20 0
      content-directory-schemas/types/entities/LanguageEntity.d.ts
  85. 78 0
      content-directory-schemas/types/entities/LicenseEntity.d.ts
  86. 70 0
      content-directory-schemas/types/entities/MediaLocationEntity.d.ts
  87. 16 0
      content-directory-schemas/types/entities/UserDefinedLicenseEntity.d.ts
  88. 402 0
      content-directory-schemas/types/entities/VideoEntity.d.ts
  89. 16 0
      content-directory-schemas/types/entities/VideoMediaEncodingEntity.d.ts
  90. 131 0
      content-directory-schemas/types/entities/VideoMediaEntity.d.ts
  91. 56 0
      content-directory-schemas/types/extrinsics/AddClassSchema.d.ts
  92. 30 0
      content-directory-schemas/types/extrinsics/CreateClass.d.ts
  93. 2 0
      content-directory-schemas/typings/@joystream/prettier-config/index.d.ts
  94. 50 2
      content-directory-schemas/vscode-recommended.settings.json
  95. 16 1
      types/src/content-directory/index.ts
  96. 0 188
      utils/api-examples/scripts/init-new-content-directory.js

+ 1 - 0
content-directory-schemas/.gitignore

@@ -0,0 +1 @@
+operations.json

+ 3 - 4
content-directory-schemas/README.md

@@ -1,10 +1,9 @@
 ### Content directory json schemas and inputs
 
 #### Working in `VSCode`
-1. Create `.vscode` folder inside your working directory (if doesn't already exist)
+1. Create `.vscode` folder inside your monorepo working directory (if doesn't already exist)
 1. Copy `vscode-recommended.settings.json` into `.vscode` directory and rename it to `settings.json` (or merge it with the exsisting `settings.json`)
-1. If your working directory is not `content-directory-schema`, modify the `"url"` properties under `"json.schemas"` to match the relative paths from your working directory (ie. if inside root monorepo directory, you will need to add `/content-directory-schema`)
-1. Get the benefit of live-validation of files inside `inputs`! (you must follow the `*Class.json`, `*Schema.json` naming pattern)
+1. Get the benefit of live-validation of files inside `inputs`! (you must follow the `*Class.json`, `*Schema.json`, `*{EntityName}Batch` naming pattern)
 
 #### Validate via CLI
-Run `yarn workspace cd-schemas validate` or `yarn validate` (if inside `content-directory-schemas`) to validate json schemas and all inputs in the `/inputs` directory.
+Run `yarn workspace cd-schemas validate` or `yarn validate` (if inside `content-directory-schemas`) to validate json schemas and inputs inside the `/inputs` directory.

+ 3 - 1
content-directory-schemas/inputs/classes/10_LicenseClass.json

@@ -1,4 +1,6 @@
 {
   "name": "License",
-  "description": "Describes a license the media can be published under"
+  "description": "Describes a license the media can be published under",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 6 - 0
content-directory-schemas/inputs/classes/11_VideoMediaClass.json

@@ -0,0 +1,6 @@
+{
+  "name": "VideoMedia",
+  "description": "Describes a video media object",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
+}

+ 6 - 0
content-directory-schemas/inputs/classes/12_VideoClass.json

@@ -0,0 +1,6 @@
+{
+  "name": "Video",
+  "description": "Describes a Video",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
+}

+ 3 - 1
content-directory-schemas/inputs/classes/1_LanguageClass.json

@@ -1,4 +1,6 @@
 {
   "name": "Language",
-  "description": "A language in which the content on the platform may be published"
+  "description": "A language in which the content on the platform may be published",
+  "maximum_entities_count": 100,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/2_HttpMediaLocationClass.json

@@ -1,4 +1,6 @@
 {
   "name": "HttpMediaLocation",
-  "description": "An object describing http location of media object"
+  "description": "An object describing http location of media object",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/3_JoystreamMediaLocationClass.json

@@ -1,4 +1,6 @@
 {
   "name": "JoystreamMediaLocation",
-  "description": "An object describing location of media object in a format specific to Joystream platform"
+  "description": "An object describing location of media object in a format specific to Joystream platform",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/4_MediaLocationClass.json

@@ -1,4 +1,6 @@
 {
   "name": "MediaLocationClass",
-  "description": "An object describing how the related media object can be accessed"
+  "description": "An object describing how the related media object can be accessed",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/5_ContentCategoryClass.json

@@ -1,4 +1,6 @@
 {
   "name": "ContentCategory",
-  "description": "A category the content may be published under"
+  "description": "A category the content may be published under",
+  "maximum_entities_count": 100,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/6_ChannelClass.json

@@ -1,4 +1,6 @@
 {
   "name": "Channel",
-  "description": "A channel belonging to certain member. Members can publish certain type of content (ie. videos) through channels."
+  "description": "A channel belonging to certain member. Members can publish certain type of content (ie. videos) through channels.",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/7_VideoMediaEncodingClass.json

@@ -1,4 +1,6 @@
 {
   "name": "VideoMediaEncoding",
-  "description": "Available encoding format for the video media"
+  "description": "Available encoding format for the video media",
+  "maximum_entities_count": 100,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/8_KnownLicenseClass.json

@@ -1,4 +1,6 @@
 {
   "name": "KnownLicenseType",
-  "description": "A commonly recognized license (ie. CC_BY_SA)"
+  "description": "A commonly recognized license (ie. CC_BY_SA)",
+  "maximum_entities_count": 100,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 3 - 1
content-directory-schemas/inputs/classes/9_UserDefinedLicenseClass.json

@@ -1,4 +1,6 @@
 {
   "name": "UserDefinedLicense",
-  "description": "Custom license defined by the user"
+  "description": "Custom license defined by the user",
+  "maximum_entities_count": 400,
+  "default_entity_creation_voucher_upper_bound": 50
 }

+ 62 - 0
content-directory-schemas/inputs/entityBatches/12_VideoBatch.json

@@ -0,0 +1,62 @@
+[
+  {
+    "title": "Caminades 2",
+    "description": "Caminandes 2: Gran Dillama",
+    "language": { "existing": { "Code": "EN" } },
+    "category": { "existing": { "Name": "Cartoon" } },
+    "channel": { "existing": { "title": "Joystream Cartoons" } },
+    "duration": 146,
+    "hasMarketing": false,
+    "isCurated": false,
+    "isPublic": true,
+    "media": {
+      "new": {
+        "encoding": { "existing": { "Name": "MPEG4" } },
+        "location": {
+          "new": {
+            "httpMediaLocation": {
+              "new": {
+                "url": "http://www.caminandes.com/download/02_gran_dillama_1080p.zip"
+              }
+            }
+          }
+        },
+        "pixelWidth": 1920,
+        "pixelHeight": 1080
+      }
+    },
+    "thumbnailURL": "http://www.caminandes.com/wp-content/uploads/2016/02/web_header4.png",
+    "isExplicit": false,
+    "license": { "new": { "knownLicense": { "existing": { "code": "CC_BY" } } } }
+  },
+  {
+    "title": "Caminades 3",
+    "description": "Caminandes 3: Llamigos",
+    "language": { "existing": { "Code": "EN" } },
+    "category": { "existing": { "Name": "Cartoon" } },
+    "channel": { "existing": { "title": "Joystream Cartoons" } },
+    "duration": 150,
+    "hasMarketing": false,
+    "isCurated": false,
+    "isPublic": true,
+    "media": {
+      "new": {
+        "encoding": { "existing": { "Name": "MPEG4" } },
+        "location": {
+          "new": {
+            "httpMediaLocation": {
+              "new": {
+                "url": "http://www.caminandes.com/download/03_caminandes_llamigos_1080p.mp4"
+              }
+            }
+          }
+        },
+        "pixelWidth": 1920,
+        "pixelHeight": 1080
+      }
+    },
+    "thumbnailURL": "http://www.caminandes.com/wp-content/uploads/2016/02/web_header4.png",
+    "isExplicit": false,
+    "license": { "new": { "knownLicense": { "existing": { "code": "CC_BY" } } } }
+  }
+]

+ 5 - 0
content-directory-schemas/inputs/entityBatches/1_LanguageBatch.json

@@ -0,0 +1,5 @@
+[
+  { "Code": "EN", "Name": "English" },
+  { "Code": "RU", "Name": "Russian" },
+  { "Code": "DE", "Name": "German" }
+]

+ 4 - 0
content-directory-schemas/inputs/entityBatches/5_ContentCategoryBatch.json

@@ -0,0 +1,4 @@
+[
+  { "Name": "Cartoon", "Description": "Content which is a cartoon or related to cartoons" },
+  { "Name": "Sports", "Description": "Content related to sports" }
+]

+ 11 - 0
content-directory-schemas/inputs/entityBatches/6_ChannelBatch.json

@@ -0,0 +1,11 @@
+[
+  {
+    "title": "Joystream Cartoons",
+    "description": "Joystream Cartoons channel",
+    "language": { "existing": { "Code": "EN" } },
+    "coverPhotoUrl": "https://user-images.githubusercontent.com/4144334/91547902-7e90db00-e91c-11ea-9f5c-45d4921928d5.png",
+    "avatarPhotoURL": "https://user-images.githubusercontent.com/4144334/91546674-ba2aa580-e91a-11ea-96e2-abc7654c0461.png",
+    "isPublic": true,
+    "isCurated": false
+  }
+]

+ 3 - 0
content-directory-schemas/inputs/entityBatches/7_VideoMediaEncodingBatch.json

@@ -0,0 +1,3 @@
+[
+  { "Name": "MPEG4" }
+]

+ 8 - 0
content-directory-schemas/inputs/entityBatches/8_KnownLicenseBatch.json

@@ -0,0 +1,8 @@
+[
+  { "code": "CC_BY" },
+  { "code": "CC_BY_SA" },
+  { "code": "CC_BY_ND" },
+  { "code": "CC_BY_NC" },
+  { "code": "CC_BY_NC_SA" },
+  { "code": "CC_BY_NC_ND" }
+]

+ 2 - 2
content-directory-schemas/inputs/schemas/10_LicenseSchema.json

@@ -5,13 +5,13 @@
       "name": "knownLicense",
       "description": "Reference to a known license",
       "required": false,
-      "property_type": { "Single": { "Reference": { "classId": 8 } } }
+      "property_type": { "Single": { "Reference": [8, false] } }
     },
     {
       "name": "userDefinedLicense",
       "description": "Reference to user-defined license",
       "required": false,
-      "property_type": { "Single": { "Reference": { "classId": 9, "sameOwner": true } } }
+      "property_type": { "Single": { "Reference": [9, true] } }
     }
   ]
 }

+ 35 - 0
content-directory-schemas/inputs/schemas/11_VideoMediaSchema.json

@@ -0,0 +1,35 @@
+{
+  "classId": 11,
+  "newProperties": [
+    {
+      "name": "encoding",
+      "description": "Encoding of the video media object",
+      "required": true,
+      "property_type": { "Single": { "Reference": [7, false] } }
+    },
+    {
+      "name": "pixelWidth",
+      "description": "Video media width in pixels",
+      "required": true,
+      "property_type": { "Single": "Uint16" }
+    },
+    {
+      "name": "pixelHeight",
+      "description": "Video media height in pixels",
+      "required": true,
+      "property_type": { "Single": "Uint16" }
+    },
+    {
+      "name": "size",
+      "description": "Video media size in bytes",
+      "required": false,
+      "property_type": { "Single": "Uint64" }
+    },
+    {
+      "name": "location",
+      "description": "Location of the video media object",
+      "required": true,
+      "property_type": { "Single": { "Reference": [4, true] } }
+    }
+  ]
+}

+ 97 - 0
content-directory-schemas/inputs/schemas/12_VideoSchema.json

@@ -0,0 +1,97 @@
+{
+  "classId": 12,
+  "newProperties": [
+    {
+      "name": "channel",
+      "description": "Reference to member's channel",
+      "required": true,
+      "property_type": { "Single": { "Reference": [6, true] } }
+    },
+    {
+      "name": "category",
+      "description": "Reference to a video category",
+      "required": true,
+      "property_type": { "Single": { "Reference": [5, false] } }
+    },
+    {
+      "name": "title",
+      "description": "The title of the video",
+      "required": true,
+      "property_type": { "Single": { "Text": 64 } }
+    },
+    {
+      "name": "description",
+      "description": "The description of the Video",
+      "required": true,
+      "property_type": { "Single": { "Text": 1024 } }
+    },
+    {
+      "name": "duration",
+      "description": "Video duration in seconds",
+      "required": true,
+      "property_type": { "Single": "Uint32" }
+    },
+    {
+      "name": "skippableIntroDuration",
+      "description": "Video's kippable intro duration in seconds",
+      "required": false,
+      "property_type": { "Single": "Uint16" }
+    },
+    {
+      "name": "thumbnailURL",
+      "description": "Video thumbnail url (recommended ratio: 16:9)",
+      "required": true,
+      "property_type": { "Single": { "Text": 256 } }
+    },
+    {
+      "name": "language",
+      "description": "Video's main langauge",
+      "required": false,
+      "property_type": { "Single": { "Reference": [1, false] } }
+    },
+    {
+      "name": "media",
+      "description": "Reference to VideoMedia",
+      "required": true,
+      "property_type": { "Single": { "Reference": [11, true] } }
+    },
+    {
+      "name": "hasMarketing",
+      "description": "Whether or not Video contains marketing",
+      "required": false,
+      "property_type": { "Single": "Bool" }
+    },
+    {
+      "name": "publishedBeforeJoystream",
+      "description": "If the Video was published on other platform before beeing published on Joystream - the original publication date",
+      "required": false,
+      "property_type": { "Single": "Uint32" }
+    },
+    {
+      "name": "isPublic",
+      "description": "Whether the Video is supposed to be publically displayed",
+      "required": true,
+      "property_type": { "Single": "Bool" }
+    },
+    {
+      "name": "isCurated",
+      "description": "Whether the Video has been curated (verified) by a Curator",
+      "required": true,
+      "property_type": { "Single": "Bool" },
+      "locking_policy": { "is_locked_from_controller": true }
+    },
+    {
+      "name": "isExplicit",
+      "description": "Whether the Video contains explicit material.",
+      "required": true,
+      "property_type": { "Single": "Bool" },
+      "locking_policy": { "is_locked_from_controller": true }
+    },
+    {
+      "name": "license",
+      "description": "A License the Video is published under",
+      "required": true,
+      "property_type": { "Single": { "Reference": [10, true] } }
+    }
+  ]
+}

+ 1 - 1
content-directory-schemas/inputs/schemas/1_LanguageSchema.json

@@ -5,13 +5,13 @@
       "name": "Name",
       "description": "The name of the language (ie. English)",
       "required": true,
-      "unique": true,
       "property_type": { "Single": { "Text": 64 } }
     },
     {
       "name": "Code",
       "description": "ISO 639-1 code of the language (ie. en)",
       "required": true,
+      "unique": true,
       "property_type": { "Single": { "Text": 2 } }
     }
   ]

+ 1 - 1
content-directory-schemas/inputs/schemas/3_JoystreamMediaLocationSchema.json

@@ -4,7 +4,7 @@
     {
       "name": "dataObjectId",
       "description": "Id of the data object in the Joystream runtime dataDirectory module",
-      "property_type": { "Single": "Uint64" },
+      "property_type": { "Single": { "Text": 48 } },
       "required": true,
       "unique": true
     }

+ 2 - 2
content-directory-schemas/inputs/schemas/4_MediaLocationSchema.json

@@ -6,13 +6,13 @@
       "name": "httpMediaLocation",
       "description": "A reference to HttpMediaLocation",
       "required": false,
-      "property_type": { "Single": { "Reference": { "classId": 2, "sameOwner": true } } }
+      "property_type": { "Single": { "Reference": [2, true] } }
     },
     {
       "name": "joystreamMediaLocation",
       "description": "A reference to JoystreamMediaLocation",
       "required": false,
-      "property_type": { "Single": { "Reference": { "classId": 3, "sameOwner": true } } }
+      "property_type": { "Single": { "Reference": [3, true] } }
     }
   ]
 }

+ 1 - 1
content-directory-schemas/inputs/schemas/6_ChannelSchema.json

@@ -44,7 +44,7 @@
       "name": "language",
       "description": "The primary langauge of the channel's content",
       "required": false,
-      "property_type": { "Single": { "Reference": { "classId": 1, "sameOwner": false } } }
+      "property_type": { "Single": { "Reference": [1, false] } }
     }
   ]
 }

+ 0 - 0
content-directory-schemas/inputs/schemas/7_VideoMediaEncoding.json → content-directory-schemas/inputs/schemas/7_VideoMediaEncodingSchema.json


+ 1 - 1
content-directory-schemas/inputs/schemas/9_UserDefinedLicenseSchema.json

@@ -6,7 +6,7 @@
       "description": "Custom license content",
       "required": true,
       "property_type": {
-        "Single": { "Text": 65535 }
+        "Single": { "Text": 4096 }
       }
     }
   ]

+ 13 - 3
content-directory-schemas/package.json

@@ -4,14 +4,24 @@
   "description": "JSON schemas, inputs and related tooling for Joystream content directory 2.0",
   "author": "Joystream contributors",
   "scripts": {
-    "validate": "ts-node ./scripts/validate.ts"
+    "validate": "ts-node ./scripts/validate.ts",
+    "generate:types": "ts-node --files ./scripts/schemasToTS.ts",
+    "generate:entity-schemas": "ts-node ./scripts/inputSchemasToEntitySchemas.ts",
+    "generate:all": "yarn generate:entity-schemas && yarn generate:types",
+    "initialize:alice-as-lead": "ts-node ./scripts/devInitAliceLead.ts",
+    "initialize:content-dir": "ts-node ./scripts/initializeContentDir.ts",
+    "initialize:dev": "yarn initialize:alice-as-lead && yarn initialize:content-dir"
   },
   "dependencies": {
-    "ajv": "6.12.5"
+    "ajv": "6.12.5",
+    "@joystream/prettier-config": "*",
+    "@polkadot/api": "1.26.1",
+    "@joystream/types": "^0.14.0"
   },
   "devDependencies": {
     "ts-node": "^8.8.2",
-    "typescript": "^3.9.7"
+    "typescript": "^3.9.7",
+    "json-schema-to-typescript": "^9.1.1"
   },
   "repository": {
     "type": "git",

+ 75 - 0
content-directory-schemas/schemas/entities/ChannelEntity.schema.json

@@ -0,0 +1,75 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ChannelEntity.schema.json",
+    "title": "ChannelEntity",
+    "description": "JSON schema for entities based on Channel runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "title",
+        "description",
+        "coverPhotoUrl",
+        "avatarPhotoURL",
+        "isPublic",
+        "isCurated"
+    ],
+    "properties": {
+        "title": {
+            "type": "string",
+            "maxLength": 64,
+            "description": "The title of the Channel"
+        },
+        "description": {
+            "type": "string",
+            "maxLength": 1024,
+            "description": "The description of a Channel"
+        },
+        "coverPhotoUrl": {
+            "type": "string",
+            "maxLength": 256,
+            "description": "Url for Channel's cover (background) photo. Recommended ratio: 16:9."
+        },
+        "avatarPhotoURL": {
+            "type": "string",
+            "maxLength": 256,
+            "description": "Channel's avatar photo."
+        },
+        "isPublic": {
+            "type": "boolean",
+            "description": "Flag signaling whether a channel is public."
+        },
+        "isCurated": {
+            "type": "boolean",
+            "description": "Flag signaling whether a channel is curated/verified."
+        },
+        "language": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./LanguageEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/LanguageRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "The primary langauge of the channel's content"
+        }
+    }
+}

+ 23 - 0
content-directory-schemas/schemas/entities/ContentCategoryEntity.schema.json

@@ -0,0 +1,23 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ContentCategoryEntity.schema.json",
+    "title": "ContentCategoryEntity",
+    "description": "JSON schema for entities based on ContentCategory runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "Name"
+    ],
+    "properties": {
+        "Name": {
+            "type": "string",
+            "maxLength": 64,
+            "description": "The name of the category"
+        },
+        "Description": {
+            "type": "string",
+            "maxLength": 1024,
+            "description": "The description of the category"
+        }
+    }
+}

+ 24 - 0
content-directory-schemas/schemas/entities/HttpMediaLocationEntity.schema.json

@@ -0,0 +1,24 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/HttpMediaLocationEntity.schema.json",
+    "title": "HttpMediaLocationEntity",
+    "description": "JSON schema for entities based on HttpMediaLocation runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "url"
+    ],
+    "properties": {
+        "url": {
+            "type": "string",
+            "maxLength": 256,
+            "description": "The http url pointing to the media"
+        },
+        "port": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 65535,
+            "description": "The port to use when connecting to the http url (defaults to 80)"
+        }
+    }
+}

+ 18 - 0
content-directory-schemas/schemas/entities/JoystreamMediaLocationEntity.schema.json

@@ -0,0 +1,18 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/JoystreamMediaLocationEntity.schema.json",
+    "title": "JoystreamMediaLocationEntity",
+    "description": "JSON schema for entities based on JoystreamMediaLocation runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "dataObjectId"
+    ],
+    "properties": {
+        "dataObjectId": {
+            "type": "string",
+            "maxLength": 48,
+            "description": "Id of the data object in the Joystream runtime dataDirectory module"
+        }
+    }
+}

+ 33 - 0
content-directory-schemas/schemas/entities/KnownLicenseEntity.schema.json

@@ -0,0 +1,33 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/KnownLicenseEntity.schema.json",
+    "title": "KnownLicenseEntity",
+    "description": "JSON schema for entities based on KnownLicense runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "code"
+    ],
+    "properties": {
+        "code": {
+            "type": "string",
+            "maxLength": 16,
+            "description": "Short, commonly recognized code of the licence (ie. CC_BY_SA)"
+        },
+        "name": {
+            "type": "string",
+            "maxLength": 64,
+            "description": "Full, descriptive name of the license (ie. Creative Commons - Attribution-NonCommercial-NoDerivs)"
+        },
+        "description": {
+            "type": "string",
+            "maxLength": 1024,
+            "description": "Short description of the license conditions"
+        },
+        "url": {
+            "type": "string",
+            "maxLength": 256,
+            "description": "An url pointing to full license content"
+        }
+    }
+}

+ 24 - 0
content-directory-schemas/schemas/entities/LanguageEntity.schema.json

@@ -0,0 +1,24 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LanguageEntity.schema.json",
+    "title": "LanguageEntity",
+    "description": "JSON schema for entities based on Language runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "Name",
+        "Code"
+    ],
+    "properties": {
+        "Name": {
+            "type": "string",
+            "maxLength": 64,
+            "description": "The name of the language (ie. English)"
+        },
+        "Code": {
+            "type": "string",
+            "maxLength": 2,
+            "description": "ISO 639-1 code of the language (ie. en)"
+        }
+    }
+}

+ 69 - 0
content-directory-schemas/schemas/entities/LicenseEntity.schema.json

@@ -0,0 +1,69 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LicenseEntity.schema.json",
+    "title": "LicenseEntity",
+    "description": "JSON schema for entities based on License runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [],
+    "properties": {
+        "knownLicense": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./KnownLicenseEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/KnownLicenseRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Reference to a known license"
+        },
+        "userDefinedLicense": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./UserDefinedLicenseEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/UserDefinedLicenseRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Reference to user-defined license"
+        }
+    }
+}

+ 69 - 0
content-directory-schemas/schemas/entities/MediaLocationEntity.schema.json

@@ -0,0 +1,69 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/MediaLocationEntity.schema.json",
+    "title": "MediaLocationEntity",
+    "description": "JSON schema for entities based on MediaLocation runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [],
+    "properties": {
+        "httpMediaLocation": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./HttpMediaLocationEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/HttpMediaLocationRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "A reference to HttpMediaLocation"
+        },
+        "joystreamMediaLocation": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./JoystreamMediaLocationEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/JoystreamMediaLocationRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "A reference to JoystreamMediaLocation"
+        }
+    }
+}

+ 18 - 0
content-directory-schemas/schemas/entities/UserDefinedLicenseEntity.schema.json

@@ -0,0 +1,18 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/UserDefinedLicenseEntity.schema.json",
+    "title": "UserDefinedLicenseEntity",
+    "description": "JSON schema for entities based on UserDefinedLicense runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "content"
+    ],
+    "properties": {
+        "content": {
+            "type": "string",
+            "maxLength": 4096,
+            "description": "Custom license content"
+        }
+    }
+}

+ 217 - 0
content-directory-schemas/schemas/entities/VideoEntity.schema.json

@@ -0,0 +1,217 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoEntity.schema.json",
+    "title": "VideoEntity",
+    "description": "JSON schema for entities based on Video runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "channel",
+        "category",
+        "title",
+        "description",
+        "duration",
+        "thumbnailURL",
+        "media",
+        "isPublic",
+        "isCurated",
+        "isExplicit",
+        "license"
+    ],
+    "properties": {
+        "channel": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./ChannelEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/ChannelRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Reference to member's channel"
+        },
+        "category": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./ContentCategoryEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/ContentCategoryRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Reference to a video category"
+        },
+        "title": {
+            "type": "string",
+            "maxLength": 64,
+            "description": "The title of the video"
+        },
+        "description": {
+            "type": "string",
+            "maxLength": 1024,
+            "description": "The description of the Video"
+        },
+        "duration": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 4294967295,
+            "description": "Video duration in seconds"
+        },
+        "skippableIntroDuration": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 65535,
+            "description": "Video's kippable intro duration in seconds"
+        },
+        "thumbnailURL": {
+            "type": "string",
+            "maxLength": 256,
+            "description": "Video thumbnail url (recommended ratio: 16:9)"
+        },
+        "language": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./LanguageEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/LanguageRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Video's main langauge"
+        },
+        "media": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./VideoMediaEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/VideoMediaRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Reference to VideoMedia"
+        },
+        "hasMarketing": {
+            "type": "boolean",
+            "description": "Whether or not Video contains marketing"
+        },
+        "publishedBeforeJoystream": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 4294967295,
+            "description": "If the Video was published on other platform before beeing published on Joystream - the original publication date"
+        },
+        "isPublic": {
+            "type": "boolean",
+            "description": "Whether the Video is supposed to be publically displayed"
+        },
+        "isCurated": {
+            "type": "boolean",
+            "description": "Whether the Video has been curated (verified) by a Curator"
+        },
+        "isExplicit": {
+            "type": "boolean",
+            "description": "Whether the Video contains explicit material."
+        },
+        "license": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./LicenseEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/LicenseRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "A License the Video is published under"
+        }
+    }
+}

+ 18 - 0
content-directory-schemas/schemas/entities/VideoMediaEncodingEntity.schema.json

@@ -0,0 +1,18 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaEncodingEntity.schema.json",
+    "title": "VideoMediaEncodingEntity",
+    "description": "JSON schema for entities based on VideoMediaEncoding runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "Name"
+    ],
+    "properties": {
+        "Name": {
+            "type": "string",
+            "maxLength": 32,
+            "description": "The name of the encoding format (ie. H264_mpeg4)"
+        }
+    }
+}

+ 91 - 0
content-directory-schemas/schemas/entities/VideoMediaEntity.schema.json

@@ -0,0 +1,91 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaEntity.schema.json",
+    "title": "VideoMediaEntity",
+    "description": "JSON schema for entities based on VideoMedia runtime schema",
+    "type": "object",
+    "additionalProperties": false,
+    "required": [
+        "encoding",
+        "pixelWidth",
+        "pixelHeight",
+        "location"
+    ],
+    "properties": {
+        "encoding": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./VideoMediaEncodingEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/VideoMediaEncodingRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Encoding of the video media object"
+        },
+        "pixelWidth": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 65535,
+            "description": "Video media width in pixels"
+        },
+        "pixelHeight": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 65535,
+            "description": "Video media height in pixels"
+        },
+        "size": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Video media size in bytes"
+        },
+        "location": {
+            "oneOf": [
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "new"
+                    ],
+                    "properties": {
+                        "new": {
+                            "$ref": "./MediaLocationEntity.schema.json"
+                        }
+                    }
+                },
+                {
+                    "type": "object",
+                    "additionalProperties": false,
+                    "required": [
+                        "existing"
+                    ],
+                    "properties": {
+                        "existing": {
+                            "$ref": "../entityReferences/MediaLocationRef.schema.json"
+                        }
+                    }
+                }
+            ],
+            "description": "Location of the video media object"
+        }
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/ChannelBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ChannelBatch.schema.json",
+    "title": "ChannelBatch",
+    "description": "JSON schema for batch of entities based on Channel runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/ChannelEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/ContentCategoryBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ContentCategoryBatch.schema.json",
+    "title": "ContentCategoryBatch",
+    "description": "JSON schema for batch of entities based on ContentCategory runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/ContentCategoryEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/HttpMediaLocationBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/HttpMediaLocationBatch.schema.json",
+    "title": "HttpMediaLocationBatch",
+    "description": "JSON schema for batch of entities based on HttpMediaLocation runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/HttpMediaLocationEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/JoystreamMediaLocationBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/JoystreamMediaLocationBatch.schema.json",
+    "title": "JoystreamMediaLocationBatch",
+    "description": "JSON schema for batch of entities based on JoystreamMediaLocation runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/JoystreamMediaLocationEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/KnownLicenseBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/KnownLicenseBatch.schema.json",
+    "title": "KnownLicenseBatch",
+    "description": "JSON schema for batch of entities based on KnownLicense runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/KnownLicenseEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/LanguageBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LanguageBatch.schema.json",
+    "title": "LanguageBatch",
+    "description": "JSON schema for batch of entities based on Language runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/LanguageEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/LicenseBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LicenseBatch.schema.json",
+    "title": "LicenseBatch",
+    "description": "JSON schema for batch of entities based on License runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/LicenseEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/MediaLocationBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/MediaLocationBatch.schema.json",
+    "title": "MediaLocationBatch",
+    "description": "JSON schema for batch of entities based on MediaLocation runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/MediaLocationEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/UserDefinedLicenseBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/UserDefinedLicenseBatch.schema.json",
+    "title": "UserDefinedLicenseBatch",
+    "description": "JSON schema for batch of entities based on UserDefinedLicense runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/UserDefinedLicenseEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/VideoBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoBatch.schema.json",
+    "title": "VideoBatch",
+    "description": "JSON schema for batch of entities based on Video runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/VideoEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/VideoMediaBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaBatch.schema.json",
+    "title": "VideoMediaBatch",
+    "description": "JSON schema for batch of entities based on VideoMedia runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/VideoMediaEntity.schema.json"
+    }
+}

+ 10 - 0
content-directory-schemas/schemas/entityBatches/VideoMediaEncodingBatch.schema.json

@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaEncodingBatch.schema.json",
+    "title": "VideoMediaEncodingBatch",
+    "description": "JSON schema for batch of entities based on VideoMediaEncoding runtime schema",
+    "type": "array",
+    "items": {
+        "$ref": "../entities/VideoMediaEncodingEntity.schema.json"
+    }
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/ChannelRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ChannelReference.schema.json",
+    "title": "ChannelReference",
+    "description": "JSON schema for reference to Channel entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "title"
+            ],
+            "properties": {
+                "title": {
+                    "type": "string",
+                    "maxLength": 64,
+                    "description": "The title of the Channel"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/ContentCategoryRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/ContentCategoryReference.schema.json",
+    "title": "ContentCategoryReference",
+    "description": "JSON schema for reference to ContentCategory entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "Name"
+            ],
+            "properties": {
+                "Name": {
+                    "type": "string",
+                    "maxLength": 64,
+                    "description": "The name of the category"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/HttpMediaLocationRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/HttpMediaLocationReference.schema.json",
+    "title": "HttpMediaLocationReference",
+    "description": "JSON schema for reference to HttpMediaLocation entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/JoystreamMediaLocationRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/JoystreamMediaLocationReference.schema.json",
+    "title": "JoystreamMediaLocationReference",
+    "description": "JSON schema for reference to JoystreamMediaLocation entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "dataObjectId"
+            ],
+            "properties": {
+                "dataObjectId": {
+                    "type": "string",
+                    "maxLength": 48,
+                    "description": "Id of the data object in the Joystream runtime dataDirectory module"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/KnownLicenseRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/KnownLicenseReference.schema.json",
+    "title": "KnownLicenseReference",
+    "description": "JSON schema for reference to KnownLicense entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "code"
+            ],
+            "properties": {
+                "code": {
+                    "type": "string",
+                    "maxLength": 16,
+                    "description": "Short, commonly recognized code of the licence (ie. CC_BY_SA)"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/LanguageRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LanguageReference.schema.json",
+    "title": "LanguageReference",
+    "description": "JSON schema for reference to Language entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "Code"
+            ],
+            "properties": {
+                "Code": {
+                    "type": "string",
+                    "maxLength": 2,
+                    "description": "ISO 639-1 code of the language (ie. en)"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/LicenseRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/LicenseReference.schema.json",
+    "title": "LicenseReference",
+    "description": "JSON schema for reference to License entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/MediaLocationRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/MediaLocationReference.schema.json",
+    "title": "MediaLocationReference",
+    "description": "JSON schema for reference to MediaLocation entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/UserDefinedLicenseRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/UserDefinedLicenseReference.schema.json",
+    "title": "UserDefinedLicenseReference",
+    "description": "JSON schema for reference to UserDefinedLicense entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 26 - 0
content-directory-schemas/schemas/entityReferences/VideoMediaEncodingRef.schema.json

@@ -0,0 +1,26 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaEncodingReference.schema.json",
+    "title": "VideoMediaEncodingReference",
+    "description": "JSON schema for reference to VideoMediaEncoding entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "object",
+            "additionalProperties": false,
+            "required": [
+                "Name"
+            ],
+            "properties": {
+                "Name": {
+                    "type": "string",
+                    "maxLength": 32,
+                    "description": "The name of the encoding format (ie. H264_mpeg4)"
+                }
+            }
+        },
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/VideoMediaRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoMediaReference.schema.json",
+    "title": "VideoMediaReference",
+    "description": "JSON schema for reference to VideoMedia entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 12 - 0
content-directory-schemas/schemas/entityReferences/VideoRef.schema.json

@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "$id": "https://joystream.org/VideoReference.schema.json",
+    "title": "VideoReference",
+    "description": "JSON schema for reference to Video entity based on runtime schema",
+    "anyOf": [
+        {
+            "type": "integer",
+            "minimum": 0
+        }
+    ]
+}

+ 9 - 14
content-directory-schemas/schemas/AddClassSchema.schema.json → content-directory-schemas/schemas/extrinsics/AddClassSchema.schema.json

@@ -6,11 +6,8 @@
   "type": "object",
   "additionalProperties": false,
   "required": [
-    "classId"
-  ],
-  "anyOf": [
-    { "required": [ "newProperties" ] },
-    { "required": [ "existingProperties" ] }
+    "classId",
+    "newProperties"
   ],
   "properties": {
     "classId": { "$ref": "#/definitions/ClassId" },
@@ -143,15 +140,13 @@
       "required": ["Reference"],
       "properties": {
         "Reference": {
-          "type": "object",
-          "additionalProperties": false,
-          "required": [
-            "classId"
-          ],
-          "properties": {
-            "sameOwner": { "$ref": "#/definitions/DefaultBoolean" },
-            "classId": { "$ref": "#/definitions/ClassId" }
-          }
+          "type": "array",
+          "minItems": 2,
+          "additionalItems": false,
+          "items": [
+            { "$ref": "#/definitions/ClassId", "description": "Referenced class ID" },
+            { "$ref": "#/definitions/DefaultBoolean", "description": "Same owner required (flag)" }
+          ]
         }
       }
     },

+ 7 - 3
content-directory-schemas/schemas/CreateClass.schema.json → content-directory-schemas/schemas/extrinsics/CreateClass.schema.json

@@ -7,7 +7,9 @@
   "additionalProperties": false,
   "required": [
     "name",
-    "description"
+    "description",
+    "maximum_entities_count",
+    "default_entity_creation_voucher_upper_bound"
   ],
   "properties": {
     "name": {
@@ -29,12 +31,14 @@
           "type": "array",
           "uniqueItems": true,
           "items": {
-            "type": "number"
+            "type": "integer"
           },
           "default": []
         }
       }
-    }
+    },
+    "maximum_entities_count": { "type": "integer" },
+    "default_entity_creation_voucher_upper_bound": { "type": "integer" }
   },
   "definitions": {
     "DefaultBoolean": {

+ 38 - 0
content-directory-schemas/schemas/propertyValidationDefs.schema.json

@@ -0,0 +1,38 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema",
+  "$id": "https://joystream.org/propertyValidationDefs.schema.json",
+  "title": "propertyValidationDefs",
+  "description": "JSON schema containing definitions for different property types input",
+  "definitions": {
+    "Bool": {
+      "type": "boolean"
+    },
+    "Uint16": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 65535
+    },
+    "Uint32": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 4294967295
+    },
+    "Uint64": {
+      "type": "integer",
+      "minimum": 0
+    },
+    "Int16": {
+      "type": "integer",
+      "minimum": -32768,
+      "maximum": 32767
+    },
+    "Int32": {
+      "type": "integer",
+      "minimum": -2147483648,
+      "maximum": 2147483647
+    },
+    "Int64": {
+      "type": "integer"
+    }
+  }
+}

+ 81 - 0
content-directory-schemas/scripts/devInitAliceLead.ts

@@ -0,0 +1,81 @@
+import { types } from '@joystream/types'
+import { ApiPromise, Keyring, WsProvider } from '@polkadot/api'
+import { SubmittableExtrinsic } from '@polkadot/api/types'
+
+async function main() {
+  // Init api
+  const WS_URI = process.env.WS_URI || 'ws://127.0.0.1:9944'
+  console.log(`Initializing the api (${WS_URI})...`)
+  const provider = new WsProvider(WS_URI)
+  const api = await ApiPromise.create({ provider, types })
+  // Init ALICE keypair
+  const keyring = new Keyring({ type: 'sr25519' })
+  keyring.addFromUri('//Alice', { name: 'Alice' })
+  const ALICE = keyring.getPairs()[0]
+
+  let nonce = (await api.query.system.account(ALICE.address)).nonce.toNumber()
+  const stdCall = (tx: SubmittableExtrinsic<'promise'>) => tx.signAndSend(ALICE, { nonce: nonce++ })
+  const sudoCall = (tx: SubmittableExtrinsic<'promise'>) => api.tx.sudo.sudo(tx).signAndSend(ALICE, { nonce: nonce++ })
+
+  // Create membership if not already created
+  let aliceMemberId: number | undefined = (await api.query.members.memberIdsByControllerAccountId(ALICE.address))
+    .toArray()[0]
+    ?.toNumber()
+
+  if (aliceMemberId === undefined) {
+    console.log('Sending Alice member account creation extrinsic...')
+    aliceMemberId = (await api.query.members.nextMemberId()).toNumber()
+    await stdCall(api.tx.members.buyMembership(0, 'alice', null, null))
+  } else {
+    console.log(`Alice member id found: ${aliceMemberId}...`)
+  }
+
+  // Set Alice as lead if lead not already set
+  if ((await api.query.contentDirectoryWorkingGroup.currentLead()).isNone) {
+    const newOpeningId = (await api.query.contentDirectoryWorkingGroup.nextOpeningId()).toNumber()
+    const newApplicationId = (await api.query.contentDirectoryWorkingGroup.nextApplicationId()).toNumber()
+    // Create curator lead opening
+    console.log('Sending Create Curator Lead Opening extrinsic...')
+    await sudoCall(
+      api.tx.contentDirectoryWorkingGroup.addOpening(
+        { CurrentBlock: null }, // activate_at
+        { max_review_period_length: 9999 }, // OpeningPolicyCommitment
+        'api-examples curator opening', // human_readable_text
+        'Leader' // opening_type
+      )
+    )
+
+    // Apply to lead opening
+    console.log('Sending Apply to Curator Lead Opening as Alice extrinsic...')
+    await stdCall(
+      api.tx.contentDirectoryWorkingGroup.applyOnOpening(
+        aliceMemberId, // member id
+        newOpeningId, // opening id
+        ALICE.address, // address
+        null, // opt role stake
+        null, // opt appl. stake
+        'api-examples curator opening appl.' // human_readable_text
+      )
+    )
+
+    // Begin review period
+    console.log('Sending Begin Applicant Review extrinsic...')
+    await sudoCall(api.tx.contentDirectoryWorkingGroup.beginApplicantReview(newOpeningId))
+
+    // Fill opening
+    console.log('Sending Fill Opening extrinsic...')
+    await sudoCall(
+      api.tx.contentDirectoryWorkingGroup.fillOpening(
+        newOpeningId, // opening id
+        api.createType('ApplicationIdSet', [newApplicationId]), // succesful applicants
+        null // reward policy
+      )
+    )
+  } else {
+    console.log('Curators lead already exists, skipping...')
+  }
+}
+
+main()
+  .then(() => process.exit())
+  .catch((e) => console.error(e))

+ 141 - 0
content-directory-schemas/scripts/helpers/EntityBatchParser.ts

@@ -0,0 +1,141 @@
+import { AddClassSchema } from '../../types/extrinsics/AddClassSchema'
+import { FetchedInput } from './inputs'
+import { createType } from '@joystream/types'
+import { blake2AsHex } from '@polkadot/util-crypto'
+import { OperationType, ParametrizedPropertyValue } from '@joystream/types/content-directory'
+
+// TODO: Make it more typesafe
+type Batch = Record<string, any>[]
+type FetchedBatch = FetchedInput<Batch>
+
+export class EntityBatchesParser {
+  schemaInputs: FetchedInput<AddClassSchema>[]
+  batchInputs: FetchedBatch[]
+  operations: OperationType[] = []
+  entityIndexByUniqueQueryMap = new Map<string, number>()
+
+  constructor(schemaInputs: FetchedInput<AddClassSchema>[], batchInputs: FetchedBatch[]) {
+    this.schemaInputs = schemaInputs
+    this.batchInputs = batchInputs
+  }
+
+  private schemaByEntityBatchFilename(entityBatchFilename: string) {
+    const foundSchema = this.schemaInputs.find(
+      ({ fileName: schemaFilename }) => schemaFilename.replace('Schema.json', 'Batch.json') === entityBatchFilename
+    )
+    if (!foundSchema) {
+      throw new Error(`Related schema not found for entity batch: ${entityBatchFilename}`)
+    }
+
+    return foundSchema.data
+  }
+
+  private schemaByClassId(classId: number) {
+    const foundSchema = this.schemaInputs.find(({ fileName }) => parseInt(fileName.split('_')[0]) === classId)
+    if (!foundSchema) {
+      throw new Error(`Schema not found by class id: ${classId}`)
+    }
+
+    return foundSchema.data
+  }
+
+  private getRefEntitySchema(parentEntitySchema: AddClassSchema, propName: string) {
+    const refProp = parentEntitySchema.newProperties.find((p) => p.name === propName)
+    if (!refProp) {
+      throw new Error(`findRefEntitySchema: Property ${propName} not found in class ${parentEntitySchema.classId}`)
+    }
+    const refClassId = parseInt(
+      createType('PropertyType', refProp.property_type).asType('Single').asType('Reference')[0].toString()
+    )
+    return this.schemaByClassId(refClassId)
+  }
+
+  private getUniqueQueryHash(uniquePropVal: Record<string, any>, classId: number) {
+    return blake2AsHex(JSON.stringify([classId, uniquePropVal]))
+  }
+
+  private findEntityIndexByUniqueQuery(uniquePropVal: Record<string, any>, classId: number) {
+    const hash = this.getUniqueQueryHash(uniquePropVal, classId)
+    const foundIndex = this.entityIndexByUniqueQueryMap.get(hash)
+    if (foundIndex === undefined) {
+      throw new Error(
+        `findEntityIndexByUniqueQuery failed for class ${classId} and query: ${JSON.stringify(uniquePropVal)}`
+      )
+    }
+
+    return foundIndex
+  }
+
+  private parseEntityInput(entityInput: Record<string, any>, schema: AddClassSchema) {
+    const parametrizedPropertyValues = Object.entries(entityInput).map(([propertyName, propertyValue]) => {
+      const schemaPropertyIndex = schema.newProperties.findIndex((p) => p.name === propertyName)
+      const schemaPropertyType = createType('PropertyType', schema.newProperties[schemaPropertyIndex].property_type)
+
+      let value: ParametrizedPropertyValue
+
+      // Handle references
+      if (schemaPropertyType.isOfType('Single') && schemaPropertyType.asType('Single').isOfType('Reference')) {
+        const refEntitySchema = this.getRefEntitySchema(schema, propertyName)
+        let entityIndex: number
+        if (Object.keys(propertyValue).includes('new')) {
+          entityIndex = this.parseEntityInput(propertyValue.new, refEntitySchema)
+        } else if (Object.keys(propertyValue).includes('existing')) {
+          entityIndex = this.findEntityIndexByUniqueQuery(propertyValue.existing, refEntitySchema.classId)
+        } else {
+          throw new Error(`Invalid reference property value: ${JSON.stringify(propertyValue)}`)
+        }
+        value = createType('ParametrizedPropertyValue', { InternalEntityJustAdded: entityIndex })
+      } else {
+        value = createType('ParametrizedPropertyValue', {
+          InputPropertyValue: schemaPropertyType.toInputPropertyValue(propertyValue).toJSON(),
+        })
+      }
+
+      return {
+        in_class_index: schemaPropertyIndex,
+        value: value.toJSON(),
+      }
+    })
+
+    // Add operations
+    const createEntityOperationIndex = this.operations.length
+    this.operations.push(createType('OperationType', { CreateEntity: { class_id: schema.classId } }))
+    this.operations.push(
+      createType('OperationType', {
+        AddSchemaSupportToEntity: {
+          schema_id: 0,
+          entity_id: { InternalEntityJustAdded: createEntityOperationIndex },
+          parametrized_property_values: parametrizedPropertyValues,
+        },
+      })
+    )
+
+    // Add entries to entityIndexByUniqueQueryMap
+    schema.newProperties
+      .filter((p) => p.unique)
+      .forEach(({ name }) => {
+        const hash = this.getUniqueQueryHash({ [name]: entityInput[name] }, schema.classId)
+        this.entityIndexByUniqueQueryMap.set(hash, createEntityOperationIndex)
+      })
+
+    // Return CreateEntity operation index
+    return createEntityOperationIndex
+  }
+
+  private reset() {
+    this.entityIndexByUniqueQueryMap = new Map<string, number>()
+    this.operations = []
+  }
+
+  public getOperations() {
+    this.batchInputs.forEach(({ fileName: batchFilename, data: batch }) => {
+      const entitySchema = this.schemaByEntityBatchFilename(batchFilename)
+      batch.forEach((entityInput) => this.parseEntityInput(entityInput, entitySchema))
+    })
+
+    const operations = this.operations
+    this.reset()
+
+    return operations
+  }
+}

+ 15 - 0
content-directory-schemas/scripts/helpers/entitySchemas.ts

@@ -0,0 +1,15 @@
+import fs from 'fs'
+import { getInputsLocation } from './inputs'
+
+const schemaInputFilenames = fs.readdirSync(getInputsLocation('schemas'))
+
+type EntitySchemaType = 'Ref' | 'Entity' | 'Batch'
+
+export const schemaFilenameToEntitySchemaName = (inputFilename: string, schemaType?: EntitySchemaType) =>
+  inputFilename.split('_')[1].replace('Schema.json', schemaType || '')
+
+export const classIdToEntitySchemaName = (classId: number, schemaType: EntitySchemaType) =>
+  schemaFilenameToEntitySchemaName(
+    schemaInputFilenames.find((fileName) => fileName.startsWith(`${classId}_`))!,
+    schemaType
+  )

+ 26 - 0
content-directory-schemas/scripts/helpers/inputs.ts

@@ -0,0 +1,26 @@
+import path from 'path'
+import fs from 'fs'
+
+export const INPUTS_LOCATION = path.join(__dirname, '../../inputs')
+export const INPUT_TYPES = ['classes', 'schemas', 'entityBatches'] as const
+
+export type InputType = typeof INPUT_TYPES[number]
+export type FetchedInput<Schema = any> = { fileName: string; data: Schema }
+
+export const sortFiles = (filenameA: string, filenameB: string) =>
+  parseInt(filenameA.split('_')[0]) - parseInt(filenameB.split('_')[0])
+
+export const getInputsLocation = (inputType: InputType) => path.join(INPUTS_LOCATION, inputType)
+
+export function getInputs<Schema = any>(inputType: InputType): FetchedInput<Schema>[] {
+  return fs
+    .readdirSync(getInputsLocation(inputType))
+    .sort(sortFiles)
+    .map((fileName) => {
+      const inputJson = fs.readFileSync(path.join(INPUTS_LOCATION, inputType, fileName)).toString()
+      return {
+        fileName,
+        data: JSON.parse(inputJson) as Schema,
+      }
+    })
+}

+ 93 - 0
content-directory-schemas/scripts/initializeContentDir.ts

@@ -0,0 +1,93 @@
+import { CreateClass } from '../types/extrinsics/CreateClass'
+import { AddClassSchema } from '../types/extrinsics/AddClassSchema'
+import { types } from '@joystream/types'
+import { ApiPromise, Keyring, WsProvider } from '@polkadot/api'
+import { JoyBTreeSet } from '@joystream/types/common'
+import { PropertyId } from '@joystream/types/content-directory'
+import { getInputs } from './helpers/inputs'
+import { SubmittableExtrinsic } from '@polkadot/api/types'
+import { EntityBatchesParser } from './helpers/EntityBatchParser'
+import fs from 'fs'
+import path from 'path'
+
+type DescribedExtrinsic = {
+  type: string
+  inputFilename: string
+  tx: SubmittableExtrinsic<'promise'>
+}
+
+// Classes
+const classInputs = getInputs<CreateClass>('classes')
+const schemaInputs = getInputs<AddClassSchema>('schemas')
+const entityBatchInputs = getInputs('entityBatches')
+
+async function main() {
+  // Init api
+  const WS_URI = process.env.WS_URI || 'ws://127.0.0.1:9944'
+  console.log(`Initializing the api (${WS_URI})...`)
+  const provider = new WsProvider(WS_URI)
+  const api = await ApiPromise.create({ provider, types })
+  // Init ALICE keypair
+  const keyring = new Keyring({ type: 'sr25519' })
+  keyring.addFromUri('//Alice', { name: 'Alice' })
+  const ALICE = keyring.getPairs()[0]
+
+  // Emptiness check
+  if ((await api.query.contentDirectory.nextClassId()).toNumber() > 1) {
+    console.log('Content directory is not empty! Skipping...')
+    process.exit()
+  }
+
+  const classExtrinsics = classInputs.map(({ data, fileName }) => ({
+    type: 'CreateClass',
+    inputFilename: fileName,
+    tx: api.tx.contentDirectory.createClass(
+      data.name,
+      data.description,
+      data.class_permissions || {},
+      data.maximum_entities_count,
+      data.default_entity_creation_voucher_upper_bound
+    ),
+  }))
+  // Schemas
+  const schemaExtrinsics = schemaInputs.map(({ data, fileName }) => ({
+    type: 'AddClassSchema',
+    inputFilename: fileName,
+    tx: api.tx.contentDirectory.addClassSchema(
+      data.classId,
+      new (JoyBTreeSet(PropertyId))(api.registry, data.existingProperties),
+      data.newProperties || []
+    ),
+  }))
+
+  let nonce = (await api.query.system.account(ALICE.address)).nonce.toNumber()
+  console.log('Initializing classes and schemas...\n')
+  const extrinsics: DescribedExtrinsic[] = [...classExtrinsics, ...schemaExtrinsics]
+  for (const { type, inputFilename, tx } of extrinsics) {
+    console.log(`Sending ${type} extrinsic based on input file: ${inputFilename}`)
+    await tx.signAndSend(ALICE, { nonce: nonce++ })
+  }
+
+  console.log('Initializing entities...\n')
+  // Entity batches
+  const entityBatchParser = new EntityBatchesParser(schemaInputs, entityBatchInputs)
+  console.log('Parsing input into operations...')
+  const operations = entityBatchParser.getOperations()
+  // Save operations in operations.json (for reference in case of errors)
+  const outputPath = path.join(__dirname, '../operations.json')
+  console.log(`Saving entity batch operations in ${outputPath}...`)
+  fs.writeFileSync(
+    outputPath,
+    JSON.stringify(
+      operations.map((o) => o.toJSON()),
+      null,
+      4
+    )
+  )
+  console.log('Sending Transaction extrinsic...')
+  await api.tx.contentDirectory.transaction({ Lead: null }, operations).signAndSend(ALICE, { nonce: nonce++ })
+}
+
+main()
+  .then(() => process.exit())
+  .catch((e) => console.error(e))

+ 145 - 0
content-directory-schemas/scripts/inputSchemasToEntitySchemas.ts

@@ -0,0 +1,145 @@
+import fs from 'fs'
+import path from 'path'
+import {
+  AddClassSchema,
+  HashProperty,
+  Property,
+  ReferenceProperty,
+  SinglePropertyVariant,
+  TextProperty,
+  VecPropertyVariant,
+} from '../types/extrinsics/AddClassSchema'
+import _ from 'lodash'
+import { schemaFilenameToEntitySchemaName, classIdToEntitySchemaName } from './helpers/entitySchemas'
+
+import PRIMITIVE_PROPERTY_DEFS from '../schemas/propertyValidationDefs.schema.json'
+import { getInputsLocation } from './helpers/inputs'
+
+const INPUTS_LOCATION = getInputsLocation('schemas')
+const SINGLE_ENTITY_SCHEMAS_LOCATION = path.join(__dirname, '../schemas/entities')
+const BATCH_OF_ENITIES_SCHEMAS_LOCATION = path.join(__dirname, '../schemas/entityBatches')
+const ENTITY_REFERENCE_SCHEMAS_LOCATION = path.join(__dirname, '../schemas/entityReferences')
+
+const inputFilenames = fs.readdirSync(INPUTS_LOCATION)
+
+const strictObjectDef = (def: Record<string, any>) => ({
+  type: 'object',
+  additionalProperties: false,
+  ...def,
+})
+
+const onePropertyObjectDef = (propertyName: string, propertyDef: Record<string, any>) =>
+  strictObjectDef({
+    required: [propertyName],
+    properties: {
+      [propertyName]: propertyDef,
+    },
+  })
+
+const TextPropertyDef = ({ Text: maxLength }: TextProperty) => ({
+  type: 'string',
+  maxLength,
+})
+
+const HashPropertyDef = ({ Hash: maxLength }: HashProperty) => ({
+  type: 'string',
+  maxLength,
+})
+
+const ReferencePropertyDef = ({ Reference: ref }: ReferenceProperty) => ({
+  'oneOf': [
+    onePropertyObjectDef('new', { '$ref': `./${classIdToEntitySchemaName(ref[0], 'Entity')}.schema.json` }),
+    onePropertyObjectDef('existing', {
+      '$ref': `../entityReferences/${classIdToEntitySchemaName(ref[0], 'Ref')}.schema.json`,
+    }),
+  ],
+})
+
+const SinglePropertyDef = ({ Single: singlePropType }: SinglePropertyVariant) => {
+  if (typeof singlePropType === 'string') {
+    return PRIMITIVE_PROPERTY_DEFS.definitions[singlePropType]
+  } else if ((singlePropType as TextProperty).Text) {
+    return TextPropertyDef(singlePropType as TextProperty)
+  } else if ((singlePropType as HashProperty).Hash) {
+    return HashPropertyDef(singlePropType as HashProperty)
+  } else if ((singlePropType as ReferenceProperty).Reference) {
+    return ReferencePropertyDef(singlePropType as ReferenceProperty)
+  }
+
+  throw new Error(`Unknown single proprty type: ${JSON.stringify(singlePropType)}`)
+}
+
+const VecPropertyDef = ({ Vector: vec }: VecPropertyVariant) => ({
+  type: 'array',
+  maxItems: vec.max_length,
+  'items': SinglePropertyDef({ Single: vec.vec_type }),
+})
+
+const PropertyDef = ({ property_type: propertyType, description }: Property) => ({
+  ...((propertyType as SinglePropertyVariant).Single
+    ? SinglePropertyDef(propertyType as SinglePropertyVariant)
+    : VecPropertyDef(propertyType as VecPropertyVariant)),
+  description,
+})
+
+inputFilenames.forEach((fileName) => {
+  const inputFilePath = path.join(INPUTS_LOCATION, fileName)
+  const inputJson = fs.readFileSync(inputFilePath).toString()
+  const inputData = JSON.parse(inputJson) as AddClassSchema
+
+  const schemaName = schemaFilenameToEntitySchemaName(fileName)
+
+  if (inputData.newProperties && !inputData.existingProperties) {
+    const properites = inputData.newProperties
+    const propertiesObj = properites.reduce((pObj, p) => {
+      pObj[p.name] = PropertyDef(p)
+      return pObj
+    }, {} as Record<string, ReturnType<typeof PropertyDef>>)
+
+    const EntitySchema = {
+      '$schema': 'http://json-schema.org/draft-07/schema',
+      '$id': `https://joystream.org/${schemaName}Entity.schema.json`,
+      'title': `${schemaName}Entity`,
+      'description': `JSON schema for entities based on ${schemaName} runtime schema`,
+      ...strictObjectDef({
+        required: properites.filter((p) => p.required).map((p) => p.name),
+        properties: propertiesObj,
+      }),
+    }
+
+    const ReferenceSchema = {
+      '$schema': 'http://json-schema.org/draft-07/schema',
+      '$id': `https://joystream.org/${schemaName}Reference.schema.json`,
+      'title': `${schemaName}Reference`,
+      'description': `JSON schema for reference to ${schemaName} entity based on runtime schema`,
+      'anyOf': [
+        ...properites.filter((p) => p.required && p.unique).map((p) => onePropertyObjectDef(p.name, PropertyDef(p))),
+        PRIMITIVE_PROPERTY_DEFS.definitions.Uint64,
+      ],
+    }
+
+    const BatchSchema = {
+      '$schema': 'http://json-schema.org/draft-07/schema',
+      '$id': `https://joystream.org/${schemaName}Batch.schema.json`,
+      'title': `${schemaName}Batch`,
+      'description': `JSON schema for batch of entities based on ${schemaName} runtime schema`,
+      'type': 'array',
+      'items': { '$ref': `../entities/${schemaName}Entity.schema.json` },
+    }
+
+    const entitySchemaPath = path.join(SINGLE_ENTITY_SCHEMAS_LOCATION, `${schemaName}Entity.schema.json`)
+    fs.writeFileSync(entitySchemaPath, JSON.stringify(EntitySchema, undefined, 4))
+    console.log(`${entitySchemaPath} succesfully generated!`)
+
+    const entityReferenceSchemaPath = path.join(ENTITY_REFERENCE_SCHEMAS_LOCATION, `${schemaName}Ref.schema.json`)
+    fs.writeFileSync(entityReferenceSchemaPath, JSON.stringify(ReferenceSchema, undefined, 4))
+    console.log(`${entityReferenceSchemaPath} succesfully generated!`)
+
+    const batchOfEntitiesSchemaPath = path.join(BATCH_OF_ENITIES_SCHEMAS_LOCATION, `${schemaName}Batch.schema.json`)
+    fs.writeFileSync(batchOfEntitiesSchemaPath, JSON.stringify(BatchSchema, undefined, 4))
+    console.log(`${batchOfEntitiesSchemaPath} succesfully generated!`)
+  } else {
+    console.log('WARNING: Schemas with "existingProperties" not supported yet!')
+    console.log('Skipping...')
+  }
+})

+ 41 - 0
content-directory-schemas/scripts/schemasToTS.ts

@@ -0,0 +1,41 @@
+import fs from 'fs'
+import path from 'path'
+import { compileFromFile } from 'json-schema-to-typescript'
+// TODO: This will require publishing @joystream/prettier-config if we want to include it in joystream-js
+import prettierConfig from '@joystream/prettier-config'
+
+const SCHEMAS_LOCATION = path.join(__dirname, '../schemas')
+const OUTPUT_TYPES_LOCATION = path.join(__dirname, '../types')
+
+const SUBDIRS_INCLUDED = ['extrinsics', 'entities'] as const
+
+async function main() {
+  for (const subdirName of fs.readdirSync(SCHEMAS_LOCATION)) {
+    if (!SUBDIRS_INCLUDED.includes(subdirName as any)) {
+      console.log(`Subdir/filename not included: ${subdirName} - skipping...`)
+      continue
+    }
+    const schemaSubdir = subdirName as typeof SUBDIRS_INCLUDED[number]
+    for (const schemaFilename of fs.readdirSync(path.join(SCHEMAS_LOCATION, schemaSubdir))) {
+      const schemaFilePath = path.join(SCHEMAS_LOCATION, schemaSubdir, schemaFilename)
+      const outputFilename = schemaFilename.replace('.schema.json', '.d.ts')
+      const outputFilePath = path.join(OUTPUT_TYPES_LOCATION, schemaSubdir, outputFilename)
+      try {
+        await compileFromFile(schemaFilePath, {
+          cwd: path.join(SCHEMAS_LOCATION, schemaSubdir),
+          style: prettierConfig,
+        }).then((ts) => {
+          fs.writeFileSync(outputFilePath, ts)
+          console.log(`${outputFilePath} succesfully generated!`)
+        })
+      } catch (e) {
+        console.log(`${outputFilePath} compilation FAILED!`)
+        console.error(e)
+      }
+    }
+  }
+}
+
+main()
+  .then(() => process.exit())
+  .catch((e) => console.error(e))

+ 11 - 26
content-directory-schemas/scripts/validate.ts

@@ -1,25 +1,23 @@
+// TODO: Add entity batches validation
 import Ajv from 'ajv'
-import fs from 'fs'
-import path from 'path'
-import CreateClassSchema from '../schemas/CreateClass.schema.json'
-import AddClassSchemaSchema from '../schemas/AddClassSchema.schema.json'
-
-const INPUTS_LOCATION = path.join(__dirname, '../inputs')
+import CreateClassSchema from '../schemas/extrinsics/CreateClass.schema.json'
+import AddClassSchemaSchema from '../schemas/extrinsics/AddClassSchema.schema.json'
+import { getInputs, InputType } from './helpers/inputs'
 
 type JsonSchema = {
   schemaName: string
   jsonSchema: Record<string, unknown>
-  relatedInputDirectory: string
+  relatedInputType: InputType
 }
 
 const schemas: JsonSchema[] = [
-  { schemaName: 'CreateClass', jsonSchema: CreateClassSchema, relatedInputDirectory: 'classes' },
-  { schemaName: 'AddClassSchema', jsonSchema: AddClassSchemaSchema, relatedInputDirectory: 'schemas' },
+  { schemaName: 'CreateClass', jsonSchema: CreateClassSchema, relatedInputType: 'classes' },
+  { schemaName: 'AddClassSchema', jsonSchema: AddClassSchemaSchema, relatedInputType: 'schemas' },
 ]
 
 const ajv = new Ajv({ allErrors: true })
 
-schemas.forEach(({ schemaName, jsonSchema, relatedInputDirectory }) => {
+schemas.forEach(({ schemaName, jsonSchema, relatedInputType }) => {
   // Validate the schema itself
   console.log(`Validating schema for ${schemaName}...`)
   if (!ajv.validateSchema(jsonSchema)) {
@@ -32,22 +30,9 @@ schemas.forEach(({ schemaName, jsonSchema, relatedInputDirectory }) => {
 
   // Validate inputs
   console.log('Validating inputs...')
-  fs.readdirSync(path.join(INPUTS_LOCATION, relatedInputDirectory)).forEach((fileName) => {
-    const inputRelativePath = path.join(relatedInputDirectory, fileName)
-    console.log(`Validating ${inputRelativePath}...`)
-    const inputJson = fs.readFileSync(path.join(INPUTS_LOCATION, inputRelativePath)).toString()
-    let inputData
-    try {
-      inputData = JSON.parse(inputJson)
-    } catch (e) {
-      console.log(`\nERROR: ${inputRelativePath} - cannot parse the json!`)
-      console.log('\n')
-      process.exitCode = 100
-      return
-    }
-
-    if (!ajv.validate(jsonSchema, inputData)) {
-      console.log(`\nERROR! ${inputRelativePath} - validation failed!`)
+  getInputs(relatedInputType).forEach(({ fileName, data }) => {
+    if (!ajv.validate(jsonSchema, data)) {
+      console.log(`\nERROR! ${relatedInputType}/${fileName} - validation failed!`)
       console.log(ajv.errorsText(undefined, { separator: '\n' }))
       console.log('\n')
       process.exitCode = 100

+ 9 - 3
content-directory-schemas/tsconfig.json

@@ -4,7 +4,6 @@
     "module": "commonjs",
     "strict": true,
     "noImplicitAny": true,
-    "noUnusedLocals": true,
     "noImplicitReturns": true,
     "moduleResolution": "node",
     "allowSyntheticDefaultImports": true,     /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
@@ -15,7 +14,14 @@
       "node"
     ],
     "forceConsistentCasingInFileNames": true,
-    "baseUrl": "."
+    "baseUrl": ".",
+    "typeRoots": [
+      "typings"
+    ],
+    "paths": {
+      "@polkadot/types/augment": ["../types/augment-codec/augment-types.ts"],
+      "@polkadot/api/augment": ["../types/augment-codec/augment-api.ts"]
+    }
   },
-  "include": [ "scripts/**/*" ]
+  "include": [ "scripts/**/*", "typings/**/*" ]
 }

+ 71 - 0
content-directory-schemas/types/entities/ChannelEntity.d.ts

@@ -0,0 +1,71 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for reference to Language entity based on runtime schema
+ */
+export type LanguageReference =
+  | {
+      /**
+       * ISO 639-1 code of the language (ie. en)
+       */
+      Code: string
+    }
+  | number
+
+/**
+ * JSON schema for entities based on Channel runtime schema
+ */
+export interface ChannelEntity {
+  /**
+   * The title of the Channel
+   */
+  title: string
+  /**
+   * The description of a Channel
+   */
+  description: string
+  /**
+   * Url for Channel's cover (background) photo. Recommended ratio: 16:9.
+   */
+  coverPhotoUrl: string
+  /**
+   * Channel's avatar photo.
+   */
+  avatarPhotoURL: string
+  /**
+   * Flag signaling whether a channel is public.
+   */
+  isPublic: boolean
+  /**
+   * Flag signaling whether a channel is curated/verified.
+   */
+  isCurated: boolean
+  /**
+   * The primary langauge of the channel's content
+   */
+  language?:
+    | {
+        new: LanguageEntity
+      }
+    | {
+        existing: LanguageReference
+      }
+}
+/**
+ * JSON schema for entities based on Language runtime schema
+ */
+export interface LanguageEntity {
+  /**
+   * The name of the language (ie. English)
+   */
+  Name: string
+  /**
+   * ISO 639-1 code of the language (ie. en)
+   */
+  Code: string
+}

+ 20 - 0
content-directory-schemas/types/entities/ContentCategoryEntity.d.ts

@@ -0,0 +1,20 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on ContentCategory runtime schema
+ */
+export interface ContentCategoryEntity {
+  /**
+   * The name of the category
+   */
+  Name: string
+  /**
+   * The description of the category
+   */
+  Description?: string
+}

+ 20 - 0
content-directory-schemas/types/entities/HttpMediaLocationEntity.d.ts

@@ -0,0 +1,20 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on HttpMediaLocation runtime schema
+ */
+export interface HttpMediaLocationEntity {
+  /**
+   * The http url pointing to the media
+   */
+  url: string
+  /**
+   * The port to use when connecting to the http url (defaults to 80)
+   */
+  port?: number
+}

+ 16 - 0
content-directory-schemas/types/entities/JoystreamMediaLocationEntity.d.ts

@@ -0,0 +1,16 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on JoystreamMediaLocation runtime schema
+ */
+export interface JoystreamMediaLocationEntity {
+  /**
+   * Id of the data object in the Joystream runtime dataDirectory module
+   */
+  dataObjectId: string
+}

+ 28 - 0
content-directory-schemas/types/entities/KnownLicenseEntity.d.ts

@@ -0,0 +1,28 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on KnownLicense runtime schema
+ */
+export interface KnownLicenseEntity {
+  /**
+   * Short, commonly recognized code of the licence (ie. CC_BY_SA)
+   */
+  code: string
+  /**
+   * Full, descriptive name of the license (ie. Creative Commons - Attribution-NonCommercial-NoDerivs)
+   */
+  name?: string
+  /**
+   * Short description of the license conditions
+   */
+  description?: string
+  /**
+   * An url pointing to full license content
+   */
+  url?: string
+}

+ 20 - 0
content-directory-schemas/types/entities/LanguageEntity.d.ts

@@ -0,0 +1,20 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on Language runtime schema
+ */
+export interface LanguageEntity {
+  /**
+   * The name of the language (ie. English)
+   */
+  Name: string
+  /**
+   * ISO 639-1 code of the language (ie. en)
+   */
+  Code: string
+}

+ 78 - 0
content-directory-schemas/types/entities/LicenseEntity.d.ts

@@ -0,0 +1,78 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for reference to KnownLicense entity based on runtime schema
+ */
+export type KnownLicenseReference =
+  | {
+      /**
+       * Short, commonly recognized code of the licence (ie. CC_BY_SA)
+       */
+      code: string
+    }
+  | number
+/**
+ * JSON schema for reference to UserDefinedLicense entity based on runtime schema
+ */
+export type UserDefinedLicenseReference = number
+
+/**
+ * JSON schema for entities based on License runtime schema
+ */
+export interface LicenseEntity {
+  /**
+   * Reference to a known license
+   */
+  knownLicense?:
+    | {
+        new: KnownLicenseEntity
+      }
+    | {
+        existing: KnownLicenseReference
+      }
+  /**
+   * Reference to user-defined license
+   */
+  userDefinedLicense?:
+    | {
+        new: UserDefinedLicenseEntity
+      }
+    | {
+        existing: UserDefinedLicenseReference
+      }
+}
+/**
+ * JSON schema for entities based on KnownLicense runtime schema
+ */
+export interface KnownLicenseEntity {
+  /**
+   * Short, commonly recognized code of the licence (ie. CC_BY_SA)
+   */
+  code: string
+  /**
+   * Full, descriptive name of the license (ie. Creative Commons - Attribution-NonCommercial-NoDerivs)
+   */
+  name?: string
+  /**
+   * Short description of the license conditions
+   */
+  description?: string
+  /**
+   * An url pointing to full license content
+   */
+  url?: string
+}
+/**
+ * JSON schema for entities based on UserDefinedLicense runtime schema
+ */
+export interface UserDefinedLicenseEntity {
+  /**
+   * Custom license content
+   */
+  content: string
+}

+ 70 - 0
content-directory-schemas/types/entities/MediaLocationEntity.d.ts

@@ -0,0 +1,70 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for reference to HttpMediaLocation entity based on runtime schema
+ */
+export type HttpMediaLocationReference = number
+/**
+ * JSON schema for reference to JoystreamMediaLocation entity based on runtime schema
+ */
+export type JoystreamMediaLocationReference =
+  | {
+      /**
+       * Id of the data object in the Joystream runtime dataDirectory module
+       */
+      dataObjectId: string
+    }
+  | number
+
+/**
+ * JSON schema for entities based on MediaLocation runtime schema
+ */
+export interface MediaLocationEntity {
+  /**
+   * A reference to HttpMediaLocation
+   */
+  httpMediaLocation?:
+    | {
+        new: HttpMediaLocationEntity
+      }
+    | {
+        existing: HttpMediaLocationReference
+      }
+  /**
+   * A reference to JoystreamMediaLocation
+   */
+  joystreamMediaLocation?:
+    | {
+        new: JoystreamMediaLocationEntity
+      }
+    | {
+        existing: JoystreamMediaLocationReference
+      }
+}
+/**
+ * JSON schema for entities based on HttpMediaLocation runtime schema
+ */
+export interface HttpMediaLocationEntity {
+  /**
+   * The http url pointing to the media
+   */
+  url: string
+  /**
+   * The port to use when connecting to the http url (defaults to 80)
+   */
+  port?: number
+}
+/**
+ * JSON schema for entities based on JoystreamMediaLocation runtime schema
+ */
+export interface JoystreamMediaLocationEntity {
+  /**
+   * Id of the data object in the Joystream runtime dataDirectory module
+   */
+  dataObjectId: string
+}

+ 16 - 0
content-directory-schemas/types/entities/UserDefinedLicenseEntity.d.ts

@@ -0,0 +1,16 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on UserDefinedLicense runtime schema
+ */
+export interface UserDefinedLicenseEntity {
+  /**
+   * Custom license content
+   */
+  content: string
+}

+ 402 - 0
content-directory-schemas/types/entities/VideoEntity.d.ts

@@ -0,0 +1,402 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for reference to Language entity based on runtime schema
+ */
+export type LanguageReference =
+  | {
+      /**
+       * ISO 639-1 code of the language (ie. en)
+       */
+      Code: string
+    }
+  | number
+/**
+ * JSON schema for reference to Channel entity based on runtime schema
+ */
+export type ChannelReference =
+  | {
+      /**
+       * The title of the Channel
+       */
+      title: string
+    }
+  | number
+/**
+ * JSON schema for reference to ContentCategory entity based on runtime schema
+ */
+export type ContentCategoryReference =
+  | {
+      /**
+       * The name of the category
+       */
+      Name: string
+    }
+  | number
+/**
+ * JSON schema for reference to VideoMediaEncoding entity based on runtime schema
+ */
+export type VideoMediaEncodingReference =
+  | {
+      /**
+       * The name of the encoding format (ie. H264_mpeg4)
+       */
+      Name: string
+    }
+  | number
+/**
+ * JSON schema for reference to HttpMediaLocation entity based on runtime schema
+ */
+export type HttpMediaLocationReference = number
+/**
+ * JSON schema for reference to JoystreamMediaLocation entity based on runtime schema
+ */
+export type JoystreamMediaLocationReference =
+  | {
+      /**
+       * Id of the data object in the Joystream runtime dataDirectory module
+       */
+      dataObjectId: string
+    }
+  | number
+/**
+ * JSON schema for reference to MediaLocation entity based on runtime schema
+ */
+export type MediaLocationReference = number
+/**
+ * JSON schema for reference to VideoMedia entity based on runtime schema
+ */
+export type VideoMediaReference = number
+/**
+ * JSON schema for reference to KnownLicense entity based on runtime schema
+ */
+export type KnownLicenseReference =
+  | {
+      /**
+       * Short, commonly recognized code of the licence (ie. CC_BY_SA)
+       */
+      code: string
+    }
+  | number
+/**
+ * JSON schema for reference to UserDefinedLicense entity based on runtime schema
+ */
+export type UserDefinedLicenseReference = number
+/**
+ * JSON schema for reference to License entity based on runtime schema
+ */
+export type LicenseReference = number
+
+/**
+ * JSON schema for entities based on Video runtime schema
+ */
+export interface VideoEntity {
+  /**
+   * Reference to member's channel
+   */
+  channel:
+    | {
+        new: ChannelEntity
+      }
+    | {
+        existing: ChannelReference
+      }
+  /**
+   * Reference to a video category
+   */
+  category:
+    | {
+        new: ContentCategoryEntity
+      }
+    | {
+        existing: ContentCategoryReference
+      }
+  /**
+   * The title of the video
+   */
+  title: string
+  /**
+   * The description of the Video
+   */
+  description: string
+  /**
+   * Video duration in seconds
+   */
+  duration: number
+  /**
+   * Video's kippable intro duration in seconds
+   */
+  skippableIntroDuration?: number
+  /**
+   * Video thumbnail url (recommended ratio: 16:9)
+   */
+  thumbnailURL: string
+  /**
+   * Video's main langauge
+   */
+  language?:
+    | {
+        new: LanguageEntity
+      }
+    | {
+        existing: LanguageReference
+      }
+  /**
+   * Reference to VideoMedia
+   */
+  media:
+    | {
+        new: VideoMediaEntity
+      }
+    | {
+        existing: VideoMediaReference
+      }
+  /**
+   * Whether or not Video contains marketing
+   */
+  hasMarketing?: boolean
+  /**
+   * If the Video was published on other platform before beeing published on Joystream - the original publication date
+   */
+  publishedBeforeJoystream?: number
+  /**
+   * Whether the Video is supposed to be publically displayed
+   */
+  isPublic: boolean
+  /**
+   * Whether the Video has been curated (verified) by a Curator
+   */
+  isCurated: boolean
+  /**
+   * Whether the Video contains explicit material.
+   */
+  isExplicit: boolean
+  /**
+   * A License the Video is published under
+   */
+  license:
+    | {
+        new: LicenseEntity
+      }
+    | {
+        existing: LicenseReference
+      }
+}
+/**
+ * JSON schema for entities based on Channel runtime schema
+ */
+export interface ChannelEntity {
+  /**
+   * The title of the Channel
+   */
+  title: string
+  /**
+   * The description of a Channel
+   */
+  description: string
+  /**
+   * Url for Channel's cover (background) photo. Recommended ratio: 16:9.
+   */
+  coverPhotoUrl: string
+  /**
+   * Channel's avatar photo.
+   */
+  avatarPhotoURL: string
+  /**
+   * Flag signaling whether a channel is public.
+   */
+  isPublic: boolean
+  /**
+   * Flag signaling whether a channel is curated/verified.
+   */
+  isCurated: boolean
+  /**
+   * The primary langauge of the channel's content
+   */
+  language?:
+    | {
+        new: LanguageEntity
+      }
+    | {
+        existing: LanguageReference
+      }
+}
+/**
+ * JSON schema for entities based on Language runtime schema
+ */
+export interface LanguageEntity {
+  /**
+   * The name of the language (ie. English)
+   */
+  Name: string
+  /**
+   * ISO 639-1 code of the language (ie. en)
+   */
+  Code: string
+}
+/**
+ * JSON schema for entities based on ContentCategory runtime schema
+ */
+export interface ContentCategoryEntity {
+  /**
+   * The name of the category
+   */
+  Name: string
+  /**
+   * The description of the category
+   */
+  Description?: string
+}
+/**
+ * JSON schema for entities based on VideoMedia runtime schema
+ */
+export interface VideoMediaEntity {
+  /**
+   * Encoding of the video media object
+   */
+  encoding:
+    | {
+        new: VideoMediaEncodingEntity
+      }
+    | {
+        existing: VideoMediaEncodingReference
+      }
+  /**
+   * Video media width in pixels
+   */
+  pixelWidth: number
+  /**
+   * Video media height in pixels
+   */
+  pixelHeight: number
+  /**
+   * Video media size in bytes
+   */
+  size?: number
+  /**
+   * Location of the video media object
+   */
+  location:
+    | {
+        new: MediaLocationEntity
+      }
+    | {
+        existing: MediaLocationReference
+      }
+}
+/**
+ * JSON schema for entities based on VideoMediaEncoding runtime schema
+ */
+export interface VideoMediaEncodingEntity {
+  /**
+   * The name of the encoding format (ie. H264_mpeg4)
+   */
+  Name: string
+}
+/**
+ * JSON schema for entities based on MediaLocation runtime schema
+ */
+export interface MediaLocationEntity {
+  /**
+   * A reference to HttpMediaLocation
+   */
+  httpMediaLocation?:
+    | {
+        new: HttpMediaLocationEntity
+      }
+    | {
+        existing: HttpMediaLocationReference
+      }
+  /**
+   * A reference to JoystreamMediaLocation
+   */
+  joystreamMediaLocation?:
+    | {
+        new: JoystreamMediaLocationEntity
+      }
+    | {
+        existing: JoystreamMediaLocationReference
+      }
+}
+/**
+ * JSON schema for entities based on HttpMediaLocation runtime schema
+ */
+export interface HttpMediaLocationEntity {
+  /**
+   * The http url pointing to the media
+   */
+  url: string
+  /**
+   * The port to use when connecting to the http url (defaults to 80)
+   */
+  port?: number
+}
+/**
+ * JSON schema for entities based on JoystreamMediaLocation runtime schema
+ */
+export interface JoystreamMediaLocationEntity {
+  /**
+   * Id of the data object in the Joystream runtime dataDirectory module
+   */
+  dataObjectId: string
+}
+/**
+ * JSON schema for entities based on License runtime schema
+ */
+export interface LicenseEntity {
+  /**
+   * Reference to a known license
+   */
+  knownLicense?:
+    | {
+        new: KnownLicenseEntity
+      }
+    | {
+        existing: KnownLicenseReference
+      }
+  /**
+   * Reference to user-defined license
+   */
+  userDefinedLicense?:
+    | {
+        new: UserDefinedLicenseEntity
+      }
+    | {
+        existing: UserDefinedLicenseReference
+      }
+}
+/**
+ * JSON schema for entities based on KnownLicense runtime schema
+ */
+export interface KnownLicenseEntity {
+  /**
+   * Short, commonly recognized code of the licence (ie. CC_BY_SA)
+   */
+  code: string
+  /**
+   * Full, descriptive name of the license (ie. Creative Commons - Attribution-NonCommercial-NoDerivs)
+   */
+  name?: string
+  /**
+   * Short description of the license conditions
+   */
+  description?: string
+  /**
+   * An url pointing to full license content
+   */
+  url?: string
+}
+/**
+ * JSON schema for entities based on UserDefinedLicense runtime schema
+ */
+export interface UserDefinedLicenseEntity {
+  /**
+   * Custom license content
+   */
+  content: string
+}

+ 16 - 0
content-directory-schemas/types/entities/VideoMediaEncodingEntity.d.ts

@@ -0,0 +1,16 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for entities based on VideoMediaEncoding runtime schema
+ */
+export interface VideoMediaEncodingEntity {
+  /**
+   * The name of the encoding format (ie. H264_mpeg4)
+   */
+  Name: string
+}

+ 131 - 0
content-directory-schemas/types/entities/VideoMediaEntity.d.ts

@@ -0,0 +1,131 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * JSON schema for reference to VideoMediaEncoding entity based on runtime schema
+ */
+export type VideoMediaEncodingReference =
+  | {
+      /**
+       * The name of the encoding format (ie. H264_mpeg4)
+       */
+      Name: string
+    }
+  | number
+/**
+ * JSON schema for reference to HttpMediaLocation entity based on runtime schema
+ */
+export type HttpMediaLocationReference = number
+/**
+ * JSON schema for reference to JoystreamMediaLocation entity based on runtime schema
+ */
+export type JoystreamMediaLocationReference =
+  | {
+      /**
+       * Id of the data object in the Joystream runtime dataDirectory module
+       */
+      dataObjectId: string
+    }
+  | number
+/**
+ * JSON schema for reference to MediaLocation entity based on runtime schema
+ */
+export type MediaLocationReference = number
+
+/**
+ * JSON schema for entities based on VideoMedia runtime schema
+ */
+export interface VideoMediaEntity {
+  /**
+   * Encoding of the video media object
+   */
+  encoding:
+    | {
+        new: VideoMediaEncodingEntity
+      }
+    | {
+        existing: VideoMediaEncodingReference
+      }
+  /**
+   * Video media width in pixels
+   */
+  pixelWidth: number
+  /**
+   * Video media height in pixels
+   */
+  pixelHeight: number
+  /**
+   * Video media size in bytes
+   */
+  size?: number
+  /**
+   * Location of the video media object
+   */
+  location:
+    | {
+        new: MediaLocationEntity
+      }
+    | {
+        existing: MediaLocationReference
+      }
+}
+/**
+ * JSON schema for entities based on VideoMediaEncoding runtime schema
+ */
+export interface VideoMediaEncodingEntity {
+  /**
+   * The name of the encoding format (ie. H264_mpeg4)
+   */
+  Name: string
+}
+/**
+ * JSON schema for entities based on MediaLocation runtime schema
+ */
+export interface MediaLocationEntity {
+  /**
+   * A reference to HttpMediaLocation
+   */
+  httpMediaLocation?:
+    | {
+        new: HttpMediaLocationEntity
+      }
+    | {
+        existing: HttpMediaLocationReference
+      }
+  /**
+   * A reference to JoystreamMediaLocation
+   */
+  joystreamMediaLocation?:
+    | {
+        new: JoystreamMediaLocationEntity
+      }
+    | {
+        existing: JoystreamMediaLocationReference
+      }
+}
+/**
+ * JSON schema for entities based on HttpMediaLocation runtime schema
+ */
+export interface HttpMediaLocationEntity {
+  /**
+   * The http url pointing to the media
+   */
+  url: string
+  /**
+   * The port to use when connecting to the http url (defaults to 80)
+   */
+  port?: number
+}
+/**
+ * JSON schema for entities based on JoystreamMediaLocation runtime schema
+ */
+export interface JoystreamMediaLocationEntity {
+  /**
+   * Id of the data object in the Joystream runtime dataDirectory module
+   */
+  dataObjectId: string
+}

+ 56 - 0
content-directory-schemas/types/extrinsics/AddClassSchema.d.ts

@@ -0,0 +1,56 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+export type ClassId = number
+export type PropertyInSchemIndex = number
+export type SinglePropertyType = PrimitiveProperty | TextProperty | HashProperty | ReferenceProperty
+export type PrimitiveProperty = 'Bool' | 'Uint16' | 'Uint32' | 'Uint64' | 'Int16' | 'Int32' | 'Int64'
+export type MaxTextLength = number
+export type MaxVecItems = number
+export type PropertyName = string
+export type PropertyDescription = string
+export type DefaultBoolean = boolean
+
+/**
+ * JSON schema to describe a new schema for a certain class in Joystream network
+ */
+export interface AddClassSchema {
+  classId: ClassId
+  existingProperties?: [PropertyInSchemIndex, ...PropertyInSchemIndex[]]
+  newProperties: [Property, ...Property[]]
+}
+export interface Property {
+  property_type: SinglePropertyVariant | VecPropertyVariant
+  name: PropertyName
+  description?: PropertyDescription
+  required?: DefaultBoolean
+  unique?: DefaultBoolean
+  locking_policy?: LockingPolicy
+}
+export interface SinglePropertyVariant {
+  Single: SinglePropertyType
+}
+export interface TextProperty {
+  Text: MaxTextLength
+}
+export interface HashProperty {
+  Hash: MaxTextLength
+}
+export interface ReferenceProperty {
+  Reference: [number, boolean]
+}
+export interface VecPropertyVariant {
+  Vector: VecPropertyType
+}
+export interface VecPropertyType {
+  vec_type: SinglePropertyType
+  max_length: MaxVecItems
+}
+export interface LockingPolicy {
+  is_locked_from_maintainer?: DefaultBoolean
+  is_locked_from_controller?: DefaultBoolean
+}

+ 30 - 0
content-directory-schemas/types/extrinsics/CreateClass.d.ts

@@ -0,0 +1,30 @@
+/* tslint:disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+export type DefaultBoolean = boolean
+
+/**
+ * JSON schema to describe a new class for Joystream network
+ */
+export interface CreateClass {
+  /**
+   * Name of this class. Required property.
+   */
+  name: string
+  /**
+   * Description of this class.
+   */
+  description: string
+  class_permissions?: {
+    any_member?: DefaultBoolean
+    entity_creation_blocked?: DefaultBoolean
+    all_entity_property_values_locked?: DefaultBoolean
+    maintainers?: number[]
+  }
+  maximum_entities_count: number
+  default_entity_creation_voucher_upper_bound: number
+}

+ 2 - 0
content-directory-schemas/typings/@joystream/prettier-config/index.d.ts

@@ -0,0 +1,2 @@
+// Prevent declaration file not found error
+declare module '@joystream/prettier-config'

+ 50 - 2
content-directory-schemas/vscode-recommended.settings.json

@@ -2,11 +2,59 @@
   "json.schemas": [
     {
       "fileMatch": ["*Schema.json"],
-      "url": "/schemas/AddClassSchema.schema.json"
+      "url": "/content-directory-schemas/schemas/extrinsics/AddClassSchema.schema.json"
     },
     {
       "fileMatch": ["*Class.json"],
-      "url": "/schemas/CreateClass.schema.json"
+      "url": "/content-directory-schemas/schemas/extrinsics/CreateClass.schema.json"
+    },
+    {
+      "fileMatch": ["*_LanguageBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/LanguageBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_MediaLocationBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/MediaLocationBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_HttpMediaLocationBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/HttpMediaLocationBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_JoystreamMediaLocationBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/JoystreamMediaLocationBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_ContentCategoryBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/ContentCategoryBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_ChannelBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/ChannelBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_VideoMediaEncodingBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/VideoMediaEncodingBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_KnownLicenseBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/KnownLicenseBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_UserDefinedLicenseBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/UserDefinedLicenseBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_LicenseBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/LicenseBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_VideoMediaBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/VideoMediaBatch.schema.json"
+    },
+    {
+      "fileMatch": ["*_VideoBatch.json"],
+      "url": "/content-directory-schemas/schemas/entityBatches/VideoBatch.schema.json"
     }
   ]
 }

+ 16 - 1
types/src/content-directory/index.ts

@@ -44,7 +44,22 @@ export class PropertyTypeVector extends JoyStructDecorated({
 export class PropertyType extends JoyEnum({
   Single: PropertyTypeSingle,
   Vector: PropertyTypeVector,
-}) {}
+}) {
+  toInputPropertyValue(value: any): InputPropertyValue {
+    const inputPwType: keyof typeof InputPropertyValue['typeDefinitions'] = this.type
+    const subtype = this.isOfType('Single') ? this.asType('Single').type : this.asType('Vector').vec_type.type
+
+    if (inputPwType === 'Single') {
+      const inputPwSubtype: keyof typeof InputValue['typeDefinitions'] = subtype === 'Hash' ? 'TextToHash' : subtype
+
+      return new InputPropertyValue(this.registry, { [inputPwType]: { [inputPwSubtype]: value } })
+    } else {
+      const inputPwSubtype: keyof typeof VecInputValue['typeDefinitions'] = subtype === 'Hash' ? 'TextToHash' : subtype
+
+      return new InputPropertyValue(this.registry, { [inputPwType]: { [inputPwSubtype]: value } })
+    }
+  }
+}
 
 export class PropertyLockingPolicy extends JoyStructDecorated({
   is_locked_from_maintainer: bool,

+ 0 - 188
utils/api-examples/scripts/init-new-content-directory.js

@@ -1,188 +0,0 @@
-/* global api, hashing, keyring, types, util, joy */
-
-// run this script with:
-// yarn script initNewContentDir
-//
-// or copy and paste the code into the pioneer javascript toolbox at:
-// https://testnet.joystream.org/#/js
-
-const script = async ({ api, keyring }) => {
-  // Get sudo addr
-  const sudoAddress = (await api.query.sudo.key()).toString()
-  let sudo
-  if (typeof window === 'undefined') {
-    // In node, get the keyPair if the keyring was provided
-    sudo = keyring.getPair(sudoAddress)
-  } else {
-    // Pioneer: let the UI Signer handle it
-    sudo = sudoAddress
-  }
-
-  let nonce = (await api.query.system.account(sudoAddress)).nonce.toNumber()
-
-  const NEW_OPENING_ID = await api.query.contentDirectoryWorkingGroup.nextOpeningId()
-  const NEW_CLASS_ID = await api.query.contentDirectory.nextClassId()
-  const ALICE_MEMBER_ID = 0 // We assume it exists
-
-  const sudoCall = (tx) => api.tx.sudo.sudo(tx).signAndSend(sudo, { nonce: nonce++ })
-
-  // Create curator lead opening
-  await sudoCall(
-    api.tx.contentDirectoryWorkingGroup.addOpening(
-      { CurrentBlock: null }, // activate_at
-      { commitment: { max_review_period_length: 9999 } }, // OpeningPolicyCommitment
-      'api-examples curator opening', // human_readable_text
-      { Leader: null } // opening_type
-    )
-  )
-
-  // Apply to lead opening
-  await api.tx.contentDirectoryWorkingGroup
-    .applyOnOpening(
-      ALICE_MEMBER_ID, // member id
-      NEW_OPENING_ID, // opening id
-      sudoAddress, // address
-      null, // opt role stake
-      null, // opt appl. stake
-      'api-examples curator opening appl.' // human_readable_text
-    )
-    .signAndSend(sudo, { nonce: nonce++ })
-
-  // Begin review period
-  await sudoCall(api.tx.contentDirectoryWorkingGroup.beginApplicantReview(NEW_OPENING_ID))
-
-  // Fill opening
-  await sudoCall(
-    api.tx.contentDirectoryWorkingGroup.fillOpening(
-      NEW_OPENING_ID, // opening id
-      [ALICE_MEMBER_ID], // succesful applicants
-      null // reward policy
-    )
-  )
-
-  // Create person class
-  await api.tx.contentDirectory
-    .createClass(
-      'Person',
-      'A class describing a person',
-      // ClassPermissions
-      {
-        any_member: true,
-        entity_creation_blocked: false,
-        all_entity_property_values_locked: false,
-        maintainers: [],
-      },
-      10, // maximum_entities_count
-      5 // default_entity_creation_voucher_upper_bound
-    )
-    .signAndSend(sudo, { nonce: nonce++ })
-
-  // Add schema to person class
-  await api.tx.contentDirectory
-    .addClassSchema(
-      NEW_CLASS_ID,
-      [], // existing_properties
-      // new_properties:
-      [
-        {
-          property_type: { Single: { Text: 64 } },
-          required: true,
-          unique: false,
-          name: 'firstname',
-          description: "Person's first name",
-          locking_policy: { is_locked_from_maintainer: false, is_locked_from_controller: false },
-        },
-        {
-          property_type: { Single: { Text: 64 } },
-          required: true,
-          unique: false,
-          name: 'lastname',
-          description: "Person's last name",
-          locking_policy: { is_locked_from_maintainer: false, is_locked_from_controller: false },
-        },
-        {
-          property_type: { Single: { Uint16: null } },
-          required: true,
-          unique: false,
-          name: 'age',
-          description: "Person's age",
-          locking_policy: { is_locked_from_maintainer: false, is_locked_from_controller: false },
-        },
-        {
-          property_type: { Vector: { vec_type: { Text: 32 }, max_length: 10 } },
-          required: false,
-          unique: false,
-          name: 'hobbys',
-          description: "Person's hobbys",
-          locking_policy: { is_locked_from_maintainer: false, is_locked_from_controller: false },
-        },
-      ]
-    )
-    .signAndSend(sudo, { nonce: nonce++ })
-
-  // Add another schema to person class
-  await api.tx.contentDirectory
-    .addClassSchema(
-      NEW_CLASS_ID,
-      [0, 1, 2, 3], // This still has to be in the right order (BTreeSet is part of the extrinsic metadata)
-      // new_properties:
-      [
-        {
-          property_type: { Single: { Text: 64 } },
-          required: true,
-          unique: true,
-          name: 'uniqueIdentifier',
-          description: "Person's unique identifier",
-          locking_policy: { is_locked_from_maintainer: false, is_locked_from_controller: false },
-        },
-      ]
-    )
-    .signAndSend(sudo, { nonce: nonce++ })
-
-  // Create person entity via "transaction" extrinsic
-  await api.tx.contentDirectory
-    .transaction(
-      { Member: ALICE_MEMBER_ID }, // actor
-      // operations:
-      [
-        { CreateEntity: { class_id: NEW_CLASS_ID } },
-        {
-          AddSchemaSupportToEntity: {
-            entity_id: { InternalEntityJustAdded: 0 },
-            schema_id: 1,
-            parametrized_property_values: [
-              {
-                in_class_index: 0,
-                value: { InputPropertyValue: { Single: { Text: 'John' } } },
-              },
-              {
-                in_class_index: 1,
-                value: { InputPropertyValue: { Single: { Text: 'Doe' } } },
-              },
-              {
-                in_class_index: 2,
-                value: { InputPropertyValue: { Single: { Uint16: 20 } } },
-              },
-              {
-                in_class_index: 3,
-                value: { InputPropertyValue: { Vector: { Text: ['blockchain', 'cryptocurrencies'] } } },
-              },
-              {
-                in_class_index: 4,
-                value: { InputPropertyValue: { Single: { Text: 'john_doe_unique_identifier' } } },
-              },
-            ],
-          },
-        },
-      ]
-    )
-    .signAndSend(sudo, { nonce: nonce++ })
-}
-
-if (typeof module === 'undefined') {
-  // Pioneer js-toolbox
-  script({ api, hashing, keyring, types, util, joy })
-} else {
-  // Node
-  module.exports = script
-}