Browse Source

Refactor preview: move from endpoint to contentapi

Guénaël Muller 6 years ago
parent
commit
1e07daa6b6

+ 26 - 0
tracim/config.py View File

@@ -411,6 +411,25 @@ class CFG(object):
411 411
         #     self.RADICALE_CLIENT_BASE_URL_HOST,
412 412
         #     self.RADICALE_CLIENT_BASE_URL_PREFIX,
413 413
         # )
414
+        preview_jpg_allowed_sizes = settings.get('preview.jpg.allowed_sizes', '')  # nopep8
415
+        self.PREVIEW_JPG_ALLOWED_SIZES = []
416
+        if preview_jpg_allowed_sizes:
417
+            for size in preview_jpg_allowed_sizes.split(','):
418
+                parts = preview_jpg_allowed_sizes.split('x')
419
+                assert len(parts) == 2
420
+                width, height = parts
421
+                assert width.is_decimal()
422
+                assert height.is_decimal()
423
+                size = PreviewSize(int(width), int(height))
424
+                self.PREVIEW_JPG_ALLOWED_SIZES.append(size)
425
+
426
+            self.PREVIEW_JPG_RESTRICTED_SIZES = asbool(settings.get(
427
+                'preview.jpg.restricted_sizes', False
428
+            ))
429
+        if not self.PREVIEW_JPG_ALLOWED_SIZES:
430
+            size = PreviewSize(256, 256)
431
+            self.PREVIEW_JPG_ALLOWED_SIZES.append(size)
432
+
414 433
 
415 434
     def configure_filedepot(self):
416 435
         depot_storage_name = self.DEPOT_STORAGE_NAME
@@ -427,3 +446,10 @@ class CFG(object):
427 446
 
428 447
         TREEVIEW_FOLDERS = 'folders'
429 448
         TREEVIEW_ALL = 'all'
449
+
450
+
451
+class PreviewSize(object):
452
+
453
+    def __init__(self, width: int, height: int) -> None:
454
+        self.width = width
455
+        self.height = height

+ 7 - 0
tracim/exceptions.py View File

@@ -147,3 +147,10 @@ class EmptyRawContentNotAllowed(EmptyValueNotAllowed):
147 147
 
148 148
 class RevisionDoesNotMatchThisContent(TracimException):
149 149
     pass
150
+
151
+
152
+class PageOfPreviewNotFound(NotFound):
153
+    pass
154
+
155
+class PreviewSizeNotAllowed(TracimException):
156
+    pass

+ 92 - 0
tracim/lib/core/content.py View File

@@ -7,6 +7,7 @@ import typing
7 7
 from operator import itemgetter
8 8
 
9 9
 import transaction
10
+from preview_generator.manager import PreviewManager
10 11
 from sqlalchemy import func
11 12
 from sqlalchemy.orm import Query
12 13
 from depot.manager import DepotManager
@@ -25,6 +26,8 @@ from sqlalchemy.sql.elements import and_
25 26
 from tracim.lib.utils.utils import cmp_to_key
26 27
 from tracim.lib.core.notifications import NotifierFactory
27 28
 from tracim.exceptions import SameValueError
29
+from tracim.exceptions import PageOfPreviewNotFound
30
+from tracim.exceptions import PreviewSizeNotAllowed
28 31
 from tracim.exceptions import EmptyRawContentNotAllowed
29 32
 from tracim.exceptions import RevisionDoesNotMatchThisContent
30 33
 from tracim.exceptions import EmptyLabelNotAllowed
@@ -134,6 +137,7 @@ class ContentApi(object):
134 137
         self._show_all_type_of_contents_in_treeview = all_content_in_treeview
135 138
         self._force_show_all_types = force_show_all_types
136 139
         self._disable_user_workspaces_filter = disable_user_workspaces_filter
140
+        self.preview_manager = PreviewManager(self._config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
137 141
 
138 142
     @contextmanager
139 143
     def show(
@@ -721,6 +725,94 @@ class ContentApi(object):
721 725
             ),
722 726
         ))
723 727
 
