# HG changeset patch # User Sverre Rabbelier # Date 1227215181 0 # Node ID 661ab830e9212735f8f883847028d52ef3fab316 # Parent ec1dcd70b97e3d3b74fe70a6a3b78bb4c64bca27 Deleted unused files and files diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/menu.py --- a/app/soc/logic/menu.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Representations and manipulation of arbitrarily nested menus. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from django.utils import datastructures - - -class Menu: - """Ordered collection of MenuItem objects. - - MenuItems are retrievable as an ordered list or individually by their - MenuItem.text key. - """ - - def __init__(self, items=None): - """Initializes ordered list of MenuItems. - - Args: - items: list of MenuItem objects in display order - """ - if not items: - items = [] - - items = [(i.name, i) for i in items] - self._items = datastructures.SortedDict(data=items) - - def getItem(self, name): - """Returns a MenuItem retrieved by its MenuItem.text.""" - return self._items.get(name) - - def setItem(self, item): - """Overwrites an existing MenuItem, or appends a new one.""" - self._items[item.name] = item - - def delItem(self, name): - """Removes an existing MenuItem.""" - del self._items[name] - - def _getItems(self): - """Returns an ordered list of the MenuItems.""" - return self._items.values() - - items = property(_getItems, doc= - """Read-only list of MenuItems, for use in templates.""") - - -class MenuItem: - """Provides menu item properties as easily-accessible attributes. - """ - - def __init__(self, name, value=None, selected=False, annotation=None, - sub_menu=None): - """Initializes the menu item attributes from supplied arguments. - - Args: - name: name of the menu item - value: optional value associated with the menu item; - default is None - selected: Boolean indicating if this menu item is selected; - default is False - annotation: optional annotation associated with the menu item; - default is None - sub_menu: a Menu of sub-items to display below this menu item; - default is None, indicating no sub-menu - """ - self.name = name - self.value = value - self.selected = selected - self.annotation = annotation - self.sub_menu = sub_menu diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/no_overwrite_sorted_dict.py --- a/app/soc/logic/no_overwrite_sorted_dict.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Like Django SortedDict, but no repeated assignments to the same key. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from django.utils import datastructures - - -class NoOverwriteSortedDict(datastructures.SortedDict): - """SortedDict where each key can be given a value only once. - - The purpose of this data structure is to be able to detect when - an attempt is made to overwrite the value of an existing key - in the SortedDict. This is to catch, for example, cases such as - a registry where two different callers attempt to register the - same view, handler, etc. - - It is still possible to pop or del a key out of the dict and then - add it back to the dict. - """ - - KEY_ALREADY_PRESENT_ERROR_FMT = \ - '%s already present, value cannot be overwritten' - - def __init__(self, data=None): - if data is None: - data = {} - - # call SortedDict's parent __init__() - # (bypassing the __init__() of SortedDict itself, since it will not - # enforce our no-overwrite requirement) - super(datastructures.SortedDict, self).__init__(data) - - if isinstance(data, dict): - self.keyOrder = data.keys() - else: - self.keyOrder = [] - - for key, value in data: - if key in self.keyOrder: - # key has already been given a value, and that value is not - # permitted to be overwritten, so raise an error - raise KeyError(self.KEY_ALREADY_PRESENT_ERROR_FMT % key) - - self.keyOrder.append(key) - - def __setitem__(self, key, value): - if key in self.keyOrder: - # key has already been given a value, and that value is not permitted - # to be overwritten, so raise an error - raise KeyError(self.KEY_ALREADY_PRESENT_ERROR_FMT % key) - - super(NoOverwriteSortedDict, self).__setitem__(key, value) diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/site/__init__.py diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/site/map.py --- a/app/soc/logic/site/map.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,437 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Site map information, used to generate sidebar menus, urlpatterns, etc. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from google.appengine.api import users - -from django.conf.urls import defaults - -from soc.logic import models -from soc.logic import path_link_name -from soc.logic.site import page - -import soc.logic.models.site_settings - - -# Home Page view -home = page.Page( - page.Url( - r'^$', - 'soc.views.models.site_settings.main_public'), - 'Google Open Source Programs', - # it should be obvious that every page comes from the home page - in_breadcrumb=False) - -# User sub-menu, changes depending on if User is signed-in or not -user_signin_sub_menu = page.NonPage( - 'user-sign-in-sub-menu', - 'User', - parent=home) - -user_signout_sub_menu = page.NonPage( - 'user-sign-out-sub-menu', - 'User', - parent=home) - -# User authentication view placeholders -# (these are not real Django views, but need to appear in menus, etc.) -user_signin = page.Page( - page.Url( - # not a real Django URL regex, just a unique placeholder - users.create_login_url('/'), - # no view, since App Engine handles this page - # (this page will not be placed in urlpatterns) - None, - # name is alternate string for view when it is not unique - name='user-sign-in'), - 'User (sign in)', - link_url=users.create_login_url('/'), - parent=user_signin_sub_menu) - -user_signout = page.Page( - page.Url( - # not a real Django URL regex, just a unique placeholder - users.create_logout_url('/'), - # no view, since App Engine handles this page - # (this page will not be placed in urlpatterns) - None, - # name is alternate string for view when it is not unique - name='user-sign-out'), - 'User (sign out)', - link_url=users.create_logout_url('/'), - parent=user_signout_sub_menu) - -# User Profile views -user_edit_self = page.Page( - page.Url( - r'^user/edit$', - 'soc.views.user.profile.create'), - 'User: Edit Your User Profile', - short_name='Site-wide User Profile', - parent=user_signout_sub_menu) - -# Site Home Page views -site_home = page.Page( - page.Url( - r'^home$', - 'soc.views.models.site_settings.main_public'), - 'Google Open Source Programs', - # it should be obvious that every page comes from the home page - in_breadcrumb=False) - - -site_sub_menu = page.NonPage( - 'site-sub-menu', - 'Site', - parent=home) - -home_settings_sub_menu = page.NonPage( - 'home-settings-sub-menu', - 'Home Settings', - parent=site_sub_menu) - -# Site Home Settings views -home_settings_list = page.Page( - page.Url( - r'^home/list$', - 'soc.views.models.home_settings.list'), - 'Site: List Home Settings', - short_name='List Home Settings', - parent=home_settings_sub_menu) - -home_settings_create = page.Page( - page.Url( - r'^home/create$', - 'soc.views.models.home_settings.create'), - 'Site: Create New Home Settings', - short_name='Create Home Settings', - parent=home_settings_sub_menu) - -home_settings_edit = page.Page( - page.Url( - r'^home/edit/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.home_settings.edit'), - 'Site: Settings', - short_name='Edit Site Settings', - parent=home_settings_sub_menu) - -home_settings_show = page.Page( - page.Url( - r'^home/show/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.home_settings.public'), - 'Show Document', - parent=home) - - -site_settings_sub_menu = page.NonPage( - 'site-settings-sub-menu', - 'Site Settings', - parent=site_sub_menu) - -# Site Home Settings views -site_settings_list = page.Page( - page.Url( - r'^site/list$', - 'soc.views.models.site_settings.list'), - 'Site: List Site Settings', - short_name='List Site Settings', - parent=site_settings_sub_menu) - -site_settings_create = page.Page( - page.Url( - r'^site/create$', - 'soc.views.models.site_settings.create'), - 'Site: Create New Site Settings', - short_name='Create Site Settings', - parent=site_settings_sub_menu) - -site_settings_edit = page.Page( - page.Url( - r'^site/edit$', - 'soc.views.models.site_settings.main_edit'), - 'Site: Settings', - short_name='Edit Main Site Settings', - parent=site_settings_sub_menu) - -site_settings_edit = page.Page( - page.Url( - r'^site/edit/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.site_settings.edit'), - 'Site: Settings', - short_name='Edit Site Settings', - parent=site_settings_sub_menu) - -site_settings_show = page.Page( - page.Url( - r'^site/show/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.site_settings.public'), - 'Show Site Settings', - parent=home) - -site_settings_delete = page.Page( - page.Url( - r'^site/delete/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.site_settings.delete'), - 'Delete Site Settings', - parent=home) - - -# User views -user_sub_menu = page.NonPage( - 'site-user-sub-menu', - 'Site: Users Sub-Menu', - short_name='Site Users', - parent=site_sub_menu) - -site_user_lookup = page.Page( - page.Url( - r'^user/lookup$', - 'soc.views.site.user.profile.lookup'), - 'Site: Look Up an Existing User', - short_name='Look Up Site User', - parent=user_sub_menu) - -user_create = page.Page( - page.Url( - r'^user/create$', - 'soc.views.models.user.create'), - 'Site: Create New User Profile', - short_name='Create Site User', - parent=user_sub_menu) - -site_user_edit = page.Page( - page.Url( - r'^user/edit/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.user.edit'), - 'Site: Modify Existing User Profile', - short_name='Modify Site User', - parent=user_sub_menu) - -user_show = page.Page( - page.Url( - r'^user/show/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.user.public'), - 'User: Show Existing User Profile', - parent=user_signout) - -user_list = page.Page( - page.Url( - r'^user/list$', - 'soc.views.models.user.list'), - 'Site: List of Users', - short_name='List Site Users', - parent=user_sub_menu) - -user_delete = page.Page( - page.Url( - r'^user/delete/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.user.delete'), - 'Site: Delete Existing User', - short_name='Delete Site User', - parent=user_sub_menu) - - -# Document views -document_show = page.Page( - page.Url( - r'^document/show/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.document.public'), - 'Show Document', - parent=home) - -# Site Document views -site_document_sub_menu = page.NonPage( - 'site-document-sub-menu', - 'Site: Documents Sub-Menu', - short_name='Site Documents', - parent=site_sub_menu) - -site_document_create = page.Page( - page.Url( - r'^document/create$', - 'soc.views.models.document.create'), - 'Site: Create New Document', - 'Create Site Document', - parent=site_document_sub_menu) - -site_document_edit = page.Page( - page.Url( - r'^document/edit/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.document.edit'), - 'Site: Modify Existing Document', - short_name='Modify Site Document', - parent=site_document_sub_menu) - -site_document_delete = page.Page( - page.Url( - r'^document/delete/%s$' % path_link_name.PATH_LINK_ID_ARGS_PATTERN, - 'soc.views.models.document.delete'), - 'Site: Delete Existing Document', - short_name='Delete Site Document', - parent=site_document_sub_menu) - -site_document_list = page.Page( - page.Url( - r'^document/list$', - 'soc.views.models.document.list'), - 'Site: List of Documents', - short_name='List Site Documents', - parent=site_document_sub_menu) - -# Sponsor Group public view -sponsor_profile = page.Page( - page.Url( - r'^sponsor/show/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.sponsor.public'), - 'Sponsor Public Profile', - parent=home) - -# Sponsor Group Site views -site_sponsor_sub_menu = page.NonPage( - 'site-sponsor-sub-menu', - 'Site: Sponsors Sub-Menu', - short_name='Site Sponsors', - parent=site_sub_menu) - -site_sponsor_create = page.Page( - page.Url( - r'^sponsor/create$', - 'soc.views.models.sponsor.create'), - 'Site: Create New Sponsor', - short_name='Create Site Sponsor', - parent=site_sponsor_sub_menu) - -site_sponsor_delete = page.Page( - page.Url( - r'^sponsor/delete/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.sponsor.delete'), - 'Site: Delete Existing Sponsor', - short_name='Delete Site Sponsor', - parent=site_sponsor_sub_menu) - -site_sponsor_edit = page.Page( - page.Url( - r'^sponsor/edit/%s$' % path_link_name.LINK_ID_ARG_PATTERN, - 'soc.views.models.sponsor.edit'), - 'Site: Modify Existing Sponsor', - short_name='Modify Site Sponsor', - parent=site_sponsor_sub_menu) - -site_sponsor_list = page.Page( - page.Url( - r'^sponsor/list$', - 'soc.views.models.sponsor.list'), - 'Site: List of Sponsors', - short_name='List Site Sponsors', - parent=site_sponsor_sub_menu) - -# Host public view -host_profile = page.Page( - page.Url( - r'^host/show/(?P%(lnp)s)/(?P%(lnp)s)$' % { - 'lnp': path_link_name.LINK_ID_PATTERN_CORE}, - 'soc.views.models.host.public'), - 'Host Public Profile', - parent=home) - -# Host Site views -site_host_sub_menu = page.NonPage( - 'site-host-sub-menu', - 'Site: Host Sub-Menu', - short_name='Site Hosts', - parent=site_sub_menu) - -site_host_create = page.Page( - page.Url( - r'^host/create$', - 'soc.views.models.host.create'), - 'Site: Create New Host', - short_name='Create Site Host', - parent=site_host_sub_menu) - -site_host_delete = page.Page( - page.Url( - r'^host/delete/(?P%(lnp)s)/(?P%(lnp)s)$' % { - 'lnp': path_link_name.LINK_ID_PATTERN_CORE}, - 'soc.views.models.host.delete'), - 'Site: Delete Existing Host', - short_name='Delete Site Host', - parent=site_host_sub_menu) - -site_host_edit = page.Page( - page.Url( - r'^host/edit/(?P%(lnp)s)/(?P%(lnp)s)$' % { - 'lnp': path_link_name.LINK_ID_PATTERN_CORE}, - 'soc.views.models.host.edit'), - 'Site: Modify Existing Host', - short_name='Modify Site Host', - parent=site_host_sub_menu) - -site_host_list = page.Page( - page.Url( - r'^host/list$', - 'soc.views.models.host.list'), - 'Site: List of Hosts', - short_name='List Site Hosts', - parent=site_host_sub_menu) - -# these are not really used... -# (r'^org/profile/(?Pghop[_0-9a-z]+)/(?P[_0-9a-z]+)/$', -# 'soc.views.person.profile.edit', -# {'template': 'ghop/person/profile/edit.html'}), -# (r'^org/profile/(?P[_0-9a-z]+)/(?P[_0-9a-z]+)/$', -# 'soc.views.person.profile.edit'), - - -ROOT_PAGES = [ - # /, first level of the sidebar menu, excluded from breadcrumbs - home, - - # alternate view of /, no menu presence - site_home, -] - - -def getDjangoUrlPatterns(pages=ROOT_PAGES): - """Returns Django urlpatterns derived from the site map Pages. - - Args: - pages: a list of page.Page objects from which to generate urlpatterns - (from them and from their child Pages); default is ROOT_PAGES - - Raises: - KeyError if more than one Page has the same urlpattern. - - TODO(tlarsen): this probably does not work correctly, currently, since - page.Page.makeDjangoUrls() returns a list, and this routine is - combining lists from potentially multiple page hierarchies. Each list - might have a urlpattern that the other contains, but this won't be - detected by the current code (will Django catch this?). This really - needs to be detected earlier via a global Page dictionary. - """ - urlpatterns = [''] - - for page in pages: - urlpatterns.extend(page.makeDjangoUrls()) - - return defaults.patterns(*urlpatterns) diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/site/page.py --- a/app/soc/logic/site/page.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,472 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Page properties, used to generate sidebar menus, urlpatterns, etc. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -import copy -import re - -from django.conf.urls import defaults - -from python25src import urllib - -from soc.logic import menu -from soc.logic.no_overwrite_sorted_dict import NoOverwriteSortedDict - - -class Url: - """The components of a Django URL pattern. - """ - - def __init__(self, regex, view, kwargs=None, name=None, prefix=''): - """Collects Django urlpatterns info into a simple object. - - The arguments to this constructor correspond directly to the items in - the urlpatterns tuple, which also correspond to the parameters of - django.conf.urls.defaults.url(). - - Args: - regex: a Django URL regex pattern, which, for obvious reason, must - be unique - view: a Django view, either a string or a callable; if a callable, - a unique 'name' string must be supplied - kwargs: optional dict of extra arguments passed to the view - function as keyword arguments, which is copy.deepcopy()'d; - default is None, which supplies an empty dict {} - name: optional name of the view; used instead of 'view' if supplied; - the 'name' or 'view' string, whichever is used, must be unique - amongst *all* Url objects supplied to a Page object - prefix: optional view prefix - """ - self.regex = regex - self.view = view - - if kwargs: - self.kwargs = copy.deepcopy(kwargs) - else: - self.kwargs = {} - - self.name = name - self.prefix = prefix - - def makeDjangoUrl(self, **extra_kwargs): - """Returns a Django url() used by urlpatterns, or None if not a view. - """ - if not self.view: - return None - - kwargs = copy.deepcopy(self.kwargs) - kwargs.update(extra_kwargs) - return defaults.url(self.regex, self.view, kwargs=kwargs, - name=self.name, prefix=self.prefix) - - _STR_FMT = '''%(indent)sregex: %(regex)s -%(indent)sview: %(view)s -%(indent)skwargs: %(kwargs)s -%(indent)sname: %(name)s -%(indent)sprefix: %(prefix)s -''' - - def asIndentedStr(self, indent=''): - """Returns an indented string representation useful for logging. - - Args: - indent: an indentation string that is prepended to each line present - in the multi-line string returned by this method. - """ - return self._STR_FMT % {'indent': indent, 'regex': self.regex, - 'view': self.view, 'kwargs': self.kwargs, - 'name': self.name, 'prefix': self.prefix} - - def __str__(self): - """Returns a string representation useful for logging. - """ - return self.asIndentedStr() - - -class Page: - """An abstraction that combines a Django view with sidebar menu info. - """ - - def __init__(self, url, long_name, short_name=None, selected=False, - annotation=None, parent=None, link_url=None, - in_breadcrumb=True, force_in_menu=False): - """Initializes the menu item attributes from supplied arguments. - - Args: - url: a Url object - long_name: title of the Page - short_name: optional menu item and breadcrumb name; default is - None, in which case long_name is used - selected: Boolean indicating if this menu item is selected; - default is False - annotation: optional annotation associated with the menu item; - default is None - parent: optional Page that is the logical "parent" of this page; - used to construct hierarchical menus and breadcrumb trails - link_url: optional alternate URL link; if supplied, it is returned - by makeLinkUrl(); default is None, and makeLinkUrl() attempts to - create a URL link from url.regex - in_breadcrumb: if True, the Page appears in breadcrumb trails; - default is True - force_in_menu: if True, the Page appears in menus even if it does - not have a usable link_url; default is False, which excludes - the Page if makeLinkUrl() returns None - """ - self.url = url - self.long_name = long_name - self.annotation = annotation - self.in_breadcrumb = in_breadcrumb - self.force_in_menu = force_in_menu - self.link_url = link_url - self.selected = selected - self.parent = parent - - # create ordered, unique mappings of URLs and view names to Pages - self.child_by_urls = NoOverwriteSortedDict() - self.child_by_views = NoOverwriteSortedDict() - - if not short_name: - short_name = long_name - - self.short_name = short_name - - if parent: - # tell parent Page about parent <- child relationship - parent.addChild(self) - - # TODO(tlarsen): build some sort of global Page dictionary to detect - # collisions sooner and to make global queries from URLs to pages - # and views to Pages possible (without requiring a recursive search) - - def getChildren(self): - """Returns an iterator over any child Pages - """ - for page in self.child_by_views.itervalues(): - yield page - - children = property(getChildren) - - def getChild(self, url=None, regex=None, view=None, - name=None, prefix=None, request_path=None): - """Returns a child Page if one can be identified; or None otherwise. - - All of the parameters to this method are optional, but at least one - must be supplied to return anything other than None. The parameters - are tried in the order they are listed in the "Args:" section, and - this method exits on the first "match". - - Args: - url: a Url object, used to overwrite the regex, view, name, and - prefix parameters if present; default is None - regex: a regex pattern string, used to return the associated - child Page - view: a view string, used to return the associated child Page - name: a name string, used to return the associated child Page - prefix: (currently unused, see TODO below in code) - request_path: optional HTTP request path string (request.path) - with no query arguments - """ - # this code is yucky; there is probably a better way... - if url: - regex = url.regex - view = url.view - name = url.name - prefix = url.prefix - - if regex in self.child_by_urls: - # regex supplied and Page found, so return that Page - return self.child_by_urls[regex][0] - - # TODO(tlarsen): make this work correctly with prefixes - - if view in self.child_views: - # view supplied and Page found, so return that Page - return self.child_by_views[view] - - if name in self.child_views: - # name supplied and Page found, so return that Page - return self.child_by_views[name] - - if request_path.startswith('/'): - request_path = request_path[1:] - - # attempt to match the HTTP request path with a Django URL pattern - for pattern, (page, regex) in self.child_by_urls: - if regex.match(request_path): - return page - - return None - - def addChild(self, page): - """Adds a unique Page as a child Page of this parent. - - Raises: - ValueError if page.url.regex is not a string. - ValueError if page.url.view is not a string. - ValueError if page.url.name is supplied but is not a string. - KeyError if page.url.regex is already associated with another Page. - KeyError if page.url.view/name is already associated with another Page. - """ - # TODO(tlarsen): see also TODO in __init__() about global Page dictionary - - url = page.url - - if url.regex: - if not isinstance(url.regex, basestring): - raise ValueError('"regex" must be a string, not a compiled regex') - - # TODO(tlarsen): see if Django has some way exposed in its API to get - # the view name from the request path matched against urlpatterns; - # if so, there would be no need for child_by_urls, because the - # request path could be converted for us by Django into a view/name, - # and we could just use child_by_views with that string instead - self.child_by_urls[url.regex] = (page, re.compile(url.regex)) - # else: NonUrl does not get indexed by regex, because it has none - - # TODO(tlarsen): make this work correctly if url has a prefix - # (not sure how to make this work with include() views...) - if url.name: - if not isinstance(url.name, basestring): - raise ValueError('"name" must be a string if it is supplied') - - view = url.name - elif isinstance(url.view, basestring): - view = url.view - else: - raise ValueError('"view" must be a string if "name" is not supplied') - - self.child_by_views[view] = page - - def delChild(self, url=None, regex=None, view=None, name=None, - prefix=None): - """Removes a child Page if one can be identified. - - All of the parameters to this method are optional, but at least one - must be supplied in order to remove a child Page. The parameters - are tried in the order they are listed in the "Args:" section, and - this method uses the first "match". - - Args: - url: a Url object, used to overwrite the regex, view, name, and - prefix parameters if present; default is None - regex: a regex pattern string, used to remove the associated - child Page - view: a view string, used to remove the associated child Page - name: a name string, used to remove the associated child Page - prefix: (currently unused, see TODO below in code) - - Raises: - KeyError if the child Page could not be definitively identified in - order to delete it. - """ - # this code is yucky; there is probably a better way... - if url: - regex = url.regex - view = url.view - name = url.name - prefix = url.prefix - - # try to find page by regex, view, or name, in turn - if regex in self.child_by_urls: - url = self.child_by_urls[regex][0].url - view = url.view - name = url.name - prefix = url.prefix - elif view in self.child_views: - # TODO(tlarsen): make this work correctly with prefixes - regex = self.child_by_views[view].url.regex - elif name in self.child_views: - regex = self.child_by_views[name].url.regex - - if regex: - # regex must refer to an existing Page at this point - del self.child_urls[regex] - - if not isinstance(view, basestring): - # use name if view is callable() or None, etc. - view = name - - # TODO(tlarsen): make this work correctly with prefixes - del self.child_by_views[view] - - - def makeLinkUrl(self): - """Makes a URL link suitable for use. - - Returns: - self.link_url if link_url was supplied to the __init__() constructor - and it is a non-False value - -OR- - a suitable URL extracted from the url.regex, if possible - -OR- - None if url.regex contains quotable characters that have not already - been quoted (that is, % is left untouched, so quote suspect - characters in url.regex that would otherwise be quoted) - """ - if self.link_url: - return self.link_url - - link = self.url.regex - - if not link: - return None - - if link.startswith('^'): - link = link[1:] - - if link.endswith('$'): - link = link[:-1] - - if not link.startswith('/'): - link = '/' + link - - # path separators and already-quoted characters are OK - if link != urllib.quote(link, safe='/%'): - return None - - return link - - def makeMenuItem(self): - """Returns a menu.MenuItem for the Page (and any child Pages). - """ - child_items = [] - - for child in self.children: - child_item = child.makeMenuItem() - if child_item: - child_items.append(child_item) - - if child_items: - sub_menu = menu.Menu(items=child_items) - else: - sub_menu = None - - link_url = self.makeLinkUrl() - - if (not sub_menu) and (not link_url) and (not self.force_in_menu): - # no sub-menu, no valid link URL, and not forced to be in menu - return None - - return menu.MenuItem( - self.short_name, value=link_url, sub_menu=sub_menu) - - def makeDjangoUrl(self): - """Returns the Django url() for the underlying self.url. - """ - return self.url.makeDjangoUrl(page_name=self.short_name) - - def makeDjangoUrls(self): - """Returns an ordered mapping of unique Django url() objects. - - Raises: - KeyError if more than one Page has the same urlpattern. - - TODO(tlarsen): this really needs to be detected earlier via a - global Page dictionary - """ - return self._makeDjangoUrlsDict().values() - - def _makeDjangoUrlsDict(self): - """Returns an ordered mapping of unique Django url() objects. - - Used to implement makeDjangoUrls(). See that method for details. - """ - urlpatterns = NoOverwriteSortedDict() - - django_url = self.makeDjangoUrl() - - if django_url: - urlpatterns[self.url.regex] = django_url - - for child in self.children: - urlpatterns.update(child._makeDjangoUrlsDict()) - - return urlpatterns - - _STR_FMT = '''%(indent)slong_name: %(long_name)s -%(indent)sshort_name: %(short_name)s -%(indent)sselected: %(selected)s -%(indent)sannotation: %(annotation)s -%(indent)surl: %(url)s -''' - - def asIndentedStr(self, indent=''): - """Returns an indented string representation useful for logging. - - Args: - indent: an indentation string that is prepended to each line present - in the multi-line string returned by this method. - """ - strings = [ - self._STR_FMT % {'indent': indent, 'long_name': self.long_name, - 'short_name': self.short_name, - 'selected': self.selected, - 'annotation': self.annotation, - 'url': self.url.asIndentedStr(indent + ' ')}] - - for child in self.children: - strings.extend(child.asIndentedStr(indent + ' ')) - - return ''.join(strings) - - def __str__(self): - """Returns a string representation useful for logging. - """ - return self.asIndentedStr() - - -class NonUrl(Url): - """Placeholder for when a site-map entry is not a linkable URL. - """ - - def __init__(self, name): - """Creates a non-linkable Url placeholder. - - Args: - name: name of the non-view placeholder; see Url.__init__() - """ - Url.__init__(self, None, None, name=name) - - def makeDjangoUrl(self, **extra_kwargs): - """Always returns None, since NonUrl is never a Django view. - """ - return None - - -class NonPage(Page): - """Placeholder for when a site-map entry is not a displayable page. - """ - - def __init__(self, non_url_name, long_name, **page_kwargs): - """Constructs a NonUrl and passes it to base Page class __init__(). - - Args: - non_url_name: unique (it *must* be) string that does not match - the 'name' or 'view' of any other Url or NonUrl object; - see Url.__init__() for details - long_name: see Page.__init__() - **page_kwargs: keyword arguments passed directly to the base - Page class __init__() - """ - non_url = NonUrl(non_url_name) - Page.__init__(self, non_url, long_name, **page_kwargs) diff -r ec1dcd70b97e -r 661ab830e921 app/soc/logic/site/sidebar.py --- a/app/soc/logic/site/sidebar.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Site-wide sidebar menu creation. - -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from google.appengine.api import users - -from soc.logic import accounts -from soc.logic import menu -from soc.logic.site import map - - -def buildUserSidebar(account=None, **ignored): - """Returns a list of menu items for the User portion of the sidebar. - - Args: - account: a Google Account (users.User) object; default is None, in which - case users.get_current_user() is called - **ignored: other keyword arguments supplied to other sidebar builder - functions, but ignored by this one - """ - if account is None: - account = users.get_current_user() - - if not account: - return [map.user_signin_sub_menu.makeMenuItem()] - - return [map.user_signout_sub_menu.makeMenuItem()] - - -def buildSiteSidebar(is_admin=None, **ignored): - """Returns a list of menu items for the Developer portion of the sidebar. - - Args: - is_admin: Boolean indicating that current user is a "Developer" - (site super-user); default is None, in which case - accounts.isDeveloper() is called - **ignored: other keyword arguments supplied to other sidebar builder - functions, but ignored by this one - """ - if is_admin is None: - is_admin = accounts.isDeveloper() - - if not is_admin: - # user is either not logged in or not a "Developer", so return no menu - return None - - return [map.site_sub_menu.makeMenuItem()] - - -def buildProgramsSidebar(**unused): - """Mock-up for Programs section of sidebar menu. - - Args: - **unused: all keyword arguments are currently unused in this mock-up - - TODO: actually implement this once Program entities are present in the - Datastore. - """ - return [ - menu.MenuItem( - 'Google Summer of Code', - value='/program/gsoc2009/home', - sub_menu=menu.Menu(items=[ - menu.MenuItem( - 'Community', - value='/program/gsoc2009/community'), - menu.MenuItem( - 'FAQs', - value='/program/gsoc2009/document/faqs'), - menu.MenuItem( - 'Terms of Service', - value='/program/gsoc2009/document/tos'), - ] - ) - ), - menu.MenuItem( - 'Google Highly Open Participation', - value='/program/ghop2008/home', - sub_menu=menu.Menu(items=[ - menu.MenuItem( - 'Community', - value='/program/ghop2008/community'), - menu.MenuItem( - 'FAQs', - value='/program/ghop2008/document/faqs'), - menu.MenuItem( - 'Contest Rules', - value='/program/ghop2008/document/rules'), - ] - ) - ), - ] - - -DEF_SIDEBAR_BUILDERS = [ - buildUserSidebar, - buildSiteSidebar, - buildProgramsSidebar, -] - -def buildSidebar(path=None, builders=DEF_SIDEBAR_BUILDERS, **builder_args): - """Calls all sidebar builders to construct the sidebar menu. - - Args: - builders: list of functions that take context as a single - argument; default is the list of sidebar builder functions present - in soc.logic.site.sidebar - **builder_args: keyword arguments passed to each sidebar builder function - - Returns: - an soc.logic.menu.Menu object containing the sidebar menu items - """ - menu_items = [] - - # call each of the sidebar builders and append any menu items they create - for builder in builders: - built_items = builder(**builder_args) - - if built_items: - menu_items.extend(built_items) - - # try to determine which of the menu items is the current path, to indicate - # that it is "selected" - if not path: - # path argument not supplied, so see if an HTTP request object was - # supplied in the builder_args - request = builder_args.get('request') - - if request: - # there is an HTTP request object, so use the path stored in it - path = request.path - - if path: - # TODO(tlarsen): scan through list and mark current request.path - # as "selected" - pass - - return menu.Menu(items=menu_items) diff -r ec1dcd70b97e -r 661ab830e921 app/soc/views/document/__init__.py diff -r ec1dcd70b97e -r 661ab830e921 app/soc/views/document/edit.py --- a/app/soc/views/document/edit.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Views for editing and examining Documents. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from google.appengine.api import users - -from django import forms -from django import http -from django.utils.translation import ugettext_lazy - -from soc.logic import models -from soc.logic import out_of_band -from soc.logic import path_link_name -from soc.logic.models import document - -from soc.views import helper -from soc.views import simple -from soc.views.helper import access -from soc.views.helper import decorators -from soc.views.user import profile - -import soc.models.document -import soc.views.helper.forms -import soc.views.helper.requests -import soc.views.helper.responses -import soc.views.helper.widgets -import soc.views.out_of_band - - -DEF_CREATE_NEW_DOC_MSG = ' You can create a new document by visiting the' \ - ' Create ' \ - 'a New Document page.' - -SUBMIT_MESSAGES = ( - ugettext_lazy('Document saved.'), -) - - -def getDocForForm(form): - """Extracts doc fields from a form and creates a new doc from it. - """ - - user = users.get_current_user() - - scope_path = form.cleaned_data.get('scope_path') - link_id = form.cleaned_data.get('link_id') - - properties = {} - properties['scope_path'] = scope_path - properties['link_id'] = link_id - properties['title'] = form.cleaned_data.get('title') - properties['short_name'] = form.cleaned_data.get('short_name') - properties['content'] = form.cleaned_data.get('content') - properties['author'] = models.user.logic.getForFields({'id': user}, unique=True) - properties['is_featured'] = form.cleaned_data.get('is_featured') - - key_fields = document.logic.getKeyFieldsFromDict(properties) - - doc = document.logic.updateOrCreateFromFields(properties, key_fields) - return doc - - -class CreateForm(helper.forms.BaseForm): - """Django form displayed when Developer creates a Document. - """ - content = forms.fields.CharField(widget=helper.widgets.TinyMCE( - attrs={'rows':10, 'cols':40})) - - class Meta: - model = soc.models.document.Document - - #: list of model fields which will *not* be gathered by the form - exclude = ['inheritance_line', 'author', 'created', 'modified'] - - def clean_scope_path(self): - scope_path = self.cleaned_data.get('scope_path') - # TODO(tlarsen): combine path and link_id and check for uniqueness - return scope_path - - def clean_link_id(self): - link_id = self.cleaned_data.get('link_id') - # TODO(tlarsen): combine path and link_id and check for uniqueness - return link_id - - -DEF_DOCS_CREATE_TMPL = 'soc/models/edit.html' - -@decorators.view -def create(request, page_name=None, template=DEF_DOCS_CREATE_TMPL): - """View to create a new Document entity. - - Args: - request: the standard django request object - page_name: the page name displayed in templates as page and header title - template: the "sibling" template (or a search list of such templates) - from which to construct the public.html template name (or names) - - Returns: - A subclass of django.http.HttpResponse which either contains the form to - be filled out, or a redirect to the correct view in the interface. - """ - - try: - access.checkIsDeveloper(request) - except soc.views.out_of_band.AccessViolationResponse, alt_response: - # TODO(tlarsen): change this to just limit the Documents that can be - # created by the User in their current Role - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page_name'] = page_name - - if request.method == 'POST': - form = CreateForm(request.POST) - - if form.is_valid(): - doc = getDocForForm(form) - - if not doc: - return http.HttpResponseRedirect('/') - - new_path = path_link_name.combinePath([doc.scope_path, doc.link_id]) - - # redirect to new /document/edit/new_path?s=0 - # (causes 'Profile saved' message to be displayed) - return helper.responses.redirectToChangedSuffix( - request, None, new_path, - params=profile.SUBMIT_PROFILE_SAVED_PARAMS) - else: # method == 'GET': - # no link ID specified, so start with an empty form - form = CreateForm() - - context['form'] = form - - return helper.responses.respond(request, template, context) - - -DEF_DOCS_EDIT_TMPL = 'soc/models/edit.html' - -class EditForm(CreateForm): - """Django form displayed a Document is edited. - """ - doc_key_name = forms.fields.CharField(widget=forms.HiddenInput) - created_by = forms.fields.CharField(widget=helper.widgets.ReadOnlyInput(), - required=False) - - -@decorators.view -def edit(request, page_name=None, scope_path=None, link_id=None, - template=DEF_DOCS_EDIT_TMPL): - """View to modify the properties of a Document Model entity. - - Args: - request: the standard django request object - page_name: the page name displayed in templates as page and header title - scope_path: the Document's site-unique "path" extracted from the URL, - minus the trailing link_id - link_id: the last portion of the Document's site-unique "path" - extracted from the URL - template: the "sibling" template (or a search list of such templates) - from which to construct the public.html template name (or names) - - Returns: - A subclass of django.http.HttpResponse which either contains the form to - be filled out, or a redirect to the correct view in the interface. - """ - - try: - access.checkIsDeveloper(request) - except soc.views.out_of_band.AccessViolationResponse, alt_response: - # TODO(tlarsen): change this to just limit the Documents that can be - # edited by the User in their current Role - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page_name'] = page_name - - doc = None # assume that no Document entity will be found - - path = path_link_name.combinePath([scope_path, link_id]) - - # try to fetch Document entity corresponding to path if one exists - try: - if path: - doc = document.logic.getFromFields(scope_path=scope_path, - link_id=link_id) - except out_of_band.ErrorResponse, error: - # show custom 404 page when path doesn't exist in Datastore - error.message = error.message + DEF_CREATE_NEW_DOC_MSG - return simple.errorResponse(request, page_name, error, template, context) - - if request.method == 'POST': - form = EditForm(request.POST) - - if form.is_valid(): - doc = getDocForForm(form) - - if not doc: - return http.HttpResponseRedirect('/') - - new_path = path_link_name.combinePath([doc.scope_path, doc.link_id]) - - # redirect to new /document/edit/new_path?s=0 - # (causes 'Profile saved' message to be displayed) - return helper.responses.redirectToChangedSuffix( - request, path, new_path, - params=profile.SUBMIT_PROFILE_SAVED_PARAMS) - else: # method == 'GET': - # try to fetch Document entity corresponding to path if one exists - if path: - if doc: - # is 'Profile saved' parameter present, but referrer was not ourself? - # (e.g. someone bookmarked the GET that followed the POST submit) - if (request.GET.get(profile.SUBMIT_MSG_PARAM_NAME) - and (not helper.requests.isReferrerSelf(request, suffix=path))): - # redirect to aggressively remove 'Profile saved' query parameter - return http.HttpResponseRedirect(request.path) - - # referrer was us, so select which submit message to display - # (may display no message if ?s=0 parameter is not present) - context['notice'] = ( - helper.requests.getSingleIndexedParamValue( - request, profile.SUBMIT_MSG_PARAM_NAME, - values=SUBMIT_MESSAGES)) - - # populate form with the existing Document entity - author_link_id = doc.author.link_id - form = EditForm(initial={'doc_key_name': doc.key().name(), - 'title': doc.title, 'scope_path': doc.scope_path, - 'link_id': doc.link_id, 'short_name': doc.short_name, - 'content': doc.content, 'author': doc.author, - 'is_featured': doc.is_featured, 'created_by': author_link_id}) - else: - if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME): - # redirect to aggressively remove 'Profile saved' query parameter - return http.HttpResponseRedirect(request.path) - - context['lookup_error'] = ugettext_lazy( - 'Document with that path not found.') - form = EditForm(initial={'link_id': link_id}) - else: # no link ID specified in the URL - if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME): - # redirect to aggressively remove 'Profile saved' query parameter - return http.HttpResponseRedirect(request.path) - - # no link ID specified, so start with an empty form - form = EditForm() - - context.update({'form': form, - 'entity': doc}) - - return helper.responses.respond(request, template, context) - - -@decorators.view -def delete(request, page_name=None, scope_path=None, link_id=None, - template=DEF_DOCS_EDIT_TMPL): - """Request handler to delete Document Model entity. - - Args: - request: the standard django request object - page_name: the page name displayed in templates as page and header title - scope_path: the Document's site-unique "path" extracted from the URL, - minus the trailing link_id - link_id: the last portion of the Document's site-unique "path" - extracted from the URL - template: the "sibling" template (or a search list of such templates) - from which to construct the public.html template name (or names) - - Returns: - A subclass of django.http.HttpResponse which redirects - to /site/document/list. - """ - - try: - access.checkIsDeveloper(request) - except soc.views.out_of_band.AccessViolationResponse, alt_response: - # TODO(tlarsen): change this to just limit the Documents that can be - # deleted by the User in their current Role - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page_name'] = page_name - - existing_doc = None - path = path_link_name.combinePath([scope_path, link_id]) - - # try to fetch Document entity corresponding to path if one exists - try: - if path: - existing_doc = document.logic.getFromFields(scope_path=scope_path, - link_id=link_id) - except out_of_band.ErrorResponse, error: - # show custom 404 page when path doesn't exist in Datastore - error.message = error.message + DEF_CREATE_NEW_DOC_MSG - return simple.errorResponse(request, page_name, error, template, context) - - if existing_doc: - document.logic.delete(existing_doc) - - return http.HttpResponseRedirect('/document/list') diff -r ec1dcd70b97e -r 661ab830e921 app/soc/views/document/list.py --- a/app/soc/views/document/list.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Views for listing Documents. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from soc.logic.models import work -from soc.views import helper -from soc.views.helper import access -from soc.views.helper import decorators - -import soc.logic -import soc.models.document -import soc.views.helper.lists -import soc.views.helper.responses -import soc.views.out_of_band - - -DEF_DOCS_LIST_ALL_TMPL = 'soc/models/list.html' - - -@decorators.view -def all(request, page_name=None, templates={}): - """Show a list of all Documents (limit rows per page). - - Args: - request: the standard Django HTTP request object - page_name: the page name displayed in templates as page and header title - template: the "sibling" template (or a search list of such templates) - from which to construct an alternate template name (or names) - - Returns: - A subclass of django.http.HttpResponse which either contains the form to - be filled out, or a redirect to the correct view in the interface. - """ - - try: - access.checkIsDeveloper(request) - except soc.views.out_of_band.AccessViolationResponse, alt_response: - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page_name'] = page_name - - offset, limit = helper.lists.cleanListParameters( - offset=request.GET.get('offset'), limit=request.GET.get('limit')) - - # Fetch one more to see if there should be a 'next' link - document = work.logic.getForLimitAndOffset(limit + 1, offset=offset) - - context['pagination_form'] = helper.lists.makePaginationForm(request, limit) - - list_templates = { - 'list_main': templates.get('list_main', - 'soc/list/list_main.html'), - 'list_pagination': templates.get('list_pagination', - 'soc/list/list_pagination.html'), - 'list_row': templates.get('list_row', - 'soc/document/list/docs_row.html'), - 'list_heading': templates.get('list_heading', - 'soc/document/list/docs_heading.html'), - } - - context = helper.lists.setList( - request, context, document, - offset=offset, limit=limit, list_templates=list_templates) - - template = templates.get('all', DEF_DOCS_LIST_ALL_TMPL) - return helper.responses.respond(request, template, context) diff -r ec1dcd70b97e -r 661ab830e921 app/soc/views/document/show.py --- a/app/soc/views/document/show.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Document viewers. - -public: how the general public sees a Document -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -from soc.logic import out_of_band -from soc.logic import path_link_name -from soc.logic.models import document -from soc.views import helper -from soc.views import simple -from soc.views.helper import decorators - -import soc.views.helper.responses -import soc.views.helper.templates - - -DEF_DOCS_PUBLIC_TMPL = 'soc/document/public.html' - -@decorators.view -def public(request, page_name=None, scope_path=None, link_id=None, - template=DEF_DOCS_PUBLIC_TMPL): - """How the "general public" sees a Document. - - Args: - request: the standard django request object - page_name: the page name displayed in templates as page and header title - scope_path: the Document's site-unique "path" extracted from the URL, - minus the trailing link_id - link_id: the last portion of the Document's site-unique "path" - extracted from the URL - template: the "sibling" template (or a search list of such templates) - from which to construct the public.html template name (or names) - - Returns: - A subclass of django.http.HttpResponse which either contains the form to - be filled out, or a redirect to the correct view in the interface. - """ - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - - # TODO: there eventually needs to be a call to some controller logic that - # implements some sort of access controls, based on the currently - # logged-in User's Roles, etc. - - # TODO: based on the User's Roles, Documents that the User can edit - # should display a link to a document edit form - - doc = None - - # try to fetch User entity corresponding to link_id if one exists - path = path_link_name.combinePath([scope_path, link_id]) - - # try to fetch Document entity corresponding to path if one exists - try: - if path: - doc = document.logic.getFromFields(scope_path=scope_path, - link_id=link_id) - except out_of_band.ErrorResponse, error: - # show custom 404 page when Document path doesn't exist in Datastore - return simple.errorResponse(request, page_name, error, template, context) - - doc.content = helper.templates.unescape(doc.content) - context['entity'] = doc - - return helper.responses.respond(request, template, context) \ No newline at end of file diff -r ec1dcd70b97e -r 661ab830e921 app/soc/views/helper/html_menu.py --- a/app/soc/views/helper/html_menu.py Thu Nov 20 21:01:18 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2008 the Melange authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Helpers for displaying arbitrarily nested menus as HTML lists. -""" - -__authors__ = [ - '"Todd Larsen" ', - ] - - -class HtmlMenu: - """Ordered collection of MenuItem objects as

