schemas.py 28KB

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