728
+    def get_pdf_preview_path(
729
+            self,
730
+            content_id: int,
731
+            revision_id: int,
732
+            page: int
733
+    ) -> str:
734
+        """
735
+        Get pdf preview of revision of content
736
+        :param content_id: id of content
737
+        :param revision_id: id of content revision
738
+        :param page: page number of the preview, useful for multipage content
739
+        :return: preview_path as string
740
+        """
741
+        file_path = self.get_one_revision_filepath(revision_id)
742
+        if page >= self.preview_manager.get_page_nb(file_path):
743
+            raise PageOfPreviewNotFound(
744
+                'page {page} of content {content_id} does not exist'.format(
745
+                    page=page,
746
+                    content_id=content_id
747
+                ),
748
+            )
749
+        jpg_preview_path = self.preview_manager.get_jpeg_preview(
750
+            file_path,
751
+            page=page
752
+        )
753
+        return jpg_preview_path
754
+
755
+    def get_full_pdf_preview_path(self, revision_id: int) -> str:
756
+        """
757
+        Get full(multiple page) pdf preview of revision of content
758
+        :param revision_id: id of revision
759
+        :return: path of the full pdf preview of this revision
760
+        """
761
+        file_path = self.get_one_revision_filepath(revision_id)
762
+        pdf_preview_path = self.preview_manager.get_pdf_preview(file_path)
763
+        return pdf_preview_path
764
+
765
+    def get_jpg_preview_path(
766
+        self,
767
+        content_id: int,
768
+        revision_id: int,
769
+        page: int,
770
+        width: int = None,
771
+        height: int = None,
772
+    ) -> str:
773
+        """
774
+        Get jpg preview of revision of content
775
+        :param content_id: id of content
776
+        :param revision_id: id of content revision
777
+        :param page: page number of the preview, useful for multipage content
778
+        :param width: width in pixel
779
+        :param height: height in pixel
780
+        :return: preview_path as string
781
+        """
782
+        file_path = self.get_one_revision_filepath(revision_id)
783
+        if page >= self.preview_manager.get_page_nb(file_path):
784
+            raise Exception(
785
+                'page {page} of revision {revision_id} of content {content_id} does not exist'.format(  # nopep8
786
+                    page=page,
787
+                    revision_id=revision_id,
788
+                    content_id=content_id,
789
+                ),
790
+            )
791
+        if not width and not height:
792
+            width = self._config.PREVIEW_JPG_ALLOWED_SIZES[0].width
793
+            height = self._config.PREVIEW_JPG_ALLOWED_SIZES[0].height
794
+
795
+        allowed_size = False
796
+        for preview_size in self._config.PREVIEW_JPG_ALLOWED_SIZES:
797
+            if width == preview_size.width and height == preview_size.height:
798
+                allowed_size = True
799
+                break
800
+
801
+        if not allowed_size and self._config.PREVIEW_JPG_RESTRICTED_SIZES:
802
+            raise PreviewSizeNotAllowed(
803
+                'Size {width}x{height} is not allowed for jpeg preview'.format(
804
+                    width=width,
805
+                    height=height,
806
+                )
807
+            )
808
+        jpg_preview_path = self.preview_manager.get_jpeg_preview(
809
+            file_path,
810
+            page=page,
811
+            width=width,
812
+            height=height,
813
+        )
814
+        return jpg_preview_path
815
+
724 816
     def get_all(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> typing.List[Content]:
725 817
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
726 818
         assert content_type is not None# DYN_REMOVE

+ 1 - 0
tracim/tests/__init__.py View File

@@ -78,6 +78,7 @@ class FunctionalTest(unittest.TestCase):
78 78
             'depot_storage_dir': '/tmp/test/depot',
79 79
             'depot_storage_name': 'test',
80 80
             'preview_cache_dir': '/tmp/test/preview_cache',
81
+            'preview.jpg.restricted_sizes': True,
81 82
 
82 83
         }
83 84
         hapic.reset_context()

+ 3 - 3
tracim/tests/functional/test_contents.py View File

@@ -1110,7 +1110,7 @@ class TestFiles(FunctionalTest):
1110 1110
 
1111 1111
     def test_api__get_sized_jpeg_preview__ok__200__nominal_case(self) -> None:
1112 1112
         """
1113
-        Set one file of a content
1113
+        get 256x256 preview of a txt file
1114 1114
         """
1115 1115
         dbsession = get_tm_session(self.session_factory, transaction.manager)
1116 1116
         admin = dbsession.query(models.User) \
@@ -1165,7 +1165,7 @@ class TestFiles(FunctionalTest):
1165 1165
 
1166 1166
     def test_api__get_full_pdf_preview__ok__200__nominal_case(self) -> None:
1167 1167
         """
1168
-        Set one file of a content
1168
+        get full pdf preview of a txt file
1169 1169
         """
1170 1170
         dbsession = get_tm_session(self.session_factory, transaction.manager)
