Add functions for CSV export of organizations and roles.
Those CSV exports are used to create Google Code GSoC projects at the end of the program for students code submissions.
#!/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."""This module contains the Question Model."""__authors__ = [ '"Todd Larsen" <tlarsen@google.com>',]from google.appengine.ext import dbimport soc.models.workclass Question(soc.models.work.Work): """Model of a Question, which is a specialized form of Work. Specific types of Questions are actually implemented in subclasses. The specific way that the properties and relations inherited from Work are used with a Question are described below. work.title: the title of the Question, used for finding the Question in a list of Questions 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.content: the Question text, asked to the respondent linkable.scope: used to scope (and, when combined with linkable.link_id, uniquely identify) a Question in the same way the property are used with Documents, etc. linkable.link_id: used to identify (and, when combined with linkable.scope, *uniquely* identify) a Question in the same way these properties are used with Documents, etc. In addition to any explicit ReferenceProperties in the Question Model and those inherited as described above, a Question entity participates in these relationships: answers) a 1:many relationship, where each Question has many different Answers associated with it as parts of Responses to Quizzes. This is implemented as the 'answers' back-reference Query of the Answer model 'question' reference. It is currently unclear how useful this back-reference will be, since the same Question could be used in multiple different Quizzes. Given this, 'answers' currently only exists for completeness. quizzes) a many:many relationship between Questions and the Quizzes that collect them into a set. This relation is not explicitly implemented, but can be obtained via a query something like: quizzes_with_a_question = db.GqlQuery( "SELECT * FROM Quiz where questions = :1", a_question.key()) Such queries are probably only needed when a Question might be altered, in order to find which Quizzes will be affected. The properties in this Model do not have verbose_name or help_text, because the dynamic nature of the forms required to create, edit, and use entities of this Model make them pretty useless. ###################################################################### # TODO(tlarsen): the following verbose comments can be removed later, when these ideas are implemented in the views and controllers; they are here now so that the concepts will not be lost before that time. The recommended use for the combination of linkable.scope and linkable.link_id is to keep the *same* link_id when copying and modifying an existing Question for a new Program (or instance of a Group that is per-Program), while changing the linkable.scope to represent the Program and Group "ownership" of the Question. For example, if a Question asking about prior GSoC participation needed to have an additional choice (see the choice_ids and choices properties below), it is desirable to keep the same linkable.link_id (and also simply append new choice_ids and choices to keep the old answer values compatible). An existing Question in the above example might be identified as something like: Question:google/gsoc2009/gsoc_past_participation <type>:<Sponsor>/<Program>/<link_id> To make it possible to query for gsoc_past_participation answers regardless of the Program, the next year, new values are added to choice_ids and choices in a new Question copied from the one above, which would then be named something (still unique) like: Question:google/gsoc2010/gsoc_past_participation Care just needs to be taken to keep the existing choice_ids and choices compatible. Other interesting possibilities also exist, such as asking about GSoC participation of the GHOP participants (some GHOP high school students have actually previously been GSoC mentors, for example). To produce unique statistics for GHOP that could also be aggregated overall in combination with GSoC, the gsoc_past_participation Question would be duplicated (unaltered) to something like: Question:google/ghop2009/gsoc_past_participation To get the combined results, query on a link_id of gsoc_past_participation. For more targeted results, include the scope to make the query more specific. Question creation to permit use cases like the one above is going to be a bit of an "advanced" skill, possibly. "Doing it wrong" the first time a Question is created will make it difficult to implement stuff like multiple-choice Questions that "grow" new choices year-over-year. A dynamic form is most definitely going to be needed to implement the Question creation and editing for multiple-choice questions. """ #: db.ListProperty of short, plain-text, "link_id-like" strings #: representing the "encoded" answer choices (must be strings compatible #: with being query arguments and being used in HTML controls and POST #: responses). #: #: If empty (None or an empty list), it is assumed that this Question #: is *not* a multiple choice question. In that case, the UI should #: display the Question as a textarea in forms and accept any plain-text. #: #: If non-empty, max_answers helps determine how the UI should display #: the Question. Also, controller logic needs to validate if the #: strings in the 'answers' property of the Answer entity come only #: from this list. #: #: Once Answers to this Question have been stored in the Datastore, #: choice_ids and choices should *not* be modified. An existing #: Question can be duplicated and then modified (but, it will be a #: different question as a result). choice_ids = db.ListProperty(item_type=str) #: db.ListProperty of human-readable choice strings, in the same order #: as, and corresponding to, the "encoded" choices in the choice_ids #: db.ListProperty. choices = db.ListProperty(item_type=str) #: db.IntegerProperty indicating the maximum number of answer values #: permitted for this question. If 'choices' does not contain a list of #: choice strings, this value is ignored (but should still only be 1). #: #: If there are 'choices' and this value is 1, the UI should render the #: Question in forms as a single-choice control ("radio buttons"). #: #: If there are 'choices' and this value is greater than 1, the UI should #: render the question as a list of check-boxes. #: #: max_answers greater than 1 combined with choices enables Questions #: like, for example, "...select the three most important...". max_answers = db.IntegerProperty(default=1) #: field storing whether the Answer to a Question is optional is_optional = db.BooleanProperty(default=False)