From ad21e8e4e5ac8f9eb38830f3024e19fd9329e288 Mon Sep 17 00:00:00 2001 From: Leif Johansson Date: Thu, 9 Feb 2012 00:16:16 +0100 Subject: * refactor api * now depends on with statement * object-pool using queues --- src/meetingtools/ac/__init__.py | 86 ++++---- src/meetingtools/ac/api.py | 17 +- src/meetingtools/apps/room/tasks.py | 54 +++-- src/meetingtools/apps/room/views.py | 211 +++++++++---------- src/meetingtools/apps/stats/views.py | 380 +++++++++++++++++------------------ 5 files changed, 383 insertions(+), 365 deletions(-) diff --git a/src/meetingtools/ac/__init__.py b/src/meetingtools/ac/__init__.py index 2727d67..6523475 100644 --- a/src/meetingtools/ac/__init__.py +++ b/src/meetingtools/ac/__init__.py @@ -1,53 +1,57 @@ from meetingtools.ac.api import ACPClient import time from meetingtools.apps.cluster.models import acc_for_user +from django.core.cache import cache +from Queue import Queue +import logging +from django.contrib.auth.models import User -def ac_api_client_cache(request,acc=None): - if acc == None: - acc = acc_for_user(request.user) - tag = 'ac_api_client_%s' % acc.name - if not request.session.has_key(tag): - request.session[tag] = ACPClientWrapper(acc) - - return request.session[tag] - -def ac_api_client_nocache(request,acc=None): - if acc == None: - acc = acc_for_user(request.user) - return ACPClientWrapper(acc) - -def ac_api_client_direct(acc): - return ACPClientWrapper(acc) - -ac_api_client = ac_api_client_cache - -def ac_api(request,acc=None): - return ACPClient(acc.api_url,acc.user,acc.password) +_pools = {} MAXCALLS = 10 MAXIDLE = 10 -class ACPClientWrapper(object): +class ClientPool(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): + def __init__(self,acc,maxsize=0,increment=5): + self._q = Queue(maxsize) + self._acc = acc + self._increment = increment + + def allocate(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 + api = None + while not api: + if self._q.empty(): + for i in range(1,self._increment): + logging.debug("adding instance %d" % i) + api = ACPClient(self._acc.api_url,self._acc.user,self._acc.password,cpool=self) + self._q.put_nowait(api) + + api = self._q.get() + if api and (api.age > MAXCALLS or now - api.lastused > MAXIDLE): + api = None + return api + +# with ac_api_client(acc) as api +# ... + +def ac_api_client(o): + acc = o + logging.debug("ac_api_client(%s)" % repr(o)) + if hasattr(o,'user') and isinstance(getattr(o,'user'),User): + acc = acc_for_user(getattr(o,'user')) + elif hasattr(o,'acc'): + acc = getattr(o,'acc') + + tag = 'ac_api_client_%d' % acc.id + pool = _pools.get(tag) + if pool is None: + pool = ClientPool(acc,maxsize=30) + _pools[tag] = pool - def __getattr__(self,name): - client = self.client_factory() - return getattr(client,name) + return pool.allocate() + + + \ No newline at end of file diff --git a/src/meetingtools/ac/api.py b/src/meetingtools/ac/api.py index c17d500..4d5559f 100644 --- a/src/meetingtools/ac/api.py +++ b/src/meetingtools/ac/api.py @@ -10,6 +10,7 @@ import logging from pprint import pformat import os import tempfile +import time from lxml import etree from meetingtools.site_logging import logger import lxml @@ -67,15 +68,29 @@ def _getset(d,key,value=None): class ACPClient(): - def __init__(self,url,username=None,password=None,cache=True): + def __init__(self,url,username=None,password=None,cache=True,cpool=None): + self._cpool = cpool + self.age = 0 + self.createtime = time.time() + self.lastused = self.createtime self.url = url self.session = None if username and password: self.login(username,password) if cache: self._cache = {'login':{},'group':{}} + + def __exit__(self,type,value,traceback): + if self._cpool: + self._cpool._q.put_nowait(self) + + def __enter__(self): + return self + def request(self,method,p={},raise_error=False): + self.age += 1 + self.lastused = time.time() u = [] u.append("action=%s" % method) if self.session: diff --git a/src/meetingtools/apps/room/tasks.py b/src/meetingtools/apps/room/tasks.py index 7bfc92a..aea6b3b 100644 --- a/src/meetingtools/apps/room/tasks.py +++ b/src/meetingtools/apps/room/tasks.py @@ -6,8 +6,7 @@ Created on Jan 18, 2012 from celery.task import periodic_task,task from celery.schedules import crontab from meetingtools.apps.cluster.models import ACCluster -from meetingtools.ac import ac_api_client, ac_api_client_nocache,\ - ac_api_client_direct +from meetingtools.ac import ac_api_client from meetingtools.apps.room.models import Room import iso8601 from django.contrib.auth.models import User @@ -17,7 +16,6 @@ import logging from datetime import datetime,timedelta from lxml import etree from django.db.models import Q -import math def _owner_username(api,sco): logging.debug(sco) @@ -87,11 +85,12 @@ def _import_one_room(acc,api,row): lastupdated = None if room: lastupdated = room.lastupdated.replace(tzinfo=None) # make the compare work - very ugly - logging.debug("last %s" % last) - logging.debug("lastupdated %s" % lastupdated) + + #logging.debug("last %s" % last) + #logging.debug("lastupdated %s" % lastupdated) if not room or lastupdated < last: (r,username) = _extended_info(api, sco_id) - logging.debug("owner: %s" % username) + logging.debug("found room owned by %s time for and update" % username) if username is None: return @@ -119,15 +118,14 @@ def _import_one_room(acc,api,row): room.unlock() def _import_acc(acc): - api = ac_api_client_direct(acc) - backthen = datetime.now()-timedelta(seconds=6000000) - backthen = backthen.replace(microsecond=0) - logging.debug(backthen.isoformat()) - r = api.request('report-bulk-objects',{'filter-type': 'meeting','filter-gt-date-modified': backthen.isoformat()}) - for row in r.et.xpath("//row"): - _import_one_room(acc,api,row) + with ac_api_client(acc) as api: + then = datetime.now()-timedelta(seconds=3600) + then = then.replace(microsecond=0) + r = api.request('report-bulk-objects',{'filter-type': 'meeting','filter-gt-date-modified': then.isoformat()}) + for row in r.et.xpath("//row"): + _import_one_room(acc,api,row) -@periodic_task(run_every=crontab(hour="*", minute="*/1", day_of_week="*")) +@periodic_task(run_every=crontab(hour="*", minute="*/5", day_of_week="*")) def import_all_rooms(): for acc in ACCluster.objects.all(): _import_acc(acc) @@ -137,22 +135,22 @@ def start_user_counts_poll(room,niter): @task(name='meetingtools.apps.room.tasks.poll_user_counts',rate_limit="10/s") def poll_user_counts(room,niter=0): - logging.debug("rechecking user_counts for room %s" % room.name) - api = ac_api_client_direct(room.acc) - (nusers,nhosts) = api.poll_user_counts(room) - if nusers > 0: - logging.debug("room occupied by %d users and %d hosts, checking again in 20 ..." % (nusers,nhosts)) - poll_user_counts.apply_async(args=[room],kwargs={'niter': 0},countdown=20) - elif niter > 0: - logging.debug("room empty, will check again in 5 for %d more times ..." % (niter -1)) - poll_user_counts.apply_async(args=[room],kwargs={'niter': niter-1},countdown=5) - return (nusers,nhosts) + logging.debug("polling user_counts for room %s" % room.name) + with ac_api_client(room.acc) as api: + (nusers,nhosts) = api.poll_user_counts(room) + if nusers > 0: + logging.debug("room occupied by %d users and %d hosts, checking again in 20 ..." % (nusers,nhosts)) + poll_user_counts.apply_async(args=[room],kwargs={'niter': 0},countdown=20) + elif niter > 0: + logging.debug("room empty, will check again in 5 for %d more times ..." % (niter -1)) + poll_user_counts.apply_async(args=[room],kwargs={'niter': niter-1},countdown=5) + return (nusers,nhosts) # belts and suspenders - we setup polling for active rooms aswell... @periodic_task(run_every=crontab(hour="*", minute="*/5", day_of_week="*")) def import_recent_user_counts(): for acc in ACCluster.objects.all(): - api = ac_api_client_direct(acc) - then = datetime.now()-timedelta(seconds=600) - for room in Room.objects.filter((Q(lastupdated__gt=then) | Q(lastvisited__gt=then)) & Q(acc=acc)): - api.poll_user_counts(room) \ No newline at end of file + with ac_api_client(acc) as api: + then = datetime.now()-timedelta(seconds=600) + for room in Room.objects.filter((Q(lastupdated__gt=then) | Q(lastvisited__gt=then)) & Q(acc=acc)): + api.poll_user_counts(room) \ No newline at end of file diff --git a/src/meetingtools/apps/room/views.py b/src/meetingtools/apps/room/views.py index 49d8481..ba949fe 100644 --- a/src/meetingtools/apps/room/views.py +++ b/src/meetingtools/apps/room/views.py @@ -9,7 +9,7 @@ from meetingtools.multiresponse import respond_to, redirect_to, json_response,\ from meetingtools.apps.room.forms import DeleteRoomForm,\ CreateRoomForm, ModifyRoomForm, TagRoomForm from django.shortcuts import get_object_or_404 -from meetingtools.ac import ac_api_client, api +from meetingtools.ac import ac_api_client import re from meetingtools.apps import room from django.contrib.auth.decorators import login_required @@ -36,54 +36,55 @@ from meetingtools.apps.room.tasks import start_user_counts_poll 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')) + with ac_api_client(acc) as api: + userid = request.user.username + folders = 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')) + with ac_api_client(acc) as api: + shared = 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 = [{'sco_id': r.get('sco-id'), - 'name': r.findtext('name'), - 'source_sco_id': r.get('source-sco-id'), - 'urlpath': r.findtext('url-path'), - 'description': r.findtext('description')} for r in meetings.et.findall('.//sco')] + with ac_api_client(acc) as api: + meetings = api.request('sco-expanded-contents',{'sco-id': my_meetings_sco_id,'filter-type': 'meeting'}) + if meetings: + rooms = [{'sco_id': r.get('sco-id'), + 'name': r.findtext('name'), + 'source_sco_id': r.get('source-sco-id'), + 'urlpath': r.findtext('url-path'), + 'description': r.findtext('description')} 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')] + with ac_api_client(acc) as api: + if my_meetings_sco_id: + my_templates = 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 = 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 = 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 @@ -121,7 +122,6 @@ def _init_update_form(request,form,acc,my_meetings_sco_id): form.fields['source_sco_id'].widget.choices = [('','-- select template --')]+[r for r in _user_templates(request,acc,my_meetings_sco_id)] def _update_room(request, room, form=None): - api = ac_api_client(request, room.acc) params = {'type':'meeting'} for attr,param in (('sco_id','sco-id'),('folder_sco_id','folder-id'),('source_sco_id','source-sco-id'),('urlpath','url-path'),('name','name'),('description','description')): @@ -141,48 +141,48 @@ def _update_room(request, room, form=None): params[param] = repr(v) logging.debug(pformat(params)) - r = api.request('sco-update', params, True) - - sco_id = r.et.find(".//sco").get('sco-id') - if form: - form.cleaned_data['sco_id'] = sco_id - form.cleaned_data['source_sco_id'] = r.et.find(".//sco").get('sco-source-id') - - room.sco_id = sco_id - room.save() - - user_principal = api.find_user(room.creator.username) - #api.request('permissions-reset',{'acl-id': sco_id},True) - api.request('permissions-update',{'acl-id': sco_id,'principal-id': user_principal.get('principal-id'),'permission-id':'host'},True) # owner is always host - - if form: - if form.cleaned_data.has_key('access'): - access = form.cleaned_data['access'] - if access == 'public': - allow(room,'anyone','view-hidden') - elif access == 'private': - allow(room,'anyone','remove') - - # XXX figure out how to keep the room permissions in sync with the AC permissions - for ace in acl(room): - principal_id = None - if ace.group: - principal = api.find_group(ace.group.name) - if principal: - principal_id = principal.get('principal-id') - elif ace.user: - principal = api.find_user(ace.user.username) - if principal: - principal_id = principal.get('principal-id') - else: - principal_id = "public-access" + with ac_api_client(room.acc) as api: + r = api.request('sco-update', params, True) + sco_id = r.et.find(".//sco").get('sco-id') + if form: + form.cleaned_data['sco_id'] = sco_id + form.cleaned_data['source_sco_id'] = r.et.find(".//sco").get('sco-source-id') - if principal_id: - api.request('permissions-update',{'acl-id': room.sco_id, 'principal-id': principal_id, 'permission-id': ace.permission},True) - - room.deleted_sco_id = None # if we just cleaned a room we zero out the deleted_sco_id field to indicate the room is now ready for use - room.save() # a second save here to avoid races - return room + room.sco_id = sco_id + room.save() + + user_principal = api.find_user(room.creator.username) + #api.request('permissions-reset',{'acl-id': sco_id},True) + api.request('permissions-update',{'acl-id': sco_id,'principal-id': user_principal.get('principal-id'),'permission-id':'host'},True) # owner is always host + + if form: + if form.cleaned_data.has_key('access'): + access = form.cleaned_data['access'] + if access == 'public': + allow(room,'anyone','view-hidden') + elif access == 'private': + allow(room,'anyone','remove') + + # XXX figure out how to keep the room permissions in sync with the AC permissions + for ace in acl(room): + principal_id = None + if ace.group: + principal = api.find_group(ace.group.name) + if principal: + principal_id = principal.get('principal-id') + elif ace.user: + principal = api.find_user(ace.user.username) + if principal: + principal_id = principal.get('principal-id') + else: + principal_id = "public-access" + + if principal_id: + api.request('permissions-update',{'acl-id': room.sco_id, 'principal-id': principal_id, 'permission-id': ace.permission},True) + + room.deleted_sco_id = None # if we just cleaned a room we zero out the deleted_sco_id field to indicate the room is now ready for use + room.save() # a second save here to avoid races + return room @never_cache @login_required @@ -272,12 +272,12 @@ def _import_room(request,acc,r): return None logging.debug("+++ looking at user counts") - api = ac_api_client(request,acc) - userlist = api.request('meeting-usermanager-user-list',{'sco-id': room.sco_id},False) - if userlist.status_code() == 'ok': - room.user_count = int(userlist.et.xpath("count(.//userdetails)")) - room.host_count = int(userlist.et.xpath("count(.//userdetails/role[text() = 'host'])")) - room.save() + with ac_api_client(acc) as api: + userlist = api.request('meeting-usermanager-user-list',{'sco-id': room.sco_id},False) + if userlist.status_code() == 'ok': + room.user_count = int(userlist.et.xpath("count(.//userdetails)")) + room.host_count = int(userlist.et.xpath("count(.//userdetails/role[text() = 'host'])")) + room.save() return room @@ -339,8 +339,8 @@ def delete(request,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) + with ac_api_client(room.acc) as api: + api.request('sco-delete',{'sco-id':room.sco_id},raise_error=True) clear_acl(room) room.delete() @@ -351,11 +351,11 @@ def delete(request,id): return respond_to(request,{'text/html':'edit.html'},{'form':form,'formtitle': 'Delete %s' % room.name,'cancelname':'Cancel','submitname':'Delete Room'}) def _clean(request,room): - api = ac_api_client(request, room.acc) - room.deleted_sco_id = room.sco_id - room.save() - api.request('sco-delete',{'sco-id':room.sco_id},raise_error=False) - room.sco_id = None + with ac_api_client(room.acc) as api: + room.deleted_sco_id = room.sco_id + room.save() + api.request('sco-delete',{'sco-id':room.sco_id},raise_error=False) + room.sco_id = None return _update_room(request, room) def go_by_id(request,id): @@ -387,12 +387,12 @@ def _goto(request,room,clean=True,promote=False): if room.is_locked(): return respond_to(request, {"text/html": "apps/room/retry.html"}, {'room': room, 'wait': 10}) - api = ac_api_client(request, room.acc) now = time.time() lastvisit = room.lastvisit() room.lastvisited = datetime.now() - api.poll_user_counts(room) + with ac_api_client(room.acc) as api: + api.poll_user_counts(room) if clean: # don't clean the room unless you get a good status code from the call to the usermanager api above if room.self_cleaning and room.user_count == 0: @@ -415,10 +415,11 @@ def _goto(request,room,clean=True,promote=False): key = _random_key(20) user_principal = api.find_user(request.user.username) principal_id = user_principal.get('principal-id') - api.request("user-update-pwd",{"user-id": principal_id, 'password': key,'password-verify': key},True) - if promote and room.self_cleaning: - if user_principal: - api.request('permissions-update',{'acl-id': room.sco_id,'principal-id': user_principal.get('principal-id'),'permission-id':'host'},True) + with ac_api_client(room.acc) as api: + api.request("user-update-pwd",{"user-id": principal_id, 'password': key,'password-verify': key},True) + if promote and room.self_cleaning: + if user_principal: + api.request('permissions-update',{'acl-id': room.sco_id,'principal-id': user_principal.get('principal-id'),'permission-id':'host'},True) r = api.request('sco-info',{'sco-id':room.sco_id},True) urlpath = r.et.findtext('.//sco/url-path') @@ -521,14 +522,14 @@ def tag(request,rid): {'form': form,'formtitle': 'Add Tag','cancelname':'Done','submitname': 'Add Tag','room': room, 'tagstring': tn,'tags': tags}) def room_recordings(request,room): - api = ac_api_client(request, room.acc) - r = api.request('sco-expanded-contents',{'sco-id': room.sco_id,'filter-icon':'archive'},True) - return [{'name': sco.findtext('name'), - 'sco_id': sco.get('sco-id'), - 'url': room.acc.make_url(sco.findtext('url-path')), - 'description': sco.findtext('description'), - 'date_created': iso8601.parse_date(sco.findtext('date-created')), - 'date_modified': iso8601.parse_date(sco.findtext('date-modified'))} for sco in r.et.findall(".//sco")] + with ac_api_client(room.acc) as api: + r = api.request('sco-expanded-contents',{'sco-id': room.sco_id,'filter-icon':'archive'},True) + return [{'name': sco.findtext('name'), + 'sco_id': sco.get('sco-id'), + 'url': room.acc.make_url(sco.findtext('url-path')), + 'description': sco.findtext('description'), + 'date_created': iso8601.parse_date(sco.findtext('date-created')), + 'date_modified': iso8601.parse_date(sco.findtext('date-modified'))} for sco in r.et.findall(".//sco")] @login_required def recordings(request,rid): diff --git a/src/meetingtools/apps/stats/views.py b/src/meetingtools/apps/stats/views.py index 1342c2e..b028d18 100644 --- a/src/meetingtools/apps/stats/views.py +++ b/src/meetingtools/apps/stats/views.py @@ -59,148 +59,148 @@ def user_minutes_api(request,username=None): if username == None: username = request.user.username - api = ac_api_client(request) - p = {'sort1-type': 'asc','sort2-type': 'asc','sort1': 'date-created','sort2': 'date-closed','filter-type': 'meeting','filter-login':username} - - form = StatCaledarForm(request.GET) - if not form.is_valid(): - return HttpResponseBadRequest() - - begin = form.cleaned_data['begin'] - end = form.cleaned_data['end'] - - if begin != None: - p['filter-gte-date-created'] = begin - if end != None: - p['filter-lt-date-created'] = end - r = api.request('report-bulk-consolidated-transactions',p) - - series = [] - d_created = None - d_closed = None - ms = 0 - curdate = None - t_ms = 0 - rc = {} - for row in r.et.xpath("//row"): - rc[row.get('sco-id')] = True - date_created_str = row.findtext("date-created") - ts_created = _iso2ts(date_created_str) - date_closed_str = row.findtext("date-closed") - ts_closed = _iso2ts(date_closed_str) + with ac_api_client(request) as api: + p = {'sort1-type': 'asc','sort2-type': 'asc','sort1': 'date-created','sort2': 'date-closed','filter-type': 'meeting','filter-login':username} - d1 = _iso2datesimple(date_created_str) - if d_created == None: - d_created = d1 - - d2 = _iso2datesimple(date_closed_str) - if d_closed == None: - d_closed = d2 - - #duration = _iso2dt(date_closed_str) - _iso2dt(date_created_str) - #sdiff = duration.total_seconds() - - if curdate == None: - curdate = d1 + form = StatCaledarForm(request.GET) + if not form.is_valid(): + return HttpResponseBadRequest() + + begin = form.cleaned_data['begin'] + end = form.cleaned_data['end'] + + if begin != None: + p['filter-gte-date-created'] = begin + if end != None: + p['filter-lt-date-created'] = end + r = api.request('report-bulk-consolidated-transactions',p) + + series = [] + d_created = None + d_closed = None + ms = 0 + curdate = None + t_ms = 0 + rc = {} + for row in r.et.xpath("//row"): + rc[row.get('sco-id')] = True + date_created_str = row.findtext("date-created") + ts_created = _iso2ts(date_created_str) + date_closed_str = row.findtext("date-closed") + ts_closed = _iso2ts(date_closed_str) - if curdate != d1: - #logging.debug(" %s: %s - %s = %d %d" % (row.findtext("name"),date_created_str,date_closed_str,ms,sdiff*1000)) + d1 = _iso2datesimple(date_created_str) + if d_created == None: + d_created = d1 + + d2 = _iso2datesimple(date_closed_str) + if d_closed == None: + d_closed = d2 + + #duration = _iso2dt(date_closed_str) - _iso2dt(date_created_str) + #sdiff = duration.total_seconds() + + if curdate == None: + curdate = d1 + + if curdate != d1: + #logging.debug(" %s: %s - %s = %d %d" % (row.findtext("name"),date_created_str,date_closed_str,ms,sdiff*1000)) + series.append([_date_ts(curdate),int(ms/60000)]) + ms = 0 + curdate = d1 + + if d1 == d2: #same date + diff = (ts_closed - ts_created) + #logging.debug("ms:: %d + %d" % (ms,diff)) + ms = ms + diff + t_ms = t_ms + diff + else: # meeting spanned midnight + ts_date_ts = _date_ts(d2) + #logging.debug("ms: %d + %d" % (ms,(ts_date_ts - ts_created))) + ms = ms + (ts_date_ts - ts_created) + series.append([_date_ts(d1),int(ms/60000)]) + #logging.debug("* %s: %s - %s = %d %d" % (row.findtext("name"),date_created_str,date_closed_str,ms,sdiff*1000)) + t_ms = t_ms + ms + curdate = d2 + #logging.debug("midnight: %d (%d)" % (ts_date_ts,ts_closed)) + ms = (ts_closed - ts_date_ts) + #logging.debug("nms: %d" % ms) + + if curdate != None and ms > 0: series.append([_date_ts(curdate),int(ms/60000)]) - ms = 0 - curdate = d1 - - if d1 == d2: #same date - diff = (ts_closed - ts_created) - #logging.debug("ms:: %d + %d" % (ms,diff)) - ms = ms + diff - t_ms = t_ms + diff - else: # meeting spanned midnight - ts_date_ts = _date_ts(d2) - #logging.debug("ms: %d + %d" % (ms,(ts_date_ts - ts_created))) - ms = ms + (ts_date_ts - ts_created) - series.append([_date_ts(d1),int(ms/60000)]) - #logging.debug("* %s: %s - %s = %d %d" % (row.findtext("name"),date_created_str,date_closed_str,ms,sdiff*1000)) - t_ms = t_ms + ms - curdate = d2 - #logging.debug("midnight: %d (%d)" % (ts_date_ts,ts_closed)) - ms = (ts_closed - ts_date_ts) - #logging.debug("nms: %d" % ms) - - if curdate != None and ms > 0: - series.append([_date_ts(curdate),int(ms/60000)]) - - return json_response({'data': sorted(series,key=lambda x: x[0]), 'rooms': len(rc.keys()), 'minutes': int(t_ms/60000)},request) + + return json_response({'data': sorted(series,key=lambda x: x[0]), 'rooms': len(rc.keys()), 'minutes': int(t_ms/60000)},request) @login_required def domain_minutes_api(request,domain): - api = ac_api_client(request) - p = {'sort': 'asc','sort1': 'date-created','filter-type': 'meeting'} - - form = StatCaledarForm(request.GET) - if not form.is_valid(): - return HttpResponseBadRequest() - - begin = form.cleaned_data['begin'] - end = form.cleaned_data['end'] - - if begin != None: - p['filter-gte-date-created'] = begin - if end != None: - p['filter-lt-date-created'] = end - r = api.request('report-bulk-consolidated-transactions',p) - - series = [] - d_created = None - d_closed = None - ms = 0 - curdate = None - t_ms = 0 - rc = {} - uc = {} - for row in r.et.xpath("//row"): - login = row.findtext("login") - if not login.endswith("@%s" % domain): - continue + with ac_api_client(request) as api: + p = {'sort': 'asc','sort1': 'date-created','filter-type': 'meeting'} - rc[row.get('sco-id')] = True - uc[row.get('principal-id')] = True - date_created_str = row.findtext("date-created") - ts_created = _iso2ts(date_created_str) - date_closed_str = row.findtext("date-closed") - ts_closed = _iso2ts(date_closed_str) + form = StatCaledarForm(request.GET) + if not form.is_valid(): + return HttpResponseBadRequest() - d1 = _iso2datesimple(date_created_str) - if d_created == None: - d_created = d1 - - d2 = _iso2datesimple(date_closed_str) - if d_closed == None: - d_closed = d2 + begin = form.cleaned_data['begin'] + end = form.cleaned_data['end'] + + if begin != None: + p['filter-gte-date-created'] = begin + if end != None: + p['filter-lt-date-created'] = end + r = api.request('report-bulk-consolidated-transactions',p) + + series = [] + d_created = None + d_closed = None + ms = 0 + curdate = None + t_ms = 0 + rc = {} + uc = {} + for row in r.et.xpath("//row"): + login = row.findtext("login") + if not login.endswith("@%s" % domain): + continue - if curdate == None: - curdate = d1 + rc[row.get('sco-id')] = True + uc[row.get('principal-id')] = True + date_created_str = row.findtext("date-created") + ts_created = _iso2ts(date_created_str) + date_closed_str = row.findtext("date-closed") + ts_closed = _iso2ts(date_closed_str) - if curdate != d1: + d1 = _iso2datesimple(date_created_str) + if d_created == None: + d_created = d1 + + d2 = _iso2datesimple(date_closed_str) + if d_closed == None: + d_closed = d2 + + if curdate == None: + curdate = d1 + + if curdate != d1: + series.append([_date_ts(curdate),int(ms/60000)]) + ms = 0 + curdate = d1 + + if d1 == d2: #same date + diff = (ts_closed - ts_created) + ms = ms + diff + t_ms = t_ms + diff + else: # meeting spanned midnight + ts_date_ts = _date_ts(d2) + ms = ms + (ts_date_ts - ts_created) + series.append([_date_ts(d1),int(ms/60000)]) + t_ms = t_ms + ms + curdate = d2 + ms = (ts_closed - ts_date_ts) + + if curdate != None and ms > 0: series.append([_date_ts(curdate),int(ms/60000)]) - ms = 0 - curdate = d1 - - if d1 == d2: #same date - diff = (ts_closed - ts_created) - ms = ms + diff - t_ms = t_ms + diff - else: # meeting spanned midnight - ts_date_ts = _date_ts(d2) - ms = ms + (ts_date_ts - ts_created) - series.append([_date_ts(d1),int(ms/60000)]) - t_ms = t_ms + ms - curdate = d2 - ms = (ts_closed - ts_date_ts) - - if curdate != None and ms > 0: - series.append([_date_ts(curdate),int(ms/60000)]) - - return json_response({'data': sorted(series,key=lambda x: x[0]), 'rooms': len(rc.keys()), 'users': len(uc.keys()), 'minutes': int(t_ms/60000)},request) + + return json_response({'data': sorted(series,key=lambda x: x[0]), 'rooms': len(rc.keys()), 'users': len(uc.keys()), 'minutes': int(t_ms/60000)},request) @login_required @@ -209,65 +209,65 @@ def room_minutes_api(request,rid): if not room.creator == request.user: return HttpResponseForbidden("You can only look at statistics for your own rooms!") - api = ac_api_client(request) - p = {'sort': 'asc','sort1': 'date-created','filter-type': 'meeting','filter-sco-id': room.sco_id} - - form = StatCaledarForm(request.GET) - if not form.is_valid(): - return HttpResponseBadRequest() - - begin = form.cleaned_data['begin'] - end = form.cleaned_data['end'] - - if begin != None: - p['filter-gte-date-created'] = begin - if end != None: - p['filter-lt-date-created'] = end - r = api.request('report-bulk-consolidated-transactions',p) - - series = [] - d_created = None - d_closed = None - ms = 0 - curdate = None - t_ms = 0 - uc = {} - for row in r.et.xpath("//row"): - uc[row.get('principal-id')] = True - date_created_str = row.findtext("date-created") - ts_created = _iso2ts(date_created_str) - date_closed_str = row.findtext("date-closed") - ts_closed = _iso2ts(date_closed_str) + with ac_api_client(request) as api: + p = {'sort': 'asc','sort1': 'date-created','filter-type': 'meeting','filter-sco-id': room.sco_id} - d1 = _iso2datesimple(date_created_str) - if d_created == None: - d_created = d1 - - d2 = _iso2datesimple(date_closed_str) - if d_closed == None: - d_closed = d2 - - if curdate == None: - curdate = d1 + form = StatCaledarForm(request.GET) + if not form.is_valid(): + return HttpResponseBadRequest() + + begin = form.cleaned_data['begin'] + end = form.cleaned_data['end'] + + if begin != None: + p['filter-gte-date-created'] = begin + if end != None: + p['filter-lt-date-created'] = end + r = api.request('report-bulk-consolidated-transactions',p) + + series = [] + d_created = None + d_closed = None + ms = 0 + curdate = None + t_ms = 0 + uc = {} + for row in r.et.xpath("//row"): + uc[row.get('principal-id')] = True + date_created_str = row.findtext("date-created") + ts_created = _iso2ts(date_created_str) + date_closed_str = row.findtext("date-closed") + ts_closed = _iso2ts(date_closed_str) - if curdate != d1: + d1 = _iso2datesimple(date_created_str) + if d_created == None: + d_created = d1 + + d2 = _iso2datesimple(date_closed_str) + if d_closed == None: + d_closed = d2 + + if curdate == None: + curdate = d1 + + if curdate != d1: + series.append([_date_ts(curdate),int(ms/60000)]) + ms = 0 + curdate = d1 + + if d1 == d2: #same date + diff = (ts_closed - ts_created) + ms = ms + diff + t_ms = t_ms + diff + else: # meeting spanned midnight + ts_date_ts = _date_ts(d2) + ms = ms + (ts_date_ts - ts_created) + series.append([_date_ts(d1),int(ms/60000)]) + t_ms = t_ms + ms + curdate = d2 + ms = (ts_closed - ts_date_ts) + + if curdate != None and ms > 0: series.append([_date_ts(curdate),int(ms/60000)]) - ms = 0 - curdate = d1 - - if d1 == d2: #same date - diff = (ts_closed - ts_created) - ms = ms + diff - t_ms = t_ms + diff - else: # meeting spanned midnight - ts_date_ts = _date_ts(d2) - ms = ms + (ts_date_ts - ts_created) - series.append([_date_ts(d1),int(ms/60000)]) - t_ms = t_ms + ms - curdate = d2 - ms = (ts_closed - ts_date_ts) - - if curdate != None and ms > 0: - series.append([_date_ts(curdate),int(ms/60000)]) - - return json_response({'data': sorted(series,key=lambda x: x[0]), 'users': len(uc.keys()), 'minutes': int(t_ms/60000)},request) \ No newline at end of file + + return json_response({'data': sorted(series,key=lambda x: x[0]), 'users': len(uc.keys()), 'minutes': int(t_ms/60000)},request) \ No newline at end of file -- cgit v1.1