Wyświetlanie informacji o błędach w XML i DC. Closes #9.
[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     if request.method == 'POST':
124         form = forms.DublinCoreForm(request.POST)
125         errors = None
126         
127         if form.is_valid():
128             def save_action():
129                 file_contents = repo._get_file(path)
130
131                 # wczytaj dokument z repozytorium
132                 document = parser.WLDocument.from_string(file_contents)                    
133                 document.book_info.update(form.cleaned_data)
134                 
135                 print "SAVING DC"
136
137                 # zapisz
138                 repo._add_file(path, document.serialize())
139                 repo._commit( \
140                     message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), \
141                     user=request.user.username )
142                 
143             try:
144                 repo.in_branch(save_action, models.user_branch(request.user) )
145             except (ParseError, ValidationError), e:
146                 errors = [e.message]
147
148         if errors is None:
149             errors = ["Pole '%s': %s\n" % (field[0], field[1].as_text()) for field in form.errors.iteritems()]
150
151         return HttpResponse( json.dumps({'result': errors and 'error' or 'ok', 'errors': errors}) );
152     
153     fulltext = repo.get_file(path, models.user_branch(request.user))
154     form = forms.DublinCoreForm(text=fulltext)       
155     return HttpResponse( json.dumps({'result': 'ok', 'content': fulltext}) ) 
156
157 # Display the main editor view
158
159 @login_required
160 def display_editor(request, path):
161     return direct_to_template(request, 'explorer/editor.html', extra_context={
162         'hash': path, 'panel_list': ['lewy', 'prawy'],
163     })
164
165 # ===============
166 # = Panel views =
167 # ===============
168
169 @ajax_login_required
170 @with_repo
171 def xmleditor_panel(request, path, repo):
172     form = forms.BookForm()
173     text = repo.get_file(path, models.user_branch(request.user))
174     
175     return direct_to_template(request, 'explorer/panels/xmleditor.html', extra_context={
176         'fpath': path,
177         'text': text,
178     })
179     
180
181 @ajax_login_required
182 def gallery_panel(request, path):
183     return direct_to_template(request, 'explorer/panels/gallery.html', extra_context={
184         'fpath': path,
185         'form': forms.ImageFoldersForm(),
186     })
187
188 @ajax_login_required
189 @with_repo
190 def htmleditor_panel(request, path, repo):
191     user_branch = models.user_branch(request.user)
192     return direct_to_template(request, 'explorer/panels/htmleditor.html', extra_context={
193         'fpath': path,
194         'html': html.transform(repo.get_file(path, user_branch), is_file=False),
195     })
196  
197
198 @ajax_login_required
199 @with_repo
200 def dceditor_panel(request, path, repo):
201     user_branch = models.user_branch(request.user)
202     doc_text = repo.get_file(path, user_branch)
203
204     document = parser.WLDocument.from_string(doc_text)
205     form = forms.DublinCoreForm(info=document.book_info)       
206
207     return direct_to_template(request, 'explorer/panels/dceditor.html', extra_context={
208         'fpath': path,
209         'form': form,
210     })
211
212
213 # =================
214 # = Utility views =
215 # =================
216 @ajax_login_required
217 def folder_images(request, folder):
218     return direct_to_template(request, 'explorer/folder_images.html', extra_context={
219         'images': models.get_images_from_folder(folder),
220     })
221
222
223 def _add_references(message, issues):
224     return message + " - " + ", ".join(map(lambda issue: "Refs #%d" % issue['id'], issues))
225
226 def _get_issues_for_file(path):
227     if not path.endswith('.xml'):
228         raise ValueError('Path must end with .xml')
229
230     book_id = path[:-4]
231     uf = None
232
233     try:
234         uf = urllib2.urlopen(settings.REDMINE_URL + 'publications/issues/%s.json' % book_id)
235         return json.loads(uf.read())
236     except urllib2.HTTPError:
237         return []
238     finally:
239         if uf: uf.close()
240
241
242 # =================
243 # = Pull requests =
244 # =================
245 def pull_requests(request):
246     return direct_to_template(request, 'manager/pull_request.html', extra_context = {
247         'objects': models.PullRequest.objects.all()} )