schemas.py 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. # coding=utf-8
  2. import marshmallow
  3. from marshmallow import post_load
  4. from marshmallow.validate import OneOf
  5. from marshmallow.validate import Range
  6. from tracim.lib.utils.utils import DATETIME_FORMAT
  7. from tracim.models.auth import Profile
  8. from tracim.models.contents import GlobalStatus
  9. from tracim.models.contents import open_status
  10. from tracim.models.contents import ContentTypeLegacy as ContentType
  11. from tracim.models.contents import ContentStatusLegacy as ContentStatus
  12. from tracim.models.context_models import ActiveContentFilter
  13. from tracim.models.context_models import ContentIdsQuery
  14. from tracim.models.context_models import UserWorkspaceAndContentPath
  15. from tracim.models.context_models import ContentCreation
  16. from tracim.models.context_models import ContentPreviewSizedPath
  17. from tracim.models.context_models import RevisionPreviewSizedPath
  18. from tracim.models.context_models import PageQuery
  19. from tracim.models.context_models import WorkspaceAndContentRevisionPath
  20. from tracim.models.context_models import WorkspaceMemberInvitation
  21. from tracim.models.context_models import WorkspaceUpdate
  22. from tracim.models.context_models import RoleUpdate
  23. from tracim.models.context_models import CommentCreation
  24. from tracim.models.context_models import TextBasedContentUpdate
  25. from tracim.models.context_models import SetContentStatus
  26. from tracim.models.context_models import CommentPath
  27. from tracim.models.context_models import MoveParams
  28. from tracim.models.context_models import WorkspaceAndContentPath
  29. from tracim.models.context_models import WorkspaceAndUserPath
  30. from tracim.models.context_models import ContentFilter
  31. from tracim.models.context_models import LoginCredentials
  32. from tracim.models.data import UserRoleInWorkspace
  33. from tracim.models.data import ActionDescription
  34. class UserDigestSchema(marshmallow.Schema):
  35. """
  36. Simple user schema
  37. """
  38. user_id = marshmallow.fields.Int(dump_only=True, example=3)
  39. avatar_url = marshmallow.fields.Url(
  40. allow_none=True,
  41. example="/api/v2/assets/avatars/suri-cate.jpg",
  42. description="avatar_url is the url to the image file. "
  43. "If no avatar, then set it to null "
  44. "(and frontend will interpret this with a default avatar)",
  45. )
  46. public_name = marshmallow.fields.String(
  47. example='Suri Cate',
  48. )
  49. class UserSchema(UserDigestSchema):
  50. """
  51. Complete user schema
  52. """
  53. email = marshmallow.fields.Email(
  54. required=True,
  55. example='suri.cate@algoo.fr'
  56. )
  57. created = marshmallow.fields.DateTime(
  58. format=DATETIME_FORMAT,
  59. description='User account creation date',
  60. )
  61. is_active = marshmallow.fields.Bool(
  62. example=True,
  63. # TODO - G.M - Explains this value.
  64. )
  65. # TODO - G.M - 17-04-2018 - Restrict timezone values
  66. timezone = marshmallow.fields.String(
  67. example="Paris/Europe",
  68. )
  69. # TODO - G.M - 17-04-2018 - check this, relative url allowed ?
  70. caldav_url = marshmallow.fields.Url(
  71. allow_none=True,
  72. relative=True,
  73. attribute='calendar_url',
  74. example="/api/v2/calendar/user/3.ics/",
  75. description="The url for calendar CalDAV direct access",
  76. )
  77. profile = marshmallow.fields.String(
  78. attribute='profile',
  79. validate=OneOf(Profile._NAME),
  80. example='managers',
  81. )
  82. class Meta:
  83. description = 'User account of Tracim'
  84. # Path Schemas
  85. class UserIdPathSchema(marshmallow.Schema):
  86. user_id = marshmallow.fields.Int(
  87. example=3,
  88. required=True,
  89. description='id of a valid user',
  90. validate=Range(min=1, error="Value must be greater than 0"),
  91. )
  92. class WorkspaceIdPathSchema(marshmallow.Schema):
  93. workspace_id = marshmallow.fields.Int(
  94. example=4,
  95. required=True,
  96. description='id of a valid workspace',
  97. validate=Range(min=1, error="Value must be greater than 0"),
  98. )
  99. class ContentIdPathSchema(marshmallow.Schema):
  100. content_id = marshmallow.fields.Int(
  101. example=6,
  102. required=True,
  103. description='id of a valid content',
  104. validate=Range(min=1, error="Value must be greater than 0"),
  105. )
  106. class RevisionIdPathSchema(marshmallow.Schema):
  107. revision_id = marshmallow.fields.Int(example=6, required=True)
  108. class WorkspaceAndUserIdPathSchema(
  109. UserIdPathSchema,
  110. WorkspaceIdPathSchema
  111. ):
  112. @post_load
  113. def make_path_object(self, data):
  114. return WorkspaceAndUserPath(**data)
  115. class WorkspaceAndContentIdPathSchema(
  116. WorkspaceIdPathSchema,
  117. ContentIdPathSchema
  118. ):
  119. @post_load
  120. def make_path_object(self, data):
  121. return WorkspaceAndContentPath(**data)
  122. class WidthAndHeightPathSchema(marshmallow.Schema):
  123. width = marshmallow.fields.Int(example=256)
  124. height = marshmallow.fields.Int(example=256)
  125. class AllowedJpgPreviewSizesSchema(marshmallow.Schema):
  126. width = marshmallow.fields.Int(example=256)
  127. height = marshmallow.fields.Int(example=256)
  128. class AllowedJpgPreviewDimSchema(marshmallow.Schema):
  129. restricted = marshmallow.fields.Bool()
  130. dimensions = marshmallow.fields.Nested(
  131. AllowedJpgPreviewSizesSchema,
  132. many=True
  133. )
  134. class WorkspaceAndContentRevisionIdPathSchema(
  135. WorkspaceIdPathSchema,
  136. ContentIdPathSchema,
  137. RevisionIdPathSchema,
  138. ):
  139. @post_load
  140. def make_path_object(self, data):
  141. return WorkspaceAndContentRevisionPath(**data)
  142. class ContentPreviewSizedPathSchema(
  143. WorkspaceAndContentIdPathSchema,
  144. WidthAndHeightPathSchema
  145. ):
  146. @post_load
  147. def make_path_object(self, data):
  148. return ContentPreviewSizedPath(**data)
  149. class RevisionPreviewSizedPathSchema(
  150. WorkspaceAndContentRevisionIdPathSchema,
  151. WidthAndHeightPathSchema
  152. ):
  153. @post_load
  154. def make_path_object(self, data):
  155. return RevisionPreviewSizedPath(**data)
  156. class UserWorkspaceAndContentIdPathSchema(
  157. UserIdPathSchema,
  158. WorkspaceIdPathSchema,
  159. ContentIdPathSchema,
  160. ):
  161. @post_load
  162. def make_path_object(self, data):
  163. return UserWorkspaceAndContentPath(**data)
  164. class UserWorkspaceIdPathSchema(
  165. UserIdPathSchema,
  166. WorkspaceIdPathSchema,
  167. ):
  168. @post_load
  169. def make_path_object(self, data):
  170. return WorkspaceAndUserPath(**data)
  171. class CommentsPathSchema(WorkspaceAndContentIdPathSchema):
  172. comment_id = marshmallow.fields.Int(
  173. example=6,
  174. description='id of a valid comment related to content content_id',
  175. required=True,
  176. validate=Range(min=1, error="Value must be greater than 0"),
  177. )
  178. @post_load
  179. def make_path_object(self, data):
  180. return CommentPath(**data)
  181. class PageQuerySchema(marshmallow.Schema):
  182. page = marshmallow.fields.Int(
  183. example=2,
  184. default=0,
  185. description='allow to show a specific page of a pdf file',
  186. validate=Range(min=0, error="Value must be positive or 0"),
  187. )
  188. @post_load
  189. def make_page_query(self, data):
  190. return PageQuery(**data)
  191. class FilterContentQuerySchema(marshmallow.Schema):
  192. parent_id = marshmallow.fields.Int(
  193. example=2,
  194. default=0,
  195. description='allow to filter items in a folder.'
  196. ' If not set, then return all contents.'
  197. ' If set to 0, then return root contents.'
  198. ' If set to another value, return all contents'
  199. ' directly included in the folder parent_id',
  200. validate=Range(min=0, error="Value must be positive or 0"),
  201. )
  202. show_archived = marshmallow.fields.Int(
  203. example=0,
  204. default=0,
  205. description='if set to 1, then show archived contents.'
  206. ' Default is 0 - hide archived content',
  207. validate=Range(min=0, max=1, error="Value must be 0 or 1"),
  208. )
  209. show_deleted = marshmallow.fields.Int(
  210. example=0,
  211. default=0,
  212. description='if set to 1, then show deleted contents.'
  213. ' Default is 0 - hide deleted content',
  214. validate=Range(min=0, max=1, error="Value must be 0 or 1"),
  215. )
  216. show_active = marshmallow.fields.Int(
  217. example=1,
  218. default=1,
  219. description='f set to 1, then show active contents. '
  220. 'Default is 1 - show active content.'
  221. ' Note: active content are content '
  222. 'that is neither archived nor deleted. '
  223. 'The reason for this parameter to exist is for example '
  224. 'to allow to show only archived documents',
  225. validate=Range(min=0, max=1, error="Value must be 0 or 1"),
  226. )
  227. content_type = marshmallow.fields.String(
  228. example=ContentType.Any,
  229. default=ContentType.Any,
  230. validate=OneOf(ContentType.allowed_type_values())
  231. )
  232. @post_load
  233. def make_content_filter(self, data):
  234. return ContentFilter(**data)
  235. class ActiveContentFilterQuerySchema(marshmallow.Schema):
  236. limit = marshmallow.fields.Int(
  237. example=2,
  238. default=0,
  239. description='if 0 or not set, return all elements, else return only '
  240. 'the first limit elem (according to offset)',
  241. validate=Range(min=0, error="Value must be positive or 0"),
  242. )
  243. before_datetime = marshmallow.fields.DateTime(
  244. format=DATETIME_FORMAT,
  245. description='return only content lastly updated before this date',
  246. )
  247. @post_load
  248. def make_content_filter(self, data):
  249. return ActiveContentFilter(**data)
  250. class ContentIdsQuerySchema(marshmallow.Schema):
  251. contents_ids = marshmallow.fields.List(
  252. marshmallow.fields.Int(
  253. example=6,
  254. validate=Range(min=1, error="Value must be greater than 0"),
  255. )
  256. )
  257. @post_load
  258. def make_contents_ids(self, data):
  259. return ContentIdsQuery(**data)
  260. ###
  261. class RoleUpdateSchema(marshmallow.Schema):
  262. role = marshmallow.fields.String(
  263. example='contributor',
  264. validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
  265. )
  266. @post_load
  267. def make_role(self, data):
  268. return RoleUpdate(**data)
  269. class WorkspaceMemberInviteSchema(RoleUpdateSchema):
  270. user_id = marshmallow.fields.Int(
  271. example=5,
  272. default=None,
  273. allow_none=True,
  274. )
  275. user_email_or_public_name = marshmallow.fields.String(
  276. example='suri@cate.fr',
  277. default=None,
  278. allow_none=True,
  279. )
  280. @post_load
  281. def make_role(self, data):
  282. return WorkspaceMemberInvitation(**data)
  283. class BasicAuthSchema(marshmallow.Schema):
  284. email = marshmallow.fields.Email(
  285. example='suri.cate@algoo.fr',
  286. required=True
  287. )
  288. password = marshmallow.fields.String(
  289. example='8QLa$<w',
  290. required=True,
  291. load_only=True,
  292. )
  293. class Meta:
  294. description = 'Entry for HTTP Basic Auth'
  295. @post_load
  296. def make_login(self, data):
  297. return LoginCredentials(**data)
  298. class LoginOutputHeaders(marshmallow.Schema):
  299. expire_after = marshmallow.fields.String()
  300. class WorkspaceModifySchema(marshmallow.Schema):
  301. label = marshmallow.fields.String(
  302. example='My Workspace',
  303. )
  304. description = marshmallow.fields.String(
  305. example='A super description of my workspace.',
  306. )
  307. @post_load
  308. def make_workspace_modifications(self, data):
  309. return WorkspaceUpdate(**data)
  310. class WorkspaceCreationSchema(WorkspaceModifySchema):
  311. pass
  312. class NoContentSchema(marshmallow.Schema):
  313. class Meta:
  314. description = 'Empty Schema'
  315. pass
  316. class WorkspaceMenuEntrySchema(marshmallow.Schema):
  317. slug = marshmallow.fields.String(example='markdown-pages')
  318. label = marshmallow.fields.String(example='Markdown Documents')
  319. route = marshmallow.fields.String(
  320. example='/#/workspace/{workspace_id}/contents/?type=mardown-page',
  321. description='the route is the frontend route. '
  322. 'It may include workspace_id '
  323. 'which must be replaced on backend size '
  324. '(the route must be ready-to-use)'
  325. )
  326. fa_icon = marshmallow.fields.String(
  327. example='file-text-o',
  328. description='CSS class of the icon. Example: file-o for using Fontawesome file-text-o icon', # nopep8
  329. )
  330. hexcolor = marshmallow.fields.String(
  331. example='#F0F9DC',
  332. description='Hexadecimal color of the entry.'
  333. )
  334. class Meta:
  335. description = 'Entry element of a workspace menu'
  336. class WorkspaceDigestSchema(marshmallow.Schema):
  337. workspace_id = marshmallow.fields.Int(
  338. example=4,
  339. validate=Range(min=1, error="Value must be greater than 0"),
  340. )
  341. slug = marshmallow.fields.String(example='intranet')
  342. label = marshmallow.fields.String(example='Intranet')
  343. sidebar_entries = marshmallow.fields.Nested(
  344. WorkspaceMenuEntrySchema,
  345. many=True,
  346. )
  347. class Meta:
  348. description = 'Digest of workspace informations'
  349. class WorkspaceSchema(WorkspaceDigestSchema):
  350. description = marshmallow.fields.String(example='All intranet data.')
  351. class Meta:
  352. description = 'Full workspace informations'
  353. class WorkspaceMemberSchema(marshmallow.Schema):
  354. role = marshmallow.fields.String(
  355. example='contributor',
  356. validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
  357. )
  358. user_id = marshmallow.fields.Int(
  359. example=3,
  360. validate=Range(min=1, error="Value must be greater than 0"),
  361. )
  362. workspace_id = marshmallow.fields.Int(
  363. example=4,
  364. validate=Range(min=1, error="Value must be greater than 0"),
  365. )
  366. user = marshmallow.fields.Nested(
  367. UserDigestSchema()
  368. )
  369. workspace = marshmallow.fields.Nested(
  370. WorkspaceDigestSchema(exclude=('sidebar_entries',))
  371. )
  372. is_active = marshmallow.fields.Bool()
  373. class Meta:
  374. description = 'Workspace Member information'
  375. class WorkspaceMemberCreationSchema(WorkspaceMemberSchema):
  376. newly_created = marshmallow.fields.Bool(
  377. exemple=False,
  378. description='Is the user completely new '
  379. '(and account was just created) or not ?',
  380. )
  381. email_sent = marshmallow.fields.Bool(
  382. exemple=False,
  383. description='Has an email been sent to user to inform him about '
  384. 'this new workspace registration and eventually his account'
  385. 'creation'
  386. )
  387. class ApplicationConfigSchema(marshmallow.Schema):
  388. pass
  389. # TODO - G.M - 24-05-2018 - Set this
  390. class ApplicationSchema(marshmallow.Schema):
  391. label = marshmallow.fields.String(example='Calendar')
  392. slug = marshmallow.fields.String(example='calendar')
  393. fa_icon = marshmallow.fields.String(
  394. example='file-o',
  395. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  396. )
  397. hexcolor = marshmallow.fields.String(
  398. example='#FF0000',
  399. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  400. )
  401. is_active = marshmallow.fields.Boolean(
  402. example=True,
  403. description='if true, the application is in use in the context',
  404. )
  405. config = marshmallow.fields.Nested(
  406. ApplicationConfigSchema,
  407. )
  408. class Meta:
  409. description = 'Tracim Application informations'
  410. class StatusSchema(marshmallow.Schema):
  411. slug = marshmallow.fields.String(
  412. example='open',
  413. description='the slug represents the type of status. '
  414. 'Statuses are open, closed-validated, closed-invalidated, closed-deprecated' # nopep8
  415. )
  416. global_status = marshmallow.fields.String(
  417. example='open',
  418. description='global_status: open, closed',
  419. validate=OneOf([status.value for status in GlobalStatus]),
  420. )
  421. label = marshmallow.fields.String(example='Open')
  422. fa_icon = marshmallow.fields.String(example='fa-check')
  423. hexcolor = marshmallow.fields.String(example='#0000FF')
  424. class ContentTypeSchema(marshmallow.Schema):
  425. slug = marshmallow.fields.String(
  426. example='pagehtml',
  427. validate=OneOf(ContentType.allowed_types()),
  428. )
  429. fa_icon = marshmallow.fields.String(
  430. example='fa-file-text-o',
  431. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  432. )
  433. hexcolor = marshmallow.fields.String(
  434. example="#FF0000",
  435. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  436. )
  437. label = marshmallow.fields.String(
  438. example='Text Documents'
  439. )
  440. creation_label = marshmallow.fields.String(
  441. example='Write a document'
  442. )
  443. available_statuses = marshmallow.fields.Nested(
  444. StatusSchema,
  445. many=True
  446. )
  447. class ContentMoveSchema(marshmallow.Schema):
  448. # TODO - G.M - 30-05-2018 - Read and apply this note
  449. # Note:
  450. # if the new workspace is different, then the backend
  451. # must check if the user is allowed to move to this workspace
  452. # (the user must be content manager of both workspaces)
  453. new_parent_id = marshmallow.fields.Int(
  454. example=42,
  455. description='id of the new parent content id.',
  456. allow_none=True,
  457. required=True,
  458. validate=Range(min=0, error="Value must be positive or 0"),
  459. )
  460. new_workspace_id = marshmallow.fields.Int(
  461. example=2,
  462. description='id of the new workspace id.',
  463. required=True,
  464. validate=Range(min=1, error="Value must be greater than 0"),
  465. )
  466. @post_load
  467. def make_move_params(self, data):
  468. return MoveParams(**data)
  469. class ContentCreationSchema(marshmallow.Schema):
  470. label = marshmallow.fields.String(
  471. example='contract for client XXX',
  472. description='Title of the content to create'
  473. )
  474. content_type = marshmallow.fields.String(
  475. example='html-documents',
  476. validate=OneOf(ContentType.allowed_types_for_folding()), # nopep8
  477. )
  478. parent_id = marshmallow.fields.Integer(
  479. example=35,
  480. description='content_id of parent content, if content should be placed in a folder, this should be folder content_id.'
  481. )
  482. @post_load
  483. def make_content_filter(self, data):
  484. return ContentCreation(**data)
  485. class ContentDigestSchema(marshmallow.Schema):
  486. content_id = marshmallow.fields.Int(
  487. example=6,
  488. validate=Range(min=1, error="Value must be greater than 0"),
  489. )
  490. slug = marshmallow.fields.Str(example='intervention-report-12')
  491. parent_id = marshmallow.fields.Int(
  492. example=34,
  493. allow_none=True,
  494. default=None,
  495. validate=Range(min=0, error="Value must be positive or 0"),
  496. )
  497. workspace_id = marshmallow.fields.Int(
  498. example=19,
  499. validate=Range(min=1, error="Value must be greater than 0"),
  500. )
  501. label = marshmallow.fields.Str(example='Intervention Report 12')
  502. content_type = marshmallow.fields.Str(
  503. example='html-documents',
  504. validate=OneOf(ContentType.allowed_types()),
  505. )
  506. sub_content_types = marshmallow.fields.List(
  507. marshmallow.fields.String(
  508. example='html-content',
  509. validate=OneOf(ContentType.allowed_types())
  510. ),
  511. description='list of content types allowed as sub contents. '
  512. 'This field is required for folder contents, '
  513. 'set it to empty list in other cases'
  514. )
  515. status = marshmallow.fields.Str(
  516. example='closed-deprecated',
  517. validate=OneOf(ContentStatus.allowed_values()),
  518. description='this slug is found in content_type available statuses',
  519. default=open_status
  520. )
  521. is_archived = marshmallow.fields.Bool(example=False, default=False)
  522. is_deleted = marshmallow.fields.Bool(example=False, default=False)
  523. show_in_ui = marshmallow.fields.Bool(
  524. example=True,
  525. description='if false, then do not show content in the treeview. '
  526. 'This may his maybe used for specific contents or '
  527. 'for sub-contents. Default is True. '
  528. 'In first version of the API, this field is always True',
  529. )
  530. class ReadStatusSchema(marshmallow.Schema):
  531. content_id = marshmallow.fields.Int(
  532. example=6,
  533. validate=Range(min=1, error="Value must be greater than 0"),
  534. )
  535. read_by_user = marshmallow.fields.Bool(example=False, default=False)
  536. #####
  537. # Content
  538. #####
  539. class ContentSchema(ContentDigestSchema):
  540. current_revision_id = marshmallow.fields.Int(example=12)
  541. created = marshmallow.fields.DateTime(
  542. format=DATETIME_FORMAT,
  543. description='Content creation date',
  544. )
  545. author = marshmallow.fields.Nested(UserDigestSchema)
  546. modified = marshmallow.fields.DateTime(
  547. format=DATETIME_FORMAT,
  548. description='date of last modification of content',
  549. )
  550. last_modifier = marshmallow.fields.Nested(UserDigestSchema)
  551. class TextBasedDataAbstractSchema(marshmallow.Schema):
  552. raw_content = marshmallow.fields.String(
  553. description='Content of the object, may be raw text or <b>html</b> for example' # nopep8
  554. )
  555. class FileInfoAbstractSchema(marshmallow.Schema):
  556. raw_content = marshmallow.fields.String(
  557. description='raw text or html description of the file'
  558. )
  559. class TextBasedContentSchema(ContentSchema, TextBasedDataAbstractSchema):
  560. pass
  561. class FileContentSchema(ContentSchema, FileInfoAbstractSchema):
  562. pass
  563. #####
  564. # Revision
  565. #####
  566. class RevisionSchema(ContentDigestSchema):
  567. comment_ids = marshmallow.fields.List(
  568. marshmallow.fields.Int(
  569. example=4,
  570. validate=Range(min=1, error="Value must be greater than 0"),
  571. )
  572. )
  573. revision_id = marshmallow.fields.Int(
  574. example=12,
  575. validate=Range(min=1, error="Value must be greater than 0"),
  576. )
  577. revision_type = marshmallow.fields.String(
  578. example=ActionDescription.CREATION,
  579. validate=OneOf(ActionDescription.allowed_values()),
  580. )
  581. created = marshmallow.fields.DateTime(
  582. format=DATETIME_FORMAT,
  583. description='Content creation date',
  584. )
  585. author = marshmallow.fields.Nested(UserDigestSchema)
  586. class TextBasedRevisionSchema(RevisionSchema, TextBasedDataAbstractSchema):
  587. pass
  588. class FileRevisionSchema(RevisionSchema, FileInfoAbstractSchema):
  589. pass
  590. class CommentSchema(marshmallow.Schema):
  591. content_id = marshmallow.fields.Int(
  592. example=6,
  593. validate=Range(min=1, error="Value must be greater than 0"),
  594. )
  595. parent_id = marshmallow.fields.Int(
  596. example=34,
  597. validate=Range(min=0, error="Value must be positive or 0"),
  598. )
  599. raw_content = marshmallow.fields.String(
  600. example='<p>This is just an html comment !</p>'
  601. )
  602. author = marshmallow.fields.Nested(UserDigestSchema)
  603. created = marshmallow.fields.DateTime(
  604. format=DATETIME_FORMAT,
  605. description='comment creation date',
  606. )
  607. class SetCommentSchema(marshmallow.Schema):
  608. raw_content = marshmallow.fields.String(
  609. example='<p>This is just an html comment !</p>'
  610. )
  611. @post_load()
  612. def create_comment(self, data):
  613. return CommentCreation(**data)
  614. class ContentModifyAbstractSchema(marshmallow.Schema):
  615. label = marshmallow.fields.String(
  616. required=True,
  617. example='contract for client XXX',
  618. description='New title of the content'
  619. )
  620. class TextBasedContentModifySchema(ContentModifyAbstractSchema, TextBasedDataAbstractSchema): # nopep8
  621. @post_load
  622. def text_based_content_update(self, data):
  623. return TextBasedContentUpdate(**data)
  624. class FileContentModifySchema(TextBasedContentModifySchema):
  625. pass
  626. class SetContentStatusSchema(marshmallow.Schema):
  627. status = marshmallow.fields.Str(
  628. example='closed-deprecated',
  629. validate=OneOf(ContentStatus.allowed_values()),
  630. description='this slug is found in content_type available statuses',
  631. default=open_status,
  632. required=True,
  633. )
  634. @post_load
  635. def set_status(self, data):
  636. return SetContentStatus(**data)