Remove the proposed WorksAuthors many:many relation and promote the "founder"
authorTodd Larsen <tlarsen@google.com>
Wed, 15 Oct 2008 19:33:50 +0000
changeset 342 72482d8e5b34
parent 341 cad57d104bc7
child 343 1c96c36b58db
Remove the proposed WorksAuthors many:many relation and promote the "founder" property from Document up to Work. Update all subclasses of Work and any affected views accordingly. This addresses review comments here: http://code.google.com/p/soc/source/detail?r=786 Patch by: Todd Larsen Review by: to-be-reviewed
app/soc/models/document.py
app/soc/models/documentation.py
app/soc/models/proposal.py
app/soc/models/question.py
app/soc/models/quiz.py
app/soc/models/response.py
app/soc/models/work.py
app/soc/models/works_authors.py
app/soc/templates/soc/site/docs/list/docs_heading.html
app/soc/templates/soc/site/docs/list/docs_row.html
app/soc/views/site/docs/edit.py
app/soc/views/site/home.py
--- a/app/soc/models/document.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/document.py	Wed Oct 15 19:33:50 2008 +0000
@@ -21,13 +21,10 @@
 ]
 
 
-import polymodel
-
 from google.appengine.ext import db
 
 from django.utils.translation import ugettext_lazy
 
-import soc.models.user
 import soc.models.work
 
 
@@ -44,9 +41,6 @@
     work.abstract:  document summary displayed as a snippet in Document
       list views
 
-    work.authors:  the Authors of the Work referred to by this relation
-      are the authors of the Document
-
     work.reviews:  reviews of the Document by Reviewers
   """
 
@@ -55,12 +49,3 @@
   #: the content is only to be displayed to Persons in Roles eligible to
   #: view them (which may be anyone, for example, with the site front page).
   content = db.TextProperty(verbose_name=ugettext_lazy('Content'))
-  
-  #: TODO(pawel.solyga): replace this with WorkAuthors relation
-  #: Required many:1 relationship indicating the founding User of the
-  #: Document (this relationship is needed to keep track of lifetime document
-  #: creation limits, used to prevent spamming, etc.).
-  founder = db.ReferenceProperty(reference_class=soc.models.user.User,
-                                 required=True, collection_name="documents",
-                                 verbose_name=ugettext_lazy('Created by'))
-
--- a/app/soc/models/documentation.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/documentation.py	Wed Oct 15 19:33:50 2008 +0000
@@ -45,8 +45,8 @@
     just an indication that the required documentation was 
     supplied but is not actually attached.
 
-  work.authors: The Authors of the Work referred to by this 
-    relation are the Administrators (or Hosts) creating the
+  work.author: The author of the Work referred to by this 
+    relation is the Administrator (or Host) creating the
     Documentation.
 
   work.reviews: Annotations to the Documentation made by other
--- a/app/soc/models/proposal.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/proposal.py	Wed Oct 15 19:33:50 2008 +0000
@@ -24,10 +24,12 @@
 
 from google.appengine.ext import db
 
-import soc.models.work
+import soc.models.document
+import soc.models.quiz
+import soc.models.response
 
 
-class Proposal(soc.models.work.Work):
+class Proposal(soc.models.document.Document):
   """Model of a Proposal, which is a specific form of a Work.
 
   The specific way that the properties and relations inherited from Work
@@ -37,10 +39,11 @@
 
   work.abstract:  publicly displayed as a proposal abstract or summary
 
-  work.authors:  the Authors of the Work referred to by this relation
-    are the authors of the Proposal
+  work.reviews:  reviews of the Proposal by Reviewers
 
-  work.reviews:  reviews of the Proposal by Reviewers
+  document.content:  the details of the Proposal; which, unlike work.abstract
+    is considered "public" information, the contents of a Proposal are only
+    displayed to Persons in Roles that have a "need to know" those details.
 
   A Proposal entity participates in the following relationships implemented 
   as a db.ReferenceProperty elsewhere in another db.Model:
