# HG changeset patch # User Todd Larsen # Date 1224306697 0 # Node ID d94ec6f104ccac073d41f9d15617bb20c3c6c19e # Parent ce8b3a9fa0de4d7b76bdc4de6691b5935d8b0dd9 Refactor various site views into more generic locations, in preparation for using access permissions to decide the fuctionality in the view, instead of having lots of cut-and-paste copies of the same view functions. site/home.py into more generic home.py site/settings.py into more generic settings.py site/docs/list.py into more generic docs/list.py site/docs/edit.py into more generic docs/edit.py Patch by: Todd Larsen Review by: to-be-reviewed diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/logic/key_name.py --- a/app/soc/logic/key_name.py Sat Oct 18 04:56:39 2008 +0000 +++ b/app/soc/logic/key_name.py Sat Oct 18 05:11:37 2008 +0000 @@ -67,10 +67,10 @@ if not path: raise Error('"path" must be non-False: "%s"' % path) - return 'SiteSettings:%s' % path + return nameHomeSettings(path, entity_type='SiteSettings') -def nameHomeSettings(path): +def nameHomeSettings(path, entity_type='HomeSettings'): """Returns a HomeSettings key name constructed from a supplied path. Raises: @@ -79,7 +79,7 @@ if not path: raise Error('"path" must be non-False: "%s"' % path) - return 'HomeSettings:%s' % path + return '%s:%s' % (entity_type, path) def nameUser(email): diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/logic/site/map.py --- a/app/soc/logic/site/map.py Sat Oct 18 04:56:39 2008 +0000 +++ b/app/soc/logic/site/map.py Sat Oct 18 05:11:37 2008 +0000 @@ -30,15 +30,23 @@ from django.conf.urls import defaults from django.utils import datastructures +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.site.home.public'), + 'soc.views.home.public', + kwargs={ + 'path': models.site_settings.logic.DEF_SITE_SETTINGS_PATH, + 'entity_type': 'SiteSettings', + 'template': 'soc/site/home/public.html', + }), 'Google Open Source Programs', # it should be obvious that every page comes from the home page in_breadcrumb=False) @@ -91,7 +99,12 @@ site_home = page.Page( page.Url( r'^site/home$', - 'soc.views.site.home.public'), + 'soc.views.home.public', + kwargs={ + 'path': models.site_settings.logic.DEF_SITE_SETTINGS_PATH, + 'entity_type': 'SiteSettings', + 'template': 'soc/site/home/public.html', + }), 'Google Open Source Programs', # it should be obvious that every page comes from the home page in_breadcrumb=False) @@ -99,7 +112,11 @@ site_settings_edit = page.Page( page.Url( r'^site/settings/edit$', - 'soc.views.site.settings.edit'), + 'soc.views.settings.edit', + kwargs={ + 'path': models.site_settings.logic.DEF_SITE_SETTINGS_PATH, + 'logic': models.site_settings.logic, + }), 'Site: Settings', short_name='Site Settings', parent=home) @@ -160,32 +177,32 @@ site_docs_create = page.Page( page.Url( - r'^site/docs/edit$', - 'soc.views.site.docs.edit.create'), + r'^docs/edit$', + 'soc.views.docs.edit.create'), 'Site: Create New Document', 'Create Site Document', parent=site_docs_sub_menu) site_docs_edit = page.Page( page.Url( - r'^site/docs/edit/%s$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN, - 'soc.views.site.docs.edit.edit'), + r'^docs/edit/%s$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN, + 'soc.views.docs.edit.edit'), 'Site: Modify Existing Document', short_name='Modify Site Document', parent=site_docs_sub_menu) site_docs_delete = page.Page( page.Url( - r'^site/docs/%s/delete$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN, - 'soc.views.site.docs.edit.delete'), + r'^docs/delete/%s$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN, + 'soc.views.docs.edit.delete'), 'Site: Delete Existing Document', short_name='Delete Site Document', parent=site_docs_sub_menu) site_docs_list = page.Page( page.Url( - r'^site/docs/list$', - 'soc.views.site.docs.list.all'), + r'^docs/list$', + 'soc.views.docs.list.all'), 'Site: List of Documents', short_name='List Site Documents', parent=site_docs_sub_menu) diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/docs/edit.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/docs/edit.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,59 @@ +{% extends "soc/base.html" %} +{% comment %} +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. +{% endcomment %} + +{% block scripts %} + +{% endblock %} +{% block header_title %} +{{ page.short_name }} + {% if existing_doc %} + "{{ existing_doc.title }}" + {% endif %} +{% endblock %} + +{% block body %} +

