e76da7474606fe44265b4d052df5947085022e9b
[audio.git] / apps / archive / views.py
1 # Create your views here.
2
3 from datetime import datetime
4 import os
5 import os.path
6 from urllib import quote
7
8 from archive import settings
9 from django.contrib.auth import logout
10 from django.contrib.auth.decorators import login_required, permission_required
11 from django.core.urlresolvers import reverse
12 from django.db.models import Q, Max
13 from django.http import Http404, HttpResponse
14 from django.shortcuts import render, redirect, get_object_or_404
15 from django.views.decorators.http import require_POST
16
17 import mutagen
18
19 from archive.constants import status
20 from archive import models
21 from archive.forms import AudiobookForm
22 from archive import tasks
23 from archive.utils import all_files
24
25
26 @login_required
27 def list_new(request):
28     division = 'new'
29
30     path = settings.NEW_PATH
31     objects = sorted(all_files(path))
32     return render(request, "archive/list_new.html", locals())
33
34
35 @permission_required('archive.change_audiobook')
36 def file_new(request, filename):
37     division = 'new'
38
39     filepath = filename.encode('utf-8')
40     root_filepath = os.path.join(settings.NEW_PATH, filename.encode('utf-8'))
41     if request.POST:
42         form = AudiobookForm(request.POST)
43         if form.is_valid():
44             try:
45                 form.save(path=filepath)
46             except IOError:
47                 raise Http404
48             return redirect(list_new)
49
50     try:
51         tags = mutagen.File(root_filepath)
52     except IOError:
53         raise Http404
54     d = {}
55     if tags:
56         for tag in tags:
57             value = tags[tag]
58             if isinstance(value, list):
59                 d[tag] = value[0]
60             else:
61                 d[tag] = value
62             if tag == 'project':
63                 try:
64                     d[tag] = models.Project.objects.get(name=d[tag]).pk
65                 except models.Project.DoesNotExist:
66                     d[tag] = None
67
68     if not request.POST:
69         form = AudiobookForm(d)
70     return render(request, "archive/file_new.html", locals())
71
72
73 @require_POST
74 @permission_required('archive.change_audiobook')
75 def move_to_archive(request, filename):
76     """ move a new file to the unmanaged files dir """
77
78     filename_str = filename.encode('utf-8')
79     old_path = os.path.join(settings.NEW_PATH, filename_str)
80     new_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
81     new_dir = os.path.split(new_path)[0]
82     if not os.path.isdir(new_dir):
83         os.makedirs(new_dir)
84
85     if not os.path.isfile(old_path):
86         raise Http404
87
88     try:
89         os.link(old_path, new_path)
90         os.unlink(old_path)
91     except OSError:
92         # destination file exists, don't overwrite it
93         # TODO: this should probably be more informative
94         return redirect(file_new, filename)
95
96     return redirect(list_new)
97
98
99 @require_POST
100 @permission_required('archive.change_audiobook')
101 def remove_to_archive(request, aid):
102     """ move a managed file to the unmanaged files dir """
103
104     audiobook = get_object_or_404(models.Audiobook, id=aid)
105     old_path = audiobook.source_file.path
106     new_path = os.path.join(settings.UNMANAGED_PATH,
107         str(audiobook.source_file)[len(settings.FILES_SAVE_PATH):].lstrip('/'))
108     new_dir = os.path.split(new_path)[0]
109     if not os.path.isdir(new_dir):
110         os.makedirs(new_dir)
111
112     if not os.path.isfile(old_path):
113         raise Http404
114
115     try:
116         os.link(old_path, new_path)
117     except OSError:
118         # destination file exists, don't overwrite it
119         # TODO: this should probably be more informative
120         return redirect(file_new, filename)
121     else:
122         os.unlink(old_path)
123         audiobook.delete()
124
125     return redirect(list_unmanaged)
126
127 @require_POST
128 @permission_required('archive.change_audiobook')
129 def move_to_new(request, filename):
130     """ move a unmanaged file to new files dir """
131
132     filename_str = filename.encode('utf-8')
133     old_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
134     new_path = os.path.join(settings.NEW_PATH, filename_str)
135     new_dir = os.path.split(new_path)[0]
136     if not os.path.isdir(new_dir):
137         os.makedirs(new_dir)
138
139     if not os.path.isfile(old_path):
140         raise Http404
141
142     try:
143         os.link(old_path, new_path)
144         os.unlink(old_path)
145     except OSError:
146         # destination file exists, don't overwrite it
147         # TODO: this should probably be more informative
148         return redirect(reverse(file_unmanaged, args=[filename]) + "?exists=1")
149
150     return redirect(list_unmanaged)
151
152
153 @require_POST
154 @permission_required('archive.change_audiobook')
155 def publish(request, aid, publish=True):
156     """ mark file for publishing """
157     audiobook = get_object_or_404(models.Audiobook, id=aid)
158     tags = {
159         'name': audiobook.title,
160         'url': audiobook.url,
161         'tags': audiobook.new_publish_tags(),
162         }
163     audiobook.mp3_tags = tags
164     audiobook.ogg_tags = tags
165     audiobook.mp3_status = audiobook.ogg_status = status.WAITING
166     audiobook.save()
167     # isn't there a race here?
168     audiobook.mp3_task = tasks.Mp3Task.delay(aid, publish).task_id
169     audiobook.ogg_task = tasks.OggTask.delay(aid, publish).task_id
170     audiobook.save()
171
172     return redirect(file_managed, aid)
173
174
175 @require_POST
176 @permission_required('archive.change_audiobook')
177 def cancel_publishing(request, aid):
178     """ cancel scheduled publishing """
179     audiobook = get_object_or_404(models.Audiobook, id=aid)
180     # TODO: cancel tasks
181     audiobook.mp3_status = None
182     audiobook.ogg_status = None
183     audiobook.save()
184     return redirect(file_managed, aid)
185
186
187 def download(request, aid, which="source"):
188     if which not in ("source", "mp3", "ogg"):
189         raise Http404
190     audiobook = get_object_or_404(models.Audiobook, id=aid)
191     file_ = getattr(audiobook, "%s_file" % which)
192     if not file_:
193         raise Http404
194     ext = file_.path.rsplit('.', 1)[-1]
195     response = HttpResponse(mimetype='application/force-download')
196     
197     response['Content-Disposition'] = "attachment; filename*=UTF-8''%s.%s" % (
198         quote(audiobook.title.encode('utf-8'), safe=''), ext)
199     response['X-Sendfile'] = file_.path.encode('utf-8')
200     return response
201
202
203 @login_required
204 def list_unpublished(request):
205     division = 'unpublished'
206
207     objects = models.Audiobook.objects.filter(Q(mp3_published=None) | Q(ogg_published=None))
208     return render(request, "archive/list_unpublished.html", locals())
209
210
211 @login_required
212 def list_publishing(request):
213     division = 'publishing'
214
215     objects = models.Audiobook.objects.exclude(mp3_status=None, ogg_status=None)
216     objects_by_status = {}
217     for o in objects:
218         if o.mp3_status:
219             k = o.mp3_status, o.get_mp3_status_display()
220             objects_by_status.setdefault(k, []).append(o)
221         if o.ogg_status and o.ogg_status != o.mp3_status:
222             k = o.ogg_status, o.get_ogg_status_display()
223             objects_by_status.setdefault(k, []).append(o)
224     status_objects = sorted(objects_by_status.items(), reverse=True)
225
226     return render(request, "archive/list_publishing.html", locals())
227
228
229 @login_required
230 def list_published(request):
231     division = 'published'
232
233     objects = models.Audiobook.objects.exclude(Q(mp3_published=None) | Q(ogg_published=None))
234     return render(request, "archive/list_published.html", locals())
235
236
237 @permission_required('archive.change_audiobook')
238 def file_managed(request, id):
239     audiobook = get_object_or_404(models.Audiobook, id=id)
240
241     if request.POST:
242         form = AudiobookForm(request.POST, instance=audiobook)
243         if form.is_valid():
244             try:
245                 form.save()
246             except IOError:
247                 raise Http404
248
249     division = 'published' if audiobook.published() else 'unpublished'
250     path = audiobook.source_file.path[len(settings.FILES_PATH):].lstrip('/')
251
252     # for tags update
253     tags = mutagen.File(audiobook.source_file.path)
254     if not tags:
255         tags = {}
256     form = AudiobookForm(instance=audiobook)
257
258     return render(request, "archive/file_managed.html", locals())
259
260
261 @login_required
262 def list_unmanaged(request):
263     division = 'unmanaged'
264
265     objects = sorted(all_files(settings.UNMANAGED_PATH))
266     return render(request, "archive/list_unmanaged.html", locals())
267
268
269 @login_required
270 def file_unmanaged(request, filename):
271     division = 'unmanaged'
272
273     tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename.encode('utf-8')))
274     if not tags:
275         tags = {}
276     
277     err_exists = request.GET.get('exists')
278     return render(request, "archive/file_unmanaged.html", locals())