1171 1171
         admin = dbsession.query(models.User) \
@@ -1228,7 +1228,7 @@ class TestFiles(FunctionalTest):
1228 1228
 
1229 1229
     def test_api__get_full_pdf_preview__err__400__png_UnavailablePreviewType(self) -> None:
1230 1230
         """
1231
-        Set one file of a content
1231
+       get full pdf preview of a png image -> error UnavailablePreviewType
1232 1232
         """
1233 1233
         dbsession = get_tm_session(self.session_factory, transaction.manager)
1234 1234
         admin = dbsession.query(models.User) \

+ 24 - 49
tracim/views/contents_api/file_controller.py View File

@@ -2,7 +2,6 @@
2 2
 import typing
3 3
 
4 4
 import transaction
5
-from depot.io.local import LocalStoredFile
6 5
 from depot.manager import DepotManager
7 6
 from preview_generator.exception import UnavailablePreviewType
8 7
 from pyramid.config import Configurator
@@ -37,7 +36,6 @@ from tracim.models.context_models import RevisionInContext
37 36
 from tracim.models.contents import ContentTypeLegacy as ContentType
38 37
 from tracim.models.contents import file_type
39 38
 from tracim.models.revision_protection import new_revision
40
-from preview_generator.manager import PreviewManager
41 39
 
42 40
 FILE_ENDPOINTS_TAG = 'Files'
43 41
 
@@ -136,7 +134,6 @@ class FileController(Controller):
136 134
     @hapic.output_file([])
137 135
     def preview_pdf(self, context, request: TracimRequest, hapic_data=None):
138 136
         app_config = request.registry.settings['CFG']
139
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
140 137
         api = ContentApi(
141 138
             current_user=request.current_user,
142 139
             session=request.dbsession,
@@ -146,13 +143,11 @@ class FileController(Controller):
146 143
             hapic_data.path.content_id,
147 144
             content_type=ContentType.Any
148 145
         )
149
-        file_path = api.get_one_revision_filepath(content.revision_id)
150
-        if hapic_data.query.page >= preview_manager.get_page_nb(file_path):
151
-            raise Exception('page {page} of content {content_id} does not exist'.format(
152
-                page=hapic_data.query.page,
153
-                content_id=content.content_id),
154
-            )
155
-        pdf_preview_path = preview_manager.get_pdf_preview(file_path, page=hapic_data.query.page)  # nopep8
146
+        pdf_preview_path = api.get_pdf_preview_path(
147
+            content.content_id,
148
+            content.revision_id,
149
+            page=hapic_data.query.page
150
+        )
156 151
         return FileResponse(pdf_preview_path)
157 152
 
158 153
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
@@ -163,7 +158,6 @@ class FileController(Controller):
163 158
     @hapic.output_file([])
164 159
     def preview_pdf_full(self, context, request: TracimRequest, hapic_data=None):
165 160
         app_config = request.registry.settings['CFG']
166
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
167 161
         api = ContentApi(
168 162
             current_user=request.current_user,
169 163
             session=request.dbsession,
@@ -173,8 +167,7 @@ class FileController(Controller):
173 167
             hapic_data.path.content_id,
174 168
             content_type=ContentType.Any
175 169
         )
176
-        file_path = api.get_one_revision_filepath(content.revision_id)
177
-        pdf_preview_path = preview_manager.get_pdf_preview(file_path)
170
+        pdf_preview_path = api.get_full_pdf_preview_path(content.revision_id)
178 171
         return FileResponse(pdf_preview_path)
179 172
 
180 173
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
@@ -186,7 +179,6 @@ class FileController(Controller):
186 179
     @hapic.output_file([])
187 180
     def preview_pdf_revision(self, context, request: TracimRequest, hapic_data=None):
188 181
         app_config = request.registry.settings['CFG']
189
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
190 182
         api = ContentApi(
191 183
             current_user=request.current_user,
192 184
             session=request.dbsession,
@@ -200,13 +192,11 @@ class FileController(Controller):
200 192
             revision_id=hapic_data.path.revision_id,
201 193
             content=content
202 194
         )
203
-        file_path = api.get_one_revision_filepath(revision.revision_id)
204
-        if hapic_data.query.page >= preview_manager.get_page_nb(file_path):
205
-            raise Exception('page {page} of content {content_id} does not exist'.format(
206
-                page=hapic_data.query.page,
207
-                content_id=content.content_id),
208
-            )
209
-        pdf_preview_path = preview_manager.get_pdf_preview(file_path, page=hapic_data.query.page)  # nopep8
195
+        pdf_preview_path = api.get_pdf_preview_path(
196
+            revision.content_id,
197
+            revision.revision_id,
198
+            page=hapic_data.query.page
199
+        )
210 200
         return FileResponse(pdf_preview_path)
