123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- # coding=utf-8
- import marshmallow
- from marshmallow import post_load
- from marshmallow.validate import OneOf
- from marshmallow.validate import Range
-
- from tracim.lib.utils.utils import DATETIME_FORMAT
- from tracim.models.auth import Profile
- from tracim.models.contents import GlobalStatus
- from tracim.models.contents import open_status
- from tracim.models.contents import ContentTypeLegacy as ContentType
- from tracim.models.contents import ContentStatusLegacy as ContentStatus
- from tracim.models.context_models import ContentCreation
- from tracim.models.context_models import ContentPreviewSizedPath
- from tracim.models.context_models import RevisionPreviewSizedPath
- from tracim.models.context_models import PageQuery
- from tracim.models.context_models import WorkspaceAndContentRevisionPath
- from tracim.models.context_models import CommentCreation
- from tracim.models.context_models import TextBasedContentUpdate
- from tracim.models.context_models import SetContentStatus
- from tracim.models.context_models import CommentPath
- from tracim.models.context_models import MoveParams
- from tracim.models.context_models import WorkspaceAndContentPath
- from tracim.models.context_models import ContentFilter
- from tracim.models.context_models import LoginCredentials
- from tracim.models.data import UserRoleInWorkspace
-
-
- class UserDigestSchema(marshmallow.Schema):
- """
- Simple user schema
- """
- user_id = marshmallow.fields.Int(dump_only=True, example=3)
- avatar_url = marshmallow.fields.Url(
- allow_none=True,
- example="/api/v2/assets/avatars/suri-cate.jpg",
- description="avatar_url is the url to the image file. "
- "If no avatar, then set it to null "
- "(and frontend will interpret this with a default avatar)",
- )
- public_name = marshmallow.fields.String(
- example='Suri Cate',
- )
-
-
- class UserSchema(UserDigestSchema):
- """
- Complete user schema
- """
- email = marshmallow.fields.Email(
- required=True,
- example='suri.cate@algoo.fr'
- )
- created = marshmallow.fields.DateTime(
- format=DATETIME_FORMAT,
- description='User account creation date',
- )
- is_active = marshmallow.fields.Bool(
- example=True,
- # TODO - G.M - Explains this value.
- )
- # TODO - G.M - 17-04-2018 - Restrict timezone values
- timezone = marshmallow.fields.String(
- example="Paris/Europe",
- )
- # TODO - G.M - 17-04-2018 - check this, relative url allowed ?
- caldav_url = marshmallow.fields.Url(
- allow_none=True,
- relative=True,
- attribute='calendar_url',
- example="/api/v2/calendar/user/3.ics/",
- description="The url for calendar CalDAV direct access",
- )
- profile = marshmallow.fields.String(
- attribute='profile',
- validate=OneOf(Profile._NAME),
- example='managers',
- )
-
- class Meta:
- description = 'User account of Tracim'
-
- # Path Schemas
-
-
- class UserIdPathSchema(marshmallow.Schema):
- user_id = marshmallow.fields.Int(
- example=3,
- required=True,
- description='id of a valid user',
- validate=Range(min=1, error="Value must be greater than 0"),
- )
-
-
- class WorkspaceIdPathSchema(marshmallow.Schema):
- workspace_id = marshmallow.fields.Int(
- example=4,
- required=True,
- description='id of a valid workspace',
- validate=Range(min=1, error="Value must be greater than 0"),
- )
-
-
- class ContentIdPathSchema(marshmallow.Schema):
- content_id = marshmallow.fields.Int(
- example=6,
- required=True,
- description='id of a valid content',
- validate=Range(min=1, error="Value must be greater than 0"),
- )
-
-
- class RevisionIdPathSchema(marshmallow.Schema):
- revision_id = marshmallow.fields.Int(example=6, required=True)
-
-
- class WorkspaceAndContentIdPathSchema(
- WorkspaceIdPathSchema,
- ContentIdPathSchema
- ):
- @post_load
- def make_path_object(self, data):
- return WorkspaceAndContentPath(**data)
-
-
- class WidthAndHeightPathSchema(marshmallow.Schema):
- width = marshmallow.fields.Int(example=256)
- height = marshmallow.fields.Int(example=256)
-
-
- class AllowedJpgPreviewSizesSchema(marshmallow.Schema):
- width = marshmallow.fields.Int(example=256)
- height = marshmallow.fields.Int(example=256)
-
-
- class AllowedJpgPreviewDimSchema(marshmallow.Schema):
- restricted = marshmallow.fields.Bool()
- dimensions = marshmallow.fields.Nested(
- AllowedJpgPreviewSizesSchema,
- many=True
- )
-
-
- class WorkspaceAndContentRevisionIdPathSchema(
- WorkspaceIdPathSchema,
- ContentIdPathSchema,
- RevisionIdPathSchema,
- ):
- @post_load
- def make_path_object(self, data):
- return WorkspaceAndContentRevisionPath(**data)
-
-
- class ContentPreviewSizedPathSchema(
- WorkspaceAndContentIdPathSchema,
- WidthAndHeightPathSchema
- ):
- @post_load
- def make_path_object(self, data):
- return ContentPreviewSizedPath(**data)
-
-
- class RevisionPreviewSizedPathSchema(
- WorkspaceAndContentRevisionIdPathSchema,
- WidthAndHeightPathSchema
- ):
- @post_load
- def make_path_object(self, data):
- return RevisionPreviewSizedPath(**data)
-
-
- class CommentsPathSchema(WorkspaceAndContentIdPathSchema):
- comment_id = marshmallow.fields.Int(
- example=6,
- description='id of a valid comment related to content content_id',
- required=True,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- @post_load
- def make_path_object(self, data):
- return CommentPath(**data)
-
-
- class PageQuerySchema(marshmallow.Schema):
- page = marshmallow.fields.Int(
- example=2,
- default=0,
- description='allow to show a specific page of a pdf file',
- validate=Range(min=0, error="Value must be positive or 0"),
- )
-
- @post_load
- def make_page_query(self, data):
- return PageQuery(**data)
-
-
- class FilterContentQuerySchema(marshmallow.Schema):
- parent_id = marshmallow.fields.Int(
- example=2,
- default=0,
- description='allow to filter items in a folder.'
- ' If not set, then return all contents.'
- ' If set to 0, then return root contents.'
- ' If set to another value, return all contents'
- ' directly included in the folder parent_id',
- validate=Range(min=0, error="Value must be positive or 0"),
- )
- show_archived = marshmallow.fields.Int(
- example=0,
- default=0,
- description='if set to 1, then show archived contents.'
- ' Default is 0 - hide archived content',
- validate=Range(min=0, max=1, error="Value must be 0 or 1"),
- )
- show_deleted = marshmallow.fields.Int(
- example=0,
- default=0,
- description='if set to 1, then show deleted contents.'
- ' Default is 0 - hide deleted content',
- validate=Range(min=0, max=1, error="Value must be 0 or 1"),
- )
- show_active = marshmallow.fields.Int(
- example=1,
- default=1,
- description='f set to 1, then show active contents. '
- 'Default is 1 - show active content.'
- ' Note: active content are content '
- 'that is neither archived nor deleted. '
- 'The reason for this parameter to exist is for example '
- 'to allow to show only archived documents',
- validate=Range(min=0, max=1, error="Value must be 0 or 1"),
- )
-
- @post_load
- def make_content_filter(self, data):
- return ContentFilter(**data)
- ###
-
-
- class BasicAuthSchema(marshmallow.Schema):
-
- email = marshmallow.fields.Email(
- example='suri.cate@algoo.fr',
- required=True
- )
- password = marshmallow.fields.String(
- example='8QLa$<w',
- required=True,
- load_only=True,
- )
-
- class Meta:
- description = 'Entry for HTTP Basic Auth'
-
- @post_load
- def make_login(self, data):
- return LoginCredentials(**data)
-
-
- class LoginOutputHeaders(marshmallow.Schema):
- expire_after = marshmallow.fields.String()
-
-
- class NoContentSchema(marshmallow.Schema):
-
- class Meta:
- description = 'Empty Schema'
- pass
-
-
- class WorkspaceMenuEntrySchema(marshmallow.Schema):
- slug = marshmallow.fields.String(example='markdown-pages')
- label = marshmallow.fields.String(example='Markdown Documents')
- route = marshmallow.fields.String(
- example='/#/workspace/{workspace_id}/contents/?type=mardown-page',
- description='the route is the frontend route. '
- 'It may include workspace_id '
- 'which must be replaced on backend size '
- '(the route must be ready-to-use)'
- )
- fa_icon = marshmallow.fields.String(
- example='file-text-o',
- description='CSS class of the icon. Example: file-o for using Fontawesome file-text-o icon', # nopep8
- )
- hexcolor = marshmallow.fields.String(
- example='#F0F9DC',
- description='Hexadecimal color of the entry.'
- )
-
- class Meta:
- description = 'Entry element of a workspace menu'
-
-
- class WorkspaceDigestSchema(marshmallow.Schema):
- workspace_id = marshmallow.fields.Int(
- example=4,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- slug = marshmallow.fields.String(example='intranet')
- label = marshmallow.fields.String(example='Intranet')
- sidebar_entries = marshmallow.fields.Nested(
- WorkspaceMenuEntrySchema,
- many=True,
- )
-
- class Meta:
- description = 'Digest of workspace informations'
-
-
- class WorkspaceSchema(WorkspaceDigestSchema):
- description = marshmallow.fields.String(example='All intranet data.')
-
- class Meta:
- description = 'Full workspace informations'
-
-
- class WorkspaceMemberSchema(marshmallow.Schema):
- role = marshmallow.fields.String(
- example='contributor',
- validate=OneOf(UserRoleInWorkspace.get_all_role_slug())
- )
- user_id = marshmallow.fields.Int(
- example=3,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- workspace_id = marshmallow.fields.Int(
- example=4,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- user = marshmallow.fields.Nested(
- UserSchema(only=('public_name', 'avatar_url'))
- )
-
- class Meta:
- description = 'Workspace Member information'
-
-
- class ApplicationConfigSchema(marshmallow.Schema):
- pass
- # TODO - G.M - 24-05-2018 - Set this
-
-
- class ApplicationSchema(marshmallow.Schema):
- label = marshmallow.fields.String(example='Calendar')
- slug = marshmallow.fields.String(example='calendar')
- fa_icon = marshmallow.fields.String(
- example='file-o',
- description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
- )
- hexcolor = marshmallow.fields.String(
- example='#FF0000',
- description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
- )
- is_active = marshmallow.fields.Boolean(
- example=True,
- description='if true, the application is in use in the context',
- )
- config = marshmallow.fields.Nested(
- ApplicationConfigSchema,
- )
-
- class Meta:
- description = 'Tracim Application informations'
-
-
- class StatusSchema(marshmallow.Schema):
- slug = marshmallow.fields.String(
- example='open',
- description='the slug represents the type of status. '
- 'Statuses are open, closed-validated, closed-invalidated, closed-deprecated' # nopep8
- )
- global_status = marshmallow.fields.String(
- example='open',
- description='global_status: open, closed',
- validate=OneOf([status.value for status in GlobalStatus]),
- )
- label = marshmallow.fields.String(example='Open')
- fa_icon = marshmallow.fields.String(example='fa-check')
- hexcolor = marshmallow.fields.String(example='#0000FF')
-
-
- class ContentTypeSchema(marshmallow.Schema):
- slug = marshmallow.fields.String(
- example='pagehtml',
- validate=OneOf(ContentType.allowed_types()),
- )
- fa_icon = marshmallow.fields.String(
- example='fa-file-text-o',
- description='CSS class of the icon. Example: file-o for using Fontawesome file-o icon', # nopep8
- )
- hexcolor = marshmallow.fields.String(
- example="#FF0000",
- description='HTML encoded color associated to the application. Example:#FF0000 for red' # nopep8
- )
- label = marshmallow.fields.String(
- example='Text Documents'
- )
- creation_label = marshmallow.fields.String(
- example='Write a document'
- )
- available_statuses = marshmallow.fields.Nested(
- StatusSchema,
- many=True
- )
-
-
- class ContentMoveSchema(marshmallow.Schema):
- # TODO - G.M - 30-05-2018 - Read and apply this note
- # Note:
- # if the new workspace is different, then the backend
- # must check if the user is allowed to move to this workspace
- # (the user must be content manager of both workspaces)
- new_parent_id = marshmallow.fields.Int(
- example=42,
- description='id of the new parent content id.',
- allow_none=True,
- required=True,
- validate=Range(min=0, error="Value must be positive or 0"),
- )
- new_workspace_id = marshmallow.fields.Int(
- example=2,
- description='id of the new workspace id.',
- required=True,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
-
- @post_load
- def make_move_params(self, data):
- return MoveParams(**data)
-
-
- class ContentCreationSchema(marshmallow.Schema):
- label = marshmallow.fields.String(
- example='contract for client XXX',
- description='Title of the content to create'
- )
- content_type = marshmallow.fields.String(
- example='html-documents',
- validate=OneOf(ContentType.allowed_types_for_folding()), # nopep8
- )
- parent_id = marshmallow.fields.Integer(
- example=35,
- description='content_id of parent content, if content should be placed in a folder, this should be folder content_id.'
- )
-
-
- @post_load
- def make_content_filter(self, data):
- return ContentCreation(**data)
-
-
- class ContentDigestSchema(marshmallow.Schema):
- content_id = marshmallow.fields.Int(
- example=6,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- slug = marshmallow.fields.Str(example='intervention-report-12')
- parent_id = marshmallow.fields.Int(
- example=34,
- allow_none=True,
- default=None,
- validate=Range(min=0, error="Value must be positive or 0"),
- )
- workspace_id = marshmallow.fields.Int(
- example=19,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- label = marshmallow.fields.Str(example='Intervention Report 12')
- content_type = marshmallow.fields.Str(
- example='html-documents',
- validate=OneOf(ContentType.allowed_types()),
- )
- sub_content_types = marshmallow.fields.List(
- marshmallow.fields.String(
- example='html-content',
- validate=OneOf(ContentType.allowed_types())
- ),
- description='list of content types allowed as sub contents. '
- 'This field is required for folder contents, '
- 'set it to empty list in other cases'
- )
- status = marshmallow.fields.Str(
- example='closed-deprecated',
- validate=OneOf(ContentStatus.allowed_values()),
- description='this slug is found in content_type available statuses',
- default=open_status
- )
- is_archived = marshmallow.fields.Bool(example=False, default=False)
- is_deleted = marshmallow.fields.Bool(example=False, default=False)
- show_in_ui = marshmallow.fields.Bool(
- example=True,
- description='if false, then do not show content in the treeview. '
- 'This may his maybe used for specific contents or '
- 'for sub-contents. Default is True. '
- 'In first version of the API, this field is always True',
- )
-
-
- #####
- # Content
- #####
-
- class ContentSchema(ContentDigestSchema):
- current_revision_id = marshmallow.fields.Int(example=12)
- created = marshmallow.fields.DateTime(
- format=DATETIME_FORMAT,
- description='Content creation date',
- )
- author = marshmallow.fields.Nested(UserDigestSchema)
- modified = marshmallow.fields.DateTime(
- format=DATETIME_FORMAT,
- description='date of last modification of content',
- )
- last_modifier = marshmallow.fields.Nested(UserDigestSchema)
-
-
- class TextBasedDataAbstractSchema(marshmallow.Schema):
- raw_content = marshmallow.fields.String(
- description='Content of the object, may be raw text or <b>html</b> for example' # nopep8
- )
-
-
- class FileInfoAbstractSchema(marshmallow.Schema):
- raw_content = marshmallow.fields.String(
- description='raw text or html description of the file'
- )
-
-
- class TextBasedContentSchema(ContentSchema, TextBasedDataAbstractSchema):
- pass
-
-
- class FileContentSchema(ContentSchema, FileInfoAbstractSchema):
- pass
-
- #####
- # Revision
- #####
-
-
- class RevisionSchema(ContentDigestSchema):
- comment_ids = marshmallow.fields.List(
- marshmallow.fields.Int(
- example=4,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- )
- revision_id = marshmallow.fields.Int(
- example=12,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- created = marshmallow.fields.DateTime(
- format=DATETIME_FORMAT,
- description='Content creation date',
- )
- author = marshmallow.fields.Nested(UserDigestSchema)
-
-
- class TextBasedRevisionSchema(RevisionSchema, TextBasedDataAbstractSchema):
- pass
-
-
- class FileRevisionSchema(RevisionSchema, FileInfoAbstractSchema):
- pass
-
-
- class CommentSchema(marshmallow.Schema):
- content_id = marshmallow.fields.Int(
- example=6,
- validate=Range(min=1, error="Value must be greater than 0"),
- )
- parent_id = marshmallow.fields.Int(
- example=34,
- validate=Range(min=0, error="Value must be positive or 0"),
- )
- raw_content = marshmallow.fields.String(
- example='<p>This is just an html comment !</p>'
- )
- author = marshmallow.fields.Nested(UserDigestSchema)
- created = marshmallow.fields.DateTime(
- format=DATETIME_FORMAT,
- description='comment creation date',
- )
-
-
- class SetCommentSchema(marshmallow.Schema):
- raw_content = marshmallow.fields.String(
- example='<p>This is just an html comment !</p>'
- )
-
- @post_load()
- def create_comment(self, data):
- return CommentCreation(**data)
-
-
- class ContentModifyAbstractSchema(marshmallow.Schema):
- label = marshmallow.fields.String(
- required=True,
- example='contract for client XXX',
- description='New title of the content'
- )
-
-
- class TextBasedContentModifySchema(ContentModifyAbstractSchema, TextBasedDataAbstractSchema): # nopep8
-
- @post_load
- def text_based_content_update(self, data):
- return TextBasedContentUpdate(**data)
-
-
- class FileContentModifySchema(TextBasedContentModifySchema):
- pass
-
-
- class SetContentStatusSchema(marshmallow.Schema):
- status = marshmallow.fields.Str(
- example='closed-deprecated',
- validate=OneOf(ContentStatus.allowed_values()),
- description='this slug is found in content_type available statuses',
- default=open_status,
- required=True,
- )
-
- @post_load
- def set_status(self, data):
- return SetContentStatus(**data)
|