Passed
Pull Request — develop (#42)
by inkhey
02:42
created

UserCreation.__init__()   A

Complexity

Conditions 1

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 19
rs 9.6
c 0
b 0
f 0
cc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# coding=utf-8
2
import typing
3
from datetime import datetime
4
from enum import Enum
5
6
from slugify import slugify
7
from sqlalchemy.orm import Session
8
from tracim_backend.config import CFG
9
from tracim_backend.config import PreviewDim
10
from tracim_backend.extensions import app_list
11
from tracim_backend.lib.core.application import ApplicationApi
12
from tracim_backend.lib.utils.utils import get_root_frontend_url
13
from tracim_backend.lib.utils.utils import password_generator
14
from tracim_backend.lib.utils.utils import CONTENT_FRONTEND_URL_SCHEMA
15
from tracim_backend.lib.utils.utils import WORKSPACE_FRONTEND_URL_SCHEMA
16
from tracim_backend.models import User
17
from tracim_backend.models.auth import Profile
18
from tracim_backend.models.auth import Group
19
from tracim_backend.models.data import Content
20
from tracim_backend.models.data import ContentRevisionRO
21
from tracim_backend.models.data import Workspace
22
from tracim_backend.models.data import UserRoleInWorkspace
23
from tracim_backend.models.roles import WorkspaceRoles
24
from tracim_backend.app_models.workspace_menu_entries import WorkspaceMenuEntry
25
from tracim_backend.app_models.contents import CONTENT_TYPES
26
27
28
class PreviewAllowedDim(object):
29
30
    def __init__(
31
            self,
32
            restricted:bool,
33
            dimensions: typing.List[PreviewDim]
34
    ) -> None:
35
        self.restricted = restricted
36
        self.dimensions = dimensions
37
38
39
class MoveParams(object):
40
    """
41
    Json body params for move action model
42
    """
43
    def __init__(self, new_parent_id: str, new_workspace_id: str = None) -> None:  # nopep8
44
        self.new_parent_id = new_parent_id
45
        self.new_workspace_id = new_workspace_id
46
47
48
class LoginCredentials(object):
49
    """
50
    Login credentials model for login model
51
    """
52
53
    def __init__(self, email: str, password: str) -> None:
54
        self.email = email
55
        self.password = password
56
57
58
class SetEmail(object):
59
    """
60
    Just an email
61
    """
62
    def __init__(self, loggedin_user_password: str, email: str) -> None:
63
        self.loggedin_user_password = loggedin_user_password
64
        self.email = email
65
66
67
class SetPassword(object):
68
    """
69
    Just an password
70
    """
71
    def __init__(self,
72
        loggedin_user_password: str,
73
        new_password: str,
74
        new_password2: str
75
    ) -> None:
76
        self.loggedin_user_password = loggedin_user_password
77
        self.new_password = new_password
78
        self.new_password2 = new_password2
79
80
81
class UserInfos(object):
82
    """
83
    Just some user infos
84
    """
85
    def __init__(self, timezone: str, public_name: str, lang: str) -> None:
86
        self.timezone = timezone
87
        self.public_name = public_name
88
        self.lang = lang
89
90
91
class UserProfile(object):
92
    """
93
    Just some user infos
94
    """
95
    def __init__(self, profile: str) -> None:
96
        self.profile = profile
97
98
99
class UserCreation(object):
100
    """
101
    Just some user infos
102
    """
103
    def __init__(
104
            self,
105
            email: str,
106
            password: str = None,
107
            public_name: str = None,
108
            timezone: str = None,
109
            profile: str = None,
110
            lang: str = None,
111
            email_notification: bool = True,
112
    ) -> None:
113
        self.email = email
114
        # INFO - G.M - 2018-08-16 - cleartext password, default value
115
        # is auto-generated.
116
        self.password = password or password_generator()
117
        self.public_name = public_name or None
118
        self.timezone = timezone or ''
119
        self.lang = lang or None
120
        self.profile = profile or Group.TIM_USER_GROUPNAME
121
        self.email_notification = email_notification
122
123
124
class WorkspaceAndContentPath(object):
125
    """
126
    Paths params with workspace id and content_id model
127
    """
128
    def __init__(self, workspace_id: int, content_id: int) -> None:
129
        self.content_id = content_id
130
        self.workspace_id = workspace_id
131
132
133
class WorkspaceAndContentRevisionPath(object):
134
    """
135
    Paths params with workspace id and content_id model
136
    """
137
    def __init__(self, workspace_id: int, content_id: int, revision_id) -> None:
138
        self.content_id = content_id
139
        self.revision_id = revision_id
140
        self.workspace_id = workspace_id
141
142
143
class ContentPreviewSizedPath(object):
144
    """
145
    Paths params with workspace id and content_id, width, heigth
146
    """
147
    def __init__(self, workspace_id: int, content_id: int, width: int, height: int) -> None:  # nopep8
148
        self.content_id = content_id
149
        self.workspace_id = workspace_id
150
        self.width = width
151
        self.height = height
152
153
154
class RevisionPreviewSizedPath(object):
155
    """
156
    Paths params with workspace id and content_id, revision_id width, heigth
157
    """
158
    def __init__(self, workspace_id: int, content_id: int, revision_id: int, width: int, height: int) -> None:  # nopep8
159
        self.content_id = content_id
160
        self.revision_id = revision_id
161
        self.workspace_id = workspace_id
162
        self.width = width
163
        self.height = height
164
165
166
class WorkspaceAndUserPath(object):
167
    """
168
    Paths params with workspace id and user_id
169
    """
170
    def __init__(self, workspace_id: int, user_id: int):
171
        self.workspace_id = workspace_id
172
        self.user_id = user_id
173
174
175
class UserWorkspaceAndContentPath(object):
176
    """
177
    Paths params with user_id, workspace id and content_id model
178
    """
179
    def __init__(self, user_id: int, workspace_id: int, content_id: int) -> None:  # nopep8
180
        self.content_id = content_id
181
        self.workspace_id = workspace_id
182
        self.user_id = user_id
183
184
185
class CommentPath(object):
186
    """
187
    Paths params with workspace id and content_id and comment_id model
188
    """
189
    def __init__(
190
        self,
191
        workspace_id: int,
192
        content_id: int,
193
        comment_id: int
194
    ) -> None:
195
        self.content_id = content_id
196
        self.workspace_id = workspace_id
197
        self.comment_id = comment_id
198
199
200
class AutocompleteQuery(object):
201
    """
202
    Autocomplete query model
203
    """
204
    def __init__(self, acp: str):
205
        self.acp = acp
206
207
208
class FileQuery(object):
209
    """
210
    File query model
211
    """
212
    def __init__(
213
        self,
214
        force_download: int = 0,
215
    ):
216
        self.force_download = force_download
217
218
219
class PageQuery(object):
220
    """
221
    Page query model
222
    """
223
    def __init__(
224
            self,
225
            force_download: int = 0,
226
            page: int = 0
227
    ):
228
        self.force_download=force_download
229
        self.page = page
230
231
232
class ContentFilter(object):
233
    """
234
    Content filter model
235
    """
236
    def __init__(
237
            self,
238
            workspace_id: int = None,
239
            parent_id: int = None,
240
            show_archived: int = 0,
241
            show_deleted: int = 0,
242
            show_active: int = 1,
243
            content_type: str = None,
244
            offset: int = None,
245
            limit: int = None,
246
    ) -> None:
247
        self.parent_id = parent_id
248
        self.workspace_id = workspace_id
249
        self.show_archived = bool(show_archived)
250
        self.show_deleted = bool(show_deleted)
251
        self.show_active = bool(show_active)
252
        self.limit = limit
253
        self.offset = offset
254
        self.content_type = content_type
255
256
257
class ActiveContentFilter(object):
258
    def __init__(
259
            self,
260
            limit: int = None,
261
            before_content_id: datetime = None,
262
    ):
263
        self.limit = limit
264
        self.before_content_id = before_content_id
265
266
267
class ContentIdsQuery(object):
268
    def __init__(
269
            self,
270
            contents_ids: typing.List[int] = None,
271
    ):
272
        self.contents_ids = contents_ids
273
274
275
class RoleUpdate(object):
276
    """
277
    Update role
278
    """
279
    def __init__(
280
        self,
281
        role: str,
282
    ):
283
        self.role = role
284
285
286
class WorkspaceMemberInvitation(object):
287
    """
288
    Workspace Member Invitation
289
    """
290
    def __init__(
291
        self,
292
        user_id: int,
293
        user_email_or_public_name: str,
294
        role: str,
295
    ):
296
        self.role = role
297
        self.user_email_or_public_name = user_email_or_public_name
298
        self.user_id = user_id
299
300
301
class WorkspaceUpdate(object):
302
    """
303
    Update workspace
304
    """
305
    def __init__(
306
        self,
307
        label: str,
308
        description: str,
309
    ):
310
        self.label = label
311
        self.description = description
312
313
314
class ContentCreation(object):
315
    """
316
    Content creation model
317
    """
318
    def __init__(
319
        self,
320
        label: str,
321
        content_type: str,
322
        parent_id: typing.Optional[int] = None,
323
    ) -> None:
324
        self.label = label
325
        self.content_type = content_type
326
        self.parent_id = parent_id or None
327
328
329
class CommentCreation(object):
330
    """
331
    Comment creation model
332
    """
333
    def __init__(
334
        self,
335
        raw_content: str,
336
    ) -> None:
337
        self.raw_content = raw_content
338
339
340
class SetContentStatus(object):
341
    """
342
    Set content status
343
    """
344
    def __init__(
345
        self,
346
        status: str,
347
    ) -> None:
348
        self.status = status
349
350
351
class TextBasedContentUpdate(object):
352
    """
353
    TextBasedContent update model
354
    """
355
    def __init__(
356
        self,
357
        label: str,
358
        raw_content: str,
359
    ) -> None:
360
        self.label = label
361
        self.raw_content = raw_content
362
363
364
class FolderContentUpdate(object):
365
    """
366
    Folder Content update model
367
    """
368
    def __init__(
369
        self,
370
        label: str,
371
        raw_content: str,
372
        sub_content_types: typing.List[str],
373
    ) -> None:
374
        self.label = label
375
        self.raw_content = raw_content
376
        self.sub_content_types = sub_content_types
377
378
379
class TypeUser(Enum):
380
    """Params used to find user"""
381
    USER_ID = 'found_id'
382
    EMAIL = 'found_email'
383
    PUBLIC_NAME = 'found_public_name'
384
385
386
class UserInContext(object):
387
    """
388
    Interface to get User data and User data related to context.
389
    """
390
391
    def __init__(self, user: User, dbsession: Session, config: CFG):
392
        self.user = user
393
        self.dbsession = dbsession
394
        self.config = config
395
396
    # Default
397
398
    @property
399
    def email(self) -> str:
400
        return self.user.email
401
402
    @property
403
    def user_id(self) -> int:
404
        return self.user.user_id
405
406
    @property
407
    def public_name(self) -> str:
408
        return self.display_name
409
410
    @property
411
    def display_name(self) -> str:
412
        return self.user.display_name
413
414
    @property
415
    def created(self) -> datetime:
416
        return self.user.created
417
418
    @property
419
    def is_active(self) -> bool:
420
        return self.user.is_active
421
422
    @property
423
    def timezone(self) -> str:
424
        return self.user.timezone
425
426
    @property
427
    def lang(self) -> str:
428
        return self.user.lang
429
430
    @property
431
    def profile(self) -> Profile:
432
        return self.user.profile.name
433
434
    @property
435
    def is_deleted(self) -> bool:
436
        return self.user.is_deleted
437
438
    # Context related
439
440
    @property
441
    def calendar_url(self) -> typing.Optional[str]:
442
        # TODO - G-M - 20-04-2018 - [Calendar] Replace calendar code to get
443
        # url calendar url.
444
        #
445
        # from tracim.lib.calendar import CalendarManager
446
        # calendar_manager = CalendarManager(None)
447
        # return calendar_manager.get_workspace_calendar_url(self.workspace_id)
448
        return None
449
450
    @property
451
    def avatar_url(self) -> typing.Optional[str]:
452
        # TODO - G-M - 20-04-2018 - [Avatar] Add user avatar feature
453
        return None
454
455
456
class WorkspaceInContext(object):
457
    """
458
    Interface to get Workspace data and Workspace data related to context.
459
    """
460
461
    def __init__(self, workspace: Workspace, dbsession: Session, config: CFG):
462
        self.workspace = workspace
463
        self.dbsession = dbsession
464
        self.config = config
465
466
    @property
467
    def workspace_id(self) -> int:
468
        """
469
        numeric id of the workspace.
470
        """
471
        return self.workspace.workspace_id
472
473
    @property
474
    def id(self) -> int:
475
        """
476
        alias of workspace_id
477
        """
478
        return self.workspace_id
479
480
    @property
481
    def label(self) -> str:
482
        """
483
        get workspace label
484
        """
485
        return self.workspace.label
486
487
    @property
488
    def description(self) -> str:
489
        """
490
        get workspace description
491
        """
492
        return self.workspace.description
493
494
    @property
495
    def slug(self) -> str:
496
        """
497
        get workspace slug
498
        """
499
        return slugify(self.workspace.label)
500
501
    @property
502
    def is_deleted(self) -> bool:
503
        """
504
        Is the workspace deleted ?
505
        """
506
        return self.workspace.is_deleted
507
508
    @property
509
    def sidebar_entries(self) -> typing.List[WorkspaceMenuEntry]:
510
        """
511
        get sidebar entries, those depends on activated apps.
512
        """
513
        # TODO - G.M - 22-05-2018 - Rework on this in
514
        # order to not use hardcoded list
515
        # list should be able to change (depending on activated/disabled
516
        # apps)
517
        app_api = ApplicationApi(
518
            app_list
519
        )
520
        return app_api.get_default_workspace_menu_entry(self.workspace)
521
522
    @property
523
    def frontend_url(self):
524
        root_frontend_url = get_root_frontend_url(self.config)
525
        workspace_frontend_url = WORKSPACE_FRONTEND_URL_SCHEMA.format(
526
            workspace_id=self.workspace_id,
527
        )
528
        return root_frontend_url + workspace_frontend_url
529
530
531
class UserRoleWorkspaceInContext(object):
532
    """
533
    Interface to get UserRoleInWorkspace data and related content
534
535
    """
536
    def __init__(
537
            self,
538
            user_role: UserRoleInWorkspace,
539
            dbsession: Session,
540
            config: CFG,
541
            # Extended params
542
            newly_created: bool = None,
543
            email_sent: bool = None
544
    )-> None:
545
        self.user_role = user_role
546
        self.dbsession = dbsession
547
        self.config = config
548
        # Extended params
549
        self.newly_created = newly_created
550
        self.email_sent = email_sent
551
552
    @property
553
    def user_id(self) -> int:
554
        """
555
        User who has the role has this id
556
        :return: user id as integer
557
        """
558
        return self.user_role.user_id
559
560
    @property
561
    def workspace_id(self) -> int:
562
        """
563
        This role apply only on the workspace with this workspace_id
564
        :return: workspace id as integer
565
        """
566
        return self.user_role.workspace_id
567
568
    # TODO - G.M - 23-05-2018 - Check the API spec for this this !
569
570
    @property
571
    def role_id(self) -> int:
572
        """
573
        role as int id, each value refer to a different role.
574
        """
575
        return self.user_role.role
576
577
    @property
578
    def role(self) -> str:
579
        return self.role_slug
580
581
    @property
582
    def role_slug(self) -> str:
583
        """
584
        simple name of the role of the user.
585
        can be anything from UserRoleInWorkspace SLUG, like
586
        'not_applicable', 'reader',
587
        'contributor', 'content-manager', 'workspace-manager'
588
        :return: user workspace role as slug.
589
        """
590
        return WorkspaceRoles.get_role_from_level(self.user_role.role).slug
591
592
    @property
593
    def is_active(self) -> bool:
594
        return self.user.is_active
595
596
    @property
597
    def do_notify(self) -> bool:
598
        return self.user_role.do_notify
599
600
    @property
601
    def user(self) -> UserInContext:
602
        """
603
        User who has this role, with context data
604
        :return: UserInContext object
605
        """
606
        return UserInContext(
607
            self.user_role.user,
608
            self.dbsession,
609
            self.config
610
        )
611
612
    @property
613
    def workspace(self) -> WorkspaceInContext:
614
        """
615
        Workspace related to this role, with his context data
616
        :return: WorkspaceInContext object
617
        """
618
        return WorkspaceInContext(
619
            self.user_role.workspace,
620
            self.dbsession,
621
            self.config
622
        )
623
624
625
class ContentInContext(object):
626
    """
627
    Interface to get Content data and Content data related to context.
628
    """
629
630
    def __init__(self, content: Content, dbsession: Session, config: CFG, user: User=None):  # nopep8
631
        self.content = content
632
        self.dbsession = dbsession
633
        self.config = config
634
        self._user = user
635
636
    # Default
637
    @property
638
    def content_id(self) -> int:
639
        return self.content.content_id
640
641
    @property
642
    def parent_id(self) -> int:
643
        """
644
        Return parent_id of the content
645
        """
646
        return self.content.parent_id
647
648
    @property
649
    def workspace_id(self) -> int:
650
        return self.content.workspace_id
651
652
    @property
653
    def label(self) -> str:
654
        return self.content.label
655
656
    @property
657
    def content_type(self) -> str:
658
        content_type = CONTENT_TYPES.get_one_by_slug(self.content.type)
659
        return content_type.slug
660
661
    @property
662
    def sub_content_types(self) -> typing.List[str]:
663
        return [_type.slug for _type in self.content.get_allowed_content_types()]  # nopep8
664
665
    @property
666
    def status(self) -> str:
667
        return self.content.status
668
669
    @property
670
    def is_archived(self) -> bool:
671
        return self.content.is_archived
672
673
    @property
674
    def is_deleted(self) -> bool:
675
        return self.content.is_deleted
676
677
    @property
678
    def raw_content(self) -> str:
679
        return self.content.description
680
681
    @property
682
    def author(self) -> UserInContext:
683
        return UserInContext(
684
            dbsession=self.dbsession,
685
            config=self.config,
686
            user=self.content.first_revision.owner
687
        )
688
689
    @property
690
    def current_revision_id(self) -> int:
691
        return self.content.revision_id
692
693
    @property
694
    def created(self) -> datetime:
695
        return self.content.created
696
697
    @property
698
    def modified(self) -> datetime:
699
        return self.updated
700
701
    @property
702
    def updated(self) -> datetime:
703
        return self.content.updated
704
705
    @property
706
    def last_modifier(self) -> UserInContext:
707
        return UserInContext(
708
            dbsession=self.dbsession,
709
            config=self.config,
710
            user=self.content.last_revision.owner
711
        )
712
713
    # Context-related
714
    @property
715
    def show_in_ui(self) -> bool:
716
        # TODO - G.M - 31-05-2018 - Enable Show_in_ui params
717
        # if false, then do not show content in the treeview.
718
        # This may his maybe used for specific contents or for sub-contents.
719
        # Default is True.
720
        # In first version of the API, this field is always True
721
        return True
722
723
    @property
724
    def slug(self) -> str:
725
        return slugify(self.content.label)
726
727
    @property
728
    def read_by_user(self) -> bool:
729
        assert self._user
730
        return not self.content.has_new_information_for(self._user)
731
732
    @property
733
    def frontend_url(self) -> str:
734
        root_frontend_url = get_root_frontend_url(self.config)
735
        content_frontend_url = CONTENT_FRONTEND_URL_SCHEMA.format(
736
            workspace_id=self.workspace_id,
737
            content_type=self.content_type,
738
            content_id=self.content_id,
739
        )
740
        return root_frontend_url + content_frontend_url
741
742
    # file specific
743
    @property
744
    def page_nb(self) -> typing.Optional[int]:
745
        """
746
        :return: page_nb of content if available, None if unavailable
747
        """
748
        if self.content.depot_file:
749
            from tracim_backend.lib.core.content import ContentApi
750
            content_api = ContentApi(
751
                current_user=self._user,
752
                session=self.dbsession,
753
                config=self.config
754
            )
755
            return content_api.get_preview_page_nb(self.content.revision_id)
756
        else:
757
            return None
758
759
    @property
760
    def mimetype(self) -> str:
761
        """
762
        :return: mimetype of content if available, None if unavailable
763
        """
764
        return self.content.file_mimetype
765
766
    @property
767
    def size(self) -> typing.Optional[int]:
768
        """
769
        :return: size of content if available, None if unavailable
770
        """
771
        if self.content.depot_file:
772
            return self.content.depot_file.file.content_length
773
        else:
774
            return None
775
776
    @property
777
    def pdf_available(self) -> bool:
778
        """
779
        :return: bool about if pdf version of content is available
780
        """
781
        if self.content.depot_file:
782
            from tracim_backend.lib.core.content import ContentApi
783
            content_api = ContentApi(
784
                current_user=self._user,
785
                session=self.dbsession,
786
                config=self.config
787
            )
788
            return content_api.has_pdf_preview(self.content.revision_id)
789
        else:
790
            return False
791
792
793
class RevisionInContext(object):
794
    """
795
    Interface to get Content data and Content data related to context.
796
    """
797
798
    def __init__(self, content_revision: ContentRevisionRO, dbsession: Session, config: CFG,  user: User=None) -> None:  # nopep8
799
        assert content_revision is not None
800
        self.revision = content_revision
801
        self.dbsession = dbsession
802
        self.config = config
803
        self._user = user
804
805
    # Default
806
    @property
807
    def content_id(self) -> int:
808
        return self.revision.content_id
809
810
    @property
811
    def parent_id(self) -> int:
812
        """
813
        Return parent_id of the content
814
        """
815
        return self.revision.parent_id
816
817
    @property
818
    def workspace_id(self) -> int:
819
        return self.revision.workspace_id
820
821
    @property
822
    def label(self) -> str:
823
        return self.revision.label
824
825
    @property
826
    def revision_type(self) -> str:
827
        return self.revision.revision_type
828
829
    @property
830
    def content_type(self) -> str:
831
        return CONTENT_TYPES.get_one_by_slug(self.revision.type).slug
832
833
    @property
834
    def sub_content_types(self) -> typing.List[str]:
835
        return [_type.slug for _type
836
                in self.revision.node.get_allowed_content_types()]
837
838
    @property
839
    def status(self) -> str:
840
        return self.revision.status
841
842
    @property
843
    def is_archived(self) -> bool:
844
        return self.revision.is_archived
845
846
    @property
847
    def is_deleted(self) -> bool:
848
        return self.revision.is_deleted
849
850
    @property
851
    def raw_content(self) -> str:
852
        return self.revision.description
853
854
    @property
855
    def author(self) -> UserInContext:
856
        return UserInContext(
857
            dbsession=self.dbsession,
858
            config=self.config,
859
            user=self.revision.owner
860
        )
861
862
    @property
863
    def revision_id(self) -> int:
864
        return self.revision.revision_id
865
866
    @property
867
    def created(self) -> datetime:
868
        return self.updated
869
870
    @property
871
    def modified(self) -> datetime:
872
        return self.updated
873
874
    @property
875
    def updated(self) -> datetime:
876
        return self.revision.updated
877
878
    @property
879
    def next_revision(self) -> typing.Optional[ContentRevisionRO]:
880
        """
881
        Get next revision (later revision)
882
        :return: next_revision
883
        """
884
        next_revision = None
885
        revisions = self.revision.node.revisions
886
        # INFO - G.M - 2018-06-177 - Get revisions more recent that
887
        # current one
888
        next_revisions = [
889
            revision for revision in revisions
890
            if revision.revision_id > self.revision.revision_id
891
        ]
892
        if next_revisions:
893
            # INFO - G.M - 2018-06-177 -sort revisions by date
894
            sorted_next_revisions = sorted(
895
                next_revisions,
896
                key=lambda revision: revision.updated
897
            )
898
            # INFO - G.M - 2018-06-177 - return only next revision
899
            return sorted_next_revisions[0]
900
        else:
901
            return None
902
903
    @property
904
    def comment_ids(self) -> typing.List[int]:
905
        """
906
        Get list of ids of all current revision related comments
907
        :return: list of comments ids
908
        """
909
        comments = self.revision.node.get_comments()
910
        # INFO - G.M - 2018-06-177 - Get comments more recent than revision.
911
        revision_comments = [
912
            comment for comment in comments
913
            if comment.created > self.revision.updated
914
        ]
915
        if self.next_revision:
916
            # INFO - G.M - 2018-06-177 - if there is a revision more recent
917
            # than current remove comments from theses rev (comments older
918
            # than next_revision.)
919
            revision_comments = [
920
                comment for comment in revision_comments
921
                if comment.created < self.next_revision.updated
922
            ]
923
        sorted_revision_comments = sorted(
924
            revision_comments,
925
            key=lambda revision: revision.created
926
        )
927
        comment_ids = []
928
        for comment in sorted_revision_comments:
929
            comment_ids.append(comment.content_id)
930
        return comment_ids
931
932
    # Context-related
933
    @property
934
    def show_in_ui(self) -> bool:
935
        # TODO - G.M - 31-05-2018 - Enable Show_in_ui params
936
        # if false, then do not show content in the treeview.
937
        # This may his maybe used for specific contents or for sub-contents.
938
        # Default is True.
939
        # In first version of the API, this field is always True
940
        return True
941
942
    @property
943
    def slug(self) -> str:
944
        return slugify(self.revision.label)
945
946
    # file specific
947
    @property
948
    def page_nb(self) -> typing.Optional[int]:
949
        """
950
        :return: page_nb of content if available, None if unavailable
951
        """
952
        if self.revision.depot_file:
953
            # TODO - G.M - 2018-09-05 - Fix circular import better
954
            from tracim_backend.lib.core.content import ContentApi
955
            content_api = ContentApi(
956
                current_user=self._user,
957
                session=self.dbsession,
958
                config=self.config
959
            )
960
            return content_api.get_preview_page_nb(self.revision.revision_id)
961
        else:
962
            return None
963
964
    @property
965
    def mimetype(self) -> str:
966
        """
967
        :return: mimetype of content if available, None if unavailable
968
        """
969
        return self.revision.file_mimetype
970
971
    @property
972
    def size(self) -> typing.Optional[int]:
973
        """
974
        :return: size of content if available, None if unavailable
975
        """
976
        if self.revision.depot_file:
977
            return self.revision.depot_file.file.content_length
978
        else:
979
            return None
980
981
    @property
982
    def pdf_available(self) -> bool:
983
        """
984
        :return: bool about if pdf version of content is available
985
        """
986
        if self.revision.depot_file:
987
            from tracim_backend.lib.core.content import ContentApi
988
            content_api = ContentApi(
989
                current_user=self._user,
990
                session=self.dbsession,
991
                config=self.config
992
            )
993
            return content_api.has_pdf_preview(self.revision.revision_id)
994
        else:
995
            return False
996