From 18fb871917ea875ed8a66c017947c2678d71f5f1 Mon Sep 17 00:00:00 2001 From: Leif Johansson Date: Wed, 9 Feb 2011 11:08:19 +0100 Subject: restructure 2 --- src/templates/meetingtools/apps/room/__init__.py | 0 src/templates/meetingtools/apps/room/admin.py | 10 + src/templates/meetingtools/apps/room/forms.py | 33 +++ src/templates/meetingtools/apps/room/models.py | 30 +++ src/templates/meetingtools/apps/room/views.py | 253 +++++++++++++++++++++++ 5 files changed, 326 insertions(+) create mode 100644 src/templates/meetingtools/apps/room/__init__.py create mode 100644 src/templates/meetingtools/apps/room/admin.py create mode 100644 src/templates/meetingtools/apps/room/forms.py create mode 100644 src/templates/meetingtools/apps/room/models.py create mode 100644 src/templates/meetingtools/apps/room/views.py (limited to 'src/templates/meetingtools/apps/room') diff --git a/src/templates/meetingtools/apps/room/__init__.py b/src/templates/meetingtools/apps/room/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/meetingtools/apps/room/admin.py b/src/templates/meetingtools/apps/room/admin.py new file mode 100644 index 0000000..13d80a8 --- /dev/null +++ b/src/templates/meetingtools/apps/room/admin.py @@ -0,0 +1,10 @@ +''' +Created on Jan 31, 2011 + +@author: leifj +''' + +from django.contrib import admin +from meetingtools.apps.room.models import Room + +admin.site.register(Room) \ No newline at end of file diff --git a/src/templates/meetingtools/apps/room/forms.py b/src/templates/meetingtools/apps/room/forms.py new file mode 100644 index 0000000..3b89297 --- /dev/null +++ b/src/templates/meetingtools/apps/room/forms.py @@ -0,0 +1,33 @@ +''' +Created on Feb 1, 2011 + +@author: leifj +''' +from django.forms.models import ModelForm +from meetingtools.apps.room.models import Room +from django.forms.widgets import Select, TextInput +from django.forms.fields import ChoiceField, BooleanField +from django.forms.forms import Form + +PUBLIC = 0 +PROTECTED = 1 +PRIVATE = 2 + +class UpdateRoomForm(ModelForm): + #protection = ChoiceField(choices=((PUBLIC,'Anyone can enter the room.'), + # (PROTECTED,'Only group members and accepted guests can enter the room.'), + # (PRIVATE,'Only group members can enter.'))) + + class Meta: + model = Room + fields = ['name','urlpath','participants','presenters','hosts','source_sco_id','self_cleaning'] + widgets = {'participants': Select(), + 'presenters': Select(), + 'hosts': Select(), + 'source_sco_id': Select(), + 'urlpath': TextInput(attrs={'size': '40'}), + 'name': TextInput(attrs={'size': '40'}), + } + +class DeleteRoomForm(Form): + confirm = BooleanField(label="Confirm remove room") \ No newline at end of file diff --git a/src/templates/meetingtools/apps/room/models.py b/src/templates/meetingtools/apps/room/models.py new file mode 100644 index 0000000..90e5868 --- /dev/null +++ b/src/templates/meetingtools/apps/room/models.py @@ -0,0 +1,30 @@ +''' +Created on Jan 31, 2011 + +@author: leifj +''' + +from django.db import models +from django.db.models.fields import CharField, BooleanField, IntegerField, SmallIntegerField +from django.db.models.fields.related import ForeignKey +from django.contrib.auth.models import User +from meetingtools.apps.cluster.models import ACCluster + +class Room(models.Model): + creator = ForeignKey(User,editable=False) + name = CharField(max_length=128,blank=True,unique=True) + urlpath = CharField(max_length=128,blank=True,unique=True) + acc = ForeignKey(ACCluster,verbose_name="Adobe Connect Cluster",editable=False) + participants = CharField(max_length=255,blank=True,verbose_name="Participants") # populate from entitlement held by creator session + presenters = CharField(max_length=255,blank=True,verbose_name="Presenters") # populate from entitlement held by creator session + hosts = CharField(max_length=255,blank=True,verbose_name="Hosts") # populate from entitlement held by creator session + self_cleaning = BooleanField(verbose_name="Clean-up when empty?") + sco_id = IntegerField(verbose_name="Adobe Connect Room",blank=False) + source_sco_id = IntegerField(verbose_name="Template",blank=True,null=True) + timecreated = models.DateTimeField(auto_now_add=True) + lastupdated = models.DateTimeField(auto_now=True) + lastvisited = models.DateTimeField(blank=True,null=True) + + def __unicode__(self): + return "%s (sco_id=%d,source_sco_id=%d)" % (self.name,self.sco_id,self.source_sco_id) + \ No newline at end of file diff --git a/src/templates/meetingtools/apps/room/views.py b/src/templates/meetingtools/apps/room/views.py new file mode 100644 index 0000000..7bdffc0 --- /dev/null +++ b/src/templates/meetingtools/apps/room/views.py @@ -0,0 +1,253 @@ +''' +Created on Jan 31, 2011 + +@author: leifj +''' +from meetingtools.apps.room.models import Room, ACCluster +from meetingtools.multiresponse import respond_to, redirect_to +from meetingtools.apps.room.forms import UpdateRoomForm, DeleteRoomForm +from django.shortcuts import get_object_or_404 +from meetingtools.ac import ac_api_client, api +import re +from meetingtools.apps import room +from django.contrib.auth.decorators import login_required +from meetingtools.apps.auth.utils import groups +import logging +from pprint import pformat +from meetingtools.utils import session +import time +from meetingtools.settings import GRACE +from django.utils.datetime_safe import datetime + +def _acc_for_user(user): + (local,domain) = user.username.split('@') + if not domain: + #raise Exception,"Improperly formatted user: %s" % user.username + domain = "nordu.net" # testing with local accts only + for acc in ACCluster.objects.all(): + for regex in acc.domain_match.split(): + if re.match(regex,domain): + return acc + raise Exception,"I don't know which cluster you belong to... (%s)" % user.username + +def _user_meeting_folder(request,acc): + if not session(request,'my_meetings_sco_id'): + connect_api = ac_api_client(request, acc) + userid = request.user.username + folders = connect_api.request('sco-search-by-field',{'filter-type': 'folder','field':'name','query':userid}).et.xpath('//sco[folder-name="User Meetings"]') + logging.debug("user meetings folder: "+pformat(folders)) + #folder = next((f for f in folders if f.findtext('.//folder-name') == 'User Meetings'), None) + if folders and len(folders) > 0: + session(request,'my_meetings_sco_id',folders[0].get('sco-id')) + return session(request,'my_meetings_sco_id') + +def _shared_templates_folder(request,acc): + if not session(request,'shared_templates_sco_id'): + connect_api = ac_api_client(request, acc) + shared = connect_api.request('sco-shortcuts').et.xpath('.//sco[@type="shared-meeting-templates"]') + logging.debug("shared templates folder: "+pformat(shared)) + #folder = next((f for f in folders if f.findtext('.//folder-name') == 'User Meetings'), None) + if shared and len(shared) > 0: + session(request,'shared_templates_sco_id',shared[0].get('sco-id')) + return session(request,'shared_templates_sco_id') + +def _user_rooms(request,acc,my_meetings_sco_id): + rooms = [] + if my_meetings_sco_id: + connect_api = ac_api_client(request, acc) + meetings = connect_api.request('sco-expanded-contents',{'sco-id': my_meetings_sco_id,'filter-type': 'meeting'}) + if meetings: + rooms = [(r.get('sco-id'),r.findtext('name'),r.get('source-sco-id'),r.findtext('url-path')) for r in meetings.et.findall('.//sco')] + return rooms + +def _user_templates(request,acc,my_meetings_sco_id): + templates = [] + connect_api = ac_api_client(request, acc) + if my_meetings_sco_id: + my_templates = connect_api.request('sco-contents',{'sco-id': my_meetings_sco_id,'filter-type': 'folder'}).et.xpath('.//sco[folder-name="My Templates"][0]') + if my_templates and len(my_templates) > 0: + my_templates_sco_id = my_templates[0].get('sco_id') + meetings = connect_api.request('sco-contents',{'sco-id': my_templates_sco_id,'filter-type': 'meeting'}) + if meetings: + templates = templates + [(r.get('sco-id'),r.findtext('name')) for r in meetings.et.findall('.//sco')] + + shared_templates_sco_id = _shared_templates_folder(request, acc) + if shared_templates_sco_id: + shared_templates = connect_api.request('sco-contents',{'sco-id': shared_templates_sco_id,'filter-type': 'meeting'}) + if shared_templates: + templates = templates + [(r.get('sco-id'),r.findtext('name')) for r in shared_templates.et.findall('.//sco')] + + return templates + +def _find_current_session(session_info): + for r in session_info.et.xpath('//row'): + #logging.debug(pformat(etree.tostring(r))) + end = r.findtext('date-end') + if end is None: + return r + return None + +def _nusers(session_info): + cur = _find_current_session(session_info) + if cur is not None: + return cur.get('num-participants') + else: + return 0 + +@login_required +def view(request,id): + room = get_object_or_404(Room,pk=id) + api = ac_api_client(request,room.acc) + room_info = api.request('sco-info',{'sco-id':room.sco_id},raise_error=True) + perm_info = api.request('permissions-info',{'acl-id':room.sco_id,'filter-principal-id': 'public-access'},raise_error=True) + session_info = api.request('report-meeting-sessions',{'sco-id':room.sco_id},raise_error=True) + + room.name = room_info.et.findtext('.//sco/name') + room.save() + return respond_to(request, + {'text/html':'apps/room/view.html'}, + {'user':request.user, + 'room':room, + 'permission': perm_info.et.find('.//principal').get('permission-id'), + 'nusers': _nusers(session_info) + }) + +def _init_update_form(request,form,acc,my_meetings_sco_id): + form.fields['participants'].widget.choices = [('','-- anyone --')]+[(g,g) for g in groups(request)] + form.fields['presenters'].widget.choices = [('','-- nobody --')]+[(g,g) for g in groups(request)] + form.fields['hosts'].widget.choices = [('','-- nobody --')]+[(g,g) for g in groups(request)] + form.fields['source_sco_id'].widget.choices = [('','-- select template --')]+[r for r in _user_templates(request,acc,my_meetings_sco_id)] + +@login_required +def update(request,id=None): + if id: + room = get_object_or_404(Room,pk=id) + acc = room.acc + what = "Update" + title = "Modify %s" % room.name + update = True + else: + acc = _acc_for_user(request.user) + room = Room(creator=request.user,acc=acc) + what = "Create" + title = "Create a new room" + update = False + + my_meetings_sco_id = _user_meeting_folder(request,acc) + + if request.method == 'POST': + form = UpdateRoomForm(request.POST,instance=room) + _init_update_form(request, form, acc, my_meetings_sco_id) + if form.is_valid(): + api = ac_api_client(request,acc) + params = {'type':'meeting','name':room.name,'folder-id':my_meetings_sco_id,'sco-id':room.sco_id,'source-sco-id':room.source_sco_id,'url-path':room.urlpath} + if form.cleaned_data.has_key('source_sco_id'): + params['source-sco-id'] = form.cleaned_data['source_sco_id'] + + if form.cleaned_data.has_key('urlpath'): + params['url-path'] = form.cleaned_data['urlpath'] + + r = api.request('sco-update',params,raise_error=True) + params['sco-id'] = r.et.find(".//sco").get('sco-id') + params['sco-source-id'] = r.et.find(".//sco").get('sco-source-id') + room = form.save() + room = _import_room(params['sco-id'],params['name'],params['source-sco-id'],params['url-path'],request.user,acc) + return redirect_to("/rooms#%d" % room.id) + else: + form = UpdateRoomForm(instance=room) + _init_update_form(request, form, acc, my_meetings_sco_id) + if update: + form.fields['urlpath'].widget.attrs['readonly'] = True + + return respond_to(request,{'text/html':'edit.html'},{'form':form,'formtitle': title,'submitname':'%s Room' % what}) + +def _import_room(sco_id,name,source_sco_id,urlpath,user,acc): + modified = False + room,created = Room.objects.get_or_create(sco_id=sco_id,acc=acc,creator=user) + + if room.name != name: + room.name = name + modified = True + + if not room.sco_id and sco_id: + room.sco_id = sco_id + modified = True + + if not room.source_sco_id and source_sco_id: + room.source_sco_id = source_sco_id + modified = True + + if room.urlpath != urlpath: + room.urlpath = urlpath.strip('/') + modified = True + + if '/' in room.urlpath: + room.urlpath = urlpath.strip('/') + modified = True + + if modified: + room.save() + + return room + +@login_required +def list(request): + acc = _acc_for_user(request.user) + my_meetings_sco_id = _user_meeting_folder(request,acc) + user_rooms = _user_rooms(request,acc,my_meetings_sco_id) + + ar = [] + for (sco_id,name,source_sco_id,urlpath) in user_rooms: + room = _import_room(sco_id,name,source_sco_id,urlpath,request.user,acc) + ar.append(int(sco_id)) + + #logging.debug(pformat(ar)) + + for r in Room.objects.filter(creator=request.user).all(): + #logging.debug(pformat(r)) + if (not r.sco_id in ar) and (not r.self_cleaning): + r.delete() + return respond_to(request,{'text/html':'apps/room/list.html'},{'user':request.user,'rooms':Room.objects.filter(creator=request.user).all()}) + +@login_required +def delete(request,id): + room = get_object_or_404(Room,pk=id) + if request.method == 'POST': + form = DeleteRoomForm(request.POST) + if form.is_valid(): + api = ac_api_client(request,room.acc) + api.request('sco-delete',{'sco-id':room.sco_id},raise_error=True) + room.delete() + return redirect_to("/rooms") + else: + form = DeleteRoomForm() + + return respond_to(request,{'text/html':'edit.html'},{'form':form,'formtitle': 'Delete %s' % room.name,'submitname':'Delete Room'}) + +def _clean(room): + pass + +def go_by_id(request,id): + room = get_object_or_404(Room,pk=id) + return goto(request,room) + +def go_by_path(request,path): + room = get_object_or_404(Room,urlpath=path) + return goto(request,room) + +def goto(request,room): + client = ac_api_client(request, room.acc) + session_info = client.request('report-meeting-sessions',{'sco-id':room.sco_id}) + + now = time.time() + if room.self_cleaning: + if (_nusers(session_info) == 0) and (abs(room.lastvisited - now) > GRACE): + _clean(room) + + room.lastvisited = datetime.now() + room.save() + + r = client.request('sco-info',{'sco-id':room.sco_id}) + urlpath = r.et.findtext('.//sco/url-path') + return redirect_to(room.acc.url+urlpath) + \ No newline at end of file -- cgit v1.1