ソースを参照

Ajout de preview-generator

Alexis CLEMENT 7 年 前
コミット
633a5f752f

+ 2 - 1
tracim/development.ini.base ファイルの表示

@@ -35,6 +35,7 @@ full_stack = true
35 35
 # You can set french as default language by uncommenting next line
36 36
 # lang = fr
37 37
 cache_dir = %(here)s/data
38
+preview_cache_dir = '/tmp/tracim/cache/previews/'
38 39
 beaker.session.key = tracim
39 40
 beaker.session.secret = 3283411b-1904-4554-b0e1-883863b53080
40 41
 
@@ -96,7 +97,7 @@ beaker.session.validate_key = 3283411b-1904-4554-b0e1-883863b53080
96 97
 # sqlalchemy.url=mysql://username:password@hostname:port/databasename
97 98
 # sqlalchemy.url = postgresql://tracimuser:tracimpassword@127.0.0.1:5432/tracimdb?client_encoding=utf8
98 99
 # sqlalchemy.url = mysql+pymysql://tracimuser:tracimpassword@127.0.0.1/tracimdb
99
-sqlalchemy.url = <replace_database_uri_here>
100
+sqlalchemy.url = sqlite:///tracimdb.sqlite
100 101
 
101 102
 #echo shouldn't be used together with the logging module.
102 103
 sqlalchemy.echo = false

+ 2 - 0
tracim/tracim/config/app_cfg.py ファイルの表示

@@ -194,6 +194,8 @@ class CFG(object):
194 194
 
195 195
     def __init__(self):
196 196
 
197
+        self.PREVIEW_CACHE = str(tg.config.get('preview_cache_dir'))
198
+
197 199
         self.DATA_UPDATE_ALLOWED_DURATION = int(tg.config.get('content.update.allowed.duration', 0))
198 200
 
199 201
         self.WEBSITE_TITLE = tg.config.get('website.title', 'TRACIM')

+ 44 - 3
tracim/tracim/controllers/content.py ファイルの表示

@@ -1,4 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2
+from tracim.config.app_cfg import CFG
3
+
2 4
 __author__ = 'damien'
3 5
 
4 6
 import sys
@@ -45,6 +47,8 @@ from tracim.model.data import UserRoleInWorkspace
45 47
 from tracim.model.data import Workspace
46 48
 from tracim.lib.integrity import render_invalid_integrity_chosen_path
47 49
 
50
+from preview_generator.manager import PreviewManager
51
+
48 52
 
49 53
 class UserWorkspaceFolderThreadCommentRestController(TIMRestController):
50 54
 
@@ -199,19 +203,56 @@ class UserWorkspaceFolderFileRestController(TIMWorkspaceContentRestController):
199 203
             show_archived=True,
200 204
             show_deleted=True,
201 205
         )
206
+        cfg = CFG.get_instance()
207
+        cache_path = cfg.PREVIEW_CACHE
208
+        preview_manager = PreviewManager(cache_path, create_folder=True)
209
+        if revision_id:
210
+            file_path = content_api.get_one_revision_filepath(revision_id)
211
+        else:
212
+            file = content_api.get_one(file_id, self._item_type)
213
+            file_path = content_api.get_one_revision_filepath(file.revision_id)
214
+        nb_page = preview_manager.get_nb_page(
215
+            file_path=file_path,
216
+        )
202 217
         if revision_id:
203
-            file = content_api.get_one_from_revision(file_id,  self._item_type, workspace, revision_id)
218
+            file = content_api.get_one_from_revision(
219
+                file_id,
220
+                self._item_type,
221
+                workspace,
222
+                revision_id
223
+            )
204 224
         else:
205 225
             file = content_api.get_one(file_id, self._item_type, workspace)
206 226
 
207 227
         fake_api_breadcrumb = self.get_breadcrumb(file_id)
208
-        fake_api_content = DictLikeClass(breadcrumb=fake_api_breadcrumb, current_user=current_user_content)
228
+        fake_api_content = DictLikeClass(
229
+            breadcrumb=fake_api_breadcrumb,
230
+            current_user=current_user_content
231
+        )
209 232
         fake_api = Context(CTX.FOLDER,
210 233
                            current_user=user).toDict(fake_api_content)
