schemas.py 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  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. do_notify = marshmallow.fields.Bool(
  372. description='has user enabled notification for this workspace',
  373. example=True,
  374. default=None,
  375. allow_none=True,
  376. )
  377. @post_load
  378. def make_role(self, data):
  379. return RoleUpdate(**data)
  380. class WorkspaceMemberInviteSchema(RoleUpdateSchema):
  381. user_id = marshmallow.fields.Int(
  382. example=5,
  383. default=None,
  384. allow_none=True,
  385. )
  386. user_email_or_public_name = marshmallow.fields.String(
  387. example='suri@cate.fr',
  388. default=None,
  389. allow_none=True,
  390. )
  391. @post_load
  392. def make_role(self, data):
  393. return WorkspaceMemberInvitation(**data)
  394. class BasicAuthSchema(marshmallow.Schema):
  395. email = marshmallow.fields.Email(
  396. example='suri.cate@algoo.fr',
  397. required=True
  398. )
  399. password = marshmallow.fields.String(
  400. example='8QLa$<w',
  401. required=True,
  402. load_only=True,
  403. )
  404. class Meta:
  405. description = 'Entry for HTTP Basic Auth'
  406. @post_load
  407. def make_login(self, data):
  408. return LoginCredentials(**data)
  409. class LoginOutputHeaders(marshmallow.Schema):
  410. expire_after = marshmallow.fields.String()
  411. class WorkspaceModifySchema(marshmallow.Schema):
  412. label = marshmallow.fields.String(
  413. example='My Workspace',
  414. )
  415. description = marshmallow.fields.String(
  416. example='A super description of my workspace.',
  417. )
  418. @post_load
  419. def make_workspace_modifications(self, data):
  420. return WorkspaceUpdate(**data)
  421. class WorkspaceCreationSchema(WorkspaceModifySchema):
  422. pass
  423. class NoContentSchema(marshmallow.Schema):
  424. class Meta:
  425. description = 'Empty Schema'
  426. pass
  427. class WorkspaceMenuEntrySchema(marshmallow.Schema):
  428. slug = marshmallow.fields.String(example='markdown-pages')
  429. label = marshmallow.fields.String(example='Markdown Documents')
  430. route = marshmallow.fields.String(
  431. example='/#/workspace/{workspace_id}/contents/?type=mardown-page',
  432. description='the route is the frontend route. '
  433. 'It may include workspace_id '
  434. 'which must be replaced on backend size '
  435. '(the route must be ready-to-use)'
  436. )
  437. fa_icon = marshmallow.fields.String(
  438. example='file-text-o',
  439. description='CSS class of the icon. Example: file-o for using Fontawesome file-text-o icon', # nopep8
  440. )
  441. hexcolor = marshmallow.fields.String(
  442. example='#F0F9DC',
  443. description='Hexadecimal color of the entry.'
  444. )
  445. class Meta:
  446. description = 'Entry element of a workspace menu'
  447. class WorkspaceDigestSchema(marshmallow.Schema):
  448. workspace_id = marshmallow.fields.Int(
  449. example=4,
  450. validate=Range(min=1, error="Value must be greater than 0"),
  451. )
  452. slug = marshmallow.fields.String(example='intranet')
  453. label = marshmallow.fields.String(example='Intranet')
  454. sidebar_entries = marshmallow.fields.Nested(
  455. WorkspaceMenuEntrySchema,
  456. many=True,
  457. )
  458. is_deleted = marshmallow.fields.Bool(example=False, default=False)
  459. class Meta:
  460. description = 'Digest of workspace informations'
  461. class WorkspaceSchema(WorkspaceDigestSchema):
  462. description = marshmallow.fields.String(example='All intranet data.')
  463. class Meta:
  464. description = 'Full workspace informations'
  465. class WorkspaceMemberSchema(marshmallow.Schema):
  466. role = marshmallow.fields.String(
  467. example='contributor',
  468. validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
  469. )
  470. user_id = marshmallow.fields.Int(
  471. example=3,
  472. validate=Range(min=1, error="Value must be greater than 0"),
  473. )
  474. workspace_id = marshmallow.fields.Int(
  475. example=4,
  476. validate=Range(min=1, error="Value must be greater than 0"),
  477. )
  478. user = marshmallow.fields.Nested(
  479. UserDigestSchema()
  480. )
  481. workspace = marshmallow.fields.Nested(
  482. WorkspaceDigestSchema(exclude=('sidebar_entries',))
  483. )
  484. is_active = marshmallow.fields.Bool()
  485. do_notify = marshmallow.fields.Bool(
  486. description='has user enabled notification for this workspace',
  487. example=True,
  488. )
  489. class Meta:
  490. description = 'Workspace Member information'
  491. class WorkspaceMemberCreationSchema(WorkspaceMemberSchema):
  492. newly_created = marshmallow.fields.Bool(
  493. exemple=False,
  494. description='Is the user completely new '
  495. '(and account was just created) or not ?',
  496. )
  497. email_sent = marshmallow.fields.Bool(
  498. exemple=False,
  499. description='Has an email been sent to user to inform him about '
  500. 'this new workspace registration and eventually his account'
  501. 'creation'
  502. )
  503. class ApplicationConfigSchema(marshmallow.Schema):
  504. pass
  505. # TODO - G.M - 24-05-2018 - Set this
  506. class ApplicationSchema(marshmallow.Schema):
  507. label = marshmallow.fields.String(example='Calendar')
  508. slug = marshmallow.fields.String(example='calendar')
  509. fa_icon = marshmallow.fields.String(
  510. example='file-o',
  511. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  512. )
  513. hexcolor = marshmallow.fields.String(
  514. example='#FF0000',
  515. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  516. )
  517. is_active = marshmallow.fields.Boolean(
  518. example=True,
  519. description='if true, the application is in use in the context',
  520. )
  521. config = marshmallow.fields.Nested(
  522. ApplicationConfigSchema,
  523. )
  524. class Meta:
  525. description = 'Tracim Application informations'
  526. class StatusSchema(marshmallow.Schema):
  527. slug = marshmallow.fields.String(
  528. example='open',
  529. description='the slug represents the type of status. '
  530. 'Statuses are open, closed-validated, closed-invalidated, closed-deprecated' # nopep8
  531. )
  532. global_status = marshmallow.fields.String(
  533. example='open',
  534. description='global_status: open, closed',
  535. validate=OneOf([status.value for status in GlobalStatus]),
  536. )
  537. label = marshmallow.fields.String(example='Open')
  538. fa_icon = marshmallow.fields.String(example='fa-check')
  539. hexcolor = marshmallow.fields.String(example='#0000FF')
  540. class ContentTypeSchema(marshmallow.Schema):
  541. slug = marshmallow.fields.String(
  542. example='pagehtml',
  543. validate=all_content_types_validator,
  544. )
  545. fa_icon = marshmallow.fields.String(
  546. example='fa-file-text-o',
  547. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  548. )
  549. hexcolor = marshmallow.fields.String(
  550. example="#FF0000",
  551. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  552. )
  553. label = marshmallow.fields.String(
  554. example='Text Documents'
  555. )
  556. creation_label = marshmallow.fields.String(
  557. example='Write a document'
  558. )
  559. available_statuses = marshmallow.fields.Nested(
  560. StatusSchema,
  561. many=True
  562. )
  563. class ContentMoveSchema(marshmallow.Schema):
  564. # TODO - G.M - 30-05-2018 - Read and apply this note
  565. # Note:
  566. # if the new workspace is different, then the backend
  567. # must check if the user is allowed to move to this workspace
  568. # (the user must be content manager of both workspaces)
  569. new_parent_id = marshmallow.fields.Int(
  570. example=42,
  571. description='id of the new parent content id.',
  572. allow_none=True,
  573. required=True,
  574. validate=Range(min=0, error="Value must be positive or 0"),
  575. )
  576. new_workspace_id = marshmallow.fields.Int(
  577. example=2,
  578. description='id of the new workspace id.',
  579. required=True,
  580. validate=Range(min=1, error="Value must be greater than 0"),
  581. )
  582. @post_load
  583. def make_move_params(self, data):
  584. return MoveParams(**data)
  585. class ContentCreationSchema(marshmallow.Schema):
  586. label = marshmallow.fields.String(
  587. example='contract for client XXX',
  588. description='Title of the content to create'
  589. )
  590. content_type = marshmallow.fields.String(
  591. example='html-document',
  592. validate=all_content_types_validator,
  593. )
  594. parent_id = marshmallow.fields.Integer(
  595. example=35,
  596. description='content_id of parent content, if content should be placed in a folder, this should be folder content_id.', # nopep8
  597. allow_none=True,
  598. default=None,
  599. validate=Range(min=1, error="Value must be positive"),
  600. )
  601. @post_load
  602. def make_content_creation(self, data):
  603. return ContentCreation(**data)
  604. class ContentDigestSchema(marshmallow.Schema):
  605. content_id = marshmallow.fields.Int(
  606. example=6,
  607. validate=Range(min=1, error="Value must be greater than 0"),
  608. )
  609. slug = marshmallow.fields.Str(example='intervention-report-12')
  610. parent_id = marshmallow.fields.Int(
  611. example=34,
  612. allow_none=True,
  613. default=None,
  614. validate=Range(min=0, error="Value must be positive or 0"),
  615. )
  616. workspace_id = marshmallow.fields.Int(
  617. example=19,
  618. validate=Range(min=1, error="Value must be greater than 0"),
  619. )
  620. label = marshmallow.fields.Str(example='Intervention Report 12')
  621. content_type = marshmallow.fields.Str(
  622. example='html-document',
  623. validate=all_content_types_validator,
  624. )
  625. sub_content_types = marshmallow.fields.List(
  626. marshmallow.fields.String(
  627. example='html-content',
  628. validate=all_content_types_validator
  629. ),
  630. description='list of content types allowed as sub contents. '
  631. 'This field is required for folder contents, '
  632. 'set it to empty list in other cases'
  633. )
  634. status = marshmallow.fields.Str(
  635. example='closed-deprecated',
  636. validate=OneOf(CONTENT_STATUS.get_all_slugs_values()),
  637. description='this slug is found in content_type available statuses',
  638. default=open_status
  639. )
  640. is_archived = marshmallow.fields.Bool(example=False, default=False)
  641. is_deleted = marshmallow.fields.Bool(example=False, default=False)
  642. show_in_ui = marshmallow.fields.Bool(
  643. example=True,
  644. description='if false, then do not show content in the treeview. '
  645. 'This may his maybe used for specific contents or '
  646. 'for sub-contents. Default is True. '
  647. 'In first version of the API, this field is always True',
  648. )
  649. class ReadStatusSchema(marshmallow.Schema):
  650. content_id = marshmallow.fields.Int(
  651. example=6,
  652. validate=Range(min=1, error="Value must be greater than 0"),
  653. )
  654. read_by_user = marshmallow.fields.Bool(example=False, default=False)
  655. #####
  656. # Content
  657. #####
  658. class ContentSchema(ContentDigestSchema):
  659. current_revision_id = marshmallow.fields.Int(example=12)
  660. created = marshmallow.fields.DateTime(
  661. format=DATETIME_FORMAT,
  662. description='Content creation date',
  663. )
  664. author = marshmallow.fields.Nested(UserDigestSchema)
  665. modified = marshmallow.fields.DateTime(
  666. format=DATETIME_FORMAT,
  667. description='date of last modification of content',
  668. )
  669. last_modifier = marshmallow.fields.Nested(UserDigestSchema)
  670. class TextBasedDataAbstractSchema(marshmallow.Schema):
  671. raw_content = marshmallow.fields.String(
  672. description='Content of the object, may be raw text or <b>html</b> for example' # nopep8
  673. )
  674. class FileInfoAbstractSchema(marshmallow.Schema):
  675. raw_content = marshmallow.fields.String(
  676. description='raw text or html description of the file'
  677. )
  678. class TextBasedContentSchema(ContentSchema, TextBasedDataAbstractSchema):
  679. pass
  680. class FileContentSchema(ContentSchema, FileInfoAbstractSchema):
  681. pass
  682. #####
  683. # Revision
  684. #####
  685. class RevisionSchema(ContentDigestSchema):
  686. comment_ids = marshmallow.fields.List(
  687. marshmallow.fields.Int(
  688. example=4,
  689. validate=Range(min=1, error="Value must be greater than 0"),
  690. )
  691. )
  692. revision_id = marshmallow.fields.Int(
  693. example=12,
  694. validate=Range(min=1, error="Value must be greater than 0"),
  695. )
  696. revision_type = marshmallow.fields.String(
  697. example=ActionDescription.CREATION,
  698. validate=OneOf(ActionDescription.allowed_values()),
  699. )
  700. created = marshmallow.fields.DateTime(
  701. format=DATETIME_FORMAT,
  702. description='Content creation date',
  703. )
  704. author = marshmallow.fields.Nested(UserDigestSchema)
  705. class TextBasedRevisionSchema(RevisionSchema, TextBasedDataAbstractSchema):
  706. pass
  707. class FileRevisionSchema(RevisionSchema, FileInfoAbstractSchema):
  708. pass
  709. class CommentSchema(marshmallow.Schema):
  710. content_id = marshmallow.fields.Int(
  711. example=6,
  712. validate=Range(min=1, error="Value must be greater than 0"),
  713. )
  714. parent_id = marshmallow.fields.Int(
  715. example=34,
  716. validate=Range(min=0, error="Value must be positive or 0"),
  717. )
  718. raw_content = marshmallow.fields.String(
  719. example='<p>This is just an html comment !</p>'
  720. )
  721. author = marshmallow.fields.Nested(UserDigestSchema)
  722. created = marshmallow.fields.DateTime(
  723. format=DATETIME_FORMAT,
  724. description='comment creation date',
  725. )
  726. class SetCommentSchema(marshmallow.Schema):
  727. raw_content = marshmallow.fields.String(
  728. example='<p>This is just an html comment !</p>'
  729. )
  730. @post_load()
  731. def create_comment(self, data):
  732. return CommentCreation(**data)
  733. class ContentModifyAbstractSchema(marshmallow.Schema):
  734. label = marshmallow.fields.String(
  735. required=True,
  736. example='contract for client XXX',
  737. description='New title of the content'
  738. )
  739. class TextBasedContentModifySchema(ContentModifyAbstractSchema, TextBasedDataAbstractSchema): # nopep8
  740. @post_load
  741. def text_based_content_update(self, data):
  742. return TextBasedContentUpdate(**data)
  743. class FolderContentModifySchema(ContentModifyAbstractSchema, TextBasedDataAbstractSchema): # nopep
  744. sub_content_types = marshmallow.fields.List(
  745. marshmallow.fields.String(
  746. example='html-document',
  747. validate=all_content_types_validator,
  748. ),
  749. description='list of content types allowed as sub contents. '
  750. 'This field is required for folder contents, '
  751. 'set it to empty list in other cases'
  752. )
  753. @post_load
  754. def folder_content_update(self, data):
  755. return FolderContentUpdate(**data)
  756. class FileContentModifySchema(TextBasedContentModifySchema):
  757. pass
  758. class SetContentStatusSchema(marshmallow.Schema):
  759. status = marshmallow.fields.Str(
  760. example='closed-deprecated',
  761. validate=OneOf(CONTENT_STATUS.get_all_slugs_values()),
  762. description='this slug is found in content_type available statuses',
  763. default=open_status,
  764. required=True,
  765. )
  766. @post_load
  767. def set_status(self, data):
  768. return SetContentStatus(**data)