root/trunk/pylucid_project/PyLucid/index.py

Revision 1821, 11.5 kB (checked in by JensDiemer, 5 months ago)

NEW: Overwrite the used stylesheet/template...

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