@@ -49,10 +52,15 @@
     Proposal as their foundation.  This relation is implemented as the
     'tasks' back-reference Query of the Task model 'proposal' reference.
   """
+  #: an optional many:1 relationship between Proposal and a Quiz that
+  #: defines what Questions were added by the prospective Proposal Reviewer
+  #: for the Proposal author to answer.
+  quiz = db.ReferenceProperty(reference_class=soc.models.quiz.Quiz,
+                              required=False, collection_name="proposals")
 
-  #: Required db.TextProperty describing the proposal in detail.
-  #: Unlike the work.abstract, which is considered "public" information,
-  #: the contents of 'details' is only to be displayed to Persons in Roles
-  #: that have a "need to know" the details.
-  details = db.TextProperty(required=True)
-
+  #: an optional 1:1 relationship where a Proposal author's Answers to
+  #: a Quiz attached to the Proposal template by the Proposal Reviewer
+  #; are collected. 
+  response = db.ReferenceProperty(
+      reference_class=soc.models.response.Response, required=False,
+      collection_name="proposal")
--- a/app/soc/models/question.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/question.py	Wed Oct 15 19:33:50 2008 +0000
@@ -39,17 +39,18 @@
 
     work.abstract:  the Question text, asked to the respondent
 
-    work.authors:  the Authors of the Work referred to by this relation
-      are the authors of the Question
+    work.author:  the author of the Work referred to by this relation
+      is the original author of the actual Question, regardless of
+      which Quizzes might incorporate the Question
 
     work.reviews:  even Questions can be "reviewed" (possibly commented
       on during creation or annotated once put into use).
 
-    work.partial_path: used to scope (and, when combined with
+    work.partial_path:  used to scope (and, when combined with
       work.link_name, uniquely identify) a Question in the same way the
       property are used with Documents, etc.
 
-    work.link_name: used to identify (and, when combined with
+    work.link_name:  used to identify (and, when combined with
       work.partial_path, *uniquely* identify) a Question in the same way
       these properties are used with Documents, etc.
       
--- a/app/soc/models/quiz.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/quiz.py	Wed Oct 15 19:33:50 2008 +0000
@@ -51,8 +51,8 @@
 
     work.abstract:  summary displayed as a snippet in Quiz list views
 
-    work.authors:  the Authors of the Work referred to by this relation
-      are the authors of the Quiz (but not necessarily the individual
+    work.author:  the author of the Work referred to by this relation
+      is the author of the Quiz (but not necessarily the individual
       Questions themselves, see the Question Model)
 
     work.reviews:  even Quizzes can be "reviewed" (possibly commented
@@ -85,6 +85,11 @@
       logic could check if a survey "passed" by querying for these
       "solution" Answers and seeing if the survey Response had the "right"
       Answers (to the one Question that matters in this case...).
+
+    proposals)  a 1:many relationship where each Quiz can produce all of
+      the Proposals that make use of the Quiz as part of the Proposal.
+      This relation is implemented as the 'proposals' back-reference Query
+      of the Proposal Model 'quiz' reference.
   """
   
   #: a many:many relationship (many:many because a given Question can be
--- a/app/soc/models/response.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/response.py	Wed Oct 15 19:33:50 2008 +0000
@@ -45,6 +45,11 @@
       The collection of Answers that make up a Response is implemented as
       the 'answers' back-reference Query of the Answer model 'response'
       reference.
+
+    proposal)  an optional 1:1 relationship where a Proposal placed its
+      Answers to a Quiz associated with the Proposal.  This relation is
+      implemented as the 'proposal' back-reference Query of the Proposal
+      Model 'response' reference.
   """
 
   #: a required many:1 relationship between Responses and a Quiz that
--- a/app/soc/models/work.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/models/work.py	Wed Oct 15 19:33:50 2008 +0000
@@ -21,11 +21,14 @@
   '"Sverre Rabbelier" <sverre@rabbelier.nl>',
 ]
 
+
+import polymodel
+
 from google.appengine.ext import db
 
 from django.utils.translation import ugettext_lazy
 
-import polymodel
+import soc.models.user
 
 
 class Work(polymodel.PolyModel):
@@ -34,14 +37,16 @@
   Work is a "base entity" of other more specific "works" created by Persons
   serving in "roles".
 
-   authors)  a many:many relationship with Roles, stored in a separate
-     WorksAuthors model, used to represent authorship of the Work.  See
-     the WorksAuthors model class for details.
-
-   reviews)  a 1:many relationship between a Work and the zero or more
-     Reviews of that Work.  This relation is implemented as the 'reviews'
-     back-reference Query of the Review model 'reviewed' reference.
+    reviews)  a 1:many relationship between a Work and the zero or more
+      Reviews of that Work.  This relation is implemented as the 'reviews'
+      back-reference Query of the Review model 'reviewed' reference.
   """
+  #: Required 1:1 relationship indicating the User who initially authored the
+  #: Work (this relationship is needed to keep track of lifetime document
+  #: creation limits, used to prevent spamming, etc.).
+  author = db.ReferenceProperty(reference_class=soc.models.user.User,
+                                 required=True, collection_name="documents",
+                                 verbose_name=ugettext_lazy('Created by'))
 
   #: Required field indicating the "title" of the work, which may have
   #: different uses depending on the specific type of the work. Works