+

+{% block instructions %} +Please use this form to edit the document. +{% endblock %} +

+
+ + {{ form.as_table }} + + + +
 
+ + + {% block submit_buttons %} + + + {% if existing_doc %} + + {% endif %} + {% endblock %} + +
+ + + + + +
+
+

+{% endblock %} diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/docs/list/all.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/docs/list/all.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,24 @@ +{% extends "soc/base.html" %} +{% comment %} +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. +{% endcomment %} +{% load forms_helpers %} +{% block body %} +

+

+{% block instructions %} +{% endblock %} +

+{% include list_main %} +

+{% endblock %} diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/docs/list/docs_heading.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/docs/list/docs_heading.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,9 @@ + + Path + Title + Linkname + Featured + Created By + Created On + Modified + diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/docs/list/docs_row.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/docs/list/docs_row.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,15 @@ + + +
+ {{ data_element.partial_path}}/{{ data_element.link_name }} +
+ +
{{ data_element.title }}
+ + +
{{ data_element.author.link_name }}
+
{{ data_element.created }}
+
{{ data_element.modified }}
+ diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/home/public.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/home/public.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,63 @@ +{% extends "soc/base.html" %} +{% comment %} +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. +{% endcomment %} + +{% block scripts %} +{% if home_settings.feed_url %} + + + +{% endif %} +{% endblock %} + +{% block page_title %} +{% if home_document %} +{{ home_document.title }} +{% else %} +{{ page.long_name }} +{% endif %} +{% endblock %} + +{% block header_title %} +{% if home_document %} +{{ home_document.short_name }} +{% else %} +{{ page.short_name }} +{% endif %} +{% endblock %} + +{% block body %} + {% if home_document %} + {{ home_document.content|safe }} +
Last updated on: {{ home_document.modified }}
+ {% else %} +{% block missing_doc %} +This is the default home page can be edited via Settings. +{% endblock %} +

+ {% endif %} + {% if home_settings.feed_url %} +

+ {% endif %} +{% endblock %} \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/settings/edit.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/settings/edit.html Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,111 @@ +{% extends "soc/base.html" %} +{% comment %} +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. +{% endcomment %} + +{% block body %} +

+

+{% block instructions %} +Please use this form to set basic home page settings. +{% endblock %} +

+

+

+
+ + {{ settings_form.as_table }} +{% if home_doc %} + + + +{% comment %} +TODO(tlarsen): OK, this is pretty lame as well. I think we need some sort + of "Document preview" that can be appended to the end of the page. Also, + There is way too much text on this page. Can a UI wizard please fix this + UI? +{% endcomment %} + + + + + + + + + + + + + + + + + + + + + + + +{% endif %} + + + + + + + {{ doc_select_form.as_table }} + + + +
 
+An existing Document is currently selected to provide the body contents of the home page: +
  + {{ home_doc.title }} +
Path: + {{ home_doc.partial_path }}/{{ home_doc.link_name }} +
Created By: + {{ home_doc.author.link_name }} +
Created On: + {{ home_doc.created }} +
Modified: + {{ home_doc.modified }} +
+

+ Any existing Document (to which access is permitted) can be used as the body contents of the home page. +

+Then, specify the Document to use below: +

+
 
 
+ + {% block submit_buttons %} + + + {% endblock %} + +
+ + + +
+
+

+{% endblock %} diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/docs/edit.html --- a/app/soc/templates/soc/site/docs/edit.html Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -{% extends "soc/base.html" %} -{% comment %} -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. -{% endcomment %} - -{% block scripts %} - -{% endblock %} -{% block header_title %} -{{ page.short_name }} - {% if existing_doc %} - "{{ existing_doc.title }}" - {% endif %} -{% endblock %} - -{% block body %} -

-

