From: yomguy Date: Tue, 9 Oct 2012 17:04:02 +0000 (+0200) Subject: add first seminar model X-Git-Tag: 0.9-probarreau~346^2~10 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=294b73a45c619b007e1cda2baa8a97d69b36ab19;p=teleforma.git add first seminar model --- diff --git a/teleforma/__init__.py b/teleforma/__init__.py old mode 100755 new mode 100644 diff --git a/teleforma/models.py b/teleforma/models.py deleted file mode 100755 index ca97430d..00000000 --- a/teleforma/models.py +++ /dev/null @@ -1,720 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -""" - teleforma - - Copyright (c) 2006-2012 Guillaume Pellerin - -# This software is governed by the CeCILL license under French law and -# abiding by the rules of distribution of free software. You can use, -# modify and/ or redistribute the software under the terms of the CeCILL -# license as circulated by CEA, CNRS and INRIA at the following URL -# "http://www.cecill.info". - -# As a counterpart to the access to the source code and rights to copy, -# modify and redistribute granted by the license, users are provided only -# with a limited warranty and the software's author, the holder of the -# economic rights, and the successive licensors have only limited -# liability. - -# In this respect, the user's attention is drawn to the risks associated -# with loading, using, modifying and/or developing or reproducing the -# software by the user in light of its specific status of free software, -# that may mean that it is complicated to manipulate, and that also -# therefore means that it is reserved for developers and experienced -# professionals having in-depth computer knowledge. Users are therefore -# encouraged to load and test the software's suitability as regards their -# requirements in conditions enabling the security of their systems and/or -# data to be ensured and, more generally, to use and operate it in the -# same conditions as regards security. - -# The fact that you are presently reading this means that you have had -# knowledge of the CeCILL license and that you accept its terms. - -# Author: Guillaume Pellerin -""" - -import os -import re -import pwd -import time -import urllib -import string -import datetime -import mimetypes -import telemeta -import django.db.models as models -from django.db.models import * -from django.forms import ModelForm, TextInput, Textarea -from django.utils.translation import ugettext_lazy as _ -from django.contrib.auth.models import User -from django.core.exceptions import ValidationError -from django.contrib.contenttypes import generic -from notes.models import Note -import jqchat.models -from django.core.paginator import InvalidPage, EmptyPage -from django.template.defaultfilters import slugify -import django.db.models as models -from south.modelsinspector import add_introspection_rules -from telemeta.models import * - -app_label = 'teleforma' - -n_sessions = 21 -session_choices = [(str(x), str(y)) for x in range(1, n_sessions) for y in range(1, n_sessions) if x == y] -server_choices = [('icecast', 'icecast'), ('stream-m', 'stream-m')] -streaming_choices = [('mp3', 'mp3'), ('ogg', 'ogg'), ('webm', 'webm'), ('mp4', 'mp4')] -mimetypes.add_type('video/webm','.webm') - - -class ShortTextField(models.TextField): - - def formfield(self, **kwargs): - kwargs.update( - {"widget": Textarea(attrs={'rows':2, 'cols':40})} - ) - return super(ShortTextField, self).formfield(**kwargs) - -add_introspection_rules([], ["^teleforma\.models\.ShortTextField"]) - - -class Organization(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - - def __unicode__(self): - return self.name - - class Meta: - db_table = app_label + '_' + 'organization' - verbose_name = _('organization') - -class Department(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - organization = ForeignKey('Organization', related_name='department', - verbose_name=_('organization')) - domain = CharField(_('Master domain'), max_length=255, blank=True) - - def __unicode__(self): - return self.name - - @property - def slug(self): - return slugify(self.__unicode__()) - - class Meta: - db_table = app_label + '_' + 'department' - verbose_name = _('department') - - -class Period(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - - def __unicode__(self): - return self.name - - class Meta: - db_table = app_label + '_' + 'period' - verbose_name = _('period') - -class CourseType(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - - def __unicode__(self): - return self.name - - class Meta: - db_table = app_label + '_' + 'course_type' - verbose_name = _('course type') - -class Course(Model): - - department = ForeignKey('Department', related_name='course', - verbose_name=_('department')) - title = CharField(_('title'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - code = CharField(_('code'), max_length=255) - date_modified = DateTimeField(_('date modified'), auto_now=True) - number = IntegerField(_('number'), blank=True, null=True) - synthesis_note = BooleanField(_('synthesis note')) - obligation = BooleanField(_('obligations')) - magistral = BooleanField(_('magistral')) - - notes = generic.GenericRelation(Note) - - def __unicode__(self): - return self.title - - @property - def slug(self): - return slugify(self.__unicode__()) - - class Meta: - db_table = app_label + '_' + 'course' - verbose_name = _('course') - ordering = ['number'] - - -class Professor(Model): - - user = ForeignKey(User, related_name='professor', - verbose_name=_('user'), unique=True) - courses = ManyToManyField('Course', related_name="professor", - verbose_name=_('courses'), - blank=True, null=True) - - def __unicode__(self): - return self.user.first_name + ' ' + self.user.last_name - - class Meta: - db_table = app_label + '_' + 'professor' - verbose_name = _('professor') - - -class Room(Model): - - organization = ForeignKey('Organization', related_name='room', verbose_name=_('organization')) - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - - def __unicode__(self): - return self.organization.name + ' - ' + self.name - - class Meta: - db_table = app_label + '_' + 'room' - verbose_name = _('room') - - -class Conference(Model): - - public_id = CharField(_('public_id'), max_length=255, blank=True) - course = ForeignKey('Course', related_name='conference', verbose_name=_('course')) - course_type = ForeignKey('CourseType', related_name='conference', verbose_name=_('course type')) - professor = ForeignKey('Professor', related_name='conference', verbose_name=_('professor'), - blank=True, null=True, on_delete=models.SET_NULL) - session = CharField(_('session'), choices=session_choices, - max_length=16, default="1") - room = ForeignKey('Room', related_name='conference', verbose_name=_('room'), - null=True, blank=True) - comment = ShortTextField(_('comment'), max_length=255, blank=True) - date_begin = DateTimeField(_('begin date'), null=True, blank=True) - date_end = DateTimeField(_('end date'), null=True, blank=True) - readers = ManyToManyField(User, related_name="conference", verbose_name=_('readers'), - blank=True, null=True) - - notes = generic.GenericRelation(Note) - - @property - def description(self): - if self.professor: - list = [self.course.department.name, self.course.title, - self.course_type.name, self.session, - self.professor.user.first_name, - self.professor.user.last_name, - str(self.date_begin)] - else: - list = [self.course.department.name, self.course.title, - self.course_type.name, self.session, - str(self.date_begin)] - return ' - '.join(list) - - @property - def slug(self): - slug = '-'.join([self.course.department.slug, - self.course.slug, - self.course_type.name.lower()]) - return slug - - def __unicode__(self): - return self.description - - def save(self, **kwargs): - self.course.save() - super(Conference, self).save(**kwargs) - - - def to_dict(self): - dict = [{'id':'public_id','value': self.public_id, 'class':'', 'label':'public_id'}, - {'id':'organization','value': self.course.department.organization, 'class':'', 'label':'Organization'}, - {'id': 'department', 'value': self.course.department , 'class':'', 'label':'Department'}, - {'id': 'professor', 'value': self.professor, 'class':'' , 'label': 'Professor'}, - {'id': 'session', 'value': self.session, 'class':'' , 'label': 'Session'}, - {'id': 'comment', 'value': self.comment, 'class':'' , 'label': 'Comment'}, - ] - return dict - - def to_json_dict(self): - data = {'id': self.public_id, 'course_code': self.course.code, - 'course_type': self.course_type.name, 'professor_id': self.professor.user.username, - 'session': self.session, - 'streams':[] } - - if self.room: - data['room'] = self.room.name - data['organization'] = self.room.organization.name - - streams = self.livestream.all() - if streams: - for stream in streams: - data['streams'].append({'host': stream.server.host, - 'port': stream.server.port, - 'server_type': stream.server.type, - 'stream_type': stream.stream_type }) - return data - - class Meta: - db_table = app_label + '_' + 'conference' - verbose_name = _('conference') - ordering = ['-date_begin'] - - -class StreamingServer(Model): - - element_type = 'streamingserver' - - host = CharField(_('host'), max_length=255) - port = CharField(_('port'), max_length=32) - type = CharField(_('type'), choices=server_choices, max_length=32) - description = CharField(_('description'), max_length=255, blank=True) - source_password = CharField(_('source password'), max_length=32) - admin_password = CharField(_('admin password'), max_length=32, blank=True) - - def __unicode__(self): - return self.host + ':' + self.port + ' - ' + self.type - - class Meta: - db_table = app_label + '_' + 'streaming_server' - verbose_name = _('streaming server') - - -class LiveStream(Model): - - element_type = 'livestream' - - conference = ForeignKey('Conference', related_name='livestream', - verbose_name=_('conference'), - blank=True, null=True, on_delete=models.SET_NULL) - server = ForeignKey('StreamingServer', related_name='livestream', - verbose_name=_('streaming server')) - stream_type = CharField(_('Streaming type'), - choices=streaming_choices, max_length=32) - streaming = BooleanField(_('streaming')) - - @property - def slug(self): - slug = '-'.join([self.conference.course.department.slug, - self.conference.course.slug, - self.conference.course_type.name.lower()]) - return slug - - @property - def mount_point(self): - if self.server.type == 'stream-m': - return 'consume/' + self.slug - else: - return self.slug + '.' + self.stream_type - - @property - def snapshot_url(self): - url = '' - if self.server.type == 'stream-m': - url = 'http://' + self.server.host + ':' + self.server.port + \ - '/snapshot/' + self.slug - return url - - @property - def url(self): - return 'http://' + self.server.host + ':' + self.server.port + '/' + self.mount_point - - def __unicode__(self): - if self.conference: - return self.conference.description - else: - return self.slug - - class Meta: - db_table = app_label + '_' + 'live_stream' - verbose_name = _('live stream') - - -class MediaBase(Model): - "Base media resource" - - title = CharField(_('title'), max_length=255, blank=True) - description = CharField(_('description'), max_length=255, blank=True) - credits = CharField(_('credits'), max_length=255, blank=True) - date_added = DateTimeField(_('date added'), auto_now_add=True) - date_modified = DateTimeField(_('date modified'), auto_now=True) - code = CharField(_('code'), max_length=255, blank=True) - is_published = BooleanField(_('published')) - mime_type = CharField(_('mime type'), blank=True) - notes = generic.GenericRelation(Note) - - def get_fields(self): - return self._meta.fields - - class Meta: - abstract = True - - -class DocumentType(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - number = IntegerField(_('number'), blank=True, null=True) - - def __unicode__(self): - return self.name - - class Meta: - db_table = app_label + '_' + 'document_type' - verbose_name = _('document type') - ordering = ['number'] - - -class Document(MediaBase): - - element_type = 'document' - - course = ForeignKey('Course', related_name='document', verbose_name=_('course')) - course_type = ManyToManyField('CourseType', related_name='document', - verbose_name=_('course type'), blank=True, null=True) - conference = ForeignKey('Conference', related_name='document', verbose_name=_('conference'), - blank=True, null=True, on_delete=models.SET_NULL) - type = ForeignKey('DocumentType', related_name='document', verbose_name=_('type'), - blank=True, null=True) - is_annal = BooleanField(_('annal')) - file = FileField(_('file'), upload_to='items/%Y/%m/%d', db_column="filename", blank=True) - readers = ManyToManyField(User, related_name="document", verbose_name=_('readers'), - blank=True, null=True) - - def is_image(self): - is_url_image = False - if self.url: - url_types = ['.png', '.jpg', '.gif', '.jpeg'] - for type in url_types: - if type in self.url or type.upper() in self.url: - is_url_image = True - return 'image' in self.mime_type or is_url_image - - def set_mime_type(self): - self.mime_type = mimetypes.guess_type(self.file.path)[0] - - def __unicode__(self): - types = ' - '.join([unicode(t) for t in self.course_type.all()]) - return ' - '.join([unicode(self.course), unicode(types), self.title ]) - - def set_read(self, user): - pass - - def get_read(self, user): - return user in self.readers - - def save(self, **kwargs): - self.course.save() - self.set_mime_type() - super(Document, self).save(**kwargs) - - class Meta: - db_table = app_label + '_' + 'document' - ordering = ['-date_added'] - - -class Media(MediaBase): - "Describe a media resource linked to a conference and a telemeta item" - - element_type = 'media' - - conference = ForeignKey('Conference', related_name='media', verbose_name=_('conference'), - blank=True, null=True, on_delete=models.SET_NULL) - course = ForeignKey('Course', related_name='media', verbose_name=_('course'), - blank=True, null=True) - course_type = ForeignKey('CourseType', related_name='media', verbose_name=_('course type'), - blank=True, null=True) - item = ForeignKey(MediaItem, related_name='media', - verbose_name='item', blank=True, null=True) - type = CharField(_('type'), choices=streaming_choices, max_length=32) - readers = ManyToManyField(User, related_name="media", verbose_name=_('readers'), - blank=True, null=True) - - def set_mime_type(self): - if self.item.file: - mime_type = mimetypes.guess_type(self.item.file.path)[0] - if mime_type == 'audio/mpeg': - self.mime_type = 'audio/mp3' - else: - self.mime_type = mime_type - self.save() - - def __unicode__(self): - if self.conference: - return self.conference.description - elif self.course: - return self.course.title + ' ' + self.course_type.name - else: - return self.item.file - - def save(self, **kwargs): - if self.course: - self.course.save() - elif self.conference: - self.conference.course.save() - super(Media, self).save(**kwargs) - - - class Meta: - db_table = app_label + '_' + 'media' - ordering = ['-date_modified'] - - -# STUDENT - -class IEJ(Model): - - name = CharField(_('name'), max_length=255) - description = CharField(_('description'), max_length=255, blank=True) - - def __unicode__(self): - return self.name - - class Meta: - db_table = app_label + '_' + 'iej' - verbose_name = _('IEJ') - verbose_name_plural = _('IEJ') - ordering = ['name'] - - -class Training(Model): - - code = CharField(_('code'), max_length=255) - name = CharField(_('name'), max_length=255, blank=True) - period = ForeignKey('Period', related_name='training', verbose_name=_('period'), - blank=True, null=True) - synthesis_note = ManyToManyField('CourseType', related_name="training_synthesis_note", - verbose_name=_('synthesis note'), - blank=True, null=True) - obligation = ManyToManyField('CourseType', related_name="training_obligation", - verbose_name=_('obligations'), - blank=True, null=True) - procedure = ManyToManyField('CourseType', related_name="training_procedure", - verbose_name=_('procedure'), - blank=True, null=True) - written_speciality = ManyToManyField('CourseType', related_name="training_written_speciality", - verbose_name=_('written speciality'), - blank=True, null=True) - oral_speciality = ManyToManyField('CourseType', related_name="training_oral_speciality", - verbose_name=_('oral speciality'), - blank=True, null=True) - oral_1 = ManyToManyField('CourseType', related_name="training_oral_1", - verbose_name=_('oral 1'), - blank=True, null=True) - oral_2 = ManyToManyField('CourseType', related_name="training_oral_2", - verbose_name=_('oral 2'), - blank=True, null=True) - options = ManyToManyField('CourseType', related_name="training_options", - verbose_name=_('options'), - blank=True, null=True) - magistral = ManyToManyField('CourseType', related_name="training_magistral", - verbose_name=_('magistral'), - blank=True, null=True) - cost = FloatField(_('cost'), blank=True, null=True) - - def __unicode__(self): - code = self.code - if self.period: - code += ' - ' + self.period.name - return code - - class Meta: - db_table = app_label + '_' + 'training' - verbose_name = _('training') - - -class Student(Model): - - user = ForeignKey(User, related_name='student', verbose_name=_('user'), unique=True ) - period = ManyToManyField('Period', related_name='student', verbose_name=_('period'), - blank=True, null=True) - iej = ForeignKey('IEJ', related_name='student', verbose_name=_('iej'), - blank=True, null=True, on_delete=models.SET_NULL) - training = ForeignKey('Training', related_name='student', verbose_name=_('training')) - platform_only = BooleanField(_('platform only')) - procedure = ForeignKey('Course', related_name="procedure", - verbose_name=_('procedure'), - blank=True, null=True) - written_speciality = ForeignKey('Course', related_name="written_speciality", - verbose_name=_('written speciality'), - blank=True, null=True) - oral_speciality = ForeignKey('Course', related_name="oral_speciality", - verbose_name=_('oral speciality'), - blank=True, null=True) - oral_1 = ForeignKey('Course', related_name="oral_1", verbose_name=_('oral 1'), - blank=True, null=True) - oral_2 = ForeignKey('Course', related_name="oral_2", verbose_name=_('oral 2'), - blank=True, null=True) - options = ForeignKey('Course', related_name="options", verbose_name=_('options'), - blank=True, null=True) - - def __unicode__(self): - try: - return self.user.last_name + ' ' + self.user.first_name - except: - return '' - - class Meta: - db_table = app_label + '_' + 'student' - verbose_name = _('student') - ordering = ['user__last_name'] - - -class Profile(models.Model): - "User profile extension" - - user = ForeignKey(User, related_name='profile', verbose_name=_('user'), unique=True) - address = TextField(_('Address'), blank=True) - postal_code = CharField(_('Postal code'), max_length=255, blank=True) - city = CharField(_('City'), max_length=255, blank=True) - country = CharField(_('Country'), max_length=255, blank=True) - language = CharField(_('Language'), max_length=255, blank=True) - telephone = CharField(_('Telephone'), max_length=255, blank=True) - expiration_date = DateField(_('Expiration_date'), blank=True, null=True) - init_password = BooleanField(_('Password initialized')) - - class Meta: - db_table = app_label + '_' + 'profiles' - verbose_name = _('profile') - - -class Payment(models.Model): - "Student payment" - - student = ForeignKey(Student, related_name="payment", verbose_name=_('student')) - amount = FloatField(_('amount')) - date_added = DateTimeField(_('date added'), auto_now_add=True) - - def __unicode__(self): - return ' - '.join([str(self.date_added), self.student.user.last_name + ' ' + \ - self.student.user.first_name, str(self.amount)]) - - class Meta: - db_table = app_label + '_' + 'payment' - verbose_name = _('payment') - ordering = ['-date_added'] - - -# TOOLS -class NamePaginator(object): - """Pagination for string-based objects""" - - def __init__(self, object_list, on=None, per_page=25): - self.object_list = object_list - self.count = len(object_list) - self.pages = [] - - # chunk up the objects so we don't need to iterate over the whole list for each letter - chunks = {} - - for obj in self.object_list: - if on: - obj_str = getattr(obj, on).encode('utf8') - else: - obj_str = obj.encode('utf8') - - if len(obj_str): - letter = str.upper(obj_str[0]) - else: - letter = '' - - if letter not in chunks: - chunks[letter] = [] - - chunks[letter].append(obj) - - # the process for assigning objects to each page - current_page = NamePage(self) - - for letter in string.ascii_uppercase: - if letter not in chunks: - current_page.add([], letter) - continue - - sub_list = chunks[letter] # the items in object_list starting with this letter - - new_page_count = len(sub_list) + current_page.count - # first, check to see if sub_list will fit or it needs to go onto a new page. - # if assigning this list will cause the page to overflow... - # and an underflow is closer to per_page than an overflow... - # and the page isn't empty (which means len(sub_list) > per_page)... - if new_page_count > per_page and \ - abs(per_page - current_page.count) < abs(per_page - new_page_count) and \ - current_page.count > 0: - # make a new page - self.pages.append(current_page) - current_page = NamePage(self) - - current_page.add(sub_list, letter) - - # if we finished the for loop with a page that isn't empty, add it - if current_page.count > 0: self.pages.append(current_page) - - def page(self, num): - """Returns a Page object for the given 1-based page number.""" - if len(self.pages) == 0: - return None - elif num > 0 and num <= len(self.pages): - return self.pages[num-1] - else: - raise InvalidPage - - @property - def num_pages(self): - """Returns the total number of pages""" - return len(self.pages) - -class NamePage(object): - def __init__(self, paginator): - self.paginator = paginator - self.object_list = [] - self.letters = [] - - @property - def count(self): - return len(self.object_list) - - @property - def start_letter(self): - if len(self.letters) > 0: - self.letters.sort(key=str.upper) - return self.letters[0] - else: return None - - @property - def end_letter(self): - if len(self.letters) > 0: - self.letters.sort(key=str.upper) - return self.letters[-1] - else: return None - - @property - def number(self): - return self.paginator.pages.index(self) + 1 - - def add(self, new_list, letter=None): - if len(new_list) > 0: - self.object_list = self.object_list + new_list - if letter: - self.letters.append(letter) - - def __repr__(self): - if self.start_letter == self.end_letter: - return self.start_letter - else: - return '%c-%c' % (self.start_letter, self.end_letter) - diff --git a/teleforma/models/__init__.py b/teleforma/models/__init__.py new file mode 100644 index 00000000..1a916370 --- /dev/null +++ b/teleforma/models/__init__.py @@ -0,0 +1,4 @@ +from core import * +from crfpa import * +from pro import * + diff --git a/teleforma/models/core.py b/teleforma/models/core.py new file mode 100644 index 00000000..8f34321b --- /dev/null +++ b/teleforma/models/core.py @@ -0,0 +1,584 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + teleforma + + Copyright (c) 2006-2012 Guillaume Pellerin + +# This software is governed by the CeCILL license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/ or redistribute the software under the terms of the CeCILL +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://www.cecill.info". + +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. + +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. + +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL license and that you accept its terms. + +# Author: Guillaume Pellerin +""" + +import os +import re +import pwd +import time +import urllib +import string +import datetime +import mimetypes + +from telemeta.models import * +import django.db.models as models +from django.db.models import * +from django.forms import ModelForm, TextInput, Textarea +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import User +from django.core.exceptions import ValidationError +from django.contrib.contenttypes import generic +from notes.models import Note +import jqchat.models +from django.core.paginator import InvalidPage, EmptyPage +from django.template.defaultfilters import slugify +import django.db.models as models +from south.modelsinspector import add_introspection_rules + +app_label = 'teleforma' + +n_sessions = 21 +session_choices = [(str(x), str(y)) for x in range(1, n_sessions) for y in range(1, n_sessions) if x == y] +server_choices = [('icecast', 'icecast'), ('stream-m', 'stream-m')] +streaming_choices = [('mp3', 'mp3'), ('ogg', 'ogg'), ('webm', 'webm'), ('mp4', 'mp4')] +mimetypes.add_type('video/webm','.webm') + + +class ShortTextField(models.TextField): + + def formfield(self, **kwargs): + kwargs.update( + {"widget": Textarea(attrs={'rows':2, 'cols':40})} + ) + return super(ShortTextField, self).formfield(**kwargs) + +add_introspection_rules([], ["^teleforma\.models\.ShortTextField"]) + + +class Organization(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + + def __unicode__(self): + return self.name + + class Meta: + db_table = app_label + '_' + 'organization' + verbose_name = _('organization') + +class Department(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + organization = ForeignKey('Organization', related_name='department', + verbose_name=_('organization')) + domain = CharField(_('Master domain'), max_length=255, blank=True) + + def __unicode__(self): + return self.name + + @property + def slug(self): + return slugify(self.__unicode__()) + + class Meta: + db_table = app_label + '_' + 'department' + verbose_name = _('department') + + +class Period(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + + def __unicode__(self): + return self.name + + class Meta: + db_table = app_label + '_' + 'period' + verbose_name = _('period') + +class CourseType(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + + def __unicode__(self): + return self.name + + class Meta: + db_table = app_label + '_' + 'course_type' + verbose_name = _('course type') + +class Course(Model): + + department = ForeignKey('Department', related_name='course', + verbose_name=_('department')) + title = CharField(_('title'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + code = CharField(_('code'), max_length=255) + date_modified = DateTimeField(_('date modified'), auto_now=True) + number = IntegerField(_('number'), blank=True, null=True) + synthesis_note = BooleanField(_('synthesis note')) + obligation = BooleanField(_('obligations')) + magistral = BooleanField(_('magistral')) + + notes = generic.GenericRelation(Note) + + def __unicode__(self): + return self.title + + @property + def slug(self): + return slugify(self.__unicode__()) + + class Meta: + db_table = app_label + '_' + 'course' + verbose_name = _('course') + ordering = ['number'] + + +class Professor(Model): + + user = ForeignKey(User, related_name='professor', + verbose_name=_('user'), unique=True) + courses = ManyToManyField('Course', related_name="professor", + verbose_name=_('courses'), + blank=True, null=True) + + def __unicode__(self): + return self.user.first_name + ' ' + self.user.last_name + + class Meta: + db_table = app_label + '_' + 'professor' + verbose_name = _('professor') + + +class Room(Model): + + organization = ForeignKey('Organization', related_name='room', verbose_name=_('organization')) + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + + def __unicode__(self): + return self.organization.name + ' - ' + self.name + + class Meta: + db_table = app_label + '_' + 'room' + verbose_name = _('room') + + +class Conference(Model): + + public_id = CharField(_('public_id'), max_length=255, blank=True) + course = ForeignKey('Course', related_name='conference', verbose_name=_('course')) + course_type = ForeignKey('CourseType', related_name='conference', verbose_name=_('course type')) + professor = ForeignKey('Professor', related_name='conference', verbose_name=_('professor'), + blank=True, null=True, on_delete=models.SET_NULL) + session = CharField(_('session'), choices=session_choices, + max_length=16, default="1") + room = ForeignKey('Room', related_name='conference', verbose_name=_('room'), + null=True, blank=True) + comment = ShortTextField(_('comment'), max_length=255, blank=True) + date_begin = DateTimeField(_('begin date'), null=True, blank=True) + date_end = DateTimeField(_('end date'), null=True, blank=True) + readers = ManyToManyField(User, related_name="conference", verbose_name=_('readers'), + blank=True, null=True) + + notes = generic.GenericRelation(Note) + + @property + def description(self): + if self.professor: + list = [self.course.department.name, self.course.title, + self.course_type.name, self.session, + self.professor.user.first_name, + self.professor.user.last_name, + str(self.date_begin)] + else: + list = [self.course.department.name, self.course.title, + self.course_type.name, self.session, + str(self.date_begin)] + return ' - '.join(list) + + @property + def slug(self): + slug = '-'.join([self.course.department.slug, + self.course.slug, + self.course_type.name.lower()]) + return slug + + def __unicode__(self): + return self.description + + def save(self, **kwargs): + self.course.save() + super(Conference, self).save(**kwargs) + + + def to_dict(self): + dict = [{'id':'public_id','value': self.public_id, 'class':'', 'label':'public_id'}, + {'id':'organization','value': self.course.department.organization, 'class':'', 'label':'Organization'}, + {'id': 'department', 'value': self.course.department , 'class':'', 'label':'Department'}, + {'id': 'professor', 'value': self.professor, 'class':'' , 'label': 'Professor'}, + {'id': 'session', 'value': self.session, 'class':'' , 'label': 'Session'}, + {'id': 'comment', 'value': self.comment, 'class':'' , 'label': 'Comment'}, + ] + return dict + + def to_json_dict(self): + data = {'id': self.public_id, 'course_code': self.course.code, + 'course_type': self.course_type.name, 'professor_id': self.professor.user.username, + 'session': self.session, + 'streams':[] } + + if self.room: + data['room'] = self.room.name + data['organization'] = self.room.organization.name + + streams = self.livestream.all() + if streams: + for stream in streams: + data['streams'].append({'host': stream.server.host, + 'port': stream.server.port, + 'server_type': stream.server.type, + 'stream_type': stream.stream_type }) + return data + + class Meta: + db_table = app_label + '_' + 'conference' + verbose_name = _('conference') + ordering = ['-date_begin'] + + +class StreamingServer(Model): + + element_type = 'streamingserver' + + host = CharField(_('host'), max_length=255) + port = CharField(_('port'), max_length=32) + type = CharField(_('type'), choices=server_choices, max_length=32) + description = CharField(_('description'), max_length=255, blank=True) + source_password = CharField(_('source password'), max_length=32) + admin_password = CharField(_('admin password'), max_length=32, blank=True) + + def __unicode__(self): + return self.host + ':' + self.port + ' - ' + self.type + + class Meta: + db_table = app_label + '_' + 'streaming_server' + verbose_name = _('streaming server') + + +class LiveStream(Model): + + element_type = 'livestream' + + conference = ForeignKey('Conference', related_name='livestream', + verbose_name=_('conference'), + blank=True, null=True, on_delete=models.SET_NULL) + server = ForeignKey('StreamingServer', related_name='livestream', + verbose_name=_('streaming server')) + stream_type = CharField(_('Streaming type'), + choices=streaming_choices, max_length=32) + streaming = BooleanField(_('streaming')) + + @property + def slug(self): + slug = '-'.join([self.conference.course.department.slug, + self.conference.course.slug, + self.conference.course_type.name.lower()]) + return slug + + @property + def mount_point(self): + if self.server.type == 'stream-m': + return 'consume/' + self.slug + else: + return self.slug + '.' + self.stream_type + + @property + def snapshot_url(self): + url = '' + if self.server.type == 'stream-m': + url = 'http://' + self.server.host + ':' + self.server.port + \ + '/snapshot/' + self.slug + return url + + @property + def url(self): + return 'http://' + self.server.host + ':' + self.server.port + '/' + self.mount_point + + def __unicode__(self): + if self.conference: + return self.conference.description + else: + return self.slug + + class Meta: + db_table = app_label + '_' + 'live_stream' + verbose_name = _('live stream') + + +class MediaBase(Model): + "Base media resource" + + title = CharField(_('title'), max_length=255, blank=True) + description = CharField(_('description'), max_length=255, blank=True) + credits = CharField(_('credits'), max_length=255, blank=True) + date_added = DateTimeField(_('date added'), auto_now_add=True) + date_modified = DateTimeField(_('date modified'), auto_now=True) + code = CharField(_('code'), max_length=255, blank=True) + is_published = BooleanField(_('published')) + mime_type = CharField(_('mime type'), blank=True) + notes = generic.GenericRelation(Note) + + def get_fields(self): + return self._meta.fields + + class Meta: + abstract = True + + +class DocumentType(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + number = IntegerField(_('number'), blank=True, null=True) + + def __unicode__(self): + return self.name + + class Meta: + db_table = app_label + '_' + 'document_type' + verbose_name = _('document type') + ordering = ['number'] + + +class Document(MediaBase): + + element_type = 'document' + + course = ForeignKey('Course', related_name='document', verbose_name=_('course')) + course_type = ManyToManyField('CourseType', related_name='document', + verbose_name=_('course type'), blank=True, null=True) + conference = ForeignKey('Conference', related_name='document', verbose_name=_('conference'), + blank=True, null=True, on_delete=models.SET_NULL) + type = ForeignKey('DocumentType', related_name='document', verbose_name=_('type'), + blank=True, null=True) + is_annal = BooleanField(_('annal')) + file = FileField(_('file'), upload_to='items/%Y/%m/%d', db_column="filename", blank=True) + readers = ManyToManyField(User, related_name="document", verbose_name=_('readers'), + blank=True, null=True) + + def is_image(self): + is_url_image = False + if self.url: + url_types = ['.png', '.jpg', '.gif', '.jpeg'] + for type in url_types: + if type in self.url or type.upper() in self.url: + is_url_image = True + return 'image' in self.mime_type or is_url_image + + def set_mime_type(self): + self.mime_type = mimetypes.guess_type(self.file.path)[0] + + def __unicode__(self): + types = ' - '.join([unicode(t) for t in self.course_type.all()]) + return ' - '.join([unicode(self.course), unicode(types), self.title ]) + + def set_read(self, user): + pass + + def get_read(self, user): + return user in self.readers + + def save(self, **kwargs): + self.course.save() + self.set_mime_type() + super(Document, self).save(**kwargs) + + class Meta: + db_table = app_label + '_' + 'document' + ordering = ['-date_added'] + + +class Media(MediaBase): + "Describe a media resource linked to a conference and a telemeta item" + + element_type = 'media' + + conference = ForeignKey('Conference', related_name='media', verbose_name=_('conference'), + blank=True, null=True, on_delete=models.SET_NULL) + course = ForeignKey('Course', related_name='media', verbose_name=_('course'), + blank=True, null=True) + course_type = ForeignKey('CourseType', related_name='media', verbose_name=_('course type'), + blank=True, null=True) + item = ForeignKey(MediaItem, related_name='media', + verbose_name='item', blank=True, null=True) + type = CharField(_('type'), choices=streaming_choices, max_length=32) + readers = ManyToManyField(User, related_name="media", verbose_name=_('readers'), + blank=True, null=True) + + def set_mime_type(self): + if self.item.file: + mime_type = mimetypes.guess_type(self.item.file.path)[0] + if mime_type == 'audio/mpeg': + self.mime_type = 'audio/mp3' + else: + self.mime_type = mime_type + self.save() + + def __unicode__(self): + if self.conference: + return self.conference.description + elif self.course: + return self.course.title + ' ' + self.course_type.name + else: + return self.item.file + + def save(self, **kwargs): + if self.course: + self.course.save() + elif self.conference: + self.conference.course.save() + super(Media, self).save(**kwargs) + + + class Meta: + db_table = app_label + '_' + 'media' + ordering = ['-date_modified'] + + +class NamePaginator(object): + """Pagination for string-based objects""" + + def __init__(self, object_list, on=None, per_page=25): + self.object_list = object_list + self.count = len(object_list) + self.pages = [] + + # chunk up the objects so we don't need to iterate over the whole list for each letter + chunks = {} + + for obj in self.object_list: + if on: + obj_str = getattr(obj, on).encode('utf8') + else: + obj_str = obj.encode('utf8') + + if len(obj_str): + letter = str.upper(obj_str[0]) + else: + letter = '' + + if letter not in chunks: + chunks[letter] = [] + + chunks[letter].append(obj) + + # the process for assigning objects to each page + current_page = NamePage(self) + + for letter in string.ascii_uppercase: + if letter not in chunks: + current_page.add([], letter) + continue + + sub_list = chunks[letter] # the items in object_list starting with this letter + + new_page_count = len(sub_list) + current_page.count + # first, check to see if sub_list will fit or it needs to go onto a new page. + # if assigning this list will cause the page to overflow... + # and an underflow is closer to per_page than an overflow... + # and the page isn't empty (which means len(sub_list) > per_page)... + if new_page_count > per_page and \ + abs(per_page - current_page.count) < abs(per_page - new_page_count) and \ + current_page.count > 0: + # make a new page + self.pages.append(current_page) + current_page = NamePage(self) + + current_page.add(sub_list, letter) + + # if we finished the for loop with a page that isn't empty, add it + if current_page.count > 0: self.pages.append(current_page) + + def page(self, num): + """Returns a Page object for the given 1-based page number.""" + if len(self.pages) == 0: + return None + elif num > 0 and num <= len(self.pages): + return self.pages[num-1] + else: + raise InvalidPage + + @property + def num_pages(self): + """Returns the total number of pages""" + return len(self.pages) + +class NamePage(object): + def __init__(self, paginator): + self.paginator = paginator + self.object_list = [] + self.letters = [] + + @property + def count(self): + return len(self.object_list) + + @property + def start_letter(self): + if len(self.letters) > 0: + self.letters.sort(key=str.upper) + return self.letters[0] + else: return None + + @property + def end_letter(self): + if len(self.letters) > 0: + self.letters.sort(key=str.upper) + return self.letters[-1] + else: return None + + @property + def number(self): + return self.paginator.pages.index(self) + 1 + + def add(self, new_list, letter=None): + if len(new_list) > 0: + self.object_list = self.object_list + new_list + if letter: + self.letters.append(letter) + + def __repr__(self): + if self.start_letter == self.end_letter: + return self.start_letter + else: + return '%c-%c' % (self.start_letter, self.end_letter) + diff --git a/teleforma/models/crfpa.py b/teleforma/models/crfpa.py new file mode 100644 index 00000000..41cb3a69 --- /dev/null +++ b/teleforma/models/crfpa.py @@ -0,0 +1,160 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + teleforma + + Copyright (c) 2006-2012 Guillaume Pellerin + +# This software is governed by the CeCILL license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/ or redistribute the software under the terms of the CeCILL +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://www.cecill.info". + +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. + +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. + +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL license and that you accept its terms. + +# Author: Guillaume Pellerin +""" + +import django.db.models as models +from django.utils.translation import ugettext_lazy as _ +from telemeta.models.core import * +from teleforma.models.core import * + + +# CRFPA + +class IEJ(Model): + + name = CharField(_('name'), max_length=255) + description = CharField(_('description'), max_length=255, blank=True) + + def __unicode__(self): + return self.name + + class Meta: + db_table = app_label + '_' + 'iej' + verbose_name = _('IEJ') + verbose_name_plural = _('IEJ') + ordering = ['name'] + + +class Training(Model): + + code = CharField(_('code'), max_length=255) + name = CharField(_('name'), max_length=255, blank=True) + period = ForeignKey('Period', related_name='training', verbose_name=_('period'), + blank=True, null=True) + synthesis_note = ManyToManyField('CourseType', related_name="training_synthesis_note", + verbose_name=_('synthesis note'), + blank=True, null=True) + obligation = ManyToManyField('CourseType', related_name="training_obligation", + verbose_name=_('obligations'), + blank=True, null=True) + procedure = ManyToManyField('CourseType', related_name="training_procedure", + verbose_name=_('procedure'), + blank=True, null=True) + written_speciality = ManyToManyField('CourseType', related_name="training_written_speciality", + verbose_name=_('written speciality'), + blank=True, null=True) + oral_speciality = ManyToManyField('CourseType', related_name="training_oral_speciality", + verbose_name=_('oral speciality'), + blank=True, null=True) + oral_1 = ManyToManyField('CourseType', related_name="training_oral_1", + verbose_name=_('oral 1'), + blank=True, null=True) + oral_2 = ManyToManyField('CourseType', related_name="training_oral_2", + verbose_name=_('oral 2'), + blank=True, null=True) + options = ManyToManyField('CourseType', related_name="training_options", + verbose_name=_('options'), + blank=True, null=True) + magistral = ManyToManyField('CourseType', related_name="training_magistral", + verbose_name=_('magistral'), + blank=True, null=True) + cost = FloatField(_('cost'), blank=True, null=True) + + def __unicode__(self): + code = self.code + if self.period: + code += ' - ' + self.period.name + return code + + class Meta: + db_table = app_label + '_' + 'training' + verbose_name = _('training') + + +class Student(Model): + + user = ForeignKey(User, related_name='student', verbose_name=_('user'), unique=True ) + period = ManyToManyField('Period', related_name='student', verbose_name=_('period'), + blank=True, null=True) + iej = ForeignKey('IEJ', related_name='student', verbose_name=_('iej'), + blank=True, null=True, on_delete=models.SET_NULL) + training = ForeignKey('Training', related_name='student', verbose_name=_('training')) + platform_only = BooleanField(_('platform only')) + procedure = ForeignKey('Course', related_name="procedure", + verbose_name=_('procedure'), + blank=True, null=True) + written_speciality = ForeignKey('Course', related_name="written_speciality", + verbose_name=_('written speciality'), + blank=True, null=True) + oral_speciality = ForeignKey('Course', related_name="oral_speciality", + verbose_name=_('oral speciality'), + blank=True, null=True) + oral_1 = ForeignKey('Course', related_name="oral_1", verbose_name=_('oral 1'), + blank=True, null=True) + oral_2 = ForeignKey('Course', related_name="oral_2", verbose_name=_('oral 2'), + blank=True, null=True) + options = ForeignKey('Course', related_name="options", verbose_name=_('options'), + blank=True, null=True) + + def __unicode__(self): + try: + return self.user.last_name + ' ' + self.user.first_name + except: + return '' + + class Meta: + db_table = app_label + '_' + 'student' + verbose_name = _('student') + ordering = ['user__last_name'] + + +class Profile(models.Model): + "User profile extension" + + user = ForeignKey(User, related_name='profile', verbose_name=_('user'), unique=True) + address = TextField(_('Address'), blank=True) + postal_code = CharField(_('Postal code'), max_length=255, blank=True) + city = CharField(_('City'), max_length=255, blank=True) + country = CharField(_('Country'), max_length=255, blank=True) + language = CharField(_('Language'), max_length=255, blank=True) + telephone = CharField(_('Telephone'), max_length=255, blank=True) + expiration_date = DateField(_('Expiration_date'), blank=True, null=True) + init_password = BooleanField(_('Password initialized')) + + class Meta: + db_table = app_label + '_' + 'profiles' + verbose_name = _('profile') + + diff --git a/teleforma/models/pro.py b/teleforma/models/pro.py new file mode 100644 index 00000000..be3ad7bc --- /dev/null +++ b/teleforma/models/pro.py @@ -0,0 +1,113 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + teleforma + + Copyright (c) 2006-2012 Guillaume Pellerin + +# This software is governed by the CeCILL license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/ or redistribute the software under the terms of the CeCILL +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://www.cecill.info". + +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. + +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. + +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL license and that you accept its terms. + +# Author: Guillaume Pellerin +""" + +from django.db.models import * +from django.utils.translation import ugettext_lazy as _ +from telemeta.models.core import * +from teleforma.models.core import * + +STATUS_CHOICES = ( + (1, _('Draft')), + (2, _('Public')), + (3, _('Close')), + ) + + +class Seminar(Model): + + course = ForeignKey(Course, related_name='seminar', verbose_name=_('course')) + title = CharField(_('title'), max_length=255, blank=True) + price = FloatField(_('price')) + status = IntegerField(_('status'), choices=STATUS_CHOICES, default=1) + rank = IntegerField(_('rank')) + + doc_1 = ForeignKey(Document, related_name=_("seminar"), + verbose_name=_('doc 1'), + blank=True, null=True) + media = ForeignKey(Media, related_name="seminar", + verbose_name=_('media'), + blank=True, null=True) + doc_2 = ForeignKey(Document, related_name="seminar", + verbose_name=_('doc 2'), + blank=True, null=True) + doc_correct = ForeignKey(Document, related_name=_("seminar"), + verbose_name=_('doc_correct'), + blank=True, null=True) + suscribers = ManyToManyField(User, related_name="seminar", verbose_name=_('suscribers'), + blank=True, null=True) + + date_added = DateTimeField(_('date added'), auto_now_add=True) + date_modified = DateTimeField(_('date modified'), auto_now=True) + + def __unicode__(self): + return '-'.join([self.course, self.rank, self.title]) + + class Meta: + db_table = app_label + '_' + 'seminar' + verbose_name = _('Seminar') + + +class Answer(Model): + + seminar = ForeignKey(Seminar, related_name=_("answer"), verbose_name=_('seminar') ) + user = ForeignKey(User, related_name=_("answer"), verbose_name=_('user')) + question = ForeignKey(Question, related_name=_("answer"), verbose_name=_('question')) + answer = TextField(_('answer')) + characters = IntegerField(_('numbers of characters')) + + def __unicode__(self): + return '-'.join([self.seminar, self.question, self.user]) + + class Meta: + db_table = app_label + '_' + 'answer' + verbose_name = _('Answer') + + +class Question(Model): + + seminar = ForeignKey(Seminar, verbose_name=_('seminar')) + title = CharField(_('title'), max_length=255, blank=True) + question = TextField(_('question')) + rank = IntegerField(_('rank')) + weight = IntegerField(_('weight')) + + def __unicode__(self): + return '-'.join([self.seminar, self.rank, self.title]) + + class Meta: + db_table = app_label + '_' + 'question' + verbose_name = _('Question') + diff --git a/teleforma/tests.py b/teleforma/tests.py old mode 100755 new mode 100644 diff --git a/teleforma/views.py b/teleforma/views.py old mode 100755 new mode 100644