...

paragraphs. - """ - ITEM_PREFIX_FMT = '%(indent)s

' - ITEM_SUFFIX_FMT = '%(indent)s

' - - def __init__(self, menu, item_class=None): - """Wraps an soc.logic.menu.Menu in order to render it as HTML. - - Args: - menu: an soc.logic.menu.Menu object - item_class: style used to render the MenuItems contained in menu; - default is None, which causes AHrefMenuItem to be used - """ - self._menu = menu - - # workaround for circular dependency between AHrefMenuItem and this class - if not item_class: - item_class = AHrefMenuItem - - self._item_class = item_class - - def getHtmlTags(self, indent): - """Returns list of HTML tags for arbitrarily nested items in the menu. - - Args: - indent: string prepended to the beginning of each line of output - (usually consists entirely of spaces) - - Returns: - a list of strings that can be joined with '\n' into a single string - to produce an entire
    ...
list in HTML - """ - tags = [] - - if self._menu.items: - tags.append(self.ITEM_PREFIX_FMT % {'indent': indent}) - - for item in self._menu.items: - tags.extend(self._item_class( - item, menu_class=self.__class__).getHtmlTags(indent + ' ')) - - tags.append(self.ITEM_SUFFIX_FMT % {'indent': indent}) - - return tags - - def __str__(self): - return '\n'.join(self.getHtmlTags('')) - - -class UlMenu(HtmlMenu): - """Ordered collection of MenuItem objects as a