--- a/app/soc/models/works_authors.py	Wed Oct 15 18:06:07 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.
-
-"""The WorksAuthors Model links one author (Role) to one Work."""
-
-__authors__ = [
-  '"Todd Larsen" <tlarsen@google.com>',
-]
-
-
-from google.appengine.ext import db
-
-import soc.models.role
-import soc.models.work
-
-
-class WorksAuthors(db.Model):
-  """Model linking one Work to its author Role.
-  """
-
-  #: the Role end of a single 1:1 link in the many:many relationship
-  #: between Works and Roles
-  author = db.ReferenceProperty(reference_class=soc.models.role.Role,
-                                required=True, collection_name='authors')
-
-  #: the Work end of a single 1:1 link in the many:many relationship
-  #: between Works and Roles
-  work = db.ReferenceProperty(reference_class=soc.models.work.Work,
-                              required=True, collection_name='works')
-
--- a/app/soc/templates/soc/site/docs/list/docs_heading.html	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/templates/soc/site/docs/list/docs_heading.html	Wed Oct 15 19:33:50 2008 +0000
@@ -4,6 +4,7 @@
   <th>Partial Path</th>
   <th>Linkname</th>
   <th>Featured</th>
-  <th>Created</th>
+  <th>Created By</th>
+  <th>Created On</th>
   <th>Modified</th>
 </tr>
--- a/app/soc/templates/soc/site/docs/list/docs_row.html	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/templates/soc/site/docs/list/docs_row.html	Wed Oct 15 19:33:50 2008 +0000
@@ -10,6 +10,7 @@
   <td><div class="partial_path">{{ data_element.partial_path }}</div></td>
   <td><div class="link_name">{{ data_element.link_name }}</div></td>
   <td><div class="featured">{{ data_element.is_featured }}</div></td>
+  <td><div class="author">{{ data_element.author.link_name }}</div></td>
   <td><div class="created">{{ data_element.created }}</div></td>
   <td><div class="modified">{{ data_element.modified }}</div></td>
 </tr>
--- a/app/soc/views/site/docs/edit.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/views/site/docs/edit.py	Wed Oct 15 19:33:50 2008 +0000
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.5
+#founder!/usr/bin/python2.5
 #
 # Copyright 2008 the Melange authors.
 #
@@ -75,7 +75,7 @@
   properties['short_name'] = form.cleaned_data.get('short_name')
   properties['abstract'] = form.cleaned_data.get('abstract')
   properties['content'] = form.cleaned_data.get('content')
-  properties['founder'] = models.user.logic.getFromFields(email=email)
+  properties['author'] = models.user.logic.getFromFields(email=email)
   properties['is_featured'] = form.cleaned_data.get('is_featured')
 
   doc = document.logic.updateOrCreateFromFields(properties,
@@ -94,7 +94,7 @@
     model = soc.models.document.Document
 
     #: list of model fields which will *not* be gathered by the form
-    exclude = ['inheritance_line', 'founder', 'created', 'modified']
+    exclude = ['inheritance_line', 'author', 'created', 'modified']
 
   def clean_partial_path(self):
     partial_path = self.cleaned_data.get('partial_path')
@@ -240,13 +240,13 @@
                 values=SUBMIT_MESSAGES))
 
         # populate form with the existing Document entity
-        founder_link_name = doc.founder.link_name
+        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,
             'abstract': doc.abstract, 'content': doc.content,
-            'founder': doc.founder, 'is_featured': doc.is_featured,
-            'created_by': founder_link_name})       
+            '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
--- a/app/soc/views/site/home.py	Wed Oct 15 18:06:07 2008 +0000
+++ b/app/soc/views/site/home.py	Wed Oct 15 19:33:50 2008 +0000
@@ -65,7 +65,7 @@
     
     #: list of model fields which will *not* be gathered by the form
     exclude = ['partial_path', 'link_name',
-               'founder', 'modified', 'created', 'inheritance_line']
+               'author', 'modified', 'created', 'inheritance_line']
 
 
 class SiteSettingsForm(helper.forms.DbModelForm):
@@ -162,7 +162,7 @@
       link_name = DEF_SITE_HOME_DOC_LINK_NAME
       partial_path=DEF_SITE_SETTINGS_PATH
       logged_in_id = users.get_current_user()
-      founder = models.user.logic.getFromFields(email=logged_in_id.email())
+      author = models.user.logic.getFromFields(email=logged_in_id.email())
 
       properties = {
         'title': document_form.cleaned_data.get('title'),
@@ -172,7 +172,7 @@
         'link_name': link_name,
         'partial_path': partial_path,
         'id': logged_in_id,
-        'founder': founder,
+        'author': author,
       }
 
       site_doc = document.logic.updateOrCreateFromFields(