Pārlūkot izejas kodu

add read/unread endpoints

Guénaël Muller 5 gadus atpakaļ
vecāks
revīzija
c3652f57c8

+ 4 - 1
tracim/lib/core/content.py Parādīt failu

@@ -1149,7 +1149,10 @@ class ContentApi(object):
1149 1149
             .filter(ContentRevisionRO.content_id==content.content_id).all()
1150 1150
 
1151 1151
         for revision in revisions:
1152
-            del revision.read_by[self._user]
1152
+            try:
1153
+                del revision.read_by[self._user]
1154
+            except KeyError:
1155
+                pass
1153 1156
 
1154 1157
         for child in content.get_valid_children():
1155 1158
             self.mark_unread(child, do_flush=False)

+ 20 - 1
tracim/models/context_models.py Parādīt failu

@@ -43,6 +43,25 @@ class WorkspaceAndContentPath(object):
43 43
         self.workspace_id = workspace_id
44 44
 
45 45
 
46
+class UserWorkspacePath(object):
47
+    """
48
+    Paths params with user_id and workspace id model
49
+    """
50
+    def __init__(self, user_id: int, workspace_id: int) -> None:
51
+        self.workspace_id = workspace_id
52
+        self.user_id = workspace_id
53
+
54
+
55
+class UserWorkspaceAndContentPath(object):
56
+    """
57
+    Paths params with user_id, workspace id and content_id model
58
+    """
59
+    def __init__(self, user_id: int, workspace_id: int, content_id: int) -> None:  # nopep8
60
+        self.content_id = content_id
61
+        self.workspace_id = workspace_id
62
+        self.user_id = user_id
63
+
64
+
46 65
 class CommentPath(object):
47 66
     """
48 67
     Paths params with workspace id and content_id and comment_id model
@@ -435,7 +454,7 @@ class ContentInContext(object):
435 454
     @property
436 455
     def read_by_user(self):
437 456
         assert self._user
438
-        return self.content.has_new_information_for(self._user)
457
+        return not self.content.has_new_information_for(self._user)
439 458
 
440 459
 
441 460
 class RevisionInContext(object):

+ 21 - 0
tracim/views/core_api/schemas.py Parādīt failu

@@ -11,6 +11,8 @@ from tracim.models.contents import open_status
11 11
 from tracim.models.contents import ContentTypeLegacy as ContentType
12 12
 from tracim.models.contents import ContentStatusLegacy as ContentStatus
13 13
 from tracim.models.context_models import ContentCreation
14
+from tracim.models.context_models import UserWorkspacePath
15
+from tracim.models.context_models import UserWorkspaceAndContentPath
14 16
 from tracim.models.context_models import CommentCreation
15 17
 from tracim.models.context_models import TextBasedContentUpdate
16 18
 from tracim.models.context_models import SetContentStatus
@@ -115,6 +117,25 @@ class WorkspaceAndContentIdPathSchema(
115 117
         return WorkspaceAndContentPath(**data)
116 118
 
117 119
 
120
+class UserWorkspaceAndContentIdPathSchema(
121
+    UserIdPathSchema,
122
+    WorkspaceIdPathSchema,
123
+    ContentIdPathSchema,
124
+):
125
+    @post_load
126
+    def make_path_object(self, data):
127
+        return UserWorkspaceAndContentPath(**data)
128
+
129
+
130
+class UserWorkspaceIdPathSchema(
131
+    UserIdPathSchema,
132
+    WorkspaceIdPathSchema,
133
+):
134
+    @post_load
135
+    def make_path_object(self, data):
136
+        return UserWorkspacePath(**data)
137
+
138
+
118 139
 class CommentsPathSchema(WorkspaceAndContentIdPathSchema):
119 140
     comment_id = marshmallow.fields.Int(
120 141
         example=6,

+ 67 - 4
tracim/views/core_api/user_controller.py Parādīt failu

@@ -3,7 +3,6 @@ from pyramid.config import Configurator
3 3
 from tracim.lib.core.content import ContentApi
4 4
 from tracim.lib.utils.authorization import require_same_user_or_profile
5 5
 from tracim.models import Group
6
-from tracim.models.context_models import WorkspaceInContext
7 6
 
8 7
 try:  # Python 3.5+
9 8
     from http import HTTPStatus
@@ -15,6 +14,9 @@ from tracim import hapic, TracimRequest
15 14
 from tracim.lib.core.workspace import WorkspaceApi
16 15
 from tracim.views.controllers import Controller
17 16
 from tracim.views.core_api.schemas import UserIdPathSchema
17
+from tracim.views.core_api.schemas import NoContentSchema
18
+from tracim.views.core_api.schemas import UserWorkspaceIdPathSchema
19
+from tracim.views.core_api.schemas import UserWorkspaceAndContentIdPathSchema
18 20
 from tracim.views.core_api.schemas import UserContentDigestSchema
19 21
 from tracim.views.core_api.schemas import ExtendedFilterQuerySchema
20 22
 from tracim.views.core_api.schemas import WorkspaceDigestSchema
@@ -35,7 +37,7 @@ class UserController(Controller):
35 37
         """