211 234
 
212 235
         dictified_file = Context(self._get_one_context,
213 236
                                  current_user=user).toDict(file, 'file')
214
-        return DictLikeClass(result = dictified_file, fake_api=fake_api)
237
+
238
+        url = []
239
+        if revision_id:
240
+            for i in range(int(nb_page)):
241
+                url.append('/previews/{}/pages/{}?revision_id={}'.format(
242
+                    file_id,
243
+                    i,
244
+                    revision_id)
245
+                )
246
+        else:
247
+            for i in range(int(nb_page)):
248
+                url.append('/previews/{}/pages/{}'.format(file_id, i))
249
+
250
+        return DictLikeClass(
251
+            result=dictified_file,
252
+            fake_api=fake_api,
253
+            nb_page=nb_page,
254
+            url=url,
255
+        )
215 256
 
216 257
     @tg.require(current_user_is_reader())
217 258
     @tg.expose()

+ 140 - 0
tracim/tracim/controllers/page.py ファイルの表示

@@ -0,0 +1,140 @@
1
+import tg
2
+from preview_generator.manager import PreviewManager
3
+from tg import expose, tmpl_context
4
+from tracim.config.app_cfg import CFG
5
+from tracim.controllers import TIMRestController
6
+from tracim.lib.content import ContentApi
7
+from tracim.model.data import ContentType
8
+
9
+__all__ = ['PagesController']
10
+
11
+class PagesController(TIMRestController):
12
+
13
+    @expose()
14
+    def _default(self):
15
+        return '<h2> Error Loading Page</h2>'
16
+
17
+    @expose()
18
+    def get_all(self, *args, **kwargs):
19
+        file_id = int(tg.request.controller_state.routing_args.get('file_id'))
20
+        return 'all the pages of document {}'.format(file_id)
21
+
22
+    @expose(content_type='image/jpeg')
23
+    def get_one(self, page_id: int, revision_id: int=None, *args, **kwargs):
24
+        file_id = int(tg.request.controller_state.routing_args.get('file_id'))
25
+
26
+        # For now it's done through database content
27
+        # but soon it'll be with disk access
28
+
29
+        user = tmpl_context.current_user
30
+        content_api = ContentApi(
31
+            user,
32
+            show_archived=True,
33
+            show_deleted=True,
34
+        )
35
+        if revision_id:
36
+            file_path = content_api.get_one_revision_filepath(revision_id)
37
+        else:
38
+            file = content_api.get_one(file_id, self._item_type)
39
+            file_path = content_api.get_one_revision_filepath(file.revision_id)
40
+
41
+        cfg = CFG.get_instance()
42
+        cache_path = cfg.PREVIEW_CACHE
43
+
44
+        preview_manager = PreviewManager(cache_path, create_folder=True)
45
+        path = preview_manager.get_jpeg_preview(
46
+            file_path=file_path,
47
+            page=page_id,
48
+            height=500,
49
+            width=500
50
+        )
51
+
52
+        with open(path, 'rb') as large:
53
+            return large.read()
54
+
55
+    @expose(content_type='image/jpeg')
56
+    def high_quality(self, page_id: int, *args, **kwargs):
57
+        file_id = int(tg.request.controller_state.routing_args.get('file_id'))
58
+
59
+        # For now it's done through database content
60
+        # but soon it'll be with disk access
61
+
62
+        user = tmpl_context.current_user
63
+        content_api = ContentApi(
64
+            user,
65
+            show_archived=True,
66
+            show_deleted=True,
67
+        )
68
+        file_name = content_api.get_one(file_id, self._item_type).file_name
69
+        cache_path = '/home/alexis/Pictures/cache/'
70
+
71
+        preview_manager = PreviewManager(cache_path, create_folder=True)
72
+        path = preview_manager.get_jpeg_preview(
73
+            file_path='/home/alexis/Pictures/cache/{}'.format(file_name),
74
+            page=page_id,
75
+            height=5000,
76
+            width=5000
77
+        )
78
+
79
+        with open(path, 'rb') as large:
80
+            return large.read()
81
+
82
+    @expose(content_type='application/pdf')
83
+    def download_pdf_full(self, *args, **kwargs):
84
+        file_id = int(tg.request.controller_state.routing_args.get('file_id'))
85
+
86
+        # For now it's done through database content
87
+        # but soon it'll be with disk access
88
+
89
+        user = tmpl_context.current_user
90
+        content_api = ContentApi(
91
+            user,
92
+            show_archived=True,
93
+            show_deleted=True,
94
+        )
95
+        file_name = content_api.get_one(file_id, self._item_type).file_name
96
+        cache_path = '/home/alexis/Pictures/cache/'
97
+
98
+        preview_manager = PreviewManager(cache_path, create_folder=True)
99
+        path = preview_manager.get_pdf_preview(
100
+            file_path='/home/alexis/Pictures/cache/{}'.format(file_name),
101
+        )
102
+
103
+        tg.response.headers['Content-Disposition'] = \
104
+            str('attachment; filename="{}"'.format(file_name))
105
+        with open(path, 'rb') as pdf:
106
+            return pdf.read()
107
+
108
+    @expose(content_type='application/pdf')
109
+    def download_pdf_one(self, page_id: int, *args, **kwargs):
110
+        file_id = int(tg.request.controller_state.routing_args.get('file_id'))
111
+        page_id = int(page_id)
112
+        # page_id = int(tg.request.controller_state.routing_args.get('page_id'))
113
+
114
+        # For now it's done through database content
115
+        # but soon it'll be with disk access
116
+
117
+        user = tmpl_context.current_user
118
+        content_api = ContentApi(
119
+            user,
120
+            show_archived=True,
121
+            show_deleted=True,
122
+        )
123
+        file_name = content_api.get_one(file_id, self._item_type).file_name
124
+
125
+        cache_path = '/home/alexis/Pictures/cache/'
126
+
127
+        preview_manager = PreviewManager(cache_path, create_folder=True)
128
+        path = preview_manager.get_pdf_preview(
129
+            file_path='/home/alexis/Pictures/cache/{}'.format(file_name),
130
+            page=page_id,
131
+        )
132
+
133
+        tg.response.headers['Content-Disposition'] = \
134
+            str('attachment; filename="{}"'.format(file_name))
135
+        with open(path, 'rb') as pdf:
136
+            return pdf.read()
137
+
138
+    @property
139
+    def _item_type(self):
140
+        return ContentType.File

