Style and too long lines fixes in soc.models.role module.
[Melange.git] / app / soc / models / role.py
blob53bf1a2193a2b05eaceb8cd82715067039fdbeb2
1 #!/usr/bin/python2.5
3 # Copyright 2008 the Melange authors.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """This module contains the Role Model."""
19 __authors__ = [
20 '"Todd Larsen" <tlarsen@google.com>',
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
22 '"Pawel Solyga" <pawel.solyga@gmail.com>',
26 from google.appengine.ext import db
28 from django.utils.translation import ugettext
30 from soc.models import countries
32 import soc.models.linkable
33 import soc.models.user
36 class Role(soc.models.linkable.Linkable):
37 """Information common to Program participation for all Roles.
39 Some details of a Role are considered "public" information, and nearly
40 all of these are optional (except for given_name, surname, and email).
41 Other details of a Role are kept "private" and are only provided to
42 other Users in roles that "need to know" this information. How these
43 fields are revealed is usually covered by Program terms of service.
45 Role is the entity that is created when a User actually participates
46 in some fashion in a Program. Role details could *possibly* be collected
47 without actual participation (voluntary, opt-in, of course).
49 A Role is a User's participation in a single Program. To avoid
50 duplication of data entry, facilities will be available for selecting
51 an existing Role associated with a particular User to be duplicated for
52 participation in a new Program.
54 A User has to have at least one Role in order to be able to create
55 any Work (such as a Document) on the site. The easiest-to-obtain Role is
56 probably Club Member (though Clubs can set their own membership criteria).
58 A Role entity participates in the following relationships implemented
59 as a db.ReferenceProperty elsewhere in another db.Model:
61 documentation) a 1:many relationship of Documentation (tax forms,
62 letters from schools, etc.) associated with the Role by Hosts. This
63 relation is implemented as the 'documentation' back-reference Query of
64 the Documentation model 'role' reference.
66 works) a many:many relationship with Works, stored in a separate
67 WorksRoles model, representing the Work authored by this Role.
68 See the WorksRoles model class for details.
69 """
71 #: A required many:1 relationship that ties (possibly multiple
72 #: entities of) Role details to a unique User. A Role cannot
73 #: exist unassociated from a login identity and credentials. The
74 #: back-reference in the User model is a Query named 'roles'.
75 user = db.ReferenceProperty(reference_class=soc.models.user.User,
76 required=True, collection_name='roles')
79 #====================================================================
80 # (public) name information
81 #====================================================================
83 #: Required field storing the parts of the Role's name
84 #: corresponding to the field names; displayed publicly.
85 #: given_name can only be lower ASCII, not UTF-8 text, because it is
86 #: used, for example, as part of the shipping (mailing) address.
87 given_name = db.StringProperty(required=True,
88 verbose_name=ugettext('First (given) name'))
89 given_name.help_text = ugettext('lower ASCII characters only')
90 given_name.group = ugettext("1. Public Info")
92 #: Required field storing the parts of the Role's name
93 #: corresponding to the field names; displayed publicly.
94 #: Surname can only be lower ASCII, not UTF-8 text, because it is
95 #: used, for example, as part of the shipping (mailing) address.
96 surname = db.StringProperty(
97 required=True,
98 verbose_name=ugettext('Last (family) name'))
99 surname.help_text = ugettext('lower ASCII characters only')
100 surname.group = ugettext("1. Public Info")
102 #: Optional field used as a display name, such as for awards
103 #: certificates. Should be the entire name in the format
104 #: the Role would like it displayed (could be surname followed by
105 #: given name in some cultures, for example). Display names can be
106 #: any valid UTF-8 text.
107 name_on_documents = db.StringProperty(
108 verbose_name=ugettext('Name on documents'))
109 name_on_documents.help_text = ugettext(
110 'Optional field used as a display name, such as for documents like '
111 'awards certificates. Should be the entire name in the format '
112 'the person would like it displayed (could be family name followed '
113 'by given name in some cultures, for example). Name on documents can be '
114 'any valid UTF-8 text.')
115 name_on_documents.group = ugettext("1. Public Info")
117 #====================================================================
118 # (public) contact information
119 #====================================================================
121 #: Required field used as the 'public' contact mechanism for the
122 #: Role (as opposed to the user.account email address which is
123 #: kept secret).
124 email = db.EmailProperty(
125 required=True,
126 verbose_name=ugettext('Email Address'))
127 email.group = ugettext("1. Public Info")
129 #: Optional field storing Instant Messaging network; displayed publicly.
130 im_network = db.StringProperty(
131 verbose_name=ugettext('IM Network'))
132 im_network.help_text = ugettext(
133 'examples: irc:irc.freenode.net xmpp:gmail.com/Home')
134 im_network.group = ugettext("1. Public Info")
136 #: Optional field storing Instant Messaging handle; displayed publicly.
137 im_handle = db.StringProperty(
138 verbose_name=ugettext('IM Handle'))
139 im_handle.help_text = ugettext(
140 'personal identifier, such as: screen name, IRC nick, user name')
141 im_handle.group = ugettext("1. Public Info")
143 #: Optional field storing a home page URL; displayed publicly.
144 home_page = db.LinkProperty(
145 verbose_name=ugettext('Home Page URL'))
146 home_page.group = ugettext("1. Public Info")
148 #: Optional field storing a blog URL; displayed publicly.
149 blog = db.LinkProperty(
150 verbose_name=ugettext('Blog URL'))
151 blog.group = ugettext("1. Public Info")
153 #: Optional field storing a URL to an image, expected to be a
154 #: personal photo (or cartoon avatar, perhaps); displayed publicly.
155 photo_url = db.LinkProperty(
156 verbose_name=ugettext('Thumbnail Photo URL'))
157 photo_url.help_text = ugettext(
158 'URL of 64x64 pixel thumbnail image')
159 photo_url.group = ugettext("1. Public Info")
161 #: Optional field storing the latitude provided by the Role; displayed
162 #: publicly.
163 latitude = db.FloatProperty(
164 verbose_name=ugettext('Latitude'))
165 latitude.help_text = ugettext(
166 'decimal degrees northerly (N), use minus sign (-) for southerly (S)')
167 latitude.group = ugettext("1. Public Info")
169 #: Optional field storing the longitude provided by the Role; displayed
170 #: publicly.
171 longitude = db.FloatProperty(
172 verbose_name=ugettext('Longitude'))
173 longitude.help_text = ugettext(
174 'decimal degrees easterly (E), use minus sign (-) for westerly (W)')
175 longitude.group = ugettext("1. Public Info")
177 #====================================================================
178 # (private) contact information
179 #====================================================================
181 #: Required field containing residence street address; kept private.
182 #: Residence street address can only be lower ASCII, not UTF-8 text, because
183 #: it may be used as a shipping address.
184 res_street = db.StringProperty(required=True,
185 verbose_name=ugettext('Street address'))
186 res_street.help_text = ugettext(
187 'street number and name, lower ASCII characters only')
188 res_street.group = ugettext("2. Contact Info (Private)")
190 #: Required field containing residence address city; kept private.
191 #: Residence city can only be lower ASCII, not UTF-8 text, because it
192 #: may be used as a shipping address.
193 res_city = db.StringProperty(required=True,
194 verbose_name=ugettext('City'))
195 res_city.help_text = ugettext('lower ASCII characters only')
196 res_city.group = ugettext("2. Contact Info (Private)")
198 #: Optional field containing residence address state or province; kept
199 #: private. Residence state/province can only be lower ASCII, not UTF-8
200 #: text, because it may be used as a shipping address.
201 res_state = db.StringProperty(
202 verbose_name=ugettext('State/Province'))
203 res_state.help_text = ugettext(
204 'optional if country/territory does not have states or provinces, '
205 'lower ASCII characters only')
206 res_state.group = ugettext("2. Contact Info (Private)")
208 #: Required field containing residence address country or territory; kept
209 #: private.
210 res_country = db.StringProperty(required=True,
211 verbose_name=ugettext('Country/Territory'),
212 choices=countries.COUNTRIES_AND_TERRITORIES)
213 res_country.group = ugettext("2. Contact Info (Private)")
215 #: Required field containing residence address postal code (ZIP code in
216 #: the United States); kept private. Residence postal code can only be
217 #: lower ASCII, not UTF-8 text, because it may be used as a shipping address.
218 res_postalcode = db.StringProperty(required=True,
219 verbose_name=ugettext('ZIP/Postal Code'))
220 res_postalcode.help_text = ugettext('lower ASCII characters only')
221 res_postalcode.group = ugettext("2. Contact Info (Private)")
223 #: Required field containing a phone number that will be used to
224 #: contact the user, also supplied to shippers; kept private.
225 phone = db.PhoneNumberProperty(
226 required=True,
227 verbose_name=ugettext('Phone Number'))
228 phone.help_text = ugettext(
229 'include complete international calling number with country code')
230 phone.group = ugettext("2. Contact Info (Private)")
232 #: field storing whether the User has agreed to publish his location
233 publish_location = db.BooleanProperty(required=False, default=False,
234 verbose_name=ugettext('Publish my location'))
235 publish_location.help_text = ugettext(
236 'Indicates whether the user agreed to publish location.')
237 publish_location.group = ugettext("2. Contact Info (Private)")
239 #: Optional field containing a separate shipping street address; kept
240 #: private. If shipping address is not present in its entirety, the
241 #: residence address will be used instead. Shipping street address can only
242 #: be lower ASCII, not UTF-8 text, because, if supplied, it is used as a
243 #: shipping address.
244 ship_street = db.StringProperty(
245 verbose_name=ugettext('Shipping Street address'))
246 ship_street.help_text = ugettext(
247 'street number and name, lower ASCII characters only, '
248 'fill in only if not same as above')
249 ship_street.group = ugettext("3. Shipping Info (Private and Optional)")
251 #: Optional field containing shipping address city; kept private.
252 #: Shipping city can only be lower ASCII, not UTF-8 text, because, if
253 #: supplied, it is used as a shipping address.
254 ship_city = db.StringProperty(
255 verbose_name=ugettext('Shipping City'))
256 ship_city.help_text = ugettext('lower ASCII characters only'
257 'fill in only if not same as above')
258 ship_city.group = ugettext("3. Shipping Info (Private and Optional)")
260 #: Optional field containing shipping address state or province; kept
261 #: private. Shipping state/province can only be lower ASCII, not UTF-8
262 #: text, because, if supplied, it is used as a shipping address.
263 ship_state = db.StringProperty(
264 verbose_name=ugettext('Shipping State/Province'))
265 ship_state.help_text = ugettext(
266 'optional if country/territory does not have states or provinces, '
267 'lower ASCII characters only, fill in only if not same as above')
268 ship_state.group = ugettext("3. Shipping Info (Private and Optional)")
270 #: Optional field containing shipping address country or territory; kept
271 #: private.
272 ship_country = db.StringProperty(
273 verbose_name=ugettext('Shipping Country/Territory'),
274 choices=countries.COUNTRIES_AND_TERRITORIES)
275 ship_country.help_text = ugettext('fill in only if not same as above')
276 ship_country.group = ugettext("3. Shipping Info (Private and Optional)")
278 #: Optional field containing shipping address postal code (ZIP code in
279 #: the United States); kept private. Shipping postal code can only be
280 #: lower ASCII, not UTF-8 text, because, if supplied, it is used as a
281 #: shipping address.
282 ship_postalcode = db.StringProperty(
283 verbose_name=ugettext('Shipping ZIP/Postal Code'))
284 ship_postalcode.help_text = ugettext('lower ASCII characters only'
285 'fill in only if not same as above')
286 ship_postalcode.group = ugettext("3. Shipping Info (Private and Optional)")
289 #====================================================================
290 # (private) personal information
291 #====================================================================
293 #: Required field containing the Role's birthdate (for
294 #: determining Program participation eligibility); kept private.
295 birth_date = db.DateProperty(
296 required=True,
297 verbose_name=ugettext('Birth Date'))
298 birth_date.help_text = ugettext(
299 'required for determining program eligibility')
300 birth_date.group = ugettext("4. Private Info")
302 #: Optional field indicating choice of t-shirt, from XXS to XXXL;
303 #: kept private.
304 tshirt_size = db.StringProperty(
305 verbose_name=ugettext('T-shirt Size'),
306 choices=('XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'))
307 tshirt_size.group = ugettext("4. Private Info")
309 #: Optional field indicating choice of t-shirt fit; kept private.
310 tshirt_style = db.StringProperty(
311 verbose_name=ugettext('T-shirt Style'),
312 choices=('male', 'female'))
313 tshirt_style.group = ugettext("4. Private Info")
315 #: field storing wheter the User has agreed to the site-wide Terms of Service.
316 #: (Not a required field because the Terms of Service might not be present
317 #: when the first User profile is created when bootstrapping the site.)
318 agreed_to_tos = db.BooleanProperty(required=False, default=False,
319 verbose_name=ugettext('I Agree to the Terms of Service'))
320 agreed_to_tos.help_text = ugettext(
321 'Indicates whether the user agreed to this role Terms of Service.')
322 agreed_to_tos.group = ugettext("5. Terms of Service")
324 #: field storing when the User has agreed to the site-wide Terms of Service.
325 #: (Not a required field because the Terms of Service might not be present
326 #: when the first User profile is created when bootstrapping the site.)
327 agreed_to_tos_on = db.DateTimeProperty(required=False, default=None,
328 verbose_name=ugettext('Has agreed to the Terms of Service on'))
329 agreed_to_tos_on.help_text = ugettext(
330 'Indicates when the user agreed to this role Terms of Service.')
331 agreed_to_tos.group = ugettext("5. Terms of Service")
333 #: field storing the status of this role
334 #: Active means that this role can exercise all it's privileges.
335 #: Invalid mean that this role cannot exercise it's privileges.
336 #: Inactive means that this role cannot exercise it's data-editing
337 #: privileges but should be able to see the data. For instance when a program
338 #: has been marked inactive an Organization Admin should still be able to see
339 #: the student applications.
340 status = db.StringProperty(default='active',
341 choices=['active','invalid','inactive'],
342 verbose_name=ugettext('Status of this Role'))
343 status.help_text = ugettext('Indicates the status of the role '
344 'concerning which privileges may be used.')
346 def name(self):
347 """Property as 'name' for use in common templates.
349 if self.name_on_documents:
350 return self.name_on_documents
351 else:
352 return '%s %s' % (self.given_name, self.surname)