Admin definitions for explorer application.
[redakcja.git] / apps / explorer / views.py
1 # -*- coding: utf-8 -*-
2 from librarian import html
3 import hg, urllib2, time
4
5 from django.utils import simplejson as json
6
7 from librarian import dcparser, parser
8 from librarian import ParseError, ValidationError
9
10 from django.views.generic.simple import direct_to_template
11
12 from django.conf import settings
13 from django.http import HttpResponseRedirect, HttpResponse
14
15 from django.core.urlresolvers import reverse
16 from django.core.paginator import Paginator, InvalidPage, EmptyPage
17
18 from django.contrib.auth.decorators import login_required, permission_required
19
20 from explorer import forms, models
21
22 #
23 # Some useful decorators
24 #
25 def with_repo(view):
26     """Open a repository for this view"""
27     def view_with_repo(request, *args, **kwargs):          
28         kwargs['repo'] = hg.Repository(settings.REPOSITORY_PATH)
29         return view(request, *args, **kwargs)
30     return view_with_repo
31
32 #
33 def ajax_login_required(view):
34     """Similar ro @login_required, but instead of redirect, 
35     just return some JSON stuff with error."""
36     def view_with_auth(request, *args, **kwargs):
37         if request.user.is_authenticated():
38             return view(request, *args, **kwargs)
39         # not authenticated
40         return HttpResponse( json.dumps({'result': 'access_denied'}) );
41     return view_with_auth
42
43 #
44 # View all files
45 #
46 @with_repo
47 def file_list(request, repo):
48     paginator = Paginator( repo.file_list('default'), 100);
49     bookform = forms.BookUploadForm()
50
51     try:
52         page = int(request.GET.get('page', '1'))
53     except ValueError:
54         page = 1
55
56     try:
57         files = paginator.page(page)
58     except (EmptyPage, InvalidPage):
59         files = paginator.page(paginator.num_pages)
60
61     return direct_to_template(request, 'explorer/file_list.html', extra_context={
62         'files': files, 'page': page, 'bookform': bookform,
63     })
64
65 @permission_required('explorer.can_add_files')
66 @with_repo
67 def file_upload(request, repo):
68     form = forms.BookUploadForm(request.POST, request.FILES)
69     if form.is_valid():
70         f = request.FILES['file']        
71
72         def upload_action():
73             print 'Adding file: %s' % f.name
74             repo._add_file(f.name, f.read().decode('utf-8'))
75             repo._commit(message="File %s uploaded from platform by %s" %
76                 (f.name, request.user.username), user=request.user.username)
77
78         repo.in_branch(upload_action, 'default')
79         return HttpResponseRedirect( reverse('editor_view', kwargs={'path': f.name}) )
80
81     return direct_to_template(request, 'explorer/file_upload.html',
82         extra_context = {'form' : form} )
83    
84 #
85 # Edit the file
86 #
87
88 @ajax_login_required
89 @with_repo
90 def file_xml(request, repo, path):
91     if request.method == 'POST':
92         errors = None
93         form = forms.BookForm(request.POST)
94         if form.is_valid():
95             print 'Saving whole text.', request.user.username
96             def save_action():
97                 print 'In branch: ' + repo.repo[None].branch()
98                 repo._add_file(path, form.cleaned_data['content'])                
99                 repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'),\
100                      user=request.user.username)
101             try:
102                 # wczytaj dokument z ciągu znaków -> weryfikacja
103                 document = parser.WLDocument.from_string(form.cleaned_data['content'])
104
105                 #  save to user's branch
106                 repo.in_branch(save_action, models.user_branch(request.user) );
107             except (ParseError, ValidationError), e:
108                 errors = [e.message]              
109
110         if not errors:
111             errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() )
112
113         return HttpResponse(json.dumps({'result': errors and 'error' or 'ok', 'errors': errors}));
114
115     form = forms.BookForm()
116     data = repo.get_file(path, models.user_branch(request.user))
117     form.fields['content'].initial = data
118     return HttpResponse( json.dumps({'result': 'ok', 'content': data}) ) 
119
120 @ajax_login_required
121 @with_repo
122 def file_dc(request, path, repo):
123     errors = None
124
125     if request.method == 'POST':
126         form = forms.DublinCoreForm(request.POST)
127         
128         if form.is_valid():
129             def save_action():
130                 file_contents = repo._get_file(path)
131
132                 # wczytaj dokument z repozytorium
133                 document = parser.WLDocument.from_string(file_contents)                    
134                 document.book_info.update(form.cleaned_data)
135                 
136                 print "SAVING DC"
137
138                 # zapisz
139                 repo._add_file(path, document.serialize())
140                 repo._commit( \
141                     message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), \
142                     user=request.user.username )
143                 
144             try:
145                 repo.in_branch(save_action, models.user_branch(request.user) )
146             except (ParseError, ValidationError), e:
147                 errors = [e.message]
148
149         if errors is None:
150             errors = ["Pole '%s': %s\n" % (field[0], field[1].as_text()) for field in form.errors.iteritems()]
151
152         return HttpResponse( json.dumps({'result': errors and 'error' or 'ok', 'errors': errors}) );
153     
154     # this is unused currently, but may come in handy 
155     content = []
156     
157     try:
158         fulltext = repo.get_file(path, models.user_branch(request.user))
159         bookinfo = dcparser.BookInfo.from_string(fulltext)
160         content = bookinfo.to_dict()
161     except (ParseError, ValidationError), e:
162         errors = [e.message]
163
164     return HttpResponse( json.dumps({'result': errors and 'error' or 'ok', 
165         'errors': errors, 'content': content }) ) 
166
167 # Display the main editor view
168
169 @login_required
170 def display_editor(request, path):
171     return direct_to_template(request, 'explorer/editor.html', extra_context={
172         'hash': path, 'panel_list': ['lewy', 'prawy'],
173     })
174
175 # ===============
176 # = Panel views =
177 # ===============
178
179 @ajax_login_required
180 @with_repo
181 def xmleditor_panel(request, path, repo):
182     form = forms.BookForm()
183     text = repo.get_file(path, models.user_branch(request.user))
184     
185     return direct_to_template(request, 'explorer/panels/xmleditor.html', extra_context={
186         'fpath': path,
187         'text': text,
188     })
189     
190
191 @ajax_login_required
192 def gallery_panel(request, path):
193     return direct_to_template(request, 'explorer/panels/gallery.html', extra_context={
194         'fpath': path,
195         'form': forms.ImageFoldersForm(),
196     })
197
198 @ajax_login_required
199 @with_repo
200 def htmleditor_panel(request, path, repo):
201     user_branch = models.user_branch(request.user)
202     try:
203         return direct_to_template(request, 'explorer/panels/htmleditor.html', extra_context={
204             'fpath': path,
205             'html': html.transform(repo.get_file(path, user_branch), is_file=False),
206         })
207     except (ParseError, ValidationError), e:
208         return direct_to_template(request, 'explorer/panels/parse_error.html', extra_context={
209             'fpath': path, 'exception_type': type(e).__name__, 'exception': e, 'panel_name': 'Edytor HTML'}) 
210
211 @ajax_login_required
212 @with_repo
213 def dceditor_panel(request, path, repo):
214     user_branch = models.user_branch(request.user)
215
216     try:
217         doc_text = repo.get_file(path, user_branch)
218
219         document = parser.WLDocument.from_string(doc_text)
220         form = forms.DublinCoreForm(info=document.book_info)       
221
222         return direct_to_template(request, 'explorer/panels/dceditor.html', extra_context={
223             'fpath': path,
224             'form': form,
225         })
226     except (ParseError, ValidationError), e:
227         return direct_to_template(request, 'explorer/panels/parse_error.html', extra_context={
228             'fpath': path, 'exception_type': type(e).__name__, 'exception': e, 
229             'panel_name': 'Edytor DublinCore'}) 
230
231 # =================
232 # = Utility views =
233 # =================
234 @ajax_login_required
235 def folder_images(request, folder):
236     return direct_to_template(request, 'explorer/folder_images.html', extra_context={
237         'images': models.get_images_from_folder(folder),
238     })
239
240
241 def _add_references(message, issues):
242     return message + " - " + ", ".join(map(lambda issue: "Refs #%d" % issue['id'], issues))
243
244 def _get_issues_for_file(path):
245     if not path.endswith('.xml'):
246         raise ValueError('Path must end with .xml')
247
248     book_id = path[:-4]
249     uf = None
250
251     try:
252         uf = urllib2.urlopen(settings.REDMINE_URL + 'publications/issues/%s.json' % book_id)
253         return json.loads(uf.read())
254     except urllib2.HTTPError:
255         return []
256     finally:
257         if uf: uf.close()
258
259
260 # =================
261 # = Pull requests =
262 # =================
263 def pull_requests(request):
264     return direct_to_template(request, 'manager/pull_request.html', extra_context = {
265         'objects': models.PullRequest.objects.all()} )