+ 24 - 0
tracim/tracim/controllers/previews.py ファイルの表示

@@ -0,0 +1,24 @@
1
+from tracim.controllers import TIMRestController
2
+from tg import expose, tmpl_context
3
+from tracim.controllers.page import PagesController
4
+
5
+__all__ = ['PreviewsController']
6
+
7
+class PreviewsController(TIMRestController):
8
+
9
+    pages = PagesController()
10
+
11
+    @expose()
12
+    def _default(self, *args, **kwargs):
13
+        return '<h2> Error Loading Page</h2>'
14
+
15
+    @expose()
16
+    def get_all(self, *args, **kwargs):
17
+        print('getall _ document')
18
+        return 'all the files'
19
+
20
+    @expose()
21
+    def get_one(self, file_id, *args, **kwargs):
22
+        print('getone _ document')
23
+        tmpl_context.file = file_id
24
+        return 'File n°{}'.format(file_id)

+ 2 - 0
tracim/tracim/controllers/root.py ファイルの表示

@@ -13,6 +13,7 @@ from tg import url
13 13
 from tg.i18n import ugettext as _
14 14
 from tracim.controllers.api import APIController
15 15
 from tracim.controllers.content import ContentController
16
+from tracim.controllers.previews import PreviewsController
16 17
 
17 18
 from tracim.lib import CST
18 19
 from tracim.lib.base import logger
@@ -62,6 +63,7 @@ class RootController(StandardController):
62 63
     # Rest controllers
