| 1 | #!/usr/bin/python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | """ |
|---|
| 4 | Forma |
|---|
| 5 | |
|---|
| 6 | Copyright (c) 2006-2012 Guillaume Pellerin <yomguy@parisson.com> |
|---|
| 7 | |
|---|
| 8 | # This software is governed by the CeCILL license under French law and |
|---|
| 9 | # abiding by the rules of distribution of free software. You can use, |
|---|
| 10 | # modify and/ or redistribute the software under the terms of the CeCILL |
|---|
| 11 | # license as circulated by CEA, CNRS and INRIA at the following URL |
|---|
| 12 | # "http://www.cecill.info". |
|---|
| 13 | |
|---|
| 14 | # As a counterpart to the access to the source code and rights to copy, |
|---|
| 15 | # modify and redistribute granted by the license, users are provided only |
|---|
| 16 | # with a limited warranty and the software's author, the holder of the |
|---|
| 17 | # economic rights, and the successive licensors have only limited |
|---|
| 18 | # liability. |
|---|
| 19 | |
|---|
| 20 | # In this respect, the user's attention is drawn to the risks associated |
|---|
| 21 | # with loading, using, modifying and/or developing or reproducing the |
|---|
| 22 | # software by the user in light of its specific status of free software, |
|---|
| 23 | # that may mean that it is complicated to manipulate, and that also |
|---|
| 24 | # therefore means that it is reserved for developers and experienced |
|---|
| 25 | # professionals having in-depth computer knowledge. Users are therefore |
|---|
| 26 | # encouraged to load and test the software's suitability as regards their |
|---|
| 27 | # requirements in conditions enabling the security of their systems and/or |
|---|
| 28 | # data to be ensured and, more generally, to use and operate it in the |
|---|
| 29 | # same conditions as regards security. |
|---|
| 30 | |
|---|
| 31 | # The fact that you are presently reading this means that you have had |
|---|
| 32 | # knowledge of the CeCILL license and that you accept its terms. |
|---|
| 33 | |
|---|
| 34 | # Author: Guillaume Pellerin <yomguy@parisson.com> |
|---|
| 35 | """ |
|---|
| 36 | |
|---|
| 37 | import os |
|---|
| 38 | import re |
|---|
| 39 | import pwd |
|---|
| 40 | import time |
|---|
| 41 | import urllib |
|---|
| 42 | import datetime |
|---|
| 43 | import mimetypes |
|---|
| 44 | import django.db.models as models |
|---|
| 45 | from django.db.models import * |
|---|
| 46 | from django.forms import ModelForm, TextInput, Textarea |
|---|
| 47 | from django.utils.translation import ugettext_lazy as _ |
|---|
| 48 | from django.contrib.auth.models import User |
|---|
| 49 | from django.core.exceptions import ValidationError |
|---|
| 50 | from telemeta.fields import * |
|---|
| 51 | from telemeta.models.core import * |
|---|
| 52 | from telemeta.models.media import * |
|---|
| 53 | |
|---|
| 54 | |
|---|
| 55 | app_label = 'forma' |
|---|
| 56 | |
|---|
| 57 | n_sessions = 21 |
|---|
| 58 | session_choices = [(str(x), str(y)) for x in range(1, n_sessions) for y in range(1, n_sessions) if x == y] |
|---|
| 59 | |
|---|
| 60 | |
|---|
| 61 | class Organization(ModelCore): |
|---|
| 62 | |
|---|
| 63 | name = CharField(_('name'), max_length=255) |
|---|
| 64 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 65 | |
|---|
| 66 | def __str__(self): |
|---|
| 67 | return self.name |
|---|
| 68 | |
|---|
| 69 | class Meta(MetaCore): |
|---|
| 70 | db_table = app_label + '_' + 'organization' |
|---|
| 71 | verbose_name = _('organization') |
|---|
| 72 | |
|---|
| 73 | class Department(ModelCore): |
|---|
| 74 | |
|---|
| 75 | name = CharField(_('name'), max_length=255) |
|---|
| 76 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 77 | organization = ForeignKey('Organization', related_name='department', verbose_name=_('organization')) |
|---|
| 78 | |
|---|
| 79 | def __str__(self): |
|---|
| 80 | return self.name |
|---|
| 81 | |
|---|
| 82 | class Meta(MetaCore): |
|---|
| 83 | db_table = app_label + '_' + 'department' |
|---|
| 84 | verbose_name = _('department') |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | class Category(ModelCore): |
|---|
| 88 | |
|---|
| 89 | name = CharField(_('name'), max_length=255) |
|---|
| 90 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 91 | |
|---|
| 92 | def __str__(self): |
|---|
| 93 | return self.name |
|---|
| 94 | |
|---|
| 95 | class Meta(MetaCore): |
|---|
| 96 | db_table = app_label + '_' + 'category' |
|---|
| 97 | verbose_name = _('category') |
|---|
| 98 | verbose_name_plural = _('categories') |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | class Course(ModelCore): |
|---|
| 102 | |
|---|
| 103 | department = ForeignKey('Department', related_name='course', verbose_name=_('department')) |
|---|
| 104 | title = CharField(_('title'), max_length=255) |
|---|
| 105 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 106 | category = ForeignKey('Category', related_name='course', verbose_name=_('category')) |
|---|
| 107 | public_id = CharField(_('public_id'), max_length=255, blank=True) |
|---|
| 108 | |
|---|
| 109 | def __str__(self): |
|---|
| 110 | return self.department.name + ' - ' + self.category.name + ' - ' + self.title |
|---|
| 111 | |
|---|
| 112 | class Meta(MetaCore): |
|---|
| 113 | db_table = app_label + '_' + 'course' |
|---|
| 114 | verbose_name = _('course') |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | class Professor(ModelCore): |
|---|
| 118 | |
|---|
| 119 | user = ForeignKey(User, related_name='professor', verbose_name=_('user'), unique=True) |
|---|
| 120 | courses = ManyToManyField('Course', related_name="professor", verbose_name=_('courses'), |
|---|
| 121 | blank=True, null=True) |
|---|
| 122 | |
|---|
| 123 | def __str__(self): |
|---|
| 124 | return self.user.username |
|---|
| 125 | |
|---|
| 126 | class Meta(MetaCore): |
|---|
| 127 | db_table = app_label + '_' + 'professor' |
|---|
| 128 | verbose_name = _('professor') |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | class Room(ModelCore): |
|---|
| 132 | |
|---|
| 133 | organization = ForeignKey('Organization', related_name='room', verbose_name=_('organization')) |
|---|
| 134 | name = CharField(_('name'), max_length=255) |
|---|
| 135 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 136 | |
|---|
| 137 | def __str__(self): |
|---|
| 138 | return self.organization.name + ' - ' + self.name |
|---|
| 139 | |
|---|
| 140 | class Meta(MetaCore): |
|---|
| 141 | db_table = app_label + '_' + 'room' |
|---|
| 142 | verbose_name = _('room') |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | class Conference(ModelCore): |
|---|
| 146 | |
|---|
| 147 | course = ForeignKey('Course', related_name='conference', verbose_name=_('course')) |
|---|
| 148 | professor = ForeignKey('Professor', related_name='conference', verbose_name=_('professor')) |
|---|
| 149 | session = CharField(_('session'), choices=session_choices, |
|---|
| 150 | max_length=16, default="1") |
|---|
| 151 | room = ForeignKey('Room', related_name='conference', verbose_name=_('room'), |
|---|
| 152 | null=True, blank=True) |
|---|
| 153 | comment = CharField(_('comment'), max_length=255, blank=True) |
|---|
| 154 | date_begin = DateTimeField(_('begin date'), null=True, blank=True) |
|---|
| 155 | date_end = DateTimeField(_('end date'), null=True, blank=True) |
|---|
| 156 | |
|---|
| 157 | @property |
|---|
| 158 | def description(self): |
|---|
| 159 | return self.course.department.name + ' - ' + self.course.title + ' - ' + \ |
|---|
| 160 | self.professor.user.first_name + ' - ' + \ |
|---|
| 161 | self.professor.user.last_name + ' - ' + str(self.date_begin) |
|---|
| 162 | |
|---|
| 163 | def __str__(self): |
|---|
| 164 | return self.description |
|---|
| 165 | |
|---|
| 166 | class Meta(MetaCore): |
|---|
| 167 | db_table = app_label + '_' + 'conference' |
|---|
| 168 | verbose_name = _('conference') |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | class MediaBase(ModelCore): |
|---|
| 172 | "Base media resource" |
|---|
| 173 | |
|---|
| 174 | credits = CharField(_('credits'), max_length=255, blank=True) |
|---|
| 175 | is_published = BooleanField(_('published')) |
|---|
| 176 | date_added = DateTimeField(_('date added'), auto_now_add=True) |
|---|
| 177 | date_modified = DateTimeField(_('date modified'), auto_now=True) |
|---|
| 178 | |
|---|
| 179 | def get_fields(self): |
|---|
| 180 | return self._meta.fields |
|---|
| 181 | |
|---|
| 182 | class Meta(MetaCore): |
|---|
| 183 | abstract = True |
|---|
| 184 | ordering = ['date_added'] |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | class Document(MediaBase): |
|---|
| 188 | |
|---|
| 189 | element_type = 'document' |
|---|
| 190 | |
|---|
| 191 | title = CharField(_('title'), max_length=255, blank=True) |
|---|
| 192 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 193 | code = CharField(_('code'), max_length=255, blank=True) |
|---|
| 194 | course = ForeignKey('Course', related_name='document', verbose_name='course') |
|---|
| 195 | conference = ForeignKey('Conference', related_name='document', verbose_name=_('conference'), |
|---|
| 196 | blank=True, null=True) |
|---|
| 197 | is_annal = BooleanField(_('annal')) |
|---|
| 198 | file = FileField(_('file'), upload_to='items/%Y/%m/%d', db_column="filename", blank=True) |
|---|
| 199 | |
|---|
| 200 | def is_image(self): |
|---|
| 201 | is_url_image = False |
|---|
| 202 | if self.url: |
|---|
| 203 | url_types = ['.png', '.jpg', '.gif', '.jpeg'] |
|---|
| 204 | for type in url_types: |
|---|
| 205 | if type in self.url or type.upper() in self.url: |
|---|
| 206 | is_url_image = True |
|---|
| 207 | return 'image' in self.mime_type or is_url_image |
|---|
| 208 | |
|---|
| 209 | def set_mime_type(self): |
|---|
| 210 | if self.file: |
|---|
| 211 | self.mime_type = mimetypes.guess_type(self.file.path)[0] |
|---|
| 212 | |
|---|
| 213 | def __str__(self): |
|---|
| 214 | if self.title and not re.match('^ *N *$', self.title): |
|---|
| 215 | return self.title |
|---|
| 216 | else: |
|---|
| 217 | return unicode(self.title) |
|---|
| 218 | |
|---|
| 219 | class Meta(MetaCore): |
|---|
| 220 | db_table = app_label + '_' + 'document' |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | class Media(MediaBase): |
|---|
| 224 | "Describe a media resource linked to a conference and a telemeta item" |
|---|
| 225 | |
|---|
| 226 | element_type = 'media' |
|---|
| 227 | |
|---|
| 228 | conference = ForeignKey('Conference', related_name='media', verbose_name=_('conference')) |
|---|
| 229 | item = ForeignKey(MediaItem, related_name='media', |
|---|
| 230 | verbose_name='item', blank=True, null=True) |
|---|
| 231 | is_live = BooleanField(_('is live')) |
|---|
| 232 | |
|---|
| 233 | def __unicode__(self): |
|---|
| 234 | description = self.conference.description |
|---|
| 235 | if self.item: |
|---|
| 236 | return description + ' _ ' + self.item.title |
|---|
| 237 | else: |
|---|
| 238 | return description |
|---|
| 239 | |
|---|
| 240 | class Meta(MetaCore): |
|---|
| 241 | db_table = app_label + '_' + 'media' |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | # STUDENT |
|---|
| 245 | |
|---|
| 246 | class IEJ(ModelCore): |
|---|
| 247 | |
|---|
| 248 | name = CharField(_('name'), max_length=255) |
|---|
| 249 | description = CharField(_('description'), max_length=255, blank=True) |
|---|
| 250 | |
|---|
| 251 | def __str__(self): |
|---|
| 252 | return self.name |
|---|
| 253 | |
|---|
| 254 | class Meta(MetaCore): |
|---|
| 255 | db_table = app_label + '_' + 'iej' |
|---|
| 256 | verbose_name = _('IEJ') |
|---|
| 257 | verbose_name_plural = _('IEJ') |
|---|
| 258 | |
|---|
| 259 | |
|---|
| 260 | class Training(ModelCore): |
|---|
| 261 | |
|---|
| 262 | name = CharField(_('name'), max_length=255, blank=True) |
|---|
| 263 | courses = ManyToManyField('Course', related_name="training", verbose_name=_('courses'), |
|---|
| 264 | blank=True, null=True) |
|---|
| 265 | |
|---|
| 266 | def __str__(self): |
|---|
| 267 | return self.name |
|---|
| 268 | |
|---|
| 269 | class Meta(MetaCore): |
|---|
| 270 | db_table = app_label + '_' + 'training' |
|---|
| 271 | verbose_name = _('training') |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | class Procedure(ModelCore): |
|---|
| 275 | |
|---|
| 276 | name = CharField(_('name'), max_length=255, blank=True) |
|---|
| 277 | |
|---|
| 278 | def __str__(self): |
|---|
| 279 | return self.name |
|---|
| 280 | |
|---|
| 281 | class Meta(MetaCore): |
|---|
| 282 | db_table = app_label + '_' + 'procedure' |
|---|
| 283 | verbose_name = _('procedure') |
|---|
| 284 | |
|---|
| 285 | |
|---|
| 286 | class Speciality(ModelCore): |
|---|
| 287 | |
|---|
| 288 | name = CharField(_('name'), max_length=255, blank=True) |
|---|
| 289 | |
|---|
| 290 | def __str__(self): |
|---|
| 291 | return self.name |
|---|
| 292 | |
|---|
| 293 | class Meta(MetaCore): |
|---|
| 294 | db_table = app_label + '_' + 'speciality' |
|---|
| 295 | verbose_name = _('speciality') |
|---|
| 296 | |
|---|
| 297 | |
|---|
| 298 | class Student(ModelCore): |
|---|
| 299 | |
|---|
| 300 | user = ForeignKey(User, related_name='student', verbose_name=_('user'), unique=True ) |
|---|
| 301 | category = ForeignKey('Category', related_name='student', verbose_name=_('category')) |
|---|
| 302 | iej = ForeignKey('IEJ', related_name='student', verbose_name=_('iej')) |
|---|
| 303 | training = ForeignKey('Training', related_name='student', |
|---|
| 304 | verbose_name='training', blank=True, null=True) |
|---|
| 305 | procedure = ForeignKey('Procedure', related_name='student', |
|---|
| 306 | verbose_name='procedure', blank=True, null=True) |
|---|
| 307 | oral_speciality = ForeignKey('Speciality', related_name='student_oral_spe', |
|---|
| 308 | verbose_name='oral speciality', blank=True, null=True) |
|---|
| 309 | written_speciality = ForeignKey('Speciality', related_name='student_written_spe', |
|---|
| 310 | verbose_name='written speciality', blank=True, null=True) |
|---|
| 311 | oral_1 = CharField(_('oral 1'), max_length=255, blank=True) |
|---|
| 312 | oral_2 = CharField(_('oral 2'), max_length=255, blank=True) |
|---|
| 313 | |
|---|
| 314 | |
|---|
| 315 | def __str__(self): |
|---|
| 316 | return self.user.username |
|---|
| 317 | |
|---|
| 318 | class Meta(MetaCore): |
|---|
| 319 | db_table = app_label + '_' + 'student' |
|---|
| 320 | verbose_name = _('student') |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | class Profile(models.Model): |
|---|
| 324 | "User profile extension" |
|---|
| 325 | |
|---|
| 326 | user = ForeignKey(User, related_name='profile', verbose_name=_('user'), unique=True) |
|---|
| 327 | address = TextField(_('Address')) |
|---|
| 328 | postal_code = CharField(_('Postal code'), max_length=255) |
|---|
| 329 | city = CharField(_('City'), max_length=255) |
|---|
| 330 | country = CharField(_('Country'), max_length=255, blank=True) |
|---|
| 331 | language = CharField(_('Language'), max_length=255, blank=True) |
|---|
| 332 | telephone = CharField(_('Telephone'), max_length=255, blank=True) |
|---|
| 333 | expiration_date = DateField(_('Expiration_date'), blank=True, null=True) |
|---|
| 334 | init_password = BooleanField(_('Password initialization')) |
|---|
| 335 | |
|---|
| 336 | class Meta(MetaCore): |
|---|
| 337 | db_table = app_label + '_' + 'profiles' |
|---|
| 338 | verbose_name = _('profile') |
|---|
| 339 | |
|---|