root/trunk/pylucid_project/PyLucid/index.py

Revision 1760, 11.2 kB (checked in by JensDiemer, 2 months ago)

bugfix Template Errors.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Rev LastChangedDate
Line 
1# -*- coding: utf-8 -*-
2"""
3    PyLucid.index
4    ~~~~~~~~~~~~~
5
6    Contains all view function, except the _install views.
7
8    - index(): Display a PyLucid CMS Page
9    - handle_command(): Answer a _command Request
10    - permalink(): redirect to the real page url
11    - redirect(): simple redirect old PyLucid URLs to the new location.
12
13    Last commit info:
14    ~~~~~~~~~~~~~~~~~
15    $LastChangedDate: $
16    $Rev: $
17    $Author: $
18
19    :copyleft: 2007-2008 by the PyLucid team, see AUTHORS for more details.
20    :license: GNU GPL v3 or above, see LICENSE for more details.
21"""
22
23from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect, \
24                                                           HttpResponseRedirect
25from django.conf import settings
26from django.template import RequestContext, TemplateSyntaxError
27from django.utils.safestring import mark_safe
28from django.utils.translation import ugettext as _
29
30from PyLucid.models import Page
31from PyLucid.system import plugin_manager
32from PyLucid.system.URLs import URLs
33from PyLucid.system.response import SimpleStringIO
34from PyLucid.system.exceptions import AccessDenied
35from PyLucid.system.context_processors import add_dynamic_context, add_css_tag
36from PyLucid.tools.utils import escape, escape_django_tags
37from PyLucid.tools.content_processors import apply_markup, \
38                                                        render_string_template
39from PyLucid.plugins_internal.page_style.page_style import replace_add_data
40
41
42
43# TODO: Remove in PyLucid >v0.8.5
44PAGE_MSG_INFO_LINK = (
45    '<a href="'
46    'http://www.pylucid.org/_goto/121/changes/#20-05-2008-page_msg'
47    '">pylucid.org - Backwards-incompatible changes - page_msg</a>'
48)
49
50def _redirect_to_login(request):
51    """
52    Redirect to the _comment auth login with the default page
53    FIXME: We should build the auth command url in a better way.
54    """
55    path = "/%s/%s/auth/login/?next=%s" % (
56        settings.COMMAND_URL_PREFIX, Page.objects.default_page.id, request.path
57    )
58    return HttpResponseRedirect(path)
59
60def _redirect_access_denied(request):
61    """
62    Redirect to login page, if the user is anonymous.
63    """
64    if not request.user.is_anonymous():
65        # The user is logged in. But he hasn't the rights to see the page
66        # or run the plugin method
67        raise AccessDenied("User can see this page content!")
68
69    return _redirect_to_login(request)
70
71
72def _render_cms_page(request, context, page_content=None):
73    """
74    render the cms page.
75    - render a normal cms request
76    - render a _command request: The page.content is the output from the plugin.
77    """
78    if request.anonymous_view == False:
79        # TODO: remove in v0.9, see: ticket:161
80        # context["robots"] was set in contex_processors.static()
81        # Hide the response from search engines
82        context["robots"] = "NONE,NOARCHIVE"
83
84    context["anonymous_view"] = request.anonymous_view
85
86    current_page = context["PAGE"]
87
88    if page_content:
89        # The page content comes e.g. from the _command plugin
90#        current_page.content = page_content
91        page_content = escape_django_tags(page_content)
92    else:
93        # get the current page data from the db
94        page_content = current_page.content
95
96        markup_no = current_page.markup
97        page_content = apply_markup(page_content, context, markup_no)
98
99    # Render only the CMS page content:
100    try:
101        page_content = render_string_template(page_content, context)
102        # If a user access a public viewable cms page, but in the page content
103        # is a lucidTag witch is a restricted method, the pylucid plugin
104        # manager would normaly raise a AccessDenied.
105        # The Problem is, if settings.TEMPLATE_DEBUG is on, we didn't get a
106        # AccessDenied directly, we always get a TemplateSyntaxError! All
107        # other errors will catched and raised a TemplateSyntaxError, too.
108        # See django/template/debug.py
109        # TODO: Instead of a redirect to the login command, we can insert
110        # the ouput from auth.login directly
111    except TemplateSyntaxError, err:
112        # Check if it was a AccessDenied exception
113        if hasattr(err, "exc_info"):
114            # sys.exc_info() added in django/template/debug.py
115            error_class = err.exc_info[1]
116            if isinstance(error_class, AccessDenied):
117                return _redirect_access_denied(request)
118           
119        raise # raise the original error
120   
121    except AccessDenied:
122        # settings.TEMPLATE_DEBUG is off
123        return _redirect_access_denied(request)
124
125    # http://www.djangoproject.com/documentation/templates_python/#filters-and-auto-escaping
126    page_content = mark_safe(page_content) # turn djngo auto-escaping off
127
128    context["PAGE"].content = page_content
129
130    template = current_page.template
131    template_content = template.content
132
133    # Render the Template to build the complete html page:
134    content = render_string_template(template_content, context)
135
136    # insert JS/CSS data from any Plugin *after* the page rendered with the
137    # django template engine:
138    content = replace_add_data(context, content)
139
140    # TODO: Remove in PyLucid >v0.8.5
141    middleware = 'PyLucid.middlewares.pagemessages.PageMessagesMiddleware'
142    if middleware not in settings.MIDDLEWARE_CLASSES:
143        msg = (
144            u"ERROR: %s not in settings.MIDDLEWARE_CLASSES!"
145            " More info: %s"
146        ) % (middleware, PAGE_MSG_INFO_LINK)
147        content = content.replace(u"<!-- page_messages -->", msg)
148
149    return HttpResponse(content)
150
151
152
153
154def _get_context(request, current_page_obj):
155    """
156    Setup the context with PyLucid objects.
157    For index() and handle_command() views.
158    """
159    # add additional attribute
160    request.anonymous_view = True
161
162    context = RequestContext(request)
163
164    context["PAGE"] = current_page_obj
165    context["URLs"] = URLs(context)
166#    context["URLs"].debug()
167
168    # For additional JavaScript and StyleSheet information.
169    # JS+CSS from internal_pages or CSS data for pygments
170    # Add into the context object. Would be integraged in the page with the
171    # additional_content middleware.
172    context["js_data"] = []
173    context["css_data"] = []
174
175    # A list of every used html DIV CSS-ID.
176    # used in PyLucid.defaulttags.lucidTag.lucidTagNode._add_unique_div()
177    context["CSS_ID_list"] = []
178
179    # add dynamic content into the context (like: login/logout link)
180    add_dynamic_context(request, context)
181
182    # Add the context to the reponse object.
183    # Used in PyLucid middlewares
184    request.CONTEXT = context
185
186    # TODO: Remove in PyLucid >v0.8.5
187    msg = 'Error, see: %s' % PAGE_MSG_INFO_LINK
188    context["messages"] = [mark_safe(msg)]
189
190    return context
191
192
193def index(request, url):
194    """
195    The main index method.
196    Return a normal cms page request.
197    Every Request will be cached for anonymous user. For the cache_key we use
198    the page shortcut from the url.
199    """
200    try:
201        current_page_obj = Page.objects.get_by_shortcut(url, request.user)
202    except Page.DoesNotExist:
203        raise Http404(_("Page '%s' doesn't exists.") % url)
204    except Page.objects.WrongShortcut, correct_url:
205        # Some parts of the URL was wrong, but we found a right page
206        # shortcut -> redirect to the right url
207        return HttpResponseRedirect(correct_url)
208    except AccessDenied:
209        if request.user.is_anonymous():
210            # FIXME: We should build the auth command url in a better way.
211            return _redirect_to_login(request)
212        else:
213            # User is logged in but access is denied,
214            # probably due to group restrictions.
215            request.user.message_set.create(message=_("Access denied"))
216            new_url = Page.objects.default_page.get_absolute_url()
217            return HttpResponseRedirect(new_url)
218
219    context = _get_context(request, current_page_obj)
220
221    # Get the response for the requested cms page:
222    response = _render_cms_page(request, context)
223
224    if getattr(request, "_use_cache", None) == None:
225        # Set _use_cache information for the PyLucid cache middleware, but only
226        # if it was set to true or false in the past
227        request._use_cache = True
228
229    return response
230
231
232def _get_page(request, page_id):
233    """
234    returns the page object.
235    TODO: Check int(page_id)!
236    """
237    try:
238        current_page_obj = Page.objects.get(id=int(page_id))
239    except Page.DoesNotExist:
240        # The ID in the url is wrong -> goto the default page
241        current_page_obj = Page.objects.default_page
242
243        user = request.user
244        if user.is_authenticated():
245            # The page_msg system is not initialized, yet. So we must use the
246            # low level message_set method, but this ony exist for user how are
247            # login.
248            # ToDo: How can we sent a message to anonymous users?
249            user.message_set.create(
250                message=_(
251                    "Error: The page ID in the url is wrong."
252                    " (goto default page.)"
253                )
254            )
255
256    return current_page_obj
257
258
259def handle_command(request, page_id, module_name, method_name, url_args):
260    """
261    handle a _command request
262    """
263    current_page_obj = _get_page(request, page_id)
264
265    context = _get_context(request, current_page_obj)
266
267    local_response = SimpleStringIO()
268
269    if url_args == "":
270        url_args = ()
271    else:
272        url_args = (url_args,)
273
274    try:
275        output = plugin_manager.handle_command(
276            context, local_response, module_name, method_name, url_args
277        )
278    except AccessDenied:
279        if request.debug:
280            # don't use errorhandling -> raise the prior error
281            raise
282        page_content = "[Permission Denied!]"
283    else:
284        if output == None:
285            # Plugin/Module has retuned the locale StringIO response object
286            page_content = local_response.getvalue()
287        elif isinstance(output, basestring):
288            page_content = output
289        elif isinstance(output, HttpResponse):
290            # e.g. send a file directly back to the client
291            return output
292        else:
293            msg = (
294                "Error: Wrong output from Plugin!"
295                " - It should be write into the response object"
296                " or return a String/HttpResponse object!"
297                " - But %s.%s has returned: %s (%s)"
298            ) % (
299                module_name, method_name,
300                escape(repr(output)), escape(str(type(output)))
301            )
302            raise AssertionError(msg)
303
304#    print module_name, method_name
305#    print page_content
306#    print "---"
307
308    if page_content:
309        # Add the CSS Info, but only if the plugin has returned content and
310        # not when the normal cms page rendered.
311        page_content = add_css_tag(
312            context, page_content, module_name, method_name
313        )
314
315    return _render_cms_page(request, context, page_content)
316
317
318def redirect(request, url):
319    """
320    simple redirect old PyLucid URLs to the new location.
321    old url:
322        ".../index.py/PageShortcut/"
323    new url:
324        ".../PageShortcut/"
325    """
326    if url == "":
327        url = "/"
328
329    return HttpResponsePermanentRedirect(url)
330
331
332def permalink(request, page_id):
333    """
334    redirect to the real page url.
335    """
336    current_page_obj = _get_page(request, page_id)
337    url = current_page_obj.get_absolute_url()
338    return redirect(request, url)
Note: See TracBrowser for help on using the browser.