-{% block instructions %} -Please use this form to edit the document. -{% endblock %} -

-
- - {{ form.as_table }} - - - -
 
- - - {% block submit_buttons %} - - - {% if existing_doc %} - - {% endif %} - {% endblock %} - -
- - - - - -
-
-

-{% endblock %} diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/docs/list/all.html --- a/app/soc/templates/soc/site/docs/list/all.html Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -{% extends "soc/base.html" %} -{% comment %} -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. -{% endcomment %} -{% load forms_helpers %} -{% block body %} -

-

-{% block instructions %} -List of Documents in Google Open Source Programs. -{% endblock %} -

-{% include list_main %} -

-{% endblock %} \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/docs/list/docs_heading.html --- a/app/soc/templates/soc/site/docs/list/docs_heading.html Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - - Path - Title - Partial Path - Linkname - Featured - Created By - Created On - Modified - diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/docs/list/docs_row.html --- a/app/soc/templates/soc/site/docs/list/docs_row.html Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ - - -
- {{ data_element.partial_path}}/{{ data_element.link_name }} -
- -
{{ data_element.title }}
-
{{ data_element.partial_path }}
- - -
{{ data_element.author.link_name }}
-
{{ data_element.created }}
-
{{ data_element.modified }}
- diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/home/public.html --- a/app/soc/templates/soc/site/home/public.html Sat Oct 18 04:56:39 2008 +0000 +++ b/app/soc/templates/soc/site/home/public.html Sat Oct 18 05:11:37 2008 +0000 @@ -1,4 +1,4 @@ -{% extends "soc/base.html" %} +{% extends "soc/home/public.html" %} {% comment %} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,50 +13,10 @@ limitations under the License. {% endcomment %} -{% block scripts %} -{% if site_settings.feed_url %} - - - -{% endif %} -{% endblock %} - -{% block page_title %} -{% if site_document %} -{{ site_document.title }} -{% else %} -Default Title -{% endif %} -{% endblock %} - -{% block header_title %} -{% if site_document %} -{{ site_document.title }} -{% else %} -Default Header -{% endif %} -{% endblock %} - -{% block body %} - {% if site_document %} - {{ site_document.content|safe }} -
Last updated on: {{ site_document.modified }}
- {% else %} -This is the default site home page that can be configured via the Site Settings interface. -The Site Settings interface also provides a mechanism to select a feed to be displayed here. +{% block missing_doc %} +The contents of this default Site home page can be changed by editing the +site/home Document. +Other elements of this page, such as a feed to be displayed below this +content, can be set using the Site Settings interface. You need to sign in as site Developer in order to change Site Settings. - {% endif %} - {% if site_settings.feed_url %} -
- {% endif %} {% endblock %} \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/templates/soc/site/settings/edit.html --- a/app/soc/templates/soc/site/settings/edit.html Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -{% extends "soc/base.html" %} -{% comment %} -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. -{% endcomment %} - -{% block scripts %} - -{% endblock %} - -{% block page_title %}Site Settings{% endblock %} -{% block header_title %} -Site Settings -{% endblock %} - -{% block body %} -

-

-{% block instructions %} -Please use this form to set basic site settings. -{% endblock %} -

-
- - {{ document_form.as_table }} - {{ settings_form.as_table }} - - - -
 
- - {% block submit_buttons %} - - - {% endblock %} - -
- - - -
-
-

