schemas.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. # coding=utf-8
  2. import marshmallow
  3. from marshmallow import post_load
  4. from marshmallow.validate import OneOf
  5. from tracim.models.auth import Profile
  6. from tracim.models.contents import CONTENT_DEFAULT_TYPE
  7. from tracim.models.contents import CONTENT_DEFAULT_STATUS
  8. from tracim.models.contents import GlobalStatus
  9. from tracim.models.contents import open_status
  10. from tracim.models.context_models import ContentCreation
  11. from tracim.models.context_models import MoveParams
  12. from tracim.models.context_models import WorkspaceAndContentPath
  13. from tracim.models.context_models import ContentFilter
  14. from tracim.models.context_models import LoginCredentials
  15. from tracim.models.data import UserRoleInWorkspace
  16. class ProfileSchema(marshmallow.Schema):
  17. slug = marshmallow.fields.String(
  18. attribute='name',
  19. validate=OneOf(Profile._NAME),
  20. example='managers',
  21. )
  22. class Meta:
  23. description = 'User Profile, give user right on whole Tracim instance.'
  24. class UserSchema(marshmallow.Schema):
  25. user_id = marshmallow.fields.Int(dump_only=True, example=3)
  26. email = marshmallow.fields.Email(
  27. required=True,
  28. example='suri.cate@algoo.fr'
  29. )
  30. public_name = marshmallow.fields.String(
  31. example='Suri Cate',
  32. )
  33. created = marshmallow.fields.DateTime(
  34. format='iso8601',
  35. description='User account creation date (iso8601 format).',
  36. )
  37. is_active = marshmallow.fields.Bool(
  38. example=True,
  39. # TODO - G.M - Explains this value.
  40. )
  41. # TODO - G.M - 17-04-2018 - Restrict timezone values
  42. timezone = marshmallow.fields.String(
  43. example="Paris/Europe",
  44. )
  45. # TODO - G.M - 17-04-2018 - check this, relative url allowed ?
  46. caldav_url = marshmallow.fields.Url(
  47. allow_none=True,
  48. relative=True,
  49. attribute='calendar_url',
  50. example="/api/v2/calendar/user/3.ics/",
  51. description="The url for calendar CalDAV direct access",
  52. )
  53. avatar_url = marshmallow.fields.Url(
  54. allow_none=True,
  55. example="/api/v2/assets/avatars/suri-cate.jpg",
  56. description="avatar_url is the url to the image file. "
  57. "If no avatar, then set it to null "
  58. "(and frontend will interpret this with a default avatar)",
  59. )
  60. profile = marshmallow.fields.Nested(
  61. ProfileSchema,
  62. many=False,
  63. )
  64. class Meta:
  65. description = 'User account of Tracim'
  66. # Path Schemas
  67. class UserIdPathSchema(marshmallow.Schema):
  68. user_id = marshmallow.fields.Int(example=3, required=True)
  69. class WorkspaceIdPathSchema(marshmallow.Schema):
  70. workspace_id = marshmallow.fields.Int(example=4, required=True)
  71. class ContentIdPathSchema(marshmallow.Schema):
  72. content_id = marshmallow.fields.Int(example=6, required=True)
  73. class WorkspaceAndContentIdPathSchema(WorkspaceIdPathSchema, ContentIdPathSchema):
  74. @post_load
  75. def make_path_object(self, data):
  76. return WorkspaceAndContentPath(**data)
  77. class FilterContentQuerySchema(marshmallow.Schema):
  78. parent_id = workspace_id = marshmallow.fields.Int(
  79. example=2,
  80. default=None,
  81. description='allow to filter items in a folder.'
  82. ' If not set, then return all contents.'
  83. ' If set to 0, then return root contents.'
  84. ' If set to another value, return all contents'
  85. ' directly included in the folder parent_id'
  86. )
  87. show_archived = marshmallow.fields.Int(
  88. example=0,
  89. default=0,
  90. description='if set to 1, then show archived contents.'
  91. ' Default is 0 - hide archived content'
  92. )
  93. show_deleted = marshmallow.fields.Int(
  94. example=0,
  95. default=0,
  96. description='if set to 1, then show deleted contents.'
  97. ' Default is 0 - hide deleted content'
  98. )
  99. show_active = marshmallow.fields.Int(
  100. example=1,
  101. default=1,
  102. description='f set to 1, then show active contents. '
  103. 'Default is 1 - show active content.'
  104. ' Note: active content are content '
  105. 'that is neither archived nor deleted. '
  106. 'The reason for this parameter to exist is for example '
  107. 'to allow to show only archived documents'
  108. )
  109. @post_load
  110. def make_content_filter(self, data):
  111. return ContentFilter(**data)
  112. ###
  113. class BasicAuthSchema(marshmallow.Schema):
  114. email = marshmallow.fields.Email(
  115. example='suri.cate@algoo.fr',
  116. required=True
  117. )
  118. password = marshmallow.fields.String(
  119. example='8QLa$<w',
  120. required=True,
  121. load_only=True,
  122. )
  123. class Meta:
  124. description = 'Entry for HTTP Basic Auth'
  125. @post_load
  126. def make_login(self, data):
  127. return LoginCredentials(**data)
  128. class LoginOutputHeaders(marshmallow.Schema):
  129. expire_after = marshmallow.fields.String()
  130. class NoContentSchema(marshmallow.Schema):
  131. class Meta:
  132. description = 'Empty Schema'
  133. pass
  134. class WorkspaceMenuEntrySchema(marshmallow.Schema):
  135. slug = marshmallow.fields.String(example='markdown-pages')
  136. label = marshmallow.fields.String(example='Markdown Documents')
  137. route = marshmallow.fields.String(
  138. example='/#/workspace/{workspace_id}/contents/?type=mardown-page',
  139. description='the route is the frontend route. '
  140. 'It may include workspace_id '
  141. 'which must be replaced on backend size '
  142. '(the route must be ready-to-use)'
  143. )
  144. fa_icon = marshmallow.fields.String(
  145. example='file-text-o',
  146. description='CSS class of the icon. Example: file-o for using Fontawesome file-text-o icon', # nopep8
  147. )
  148. hexcolor = marshmallow.fields.String(
  149. example='#F0F9DC',
  150. description='Hexadecimal color of the entry.'
  151. )
  152. class Meta:
  153. description = 'Entry element of a workspace menu'
  154. class WorkspaceDigestSchema(marshmallow.Schema):
  155. workspace_id = marshmallow.fields.Int(example=4)
  156. slug = marshmallow.fields.String(example='intranet')
  157. label = marshmallow.fields.String(example='Intranet')
  158. sidebar_entries = marshmallow.fields.Nested(
  159. WorkspaceMenuEntrySchema,
  160. many=True,
  161. )
  162. class Meta:
  163. description = 'Digest of workspace informations'
  164. class WorkspaceSchema(WorkspaceDigestSchema):
  165. description = marshmallow.fields.String(example='All intranet data.')
  166. class Meta:
  167. description = 'Full workspace informations'
  168. class WorkspaceMemberSchema(marshmallow.Schema):
  169. role = marshmallow.fields.String(
  170. example='contributor',
  171. validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
  172. )
  173. user_id = marshmallow.fields.Int(example=3)
  174. workspace_id = marshmallow.fields.Int(example=4)
  175. user = marshmallow.fields.Nested(
  176. UserSchema(only=('public_name', 'avatar_url'))
  177. )
  178. class Meta:
  179. description = 'Workspace Member information'
  180. class ApplicationConfigSchema(marshmallow.Schema):
  181. pass
  182. # TODO - G.M - 24-05-2018 - Set this
  183. class ApplicationSchema(marshmallow.Schema):
  184. label = marshmallow.fields.String(example='Calendar')
  185. slug = marshmallow.fields.String(example='calendar')
  186. fa_icon = marshmallow.fields.String(
  187. example='file-o',
  188. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  189. )
  190. hexcolor = marshmallow.fields.String(
  191. example='#FF0000',
  192. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  193. )
  194. is_active = marshmallow.fields.Boolean(
  195. example=True,
  196. description='if true, the application is in use in the context',
  197. )
  198. config = marshmallow.fields.Nested(
  199. ApplicationConfigSchema,
  200. )
  201. class Meta:
  202. description = 'Tracim Application informations'
  203. class StatusSchema(marshmallow.Schema):
  204. slug = marshmallow.fields.String(
  205. example='open',
  206. description='the slug represents the type of status. '
  207. 'Statuses are open, closed-validated, closed-invalidated, closed-deprecated' # nopep8
  208. )
  209. global_status = marshmallow.fields.String(
  210. example='open',
  211. description='global_status: open, closed',
  212. validate=OneOf([status.value for status in GlobalStatus]),
  213. )
  214. label = marshmallow.fields.String(example='Open')
  215. fa_icon = marshmallow.fields.String(example='fa-check')
  216. hexcolor = marshmallow.fields.String(example='#0000FF')
  217. class ContentTypeSchema(marshmallow.Schema):
  218. slug = marshmallow.fields.String(
  219. example='pagehtml',
  220. validate=OneOf([content.slug for content in CONTENT_DEFAULT_TYPE]),
  221. )
  222. fa_icon = marshmallow.fields.String(
  223. example='fa-file-text-o',
  224. description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
  225. )
  226. hexcolor = marshmallow.fields.String(
  227. example="#FF0000",
  228. description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
  229. )
  230. label = marshmallow.fields.String(
  231. example='Text Documents'
  232. )
  233. creation_label = marshmallow.fields.String(
  234. example='Write a document'
  235. )
  236. available_statuses = marshmallow.fields.Nested(
  237. StatusSchema,
  238. many=True
  239. )
  240. class ContentMoveSchema(marshmallow.Schema):
  241. # TODO - G.M - 30-05-2018 - Read and apply this note
  242. # Note:
  243. # if the new workspace is different, then the backend
  244. # must check if the user is allowed to move to this workspace
  245. # (the user must be content manager of both workspaces)
  246. new_parent_id = marshmallow.fields.Int(
  247. example=42,
  248. description='id of the new parent content id.'
  249. )
  250. @post_load
  251. def make_move_params(self, data):
  252. return MoveParams(**data)
  253. class ContentCreationSchema(marshmallow.Schema):
  254. label = marshmallow.fields.String(
  255. example='contract for client XXX',
  256. description='Title of the content to create'
  257. )
  258. content_type = marshmallow.fields.String(
  259. example='htmlpage',
  260. validate=OneOf([content.slug for content in CONTENT_DEFAULT_TYPE]),
  261. )
  262. @post_load
  263. def make_content_filter(self, data):
  264. return ContentCreation(**data)
  265. class ContentDigestSchema(marshmallow.Schema):
  266. content_id = marshmallow.fields.Int(example=6)
  267. slug = marshmallow.fields.Str(example='intervention-report-12')
  268. parent_id = marshmallow.fields.Int(
  269. example=34,
  270. allow_none=True,
  271. default=None
  272. )
  273. workspace_id = marshmallow.fields.Int(
  274. example=19,
  275. )
  276. label = marshmallow.fields.Str(example='Intervention Report 12')
  277. content_type = marshmallow.fields.Str(
  278. example='htmlpage',
  279. validate=OneOf([content.slug for content in CONTENT_DEFAULT_TYPE]),
  280. )
  281. sub_content_types = marshmallow.fields.List(
  282. marshmallow.fields.Str,
  283. description='list of content types allowed as sub contents. '
  284. 'This field is required for folder contents, '
  285. 'set it to empty list in other cases'
  286. )
  287. status = marshmallow.fields.Str(
  288. example='closed-deprecated',
  289. validate=OneOf([status.slug for status in CONTENT_DEFAULT_STATUS]),
  290. description='this slug is found in content_type available statuses',
  291. default=open_status
  292. )
  293. is_archived = marshmallow.fields.Bool(example=False, default=False)
  294. is_deleted = marshmallow.fields.Bool(example=False, default=False)
  295. show_in_ui = marshmallow.fields.Bool(
  296. example=True,
  297. description='if false, then do not show content in the treeview. '
  298. 'This may his maybe used for specific contents or '
  299. 'for sub-contents. Default is True. '
  300. 'In first version of the API, this field is always True',
  301. )