diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/meetingtools/ac/__init__.py | 40 | ||||
-rw-r--r-- | src/meetingtools/ac/api.py | 41 | ||||
-rw-r--r-- | src/meetingtools/apps/auth/utils.py | 9 | ||||
-rw-r--r-- | src/meetingtools/apps/auth/views.py | 72 | ||||
-rw-r--r-- | src/meetingtools/apps/room/forms.py | 43 | ||||
-rw-r--r-- | src/meetingtools/apps/room/models.py | 8 | ||||
-rw-r--r-- | src/meetingtools/apps/room/views.py | 58 | ||||
-rw-r--r-- | src/meetingtools/settings.py | 2 | ||||
-rw-r--r-- | src/templates/base.html | 2 |
9 files changed, 207 insertions, 68 deletions
diff --git a/src/meetingtools/ac/__init__.py b/src/meetingtools/ac/__init__.py index 1250a5f..4fdc2f5 100644 --- a/src/meetingtools/ac/__init__.py +++ b/src/meetingtools/ac/__init__.py @@ -1,12 +1,46 @@ from meetingtools.ac.api import ACPClient +import time -def ac_api_client_cached(request,acc): +def ac_api_client_cache(request,acc): tag = 'ac_api_client_%s' % acc.name if not request.session.has_key(tag): - request.session[tag] = ACPClient(acc.api_url,acc.user,acc.password) + request.session[tag] = ACPClientWrapper(acc) return request.session[tag] -def ac_api_client(request,acc): +def ac_api_client_nocache(request,acc): + return ACPClientWrapper(acc) + +ac_api_client = ac_api_client_nocache + +def ac_api(request,acc): return ACPClient(acc.api_url,acc.user,acc.password) + + +MAXCALLS = 10 +MAXIDLE = 10 + +class ACPClientWrapper(object): + + def __init__(self,acc): + self.acc = acc + self._delegate = None + self.ncalls = 0 + self.lastcall = time.time() + + def invalidate(self): + self._delegate = None + + def client_factory(self): + now = time.time() + if self.ncalls > MAXCALLS or now - self.lastcall > MAXIDLE or not self._delegate: + self._delegate = ACPClient(self.acc.api_url,self.acc.user,self.acc.password) + self.ncalls = 0 + self.ncalls += 1 + self.lastcall = now + return self._delegate + + def __getattr__(self,name): + client = self.client_factory() + return getattr(client,name)
\ No newline at end of file diff --git a/src/meetingtools/ac/api.py b/src/meetingtools/ac/api.py index c710298..5db5f2f 100644 --- a/src/meetingtools/ac/api.py +++ b/src/meetingtools/ac/api.py @@ -52,6 +52,15 @@ def _enc(v): ev = ev.encode('iso-8859-1') return ev +def _getset(dict,key,value=None): + if value: + if dict.has_key(key): + return dict[key] + else: + return None + else: + dict[key] = value + class ACPClient(): def __init__(self,url,username=None,password=None): @@ -59,6 +68,7 @@ class ACPClient(): self.session = None if username and password: self.login(username,password) + self._cache = {'login':{},'group':{}} def request(self,method,p={},raise_error=False): url = self.url+"?"+"action=%s" % method @@ -68,7 +78,7 @@ class ACPClient(): u = [] for (k,v) in p.items(): if v: - kv = "%s=%s" % (k,quote(str(v))) + kv = "%s=%s" % (k,quote(unicode(v))) u.append(kv) url = url + "&" + "&".join(u) @@ -100,18 +110,34 @@ class ACPClient(): raise result.exception() def find_or_create_principal(self,key,value,type,dict): + if not self._cache.has_key(type): + self._cache[type] = {} + cache = self._cache[type] + + if not cache.has_key(key): + p = self._find_or_create_principal(key,value,type,dict) + cache[key] = p + + return cache[key] + + def find_principal(self,key,value,type): + return self.find_or_create_principal(key,value,type,None) + + def _find_or_create_principal(self,key,value,type,dict): result = self.request('principal-list',{'filter-%s' % key: value,'filter-type': type}, True) principal = result.get_principal() if result.is_error(): if result.status_code() != 'no_data': result.exception() - elif principal: + elif principal and dict: dict['principal-id'] = principal.get('principal-id') - update_result = self.request('principal-update',dict) - rp = update_result.get_principal() - if not rp: - rp = principal + rp = principal + if dict: + update_result = self.request('principal-update',dict) + rp = update_result.get_principal() + if not rp: + rp = principal return rp def find_builtin(self,type): @@ -122,6 +148,9 @@ class ACPClient(): result = self.request('principal-list',{'filter-name':name,'filter-type':'group'},True) return result.get_principal() + def find_user(self,login): + return self.find_principal("login", login, "user") + def add_remove_member(self,principal_id,group_id,is_member): m = "0" if is_member: diff --git a/src/meetingtools/apps/auth/utils.py b/src/meetingtools/apps/auth/utils.py index 3a7efe6..1a0174c 100644 --- a/src/meetingtools/apps/auth/utils.py +++ b/src/meetingtools/apps/auth/utils.py @@ -14,13 +14,6 @@ def anonid(): def groups(request): groups = [] if request.user.is_authenticated(): - if request.session and request.session.has_key('entitlement'): - groups = groups + request.session['entitlement'] - - if '@' in request.user.username: - (local,domain) = request.user.username.split('@') - groups.append(domain) - for e in ('member','employee','student'): - groups.append("%s@%s" % (e,domain)) + groups = request.user.groups return groups
\ No newline at end of file diff --git a/src/meetingtools/apps/auth/views.py b/src/meetingtools/apps/auth/views.py index bbeb4be..fe2d97a 100644 --- a/src/meetingtools/apps/auth/views.py +++ b/src/meetingtools/apps/auth/views.py @@ -4,16 +4,18 @@ Created on Jul 5, 2010 @author: leifj ''' from django.http import HttpResponseRedirect -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Group import datetime from django.views.decorators.cache import never_cache import logging from meetingtools.apps.userprofile.models import UserProfile from meetingtools.multiresponse import redirect_to, make_response_dict from meetingtools.apps.room.views import _acc_for_user -from meetingtools.ac import ac_api_client +from meetingtools.ac import ac_api_client, ac_api from django.shortcuts import render_to_response from django.contrib import auth +from django_co_connector.models import co_import_from_request, add_member,\ + remove_member def meta(request,attr): v = request.META.get(attr) @@ -30,15 +32,21 @@ def meta1(request,attr): return None def _localpart(a): + if hasattr(a,'name'): + a = a.name if '@' in a: (lp,dp) = a.split('@') a = lp return a -def _is_member_or_employee(affiliations): +def _is_member_or_employee_old(affiliations): lpa = map(_localpart,affiliations) return 'student' in lpa or 'staff' in lpa or ('member' in lpa and not 'student' in lpa) +def _is_member_or_employee(user): + lpa = map(_localpart,user.groups) + return 'student' in lpa or 'staff' in lpa or ('member' in lpa and not 'student' in lpa) + @never_cache def logout(request): auth.logout(request) @@ -48,6 +56,33 @@ def logout(request): def login(request): return render_to_response('apps/auth/login.html',make_response_dict(request,{'next': request.REQUEST.get("next")})); + +def join_group(group,**kwargs): + user = kwargs['user'] + acc = _acc_for_user(user) + connect_api = ac_api(acc) + + principal = connect_api.find_principal("login", user.username, "user") + if principal: + gp = connect_api.find_group(group.name) + if gp: + connect_api.add_member(principal.get('principal-id'),gp.get('principal-id')) + + +def leave_group(group,**kwargs): + user = kwargs['user'] + acc = _acc_for_user(user) + connect_api = ac_api(acc) + + principal = connect_api.find_principal("login", user.username, "user") + if principal: + gp = connect_api.find_group(group.name) + if gp: + connect_api.remove_member(principal.get('principal-id'),gp.get('principal-id')) + +add_member.connect(join_group,sender=Group) +remove_member.connect(leave_group,sender=Group) + def accounts_login_federated(request): if request.user.is_authenticated(): profile,created = UserProfile.objects.get_or_create(user=request.user) @@ -88,38 +123,33 @@ def accounts_login_federated(request): # Allow auto_now to kick in for the lastupdated field #profile.lastupdated = datetime.datetime.now() profile.save() - - epe = meta(request,'entitlement') - # XXX Do we really need thix? - if epe: - request.session['entitlement'] = epe - - affiliations = meta(request,'affiliation') acc = _acc_for_user(request.user) connect_api = ac_api_client(request, acc) - uid = request.user.username - principal = connect_api.find_or_create_principal("login", uid, "user", + # make sure the principal is created before shooting off + principal = connect_api.find_or_create_principal("login", request.user.username, "user", {'type': "user", 'has-children': "0", 'first-name':fn, 'last-name':ln, 'email':mail, - 'login':uid, - 'ext-login':uid}) + 'login':request.user.username, + 'ext-login':request.user.username}) + + co_import_from_request(request) - member_or_employee = _is_member_or_employee(affiliations) + member_or_employee = _is_member_or_employee(request.user) for gn in ('live-admins','seminar-admins'): group = connect_api.find_builtin(gn) if group: connect_api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),member_or_employee) - (lp,domain) = uid.split('@') - for a in ('student','employee','member'): - affiliation = "%s@%s" % (a,domain) - group = connect_api.find_or_create_principal('name',affiliation,'group',{'type': 'group','has-children':'1','name': affiliation}) - member = affiliation in affiliations - connect_api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),member) + #(lp,domain) = uid.split('@') + #for a in ('student','employee','member'): + # affiliation = "%s@%s" % (a,domain) + # group = connect_api.find_or_create_principal('name',affiliation,'group',{'type': 'group','has-children':'1','name': affiliation}) + # member = affiliation in affiliations + # connect_api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),member) #for e in epe: # group = connect_api.find_or_create_principal('name',e,'group',{'type': 'group','has-children':'1','name': e}) diff --git a/src/meetingtools/apps/room/forms.py b/src/meetingtools/apps/room/forms.py index aef7d8d..a211b2d 100644 --- a/src/meetingtools/apps/room/forms.py +++ b/src/meetingtools/apps/room/forms.py @@ -3,21 +3,42 @@ Created on Feb 1, 2011 @author: leifj ''' -from django.forms.models import ModelForm +from django.forms.models import ModelChoiceField from meetingtools.apps.room.models import Room from django.forms.widgets import Select, TextInput -from django.forms.fields import ChoiceField, BooleanField +from django.forms.fields import BooleanField from django.forms.forms import Form from form_utils.forms import BetterModelForm +from django.contrib.auth.models import Group PUBLIC = 0 PROTECTED = 1 PRIVATE = 2 -class UpdateRoomForm(BetterModelForm): - #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 ModifyRoomForm(BetterModelForm): + class Meta: + model = Room + fields = ['name','source_sco_id','self_cleaning'] + fieldsets = [('name',{'fields': ['name'], + 'classes': ['step'], + 'legend': 'Step 1: Room name', + 'description': 'The room name should be short and descriptive.' + }), + ('properties',{'fields': ['self_cleaning','urlpath','source_sco_id'], + 'classes': ['step'], + 'legend': 'Step 2: Room properties', + 'description': 'These are basic properties for your room. If you set your room to be self-cleaning it will be reset every time the last participant leaves the room.'}), + ] + widgets = {'source_sco_id': Select(), + 'urlpath': TextInput(attrs={'size': '40'}), + 'name': TextInput(attrs={'size': '40'})} + + +class CreateRoomForm(BetterModelForm): + + participants = ModelChoiceField(Group,required=False) + presenters = ModelChoiceField(Group,required=False) + hosts = ModelChoiceField(Group,required=False) class Meta: model = Room @@ -34,15 +55,11 @@ class UpdateRoomForm(BetterModelForm): ('rights',{'fields': ['participants','presenters','hosts'], 'classes': ['step','submit_step'], 'legend': 'Step 3: Room rights (optional)', - 'description': 'Define the groups that are to have access to your room.'}) + 'description': 'Define the groups that are to have access to your room. If you leave the <em>Participants</em> field empty that implies that anyone who knows the URL may enter the room.'}) ] - widgets = {'participants': Select(), - 'presenters': Select(), - 'hosts': Select(), - 'source_sco_id': Select(), + widgets = {'source_sco_id': Select(), 'urlpath': TextInput(attrs={'size': '40'}), - 'name': 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/meetingtools/apps/room/models.py b/src/meetingtools/apps/room/models.py index f0adb99..1c7f2cd 100644 --- a/src/meetingtools/apps/room/models.py +++ b/src/meetingtools/apps/room/models.py @@ -10,15 +10,17 @@ from django.db.models.fields.related import ForeignKey from django.contrib.auth.models import User from meetingtools.apps.cluster.models import ACCluster import time +from django_co_acls.models import AccessControlEntry class Room(models.Model): creator = ForeignKey(User,editable=False) name = CharField(max_length=128,unique=True) urlpath = CharField(max_length=128,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 + acl = ForeignKey(AccessControlEntry,blank=True,null=True) + #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") source_sco_id = IntegerField(verbose_name="Template",blank=True,null=True) diff --git a/src/meetingtools/apps/room/views.py b/src/meetingtools/apps/room/views.py index 65e085b..0489d63 100644 --- a/src/meetingtools/apps/room/views.py +++ b/src/meetingtools/apps/room/views.py @@ -5,7 +5,8 @@ Created on Jan 31, 2011 ''' 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 meetingtools.apps.room.forms import DeleteRoomForm,\ + CreateRoomForm, ModifyRoomForm from django.shortcuts import get_object_or_404 from meetingtools.ac import ac_api_client, api import re @@ -20,6 +21,7 @@ from meetingtools.settings import GRACE from django.utils.datetime_safe import datetime from django.http import HttpResponseRedirect from django.core.exceptions import ObjectDoesNotExist +from django_co_acls.models import allow, deny, acl def _acc_for_user(user): (local,domain) = user.username.split('@') @@ -115,13 +117,17 @@ def view(request,id): }) 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)] + if form.fields.has_key('participants'): + form.fields['participants'].queryset = request.user.groups + if form.fields.has_key('presenters'): + form.fields['presenters'].queryset = request.user.groups + if form.fields.has_key('hosts'): + form.fields['hosts'].queryset = request.user.groups + if form.fields.has_key('source_sco_id'): + 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_room(request, room): +def _update_room(request, room, form=None): api = ac_api_client(request, room.acc) params = {'type':'meeting', 'name':room.name, @@ -136,7 +142,29 @@ def _update_room(request, room): room.sco_id = r.et.find(".//sco").get('sco-id') room.source_sco_id = r.et.find(".//sco").get('sco-source-id') room.save() - #room = _import_room(params['sco-id'], params['name'], params['source-sco-id'], params['url-path'], request.user, acc) + logging.debug(pformat(room)) + + for (key,perm) in [('participants','view'),('presenters','mini-host'),('hosts','host')]: + if form.cleaned_data.has_key(key): + group = form.cleaned_data[key] + if not group and key == 'participants': + group = "anyone" + permission = "view-hidden" + + if group: + allow(room, group, permission) + else: + deny(room,group,permission) + + r = api.request('permissions-reset',{'acl-id': room.sco_id},True) + user_principal = api.find_user(request.user.username) + r = api.request('permissions-update',{'acl-id': room.sco_id,'principal-id': user_principal.get('principal-id'),'permission-id':'host'}) # owner is always host + for ace in acl(room): + principal_id = "public-access" + if ace.group: + principal_id = ace.group.name + r = api.request('permissions-update',{'acl-id': room.sco_id, 'principal-id': principal_id, 'permission-id': ace.permission},True) + return room @login_required @@ -158,17 +186,21 @@ def update(request,id=None): update = False if request.method == 'POST': - form = UpdateRoomForm(request.POST,instance=room) + if update: + form = ModifyRoomForm(request.POST,instance=room) + else: + form = CreateRoomForm(request.POST,instance=room) _init_update_form(request, form, acc, room.folder_sco_id) if form.is_valid(): - room = _update_room(request, room) + room = _update_room(request, room, form) room = form.save() return redirect_to("/rooms#%d" % room.id) else: - form = UpdateRoomForm(instance=room) - _init_update_form(request, form, acc, room.folder_sco_id) if update: - form.fields['urlpath'].widget.attrs['readonly'] = True + form = ModifyRoomForm(instance=room) + else: + form = CreateRoomForm(instance=room) + _init_update_form(request, form, acc, room.folder_sco_id) return respond_to(request,{'text/html':'apps/room/%s.html' % formname},{'form':form,'formtitle': title,'submitname':'%s Room' % what}) @@ -225,7 +257,7 @@ def list(request): 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): diff --git a/src/meetingtools/settings.py b/src/meetingtools/settings.py index e46ca8d..7ea0029 100644 --- a/src/meetingtools/settings.py +++ b/src/meetingtools/settings.py @@ -100,6 +100,8 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.humanize', 'django_extensions', + 'django_co_connector', + 'django_co_acls', 'meetingtools.extensions', 'meetingtools.apps.auth', 'meetingtools.apps.room', diff --git a/src/templates/base.html b/src/templates/base.html index 48255cc..a405345 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -60,7 +60,7 @@ <body> <div id="container"> <div id="header"> - <div id="headline"><h1>SUNET Meting Tools</h1></div> + <div id="headline"><h1>SUNET Meeting Tools</h1></div> <a href="#"><img src="{% prefix %}/site-media/img/sunet-banner.png"/></a> <ul class="ui-helper-reset ui-widget ilist"> |