-{% endblock %} diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/docs/edit.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/views/docs/edit.py Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,331 @@ +#!/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() + if user: + email = user.email() + else: + email = None + + partial_path = form.cleaned_data.get('partial_path') + link_name = form.cleaned_data.get('link_name') + + properties = {} + properties['partial_path'] = partial_path + properties['link_name'] = link_name + 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.getFromFields(email=email) + properties['is_featured'] = form.cleaned_data.get('is_featured') + + doc = document.logic.updateOrCreateFromFields(properties, + partial_path=partial_path, + link_name=link_name) + return doc + + +class CreateForm(helper.forms.DbModelForm): + """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_partial_path(self): + partial_path = self.cleaned_data.get('partial_path') + # TODO(tlarsen): combine path and link_name and check for uniqueness + return partial_path + + def clean_link_name(self): + link_name = self.cleaned_data.get('link_name') + # TODO(tlarsen): combine path and link_name and check for uniqueness + return link_name + + +DEF_DOCS_CREATE_TMPL = 'soc/docs/edit.html' + +@decorators.view +def create(request, page=None, template=DEF_DOCS_CREATE_TMPL): + """View to create a new Document entity. + + Args: + request: the standard django request object + page: a soc.logic.site.page.Page object which is abstraction that combines + a Django view with sidebar menu info + 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'] = page + + 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.partial_path, doc.link_name]) + + # redirect to new /docs/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 name specified, so start with an empty form + form = CreateForm() + + context['form'] = form + + return helper.responses.respond(request, template, context) + + +DEF_DOCS_EDIT_TMPL = 'soc/docs/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=None, partial_path=None, link_name=None, + template=DEF_DOCS_EDIT_TMPL): + """View to modify the properties of a Document Model entity. + + Args: + request: the standard django request object + page: a soc.logic.site.page.Page object which is abstraction that combines + a Django view with sidebar menu info + partial_path: the Document's site-unique "path" extracted from the URL, + minus the trailing link_name + link_name: 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'] = page + + doc = None # assume that no Document entity will be found + + path = path_link_name.combinePath([partial_path, link_name]) + + # try to fetch Document entity corresponding to path if one exists + try: + if path: + doc = document.logic.getFromFields(partial_path=partial_path, + link_name=link_name) + 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, 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.partial_path, doc.link_name]) + + # redirect to new /docs/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_name = doc.author.link_name + form = EditForm(initial={'doc_key_name': doc.key().name(), + 'title': doc.title, 'partial_path': doc.partial_path, + 'link_name': doc.link_name, 'short_name': doc.short_name, + 'content': doc.content, 'author': doc.author, + 'is_featured': doc.is_featured, 'created_by': author_link_name}) + 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_name': link_name}) + else: # no link name 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 name specified, so start with an empty form + form = EditForm() + + context.update({'form': form, + 'existing_doc': doc}) + + return helper.responses.respond(request, template, context) + + +@decorators.view +def delete(request, page=None, partial_path=None, link_name=None, + template=DEF_DOCS_EDIT_TMPL): + """Request handler to delete Document Model entity. + + Args: + request: the standard django request object + page: a soc.logic.site.page.Page object which is abstraction that combines + a Django view with sidebar menu info + partial_path: the Document's site-unique "path" extracted from the URL, + minus the trailing link_name + link_name: 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/docs/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'] = page + + existing_doc = None + path = path_link_name.combinePath([partial_path, link_name]) + + # try to fetch Document entity corresponding to path if one exists + try: + if path: + existing_doc = document.logic.getFromFields(partial_path=partial_path, + link_name=link_name) + 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, error, template, context) + + if existing_doc: + document.logic.delete(existing_doc) + + return http.HttpResponseRedirect('/docs/list') diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/docs/list.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/views/docs/list.py Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,89 @@ +#!/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/docs/list/all.html' + + +@decorators.view +def all(request, page=None, templates={}): + """Show a list of all Documents (limit rows per page). + + Args: + request: the standard Django HTTP request object + page: a soc.logic.site.page.Page object which is abstraction that combines + a Django view with sidebar menu info + 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'] = page + + 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 + docs = 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/docs/list/docs_row.html'), + 'list_heading': templates.get('list_heading', + 'soc/docs/list/docs_heading.html'), + } + + context = helper.lists.setList( + request, context, docs, + 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 ce8b3a9fa0de -r d94ec6f104cc app/soc/views/group/__init__.py diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/home.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/views/home.py Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,76 @@ +#!/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. + +"""Base for all (Site, Group, etc.) home page views. + +public: how the general public sees a "home" page +""" + +__authors__ = [ + '"Todd Larsen" ', + '"Pawel Solyga" ', + ] + + +from google.appengine.ext import db + +from soc.logic import models +from soc.views import helper +from soc.views.helper import decorators + +import soc.logic.models.home_settings +import soc.views.helper.responses +import soc.views.helper.templates + + +DEF_HOME_PUBLIC_TMPL = 'soc/home/public.html' + +@decorators.view +def public(request, page=None, path=None, entity_type='HomeSettings', + template=DEF_HOME_PUBLIC_TMPL): + """How the "general public" sees a "home" page. + + Args: + request: the standard django request object. + page: a soc.logic.site.page.Page object which is abstraction that + combines a Django view with sidebar menu info + path: path (entire "scoped" portion combined with the link_name) + used to retrieve the Group's "home" settings + template: the template path to use for rendering the template. + + Returns: + A subclass of django.http.HttpResponse with generated template. + """ + # create default template context for use with any templates + context = helper.responses.getUniversalContext(request) + + settings = models.home_settings.logic.getFromFields( + path=path, entity_type=entity_type) + + if settings: + context['home_settings'] = settings + + # check if ReferenceProperty to home Document is valid + try: + home_doc = settings.home + except db.Error: + home_doc = None + + if home_doc: + home_doc.content = helper.templates.unescape(home_doc.content) + context['home_document'] = home_doc + + return helper.responses.respond(request, template, context=context) diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/settings.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/views/settings.py Sat Oct 18 05:11:37 2008 +0000 @@ -0,0 +1,182 @@ +#!/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. + +"""Home page settings views. + +edit: settings view for authorized Developers, Administrators, etc. +""" + +__authors__ = [ + '"Pawel Solyga" ', + '"Todd Larsen" ', + ] + + +from google.appengine.api import users +from google.appengine.ext import db + +from django import forms +from django.utils.translation import ugettext_lazy + +from soc.logic import models +from soc.logic import validate +from soc.logic.models import document +from soc.views import helper +from soc.views.helper import access +from soc.views.helper import decorators + +import soc.logic.models.home_settings +import soc.models.document +import soc.models.home_settings +import soc.models.work +import soc.views.helper.forms +import soc.views.helper.responses +import soc.views.helper.templates +import soc.views.helper.widgets +import soc.views.out_of_band + + +class SettingsForm(helper.forms.DbModelForm): + """Django form displayed when creating or editing Settings. + """ + + class Meta: + """Inner Meta class that defines some behavior for the form. + """ + #: db.Model subclass for which the form will gather information + model = soc.models.home_settings.HomeSettings + + #: list of model fields which will *not* be gathered by the form + exclude = ['inheritance_line', 'home'] + + def clean_feed_url(self): + feed_url = self.cleaned_data.get('feed_url') + + if feed_url == '': + # feed url not supplied (which is OK), so do not try to validate it + return None + + if not validate.isFeedURLValid(feed_url): + raise forms.ValidationError('This URL is not a valid ATOM or RSS feed.') + + return feed_url + + +class DocSelectForm(helper.forms.DbModelForm): + """Django form displayed to select a Document. + """ + + # TODO(tlarsen): partial_path will be a hard-coded read-only + # field for some (most?) User Roles + partial_path = forms.CharField(required=False, + label=soc.models.work.Work.partial_path.verbose_name, + help_text=soc.models.work.Work.partial_path.help_text) + + # TODO(tlarsen): actually, using these two text fields to specify + # the Document is pretty cheesy; this needs to be some much better + # Role-scoped Document selector that we don't have yet + link_name = forms.CharField(required=False, + label=soc.models.work.Work.link_name.verbose_name, + help_text=soc.models.work.Work.link_name.help_text) + + class Meta: + model = None + + +DEF_HOME_EDIT_TMPL = 'soc/settings/edit.html' + +@decorators.view +def edit(request, page=None, path=None, logic=models.home_settings.logic, + template=DEF_HOME_EDIT_TMPL): + """View for authorized User to edit contents of a home page. + + Args: + request: the standard django request object. + page: a soc.logic.site.page.Page object which is abstraction that + combines a Django view with sidebar menu info + template: the template path to use for rendering the template. + + Returns: + A subclass of django.http.HttpResponse with generated template. + """ + + try: + access.checkIsDeveloper(request) + except soc.views.out_of_band.AccessViolationResponse, alt_response: + # TODO(tlarsen): change this to just limit Settings paths that can be + # viewed or modified 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'] = page + + settings_form = None + doc_select_form = None + home_doc = None + + if request.method == 'POST': + settings_form = SettingsForm(request.POST) + doc_select_form = DocSelectForm(request.POST) + + if doc_select_form.is_valid() and settings_form.is_valid(): + fields = {'feed_url': settings_form.cleaned_data.get('feed_url')} + partial_path = doc_select_form.cleaned_data.get('partial_path') + link_name = doc_select_form.cleaned_data.get('link_name') + + home_doc = document.logic.getFromFields( + partial_path=partial_path, link_name=link_name) + + if home_doc: + fields['home'] = home_doc + context['notice'] = ugettext_lazy('Settings saved.') + else: + context['notice'] = ugettext_lazy('Document not specified or could not be found; other Settings saved.') + + settings = logic.updateOrCreateFromFields(fields, path=path) + + if settings.home: + home_doc = settings.home + else: # request.method == 'GET' + # try to fetch HomeSettings entity by unique key_name + settings = logic.getFromFields(path=path) + + if settings: + # populate form with the existing HomeSettings entity + settings_form = SettingsForm(instance=settings) + + # check if ReferenceProperty to home Document is valid + try: + home_doc = settings.home + except db.Error: + pass + + if home_doc: + doc_select_form = DocSelectForm(initial={ + 'partial_path': home_doc.partial_path, + 'link_name': home_doc.link_name}) + else: + doc_select_form = DocSelectForm() + else: + # no SiteSettings entity exists for this key_name, so show a blank form + settings_form = SettingsForm() + doc_select_form = DocSelectForm() + + context.update({'settings_form': settings_form, + 'doc_select_form': doc_select_form, + 'home_doc': home_doc}) + + return helper.responses.respond(request, template, context) diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/site/docs/__init__.py diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/site/docs/edit.py --- a/app/soc/views/site/docs/edit.py Sat Oct 18 04:56:39 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. - -"""Developer 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() - if user: - email = user.email() - else: - email = None - - partial_path = form.cleaned_data.get('partial_path') - link_name = form.cleaned_data.get('link_name') - - properties = {} - properties['partial_path'] = partial_path - properties['link_name'] = link_name - 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.getFromFields(email=email) - properties['is_featured'] = form.cleaned_data.get('is_featured') - - doc = document.logic.updateOrCreateFromFields(properties, - partial_path=partial_path, - link_name=link_name) - return doc - - -class CreateForm(helper.forms.DbModelForm): - """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_partial_path(self): - partial_path = self.cleaned_data.get('partial_path') - # TODO(tlarsen): combine path and link_name and check for uniqueness - return partial_path - - def clean_link_name(self): - link_name = self.cleaned_data.get('link_name') - # TODO(tlarsen): combine path and link_name and check for uniqueness - return link_name - - -DEF_SITE_DOCS_CREATE_TMPL = 'soc/site/docs/edit.html' - -@decorators.view -def create(request, page=None, template=DEF_SITE_DOCS_CREATE_TMPL): - """View for a Developer to create a new Document entity. - - Args: - request: the standard django request object - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - 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: - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page'] = page - - 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.partial_path, doc.link_name]) - - # redirect to new /site/docs/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 name specified, so start with an empty form - form = CreateForm() - - context['form'] = form - - return helper.responses.respond(request, template, context) - - -DEF_SITE_DOCS_EDIT_TMPL = 'soc/site/docs/edit.html' - -class EditForm(CreateForm): - """Django form displayed when Developer edits a Document. - """ - 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=None, partial_path=None, link_name=None, - template=DEF_SITE_DOCS_EDIT_TMPL): - """View for a Developer to modify the properties of a Document Model entity. - - Args: - request: the standard django request object - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - partial_path: the Document's site-unique "path" extracted from the URL, - minus the trailing link_name - link_name: 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: - return alt_response.response() - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page'] = page - - doc = None # assume that no Document entity will be found - - path = path_link_name.combinePath([partial_path, link_name]) - - # try to fetch Document entity corresponding to path if one exists - try: - if path: - doc = document.logic.getFromFields(partial_path=partial_path, - link_name=link_name) - 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, 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.partial_path, doc.link_name]) - - # redirect to new /site/docs/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_name = doc.author.link_name - form = EditForm(initial={'doc_key_name': doc.key().name(), - 'title': doc.title, 'partial_path': doc.partial_path, - 'link_name': doc.link_name, 'short_name': doc.short_name, - 'content': doc.content, 'author': doc.author, - 'is_featured': doc.is_featured, 'created_by': author_link_name}) - 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_name': link_name}) - else: # no link name 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 name specified, so start with an empty form - form = EditForm() - - context.update({'form': form, - 'existing_doc': doc}) - - return helper.responses.respond(request, template, context) - - -@decorators.view -def delete(request, page=None, partial_path=None, link_name=None, - template=DEF_SITE_DOCS_EDIT_TMPL): - """Request handler for a Developer to delete Document Model entity. - - Args: - request: the standard django request object - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - partial_path: the Document's site-unique "path" extracted from the URL, - minus the trailing link_name - link_name: 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/docs/list. - """ - - 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) - - existing_doc = None - path = path_link_name.combinePath([partial_path, link_name]) - - # try to fetch Document entity corresponding to path if one exists - try: - if path: - existing_doc = document.logic.getFromFields(partial_path=partial_path, - link_name=link_name) - 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, error, template, context) - - if existing_doc: - document.logic.delete(existing_doc) - - return http.HttpResponseRedirect('/site/docs/list') \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/site/docs/list.py --- a/app/soc/views/site/docs/list.py Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +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. - -"""Developer 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_SITE_DOCS_LIST_ALL_TMPL = 'soc/site/docs/list/all.html' - - -@decorators.view -def all(request, page=None, template=DEF_SITE_DOCS_LIST_ALL_TMPL): - """Show a list of all Documents (limit rows per page). - - Args: - request: the standard Django HTTP request object - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - 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'] = page - - 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 - docs = work.logic.getForLimitAndOffset(limit + 1, offset=offset) - - context['pagination_form'] = helper.lists.makePaginationForm(request, limit) - - list_templates = {'list_main': 'soc/list/list_main.html', - 'list_pagination': 'soc/list/list_pagination.html', - 'list_row': 'soc/site/docs/list/docs_row.html', - 'list_heading': 'soc/site/docs/list/docs_heading.html'} - - context = helper.lists.setList( - request, context, docs, - offset=offset, limit=limit, list_templates=list_templates) - - return helper.responses.respond(request, template, context) \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/site/home.py --- a/app/soc/views/site/home.py Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +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 Melange home page views. - -public: how the general public sees the site home page of a Melange - site -""" - -__authors__ = [ - '"Pawel Solyga" ', - ] - - -from google.appengine.ext import db - -from soc.logic import models -from soc.views import helper -from soc.views.helper import decorators - -import soc.logic.models.site_settings -import soc.views.helper.responses -import soc.views.helper.templates - - -DEF_SITE_HOME_PUBLIC_TMPL = 'soc/site/home/public.html' - -@decorators.view -def public(request, page=None, template=DEF_SITE_HOME_PUBLIC_TMPL): - """How the "general public" sees the Melange site home page. - - Args: - request: the standard django request object. - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - template: the template path to use for rendering the template. - - Returns: - A subclass of django.http.HttpResponse with generated template. - """ - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - context['page'] = page - - site_settings = models.site_settings.logic.getFromFields( - path=models.site_settings.logic.DEF_SITE_SETTINGS_PATH) - - if site_settings: - context['site_settings'] = site_settings - - # check if ReferenceProperty to home Document is valid - try: - site_doc = site_settings.home - except db.Error: - site_doc = None - - if site_doc: - site_doc.content = helper.templates.unescape(site_doc.content) - context['site_document'] = site_doc - - return helper.responses.respond(request, template, context=context) \ No newline at end of file diff -r ce8b3a9fa0de -r d94ec6f104cc app/soc/views/site/settings.py --- a/app/soc/views/site/settings.py Sat Oct 18 04:56:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +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 Melange home page views. - -public: how the general public sees the site home page of a Melange - site - -edit: site settings view for logged-in Developers -""" - -__authors__ = [ - '"Pawel Solyga" ', - ] - - -from google.appengine.api import users -from google.appengine.ext import db - -from django import forms - -from soc.logic import models -from soc.logic import validate -from soc.logic.models import document -from soc.views import helper -from soc.views.helper import access -from soc.views.helper import decorators - -import soc.logic.models.site_settings -import soc.models.document -import soc.models.site_settings -import soc.views.helper.forms -import soc.views.helper.responses -import soc.views.helper.templates -import soc.views.helper.widgets -import soc.views.out_of_band - - -class DocumentForm(helper.forms.DbModelForm): - content = forms.fields.CharField(widget=helper.widgets.TinyMCE( - attrs={'rows':10, 'cols':40})) - - class Meta: - """Inner Meta class that defines some behavior for the form. - """ - #: db.Model subclass for which the form will gather information - model = soc.models.document.Document - - #: list of model fields which will *not* be gathered by the form - exclude = ['partial_path', 'link_name', - 'author', 'modified', 'created', 'inheritance_line'] - - -class SiteSettingsForm(helper.forms.DbModelForm): - """Django form displayed when creating or editing Site Settings. - """ - class Meta: - """Inner Meta class that defines some behavior for the form. - """ - #: db.Model subclass for which the form will gather information - model = soc.models.site_settings.SiteSettings - - #: list of model fields which will *not* be gathered by the form - exclude = ['inheritance_line', 'home'] - - def clean_feed_url(self): - feed_url = self.cleaned_data.get('feed_url') - - if feed_url == '': - # feed url not supplied (which is OK), so do not try to validate it - return None - - if not validate.isFeedURLValid(feed_url): - raise forms.ValidationError('This URL is not a valid ATOM or RSS feed.') - - return feed_url - - -DEF_SITE_HOME_EDIT_TMPL = 'soc/site/settings/edit.html' - -@decorators.view -def edit(request, page=None, template=DEF_SITE_HOME_EDIT_TMPL): - """View for Developer to edit content of Melange site home page. - - Args: - request: the standard django request object. - page: a soc.logic.site.page.Page object which is abstraction that combines - a Django view with sidebar menu info - template: the template path to use for rendering the template. - - Returns: - A subclass of django.http.HttpResponse with generated template. - """ - - 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) - - settings_form = None - document_form = None - - if request.method == 'POST': - document_form = DocumentForm(request.POST) - settings_form = SiteSettingsForm(request.POST) - - if document_form.is_valid() and settings_form.is_valid(): - link_name = models.site_settings.logic.DEF_SITE_HOME_DOC_LINK_NAME - partial_path = models.site_settings.logic.DEF_SITE_SETTINGS_PATH - logged_in_id = users.get_current_user() - author = models.user.logic.getFromFields(email=logged_in_id.email()) - - properties = { - 'title': document_form.cleaned_data.get('title'), - 'short_name': document_form.cleaned_data.get('short_name'), - 'content': document_form.cleaned_data.get('content'), - 'link_name': link_name, - 'partial_path': partial_path, - 'id': logged_in_id, - 'author': author, - } - - site_doc = document.logic.updateOrCreateFromFields( - properties, partial_path=partial_path, link_name=link_name) - - feed_url = settings_form.cleaned_data.get('feed_url') - - site_settings = models.site_settings.logic.updateOrCreateFromFields( - {'feed_url': feed_url, 'home': site_doc}, - path=models.site_settings.logic.DEF_SITE_SETTINGS_PATH) - - context['notice'] = 'Site Settings saved.' - else: # request.method == 'GET' - # try to fetch SiteSettings entity by unique key_name - site_settings = models.site_settings.logic.getFromFields( - path=models.site_settings.logic.DEF_SITE_SETTINGS_PATH) - - if site_settings: - # populate form with the existing SiteSettings entity - settings_form = SiteSettingsForm(instance=site_settings) - - # check if ReferenceProperty to home Document is valid - try: - site_doc = site_settings.home - except db.Error: - site_doc = None - - else: - # no SiteSettings entity exists for this key_name, so show a blank form - settings_form = SiteSettingsForm() - site_doc = None - - if site_doc: - # populate form with the existing Document entity - document_form = DocumentForm(instance=site_doc) - else: - # no Document entity exists for this key_name, so show a blank form - document_form = DocumentForm() - - context.update({'document_form': document_form, - 'settings_form': settings_form }) - - return helper.responses.respond(request, template, context) \ No newline at end of file