source: dashwiki/wiki/views.py @ 8ff2dfa8dc699a6ba32373ebadf187b808e68bdf

Revision 8ff2dfa8dc699a6ba32373ebadf187b808e68bdf, 11.9 KB checked in by Stanislaw Klekot <dozzie@…>, 3 years ago (diff)

Added informing proxies not to cache wiki display.

  • Property mode set to 100644
Line 
1#-----------------------------------------------------------------------------
2# preamble {{{
3#-----------------------------------------------------------------------------
4# imports {{{
5
6from django.http import HttpResponse
7from django.template import RequestContext, loader
8from models import WikiPage, WikiHistoryPage
9from django.contrib.auth.decorators import login_required
10from django.contrib import messages
11
12from dashwiki.decorators import on_cancel, on_button_call
13from dashwiki.logging import getLogger, message as log
14
15# }}}
16#-----------------------------------------------------------------------------
17# tooling {{{
18
19logger = getLogger(__name__)
20
21def load_wiki_or_null(page_name):
22  from django.core.exceptions import ObjectDoesNotExist
23
24  try:
25    page = WikiPage.objects.get(name = page_name)
26  except ObjectDoesNotExist, e:
27    page = None
28    if '/' in page_name:
29      parametrized_name = page_name[0:page_name.rfind('/') + 1]
30      # XXX: hack(?) for loading parametrized wiki pages
31      try:
32        page = WikiPage.objects.get(name = parametrized_name)
33      except ObjectDoesNotExist, e:
34        pass
35
36  return page
37
38def create_cache():
39  from django.conf import settings
40  from django.core.urlresolvers import reverse
41  from dashwiki.resource_cache import ResourceCache
42  return ResourceCache(
43    settings.DASHWIKI_CACHE_ROOT,
44    reverse('cached_files'),
45  )
46
47# request and page_name are for context only (for logging)
48# TODO: limit how much time this function spends in calling remote systems
49# (timeout)
50def call_all_macros(tree, request, page_name, page_param = None):
51  from dashwiki.macros.models import Macro
52  from django.core.exceptions import ObjectDoesNotExist
53  from dashwiki.markup.ast import resolve_macros
54  import traceback # for traceback.format_exc()
55
56  def defer_return(result):
57    def func(*other_args):
58      return result
59    return func
60
61  from dashwiki.markup.nodes import node, error, tt
62
63  cache = create_cache()
64
65  def load_macro(macro_name): # {{{
66    try:
67      macro = Macro.objects.get(name = macro_name)
68    except ObjectDoesNotExist, e:
69      e_type    = e.__class__.__name__
70      e_module  = e.__class__.__module__
71      e_message = str(e)
72      e_trace   = traceback.format_exc()
73      logger.warn(log(
74        'macro does not exist',
75        ('macro_name', macro_name),
76        ('page_name',  page_name),
77        exception = {
78          'type': '%s.%s' % (e_module, e_type),
79          'message': e_message,
80        },
81      ))
82      return defer_return(
83        error(['macro ', tt(['[[@', macro_name, ']]']), ' does not exist'])
84      )
85
86    def call_macro(*macro_args):
87      try:
88        return macro.call(macro_args, cache)
89      except Exception, e:
90        e_type    = e.__class__.__name__
91        e_module  = e.__class__.__module__
92        e_message = str(e)
93        e_trace   = traceback.format_exc()
94        logger.warn(log(
95          'error when calling macro',
96          ('macro_name', macro_name),
97          ('macro_args', macro_args),
98          ('page_name',  page_name),
99          exception = {
100            'type': '%s.%s' % (e_module, e_type),
101            'message': e_message,
102            'traceback': e_trace,
103          },
104        ))
105        return error([
106          'error when calling ', tt(['[[@', macro_name, ']]']), ': ', str(e)
107        ])
108
109    return call_macro
110  # }}}
111
112  try:
113    macro_calls = {}
114    predefined_macros = {
115      'page_name':  page_name, # XXX: this includes possible page parameter
116      'page_param': page_param,
117    }
118    result = resolve_macros(tree, load_macro, macro_calls, predefined_macros)
119    if len(macro_calls) > 0:
120      cache.store('macros.json', macro_calls)
121      cache.store('syntax_tree.json', result)
122    return result
123  except Exception, e:
124    e_type    = e.__class__.__name__
125    e_module  = e.__class__.__module__
126    e_message = str(e)
127    e_trace   = traceback.format_exc()
128    logger.warn(log(
129      'error when resolving macros',
130      ('page_name',  page_name),
131      exception = {
132        'type': '%s.%s' % (e_module, e_type),
133        'message': e_message,
134        'traceback': e_trace,
135      },
136    ))
137    return node(document = node(text_paragraph = error([
138      'Error when resolving macros on this page: ', str(e)
139    ])))
140
141# }}}
142#-----------------------------------------------------------------------------
143# }}}
144#-----------------------------------------------------------------------------
145# wiki pages {{{
146#-----------------------------------------------------------------------------
147# edit_wiki() {{{
148
149@login_required
150def edit_wiki(request, page_name):
151  template = loader.get_template('edit_wiki.html')
152
153  from forms import WikiPageEdit
154  import django.shortcuts
155
156  rev = None
157  if 'rev' in request.GET:
158    from django.core.exceptions import ObjectDoesNotExist
159
160    try:
161      rev = int(request.GET['rev'])
162      page = WikiHistoryPage.objects.get(name = page_name, revision = rev)
163    except ValueError, e:
164      messages.error(request,
165        'Invalid revision "%s"' % (request.GET['rev'])
166      )
167      return django.shortcuts.redirect(request.path)
168    except ObjectDoesNotExist, e:
169      rev = None
170      messages.error(request,
171        'Revision %s does not exist' % (request.GET['rev'])
172      )
173      return django.shortcuts.redirect(request.path)
174  else:
175    page = load_wiki_or_null(page_name)
176
177  save_no_change = False
178  if page != None:
179    page_instance = { 'instance': page }
180  else:
181    page_instance = { 'initial': { 'name': page_name } }
182
183  if 'save' in request.POST:
184    page_form = WikiPageEdit(request.POST, **page_instance)
185  else:
186    page_form = WikiPageEdit(**page_instance)
187
188  # page unchanged
189  if page != None and page.content == page_form.data.get('content'):
190    messages.info(request, 'Wiki page unchanged')
191    return django.shortcuts.redirect(request.path)
192
193  if page_form.is_valid(): # try saving it {{{
194    from dashwiki.markup import ParseError
195    try:
196      page_form.save()
197      new_rev = page_form.instance.make_revision(request.user)
198      new_rev.save()
199      logger.info(log(
200        'wiki page saved',
201        page = page_form.instance.name,
202        revision = new_rev.revision,
203        author = request.user.username
204      ))
205      messages.success(request, 'Wiki page saved')
206      return django.shortcuts.redirect(request.path)
207    except ParseError, e:
208      for err in e.errors:
209        messages.error(request,
210          "Syntax error at '%s' (%s), line %d, char %d.\n"
211          "Expected one of these tokens: %s" % (
212            err['text'], err['token'], err['line'], err['char'],
213            ", ".join([str(e) for e in err['expected']])
214          )
215        )
216  # }}}}
217
218  context = RequestContext(request, {
219    'name': page_name,
220    'real_name': page_name,
221    'revision': rev,
222    'form': page_form,
223    'body_raw':  None,
224    'body_tree': None,
225    'form_target': "%s?edit=%s" % (request.path, request.GET.get('edit', "")),
226  })
227  if page != None:
228    context['body_raw']  = page.content
229    context['body_tree'] = page.get_ast()
230
231  return HttpResponse(template.render(context))
232
233# }}}
234#-----------------------------------------------------------------------------
235# remove_wiki() {{{
236
237@login_required
238def remove_wiki(request, page_name):
239  template = loader.get_template('remove_wiki.html')
240  page = load_wiki_or_null(page_name)
241  if 'confirm' in request.POST and page != None:
242    new_rev = page.make_revision(request.user, is_delete = True)
243    new_rev.save()
244    page.delete()
245    page = None
246    logger.info(log(
247      'wiki page deleted',
248      page = page_name,
249      revision = new_rev.revision,
250      author = request.user.username
251    ))
252  context = RequestContext(request, {
253    'name': page_name,
254    'real_name': page_name,
255    'form_target': "%s?remove=%s" % (request.path, request.GET.get('remove', "")),
256    'confirmed': ('confirm' in request.POST),
257  })
258
259  return HttpResponse(template.render(context))
260
261# }}}
262#-----------------------------------------------------------------------------
263# display_wiki() {{{
264
265@on_cancel
266@on_button_call(button = 'edit',   target = edit_wiki)
267@on_button_call(button = 'remove', target = remove_wiki)
268def display_wiki(request, page_name):
269  template = loader.get_template('display_wiki.html')
270
271  page = None
272  rev = None
273  real_name = page_name
274
275  if 'rev' in request.GET:
276    from django.core.exceptions import ObjectDoesNotExist
277
278    try:
279      rev = int(request.GET['rev'])
280      page = WikiHistoryPage.objects.get(name = page_name, revision = rev)
281      real_name = page.name
282    except ValueError, e:
283      messages.error(request,
284        'Invalid revision "%s"' % (request.GET['rev'])
285      )
286    except ObjectDoesNotExist, e:
287      rev = None
288      messages.error(request,
289        'Revision %s does not exist' % (request.GET['rev'])
290      )
291  else:
292    page = load_wiki_or_null(page_name)
293    if page:
294      real_name = page.name
295
296  context = RequestContext(request, {
297    'name': page_name,
298    'real_name': real_name,
299    'body_raw':  None,
300    'body_tree': None,
301    'editable': request.user.is_authenticated(),
302    'revision': rev,
303  })
304  if page != None:
305    context['body_raw']  = page.content
306    context['body_tree'] = call_all_macros(
307      page.get_ast(), request, page_name, page_name[len(real_name):]
308    )
309
310  import email.utils, time
311  response = HttpResponse(template.render(context))
312  # inform proxy not to cache this page
313  response['Expires'] = email.utils.formatdate(0, usegmt = True)
314  response['Last-Modified'] = email.utils.formatdate(usegmt = True)
315  response['Cache-Control'] = 'max-age=0, no-cache, must-revalidate, proxy-revalidate'
316  return response
317
318# }}}
319#-----------------------------------------------------------------------------
320# create_wiki() {{{
321
322@login_required
323@on_cancel(target = (display_wiki, ['WikiStart']))
324def create_wiki(request):
325  template = loader.get_template('create_wiki.html')
326
327  from forms import WikiPageCreate
328
329  if request.method == 'POST':
330    create_form = WikiPageCreate(request.POST)
331    proposed_name = create_form.data['name']
332
333    if create_form.is_valid():
334      if WikiPage.objects.filter(name = proposed_name).exists():
335        context = RequestContext(request, {
336          'form': create_form,
337          'error': 'page %s already exists' % (proposed_name),
338          'page_name': proposed_name,
339        })
340        return HttpResponse(template.render(context))
341
342      messages.success(request, 'Page %s created' % proposed_name)
343      context = RequestContext(request, {
344        'form': create_form,
345        'page_name': proposed_name,
346        'created': True,
347      })
348      return HttpResponse(template.render(context))
349    else:
350      for err in create_form.errors['name']:
351        messages.error(request, err)
352      context = RequestContext(request, {
353        'form': create_form,
354        'page_name': proposed_name,
355      })
356      return HttpResponse(template.render(context))
357
358  context = RequestContext(request, {
359    'form': WikiPageCreate(),
360  })
361  return HttpResponse(template.render(context))
362
363# }}}
364#-----------------------------------------------------------------------------
365# }}}
366#-----------------------------------------------------------------------------
367# navigation {{{
368#-----------------------------------------------------------------------------
369# list_history() {{{
370
371def list_history(request):
372  template = loader.get_template('list_history.html')
373  histpages = WikiHistoryPage.objects.all().order_by('-creation_time')
374  context = RequestContext(request, {
375    'pages': histpages,
376  })
377  return HttpResponse(template.render(context))
378
379# }}}
380#-----------------------------------------------------------------------------
381# list_pages() {{{
382
383def list_pages(request):
384  template = loader.get_template('list_pages.html')
385
386  pages = [page.name for page in WikiPage.objects.all()]
387  pages.sort()
388
389  context = RequestContext(request, {
390    'pages': pages,
391    'editable': request.user.is_authenticated(),
392  })
393  return HttpResponse(template.render(context))
394
395# }}}
396#-----------------------------------------------------------------------------
397# }}}
398#-----------------------------------------------------------------------------
399# vim:ft=python:foldmethod=marker
Note: See TracBrowser for help on using the repository browser.