63 64
     workspaces = UserWorkspaceRestController()
64 65
     user = UserRestController()
66
+    previews = PreviewsController()
65 67
 
66 68
     content = ContentController()
67 69
 

+ 1 - 0
tracim/tracim/lib/content.py ファイルの表示

@@ -475,6 +475,7 @@ class ContentApi(object):
475 475
         # python 3.6 PEP 526 -- Syntax for Variable Annotations
476 476
         # https://www.python.org/dev/peps/pep-0526/
477 477
         # dpt_file_path: str = dpt.get(dpt_stored_file)._file_path
478
+        dpt_stored_file = dpt.get(revision.depot_file_uid)
478 479
         dpt_file_path = dpt.get(dpt_stored_file)._file_path
479 480
 
480 481
         return dpt_file_path

+ 65 - 0
tracim/tracim/templates/file/getone.mak ファイルの表示

@@ -100,6 +100,71 @@
100 100
     % endif
101 101
 
102 102
     <div class="content__detail file">
103
+        <div style="width: 15%;height: 100%;border:5px solid #606060;">
104
+            <a id="preview_link"><img id='preview' alt="Preview" style="width:100%;height:100%"></a>
105
+            <table style="width:100%;height:20%;">
106
+                <tr>
107
+                    <td rowspan="2">
108
+                        <button type="button" id="prev" onclick="previous_page()" style="width:100%;height:100%;"> - </button>
109
+                    </td>
110
+                    <td>
111
+                        <a id="dl_one_pdf" style=""> Download the page </a>
112
+                    </td>
113
+                    <td rowspan="2">
114
+                        <button type="button" id="next" onclick="next_page()" style="width:100%;height:100%;"> + </button>
115
+                    </td>
116
+                </tr>
117
+                <tr>
118
+                    <td >
119
+                        <a id="dl_full_pdf" style=""> Download all </a>
120
+                    </td>
121
+                </tr>
122
+            </table>
123
+
124
+            <script type="text/javascript">
125
+                var nb_page = parseInt(${nb_page});
126
+                console.log(nb_page);
127
+                var page = 0;
128
+                var urls = [];
129
+                % for one_url in url:
130
+                urls.push('${one_url}');
131
+                % endfor
132
+                console.log(urls);
133
+                document.getElementById('preview').src = urls[page];
134
+                refresh_button();
135
+
136
+                function next_page(){
137
+                    page = page+1;
138
+                    console.log('page next');
139
+                    console.log(urls[page]);
140
+                    document.getElementById('preview').src = urls[page];
141
+                    refresh_button();
142
+                }
143
+
144
+                function previous_page(){
145
+                    page = page-1;
146
+                    console.log('page previous');
147
+                    console.log(urls[page]);
148
+                    document.getElementById('preview').src = urls[page];
149
+                    refresh_button();
150
+                }
151
+
152
+                function refresh_button(){
153
+                    console.log(page);
154
+                    document.getElementById('prev').disabled = false;
155
+                    document.getElementById('next').disabled = false;
156
+                    document.getElementById('dl_one_pdf').href = "/previews/${result.file.id}/pages/" + page + "/download_pdf_one";
157
+                    document.getElementById('dl_full_pdf').href = "/previews/${result.file.id}/pages/" + page + "/download_pdf_full";
158
+                    document.getElementById('preview_link').href = "/previews/${result.file.id}/pages/" + page + "/high_quality";
159
+                    if(page >= nb_page-1){
160
+                        document.getElementById('next').disabled = true;
161
+                    }
162
+                    if(page <= 0){
163
+                        document.getElementById('prev').disabled = true;
164
+                    }
165
+                }
166
+            </script>
167
+        </div>
103 168
         <% download_url = tg.url('/workspaces/{}/folders/{}/files/{}/download?revision_id={}'.format(result.file.workspace.id, result.file.parent.id,result.file.id,result.file.selected_revision)) %>
104 169
         <div class="t-half-spacer-above download-file-button">
105 170
             <a style="" class="btn btn-default" tittle="${_('Download the file')}"