36 38
         app_config = request.registry.settings['CFG']
37 39
         wapi = WorkspaceApi(
38
-            current_user=request.current_user,  # User
40
+            current_user=request.candidate_user,  # User
39 41
             session=request.dbsession,
40 42
             config=app_config,
41 43
         )
@@ -58,7 +60,7 @@ class UserController(Controller):
58 60
         app_config = request.registry.settings['CFG']
59 61
         content_filter = hapic_data.query
60 62
         api = ContentApi(
61
-            current_user=request.current_user,  # User
63
+            current_user=request.candidate_user,  # User
62 64
             session=request.dbsession,
63 65
             config=app_config,
64 66
             show_archived=content_filter.show_archived,
@@ -66,7 +68,7 @@ class UserController(Controller):
66 68
             show_active=content_filter.show_active,
67 69
         )
68 70
         wapi = WorkspaceApi(
69
-            current_user=request.current_user,  # User
71
+            current_user=request.candidate_user,  # User
70 72
             session=request.dbsession,
71 73
             config=app_config,
72 74
         )
@@ -85,6 +87,57 @@ class UserController(Controller):
85 87
             for content in last_actives
86 88
         ]
87 89
 
90
+    @hapic.with_api_doc(tags=[USER_ENDPOINTS_TAG])
91
+    @require_same_user_or_profile(Group.TIM_ADMIN)
92
+    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
93
+    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
94
+    def set_content_as_read(self, context, request: TracimRequest, hapic_data=None):  # nopep8
95
+        """
96
+        set user_read status of content to read
97
+        """
98
+        app_config = request.registry.settings['CFG']
99
+        api = ContentApi(
100
+            current_user=request.candidate_user,
101
+            session=request.dbsession,
102
+            config=app_config,
103
+        )
104
+        api.mark_read(request.current_content, do_flush=True)
105
+        return
106
+
107
+    @hapic.with_api_doc(tags=[USER_ENDPOINTS_TAG])
108
+    @require_same_user_or_profile(Group.TIM_ADMIN)
109
+    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
110
+    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
111
+    def set_content_as_unread(self, context, request: TracimRequest, hapic_data=None):  # nopep8
112
+        """
113
+        set user_read status of content to unread
114
+        """
115
+        app_config = request.registry.settings['CFG']
116
+        api = ContentApi(
117
+            current_user=request.candidate_user,
118
+            session=request.dbsession,
119
+            config=app_config,
120
+        )
121
+        api.mark_unread(request.current_content, do_flush=True)
122
+        return
123
+
124
+    @hapic.with_api_doc(tags=[USER_ENDPOINTS_TAG])
125
+    @require_same_user_or_profile(Group.TIM_ADMIN)
126
+    @hapic.input_path(UserWorkspaceIdPathSchema())
127
+    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
128
+    def set_workspace_as_read(self, context, request: TracimRequest, hapic_data=None):  # nopep8
129
+        """
130
+        set user_read status of all content of workspace to read
131
+        """
132
+        app_config = request.registry.settings['CFG']
133
+        api = ContentApi(
134
+            current_user=request.candidate_user,
135
+            session=request.dbsession,
136
+            config=app_config,
137
+        )
138
+        api.mark_read__workspace(request.current_workspace)
139
+        return
140
+
88 141
     def bind(self, configurator: Configurator) -> None:
89 142
         """
90 143
         Create all routes and views using pyramid configurator
@@ -98,3 +151,13 @@ class UserController(Controller):
98 151
         # last active content for user
99 152
         configurator.add_route('last_active_content', '/users/{user_id}/contents/actives', request_method='GET')  # nopep8
100 153
         configurator.add_view(self.last_active_content, route_name='last_active_content')  # nopep8
154
+
155
+        # set content as read/unread
156
+        configurator.add_route('read_content', '/users/{user_id}/workspaces/{workspace_id}/contents/{content_id}/read', request_method='PUT')  # nopep8
157
+        configurator.add_view(self.set_content_as_read, route_name='read_content')  # nopep8
158
+        configurator.add_route('unread_content', '/users/{user_id}/workspaces/{workspace_id}/contents/{content_id}/unread', request_method='PUT')  # nopep8
159
+        configurator.add_view(self.set_content_as_unread, route_name='unread_content')  # nopep8
160
+
161
+        # set workspace as read
162
+        configurator.add_route('read_workspace', '/users/{user_id}/workspaces/{workspace_id}/read', request_method='PUT')  # nopep8
163
+        configurator.add_view(self.set_workspace_as_read, route_name='read_workspace')  # nopep8