5d23947c25235bf9c6451724ceea68380aa36c0a
[qcg-portal.git] / filex / views.py
1 import mimetypes
2
3 from django.contrib.auth.decorators import login_required
4 from django.core.exceptions import PermissionDenied, SuspiciousOperation
5 from django.http import JsonResponse, StreamingHttpResponse
6 from django.shortcuts import get_object_or_404
7 from django.template.defaultfilters import filesizeformat
8 from django.utils.formats import date_format
9 from django.views.decorators.http import require_POST
10
11 from filex.forms import NewDirForm, RenameForm, FavoriteForm
12 from filex.ftp import FTPOperation, FTPException
13 from filex.models import Favorite
14 from filex.uploadhandler import with_ftp_upload_handler
15
16
17 def check_auth(request):
18     if not request.user.is_authenticated():
19         raise PermissionDenied("Login required!")
20     if not request.session['proxy']:
21         raise PermissionDenied("No proxy found!")
22
23
24 def list_content(request):
25     check_auth(request)
26
27     # TODO data validation
28     host = request.GET.get('host')
29     path = request.GET.get('path')
30     if not host or not path:
31         raise SuspiciousOperation("No path or host given!")
32
33     url = 'gsiftp://' + host + path
34
35     try:
36         listing = FTPOperation(request.session['proxy']).listing(url)
37     except FTPException as e:
38         return JsonResponse({'msg': e.message}, status=400)
39
40     data = []
41     for item in listing:
42         item['size'] = filesizeformat(item['size'])
43         item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
44
45         data.append(item)
46
47     return JsonResponse(data, safe=False)
48
49
50 def download(request):
51     check_auth(request)
52
53     # TODO data validation
54     host = request.GET.get('host')
55     path = request.GET.get('path')
56     name = request.GET.get('name')
57     if not host or not path or not name:
58         raise SuspiciousOperation("No path or host or name given!")
59
60     url = 'gsiftp://' + host + path + '/' + name
61
62     mime_type, encoding = mimetypes.guess_type(name)
63
64     response = StreamingHttpResponse(FTPOperation(request.session['proxy']).get(url),
65                                      content_type=mime_type or 'application/octet-stream')
66     response['Content-Disposition'] = 'attachment; filename={}'.format(name)
67     # TODO Content-Length (?)
68
69     if encoding:
70         response['Content-Encoding'] = encoding
71
72     return response
73
74
75 @with_ftp_upload_handler
76 def upload(request):
77     # TODO error handling
78     return JsonResponse({'success': True})
79
80
81 def info(request):
82     check_auth(request)
83
84     # TODO data validation
85     host = request.GET.get('host')
86     path = request.GET.get('path')
87     if not host or not path:
88         raise SuspiciousOperation("No path or host given!")
89
90     url = 'gsiftp://' + host + path
91
92     try:
93         return JsonResponse(FTPOperation(request.session['proxy']).info(url))
94     except FTPException as e:
95         status = 400
96         if 'No such file or directory' in e.message:
97             status = 404
98         elif 'Permission denied' in e.message:
99             status = 403
100
101         return JsonResponse({'msg': e.message}, status=status)
102
103
104 @require_POST
105 def delete(request):
106     check_auth(request)
107
108     # TODO data validation
109     host = request.POST.get('host')
110     path = request.POST.get('path')
111     dirs = request.POST.getlist('dirs')
112     files = request.POST.getlist('files')
113     if not host or not path or not (files or dirs):
114         raise SuspiciousOperation("No path or host or files given!")
115
116     url = 'gsiftp://' + host + path + '/'
117     ftp = FTPOperation(request.session['proxy'])
118
119     done, fail = [], {}
120
121     for name in dirs:
122         try:
123             ftp.rmdir(url + name)
124         except FTPException as e:
125             fail[name] = e.message
126         else:
127             done.append(name)
128
129     for name in files:
130         try:
131             ftp.delete(url + name)
132         except FTPException as e:
133             fail[name] = e.message
134         else:
135             done.append(name)
136
137     return JsonResponse({'done': done, 'fail': fail})
138
139
140 @require_POST
141 def mkdir(request):
142     check_auth(request)
143
144     # TODO actual data validation
145     form = NewDirForm(request.POST)
146
147     if form.is_valid():
148         host = form.cleaned_data['host']
149         path = form.cleaned_data['path']
150         name = form.cleaned_data['name']
151
152         url = 'gsiftp://' + host + path + '/' + name
153
154         try:
155             FTPOperation(request.session['proxy']).mkdir(url)
156         except FTPException as e:
157             msg = e.message
158         else:
159             return JsonResponse({'success': True})
160     else:
161         msg = form.errors
162
163     return JsonResponse({'msg': msg}, status=400)
164
165
166 @require_POST
167 def move(request):
168     check_auth(request)
169
170     # TODO actual data validation
171     form = RenameForm(request.POST)
172
173     if form.is_valid():
174         host = form.cleaned_data['host']
175         path = form.cleaned_data['path']
176         src = form.cleaned_data['src']
177         dst = form.cleaned_data['dst']
178
179         src_url = 'gsiftp://' + host + path + '/' + src
180         dst_url = 'gsiftp://' + host + path + '/' + dst
181
182         try:
183             FTPOperation(request.session['proxy']).move(src_url, dst_url)
184         except FTPException as e:
185             msg = e.message
186         else:
187             return JsonResponse({'success': True})
188     else:
189         msg = form.errors
190
191     return JsonResponse({'msg': msg}, status=400)
192
193
194 @require_POST
195 def compress(request):
196     check_auth(request)
197
198     # TODO data validation
199     host = request.POST.get('host')
200     path = request.POST.get('path')
201     files = request.POST.getlist('files')
202     archive = request.POST.get('archive')
203     if not host or not path or not files or not archive:
204         raise SuspiciousOperation("No path or host or files or archive given!")
205
206     server = 'gsiftp://' + host
207
208     try:
209         # consume generator with command output
210         list(FTPOperation(request.session['proxy']).compress(server, path, files, archive))
211     except FTPException as e:
212         return JsonResponse({'msg': e.message}, status=400)
213     else:
214         return JsonResponse({'success': True})
215
216
217 @require_POST
218 def extract(request):
219     check_auth(request)
220
221     # TODO data validation
222     host = request.POST.get('host')
223     archive = request.POST.get('archive')
224     dst = request.POST.get('dst')
225     if not host or not archive or not dst:
226         raise SuspiciousOperation("No path or host or files or archive given!")
227
228     server = 'gsiftp://' + host
229
230     try:
231         # consume generator with command output
232         list(FTPOperation(request.session['proxy']).extract(server, archive, dst))
233     except FTPException as e:
234         return JsonResponse({'msg': e.message}, status=400)
235     else:
236         return JsonResponse({'success': True})
237
238
239 @require_POST
240 @login_required
241 def fav_add(request):
242     data = request.POST.copy()
243     data['owner'] = request.user.id
244
245     form = FavoriteForm(data)
246
247     # TODO check if path exists
248     if form.is_valid():
249         instance = form.save()
250
251         return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
252                              'value': instance.host + instance.path})
253
254     return JsonResponse({'msg': form.errors}, status=400)
255
256
257 @require_POST
258 @login_required
259 def fav_delete(request):
260     fav = get_object_or_404(Favorite, owner=request.user, host=request.POST['host'], path=request.POST['path'])
261     fav.delete()
262
263     return JsonResponse({'success': True})