1# Copyright (c) 2012-2016 Seafile Ltd.
2import os
3import json
4import logging
5import posixpath
6import datetime
7
8from django.utils.translation import ugettext as _
9from django.utils.http import urlquote
10from django.http import HttpResponse
11from django.views.decorators.http import condition
12from django.shortcuts import render
13
14from seaserv import get_repo, get_file_id_by_path
15
16from seahub.auth.decorators import login_required_ajax, login_required
17from seahub.views import check_folder_permission
18from seahub.settings import THUMBNAIL_DEFAULT_SIZE, THUMBNAIL_EXTENSION, \
19    THUMBNAIL_ROOT, ENABLE_THUMBNAIL
20from seahub.thumbnail.utils import generate_thumbnail, \
21    get_thumbnail_src, get_share_link_thumbnail_src
22from seahub.share.models import FileShare, check_share_link_common
23
24# Get an instance of a logger
25logger = logging.getLogger(__name__)
26
27@login_required_ajax
28def thumbnail_create(request, repo_id):
29    """create thumbnail from repo file list
30
31    return thumbnail src
32    """
33
34    content_type = 'application/json; charset=utf-8'
35    result = {}
36
37    repo = get_repo(repo_id)
38    if not repo:
39        err_msg = _("Library does not exist.")
40        return HttpResponse(json.dumps({"error": err_msg}), status=400,
41                            content_type=content_type)
42
43    path = request.GET.get('path', None)
44    if not path:
45        err_msg = _("Invalid arguments.")
46        return HttpResponse(json.dumps({"error": err_msg}), status=400,
47                            content_type=content_type)
48
49    if repo.encrypted or not ENABLE_THUMBNAIL or \
50        check_folder_permission(request, repo_id, path) is None:
51        err_msg = _("Permission denied.")
52        return HttpResponse(json.dumps({"error": err_msg}), status=403,
53                            content_type=content_type)
54
55    size = request.GET.get('size', THUMBNAIL_DEFAULT_SIZE)
56    success, status_code = generate_thumbnail(request, repo_id, size, path)
57    if success:
58        src = get_thumbnail_src(repo_id, size, path)
59        result['encoded_thumbnail_src'] = urlquote(src)
60        return HttpResponse(json.dumps(result), content_type=content_type)
61    else:
62        err_msg = _('Failed to create thumbnail.')
63        return HttpResponse(json.dumps({'err_msg': err_msg}),
64                status=status_code, content_type=content_type)
65
66def latest_entry(request, repo_id, size, path):
67    obj_id = get_file_id_by_path(repo_id, path)
68    if obj_id:
69        try:
70            thumbnail_file = os.path.join(THUMBNAIL_ROOT, str(size), obj_id)
71            last_modified_time = os.path.getmtime(thumbnail_file)
72            # convert float to datatime obj
73            return datetime.datetime.fromtimestamp(last_modified_time)
74        except os.error:
75            # no thumbnail file exists
76            return None
77        except Exception as e:
78            # catch all other errors
79            logger.error(e, exc_info=True)
80            return None
81    else:
82        return None
83
84@login_required
85@condition(last_modified_func=latest_entry)
86def thumbnail_get(request, repo_id, size, path):
87    """ handle thumbnail src from repo file list
88
89    return thumbnail file to web
90    """
91
92    repo = get_repo(repo_id)
93    obj_id = get_file_id_by_path(repo_id, path)
94
95    # check if file exist
96    if not repo or not obj_id:
97        return HttpResponse()
98
99    # check if is allowed
100    if repo.encrypted or not ENABLE_THUMBNAIL or \
101        check_folder_permission(request, repo_id, path) is None:
102        return HttpResponse()
103
104    try:
105        size = int(size)
106    except ValueError as e:
107        logger.error(e)
108        return HttpResponse()
109
110    success = True
111    thumbnail_file = os.path.join(THUMBNAIL_ROOT, str(size), obj_id)
112    if not os.path.exists(thumbnail_file):
113        success, status_code = generate_thumbnail(request, repo_id, size, path)
114
115    if success:
116        try:
117            with open(thumbnail_file, 'rb') as f:
118                thumbnail = f.read()
119            return HttpResponse(content=thumbnail,
120                                content_type='image/' + THUMBNAIL_EXTENSION)
121        except IOError as e:
122            logger.error(e)
123            return HttpResponse(status=500)
124    else:
125        return HttpResponse(status=status_code)
126
127def get_real_path_by_fs_and_req_path(fileshare, req_path):
128    """ Return the real path of a file.
129
130    The file could be a file in a shared dir or a shared file.
131    """
132
133    if fileshare.s_type == 'd':
134        if fileshare.path == '/':
135            real_path = req_path
136        else:
137            real_path = posixpath.join(fileshare.path, req_path.lstrip('/'))
138    else:
139        real_path = fileshare.path
140
141    return real_path
142
143def share_link_thumbnail_create(request, token):
144    """generate thumbnail from dir download link page
145
146    return thumbnail src to web
147    """
148
149    content_type = 'application/json; charset=utf-8'
150    result = {}
151
152    fileshare = FileShare.objects.get_valid_file_link_by_token(token)
153    if not fileshare:
154        err_msg = _("Invalid token.")
155        return HttpResponse(json.dumps({"error": err_msg}), status=400,
156                            content_type=content_type)
157
158    repo_id = fileshare.repo_id
159    repo = get_repo(repo_id)
160    if not repo:
161        err_msg = _("Library does not exist.")
162        return HttpResponse(json.dumps({"error": err_msg}), status=400,
163                            content_type=content_type)
164
165    if repo.encrypted or not ENABLE_THUMBNAIL:
166        err_msg = _("Permission denied.")
167        return HttpResponse(json.dumps({"error": err_msg}), status=403,
168                            content_type=content_type)
169
170    req_path = request.GET.get('path', None)
171    if not req_path or '../' in req_path:
172        err_msg = _("Invalid arguments.")
173        return HttpResponse(json.dumps({"error": err_msg}), status=400,
174                            content_type=content_type)
175
176    real_path = get_real_path_by_fs_and_req_path(fileshare, req_path)
177
178    size = request.GET.get('size', THUMBNAIL_DEFAULT_SIZE)
179    success, status_code = generate_thumbnail(request, repo_id, size, real_path)
180    if success:
181        src = get_share_link_thumbnail_src(token, size, req_path)
182        result['encoded_thumbnail_src'] = urlquote(src)
183        return HttpResponse(json.dumps(result), content_type=content_type)
184    else:
185        err_msg = _('Failed to create thumbnail.')
186        return HttpResponse(json.dumps({'err_msg': err_msg}),
187                status=status_code, content_type=content_type)
188
189def share_link_latest_entry(request, token, size, path):
190    fileshare = FileShare.objects.get_valid_file_link_by_token(token)
191    if not fileshare:
192        return None
193
194    repo_id = fileshare.repo_id
195    repo = get_repo(repo_id)
196    if not repo:
197        return None
198
199    image_path = get_real_path_by_fs_and_req_path(fileshare, path)
200
201    obj_id = get_file_id_by_path(repo_id, image_path)
202    if obj_id:
203        try:
204            thumbnail_file = os.path.join(THUMBNAIL_ROOT, str(size), obj_id)
205            last_modified_time = os.path.getmtime(thumbnail_file)
206            # convert float to datatime obj
207            return datetime.datetime.fromtimestamp(last_modified_time)
208        except Exception as e:
209            logger.error(e)
210            # no thumbnail file exists
211            return None
212    else:
213        return None
214
215@condition(last_modified_func=share_link_latest_entry)
216def share_link_thumbnail_get(request, token, size, path):
217    """ handle thumbnail src from dir download link page
218
219    return thumbnail file to web
220    """
221
222    try:
223        size = int(size)
224    except ValueError as e:
225        logger.error(e)
226        return HttpResponse()
227
228    fileshare = FileShare.objects.get_valid_file_link_by_token(token)
229    if not fileshare:
230        return HttpResponse()
231
232    password_check_passed, err_msg = check_share_link_common(request, fileshare)
233    if not password_check_passed:
234        d = {'token': token, 'view_name': 'view_shared_dir', 'err_msg': err_msg}
235        return render(request, 'share_access_validation.html', d)
236
237    image_path = get_real_path_by_fs_and_req_path(fileshare, path)
238
239    repo_id = fileshare.repo_id
240    repo = get_repo(repo_id)
241    obj_id = get_file_id_by_path(repo_id, image_path)
242
243    # check if file exist
244    if not repo or not obj_id:
245        return HttpResponse()
246
247    # check if is allowed
248    if repo.encrypted or not ENABLE_THUMBNAIL:
249        return HttpResponse()
250
251    success = True
252    thumbnail_file = os.path.join(THUMBNAIL_ROOT, str(size), obj_id)
253    if not os.path.exists(thumbnail_file):
254        success, status_code = generate_thumbnail(request, repo_id, size, image_path)
255
256    if success:
257        try:
258            with open(thumbnail_file, 'rb') as f:
259                thumbnail = f.read()
260            return HttpResponse(content=thumbnail,
261                                content_type='image/' + THUMBNAIL_EXTENSION)
262        except IOError as e:
263            logger.error(e)
264            return HttpResponse()
265    else:
266        return HttpResponse()
267