schemas.py 26KB

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