summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/meetingtools/ac/__init__.py40
-rw-r--r--src/meetingtools/ac/api.py41
-rw-r--r--src/meetingtools/apps/auth/utils.py9
-rw-r--r--src/meetingtools/apps/auth/views.py72
-rw-r--r--src/meetingtools/apps/room/forms.py43
-rw-r--r--src/meetingtools/apps/room/models.py8
-rw-r--r--src/meetingtools/apps/room/views.py58
-rw-r--r--src/meetingtools/settings.py2
-rw-r--r--src/templates/base.html2
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">