211 201
 
212 202
     # jpg
@@ -218,7 +208,6 @@ class FileController(Controller):
218 208
     @hapic.output_file([])
219 209
     def preview_jpg(self, context, request: TracimRequest, hapic_data=None):
220 210
         app_config = request.registry.settings['CFG']
221
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
222 211
         api = ContentApi(
223 212
             current_user=request.current_user,
224 213
             session=request.dbsession,
@@ -228,13 +217,11 @@ class FileController(Controller):
228 217
             hapic_data.path.content_id,
229 218
             content_type=ContentType.Any
230 219
         )
231
-        file_path = api.get_one_revision_filepath(content.revision_id)
232
-        if hapic_data.query.page >= preview_manager.get_page_nb(file_path):
233
-            raise Exception('page {page} of content {content_id} does not exist'.format(
234
-                page=hapic_data.query.page,
235
-                content_id=content.content_id),
236
-            )
237
-        jpg_preview_path = preview_manager.get_jpeg_preview(file_path, page=hapic_data.query.page)  # nopep8
220
+        jpg_preview_path = api.get_jpg_preview_path(
221
+            content_id=content.content_id,
222
+            revision_id=content.revision_id,
223
+            page=hapic_data.query.page
224
+        )
238 225
         return FileResponse(jpg_preview_path)
239 226
 
240 227
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
@@ -245,7 +232,6 @@ class FileController(Controller):
245 232
     @hapic.output_file([])
246 233
     def sized_preview_jpg(self, context, request: TracimRequest, hapic_data=None):
247 234
         app_config = request.registry.settings['CFG']
248
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
249 235
         api = ContentApi(
250 236
             current_user=request.current_user,
251 237
             session=request.dbsession,
@@ -255,17 +241,12 @@ class FileController(Controller):
255 241
             hapic_data.path.content_id,
256 242
             content_type=ContentType.Any
257 243
         )
258
-        file_path = api.get_one_revision_filepath(content.revision_id)
259
-        if hapic_data.query.page >= preview_manager.get_page_nb(file_path):
260
-            raise Exception('page {page} of content {content_id} does not exist'.format(
261
-                page=hapic_data.query.page,
262
-                content_id=content.content_id),
263
-            )
264
-        jpg_preview_path = preview_manager.get_jpeg_preview(
265
-            file_path,
244
+        jpg_preview_path = api.get_jpg_preview_path(
245
+            content_id=content.content_id,
246
+            revision_id=content.revision_id,
266 247
             page=hapic_data.query.page,
267
-            width=hapic_data.path.width,
268 248
             height=hapic_data.path.height,
249
+            width=hapic_data.path.width,
269 250
         )
270 251
         return FileResponse(jpg_preview_path)
271 252
 
@@ -277,7 +258,6 @@ class FileController(Controller):
277 258
     @hapic.output_file([])
278 259
     def sized_preview_jpg_revision(self, context, request: TracimRequest, hapic_data=None):
279 260
         app_config = request.registry.settings['CFG']
280
-        preview_manager = PreviewManager(app_config.PREVIEW_CACHE_DIR, create_folder=True)  # nopep8
281 261
         api = ContentApi(
282 262
             current_user=request.current_user,
283 263
             session=request.dbsession,
@@ -291,17 +271,12 @@ class FileController(Controller):
291 271
             revision_id=hapic_data.path.revision_id,
292 272
             content=content
293 273
         )
294
-        file_path = api.get_one_revision_filepath(revision.revision_id)
295
-        if hapic_data.query.page >= preview_manager.get_page_nb(file_path):
296
-            raise Exception('page {page} of content {content_id} does not exist'.format(
297
-                page=hapic_data.query.page,
298
-                content_id=content.content_id),
299
-            )
300
-        jpg_preview_path = preview_manager.get_jpeg_preview(
301
-            file_path,
274
+        jpg_preview_path = api.get_jpg_preview_path(
275
+            content_id=content.content_id,
276
+            revision_id=revision.revision_id,
302 277
             page=hapic_data.query.page,
303
-            width=hapic_data.path.width,
304 278
             height=hapic_data.path.height,
279
+            width=hapic_data.path.width,
305 280
         )
306 281
         return FileResponse(jpg_preview_path)
307 282