Test coverage for vnccollab.theme.zimbrautil

vnccollab/      covered 69% (1245 of 4098 uncovered)
    theme/      covered 69% (1245 of 4098 uncovered)
        zimbrautil.py      covered 35% (130 of 203 uncovered)

    1: import urlparse
    1: from pyzimbra.z.client import ZimbraClient
    1: from pyzimbra.soap import SoapException
       
    1: from zope.interface import implements, Interface
    1: from Products.CMFPlone.utils import safe_unicode as su
    1: from plone.memoize.instance import memoize
       
       
    2: class IZimbraUtil(Interface):
    1:     """Interface for Zimbra Utility"""
       
    1:     def get_client(url_or_context, username='', password=''):
               """Returns an authenticated zimbra client.
       
               If no username is given, it's used the current user information.
               """
       
       
    1: VNC_ZIMBRA_URL = 'https://'
       
       
    2: class ZimbraUtil:
    1:     """Zimbra Utility."""
    1:     implements(IZimbraUtil)
       
    1:     @memoize
    1:     def get_client(self, url=VNC_ZIMBRA_URL, username='', password=''):
               '''Returns a ZimbraUserClient.
       
               Args:
                 @url - URL of the zimbra server, withou '/service/soap'
                 @username - Login of the user. If not present, the client
                             won't be authenticated.
                 @password - Password of the user.
               '''
    1:         url = url + '/service/soap'
    1:         client = ZimbraUtilClient(url, username, password)
    1:         return client
       
       
    1: def refreshAuthToken(func, *args, **kw):
           """Catches SoapException from passed function call and if the error is
           identified as Token Expiration error - authenticate client and then repeat
           the call.
           """
    9:     def decorated(*args, **kw):
    6:         try:
    6:             result = func(*args, **kw)
    6:         except SoapException, e:
>>>>>> msg = unicode(e)
>>>>>> if u'auth credentials have expired' in msg or \
>>>>>> u'AUTH_EXPIRED' in msg:
# authenticate, args[0] is func's method object
>>>>>> args[0].authenticate()
>>>>>> return func(*args, **kw)
else:
>>>>>> raise e
else:
>>>>>> return result
9: return decorated 2: class ZimbraUtilClient: ''' Zimbra client support class. It returns ZimbraClient results in a way more digerible by plone. 1: ''' 1: def __init__(self, url, username='', password=''): 1: self.url = url 1: p = urlparse.urlparse(self.url) 1: self.server_url = '{0}://{1}'.format(p.scheme, p.netloc) 1: self.client = ZimbraClient(url) 1: self.username = username 1: self.password = password 1: if username:
>>>>>> self.authenticate()
1: def authenticate(self):
>>>>>> self.client.authenticate(self.username, self.password)
1: @refreshAuthToken 1: def get_raw_emails(self, folder=None, searchable_text='', 1: offset=0, limit=10, 1: recip='1', sortBy='dateDesc', types='conversation'): """Returns list of email conversations. Args: @folder - if given, return list of emails from inside this folder @serchable_text - Text the email should have to be shown. @offset - if given, return list of emails starting from start @limit - return 'limit' number of emails @recip - whether to return 'to' email adress instead of 'from' for sent messages and conversations @sort_by - sort result set by given field """ 2: query = { 2: 'types': types, 2: 'limit': limit, 2: 'offset': offset, 2: 'recip': recip, 2: 'sortBy': sortBy, } 2: if folder:
>>>>>> query['query'] = 'in:%s' % folder
2: if searchable_text:
>>>>>> query['query'] = searchable_text
2: result = self.search(query)
>>>>>> return result
1: @refreshAuthToken 1: def get_emails(self, folder=None, searchable_text='', 1: offset=0, limit=10, 1: recip='1', sortBy='dateDesc', types='conversation'): 2: result = self.get_raw_emails(folder=folder, 2: searchable_text=searchable_text, offset=offset, limit=limit, 2: recip=recip, sortBy=sortBy, types=types)
>>>>>> return [self._dict_from_mail(x) for x in result]
1: @refreshAuthToken 1: def get_address_book(self, offset=0, limit=100): '''Returns the address book of the user.'''
>>>>>> query = {
>>>>>> 'types': 'contact',
>>>>>> 'sortBy': 'nameAsc',
>>>>>> 'offset': offset,
>>>>>> 'limit': limit,
>>>>>> 'query': 'in:contacts'
}
>>>>>> result = self.search(query)
>>>>>> return result
1: @refreshAuthToken def search(self, query): '''Returns the result of making the given query.''' 2: result = self.client.invoke('urn:zimbraMail', 'SearchRequest', query) # if we have activated returnAllAttrs, result is a tuple. # We're interested here only in its first element
>>>>>> if type(result) == tuple:
>>>>>> result = result[0]
# Get the result out of the list
>>>>>> if not isinstance(result, list):
>>>>>> result = [result]
>>>>>> return result
1: @refreshAuthToken def get_email(self, eid): """Returns email by given id. It also marks conversation as read. """
>>>>>> result = self.client.invoke('urn:zimbraMail', 'GetConvRequest',
>>>>>> {'c': {'id': eid, 'fetch': 'all', 'html': '1'}})[0].m
# TODO: make zimbra conversation as read
>>>>>> if not isinstance(result, list):
>>>>>> result = [result]
>>>>>> return result
1: @refreshAuthToken def get_email_thread(self, eid): """Returns conversation emails by given id. It also marks conversation as read. """
>>>>>> result = self.get_email(eid)
>>>>>> thread = []
>>>>>> for item in result:
>>>>>> from_ = [su(e._getAttr('p')) for e in item.e
>>>>>> if e._getAttr('t') == 'f']
>>>>>> from_ = from_[0] if len(from_) else ''
>>>>>> to = u', '.join([su(e._getAttr('d')) for e in item.e
>>>>>> if e._getAttr('t') == 't'])
>>>>>> thread.append({
>>>>>> 'from': from_,
>>>>>> 'to': to,
>>>>>> 'body': item,
>>>>>> 'id': item._getAttr('_orig_id'),
>>>>>> 'date': item._getAttr('d'),
})
>>>>>> return thread
1: def _dict_from_mail(self, mail): """Converts a zimbra mail into a dictionary"""
>>>>>> people = getattr(mail, 'e', [])
>>>>>> if not people:
>>>>>> people = []
>>>>>> elif not isinstance(people, list):
>>>>>> people = [people]
# prepare subject
>>>>>> subject = getattr(mail, 'su', '') or 'No Subject'
>>>>>> dct = {
>>>>>> 'subject': su(subject),
>>>>>> 'body': u'%s (%s) - %s - %s' % (u', '.join([p._getAttr('d')
>>>>>> for p in people]), mail._getAttr('n'), su(mail.su),
>>>>>> su(getattr(mail, 'fr', ''))),
>>>>>> 'unread': u'u' in (mail._getAttr('f') or ''),
>>>>>> 'id': mail._getAttr('_orig_id'),
>>>>>> 'date': mail._getAttr('d'),
>>>>>> 'cid': mail._getAttr('cid'),
}
>>>>>> return dct
1: @refreshAuthToken def create_task(self, dct): """Creates a task, given its description as a dictionary"""
>>>>>> task = dict(**dct)
>>>>>> for k, v in task.items():
>>>>>> if v is None:
>>>>>> task[k] = u''
>>>>>> task['startDate'] = self._stringFromDate(task['startDate'])
>>>>>> task['endDate'] = self._stringFromDate(task['endDate'])
>>>>>> query = {
>>>>>> 'm': {
#'l' : '24486', # List id. It could be ommited
>>>>>> 'inv': {
>>>>>> 'comp': {
>>>>>> 'name': task.get('subject', ''),
>>>>>> 'loc': task.get('location', ''),
>>>>>> 'percentComplete': task.get('percentComplete', '0'),
>>>>>> 'status': task.get('status', 'NEED'), # Not started
>>>>>> 'priority': task.get('priority', '5'), # Normal
>>>>>> 'or': {'a': task['author'], # Required
>>>>>> 'd': task.get('authorName', ''),
}, }, },
>>>>>> 'mp': {
>>>>>> 'ct': 'multipart/alternative',
>>>>>> 'mp': {
>>>>>> 'ct': 'text/plain',
>>>>>> 'content': task.get('content', '')}},
} }
>>>>>> if task['content']:
>>>>>> query['m']['mp'] = {'ct': 'text/plain',
>>>>>> 'content': task['content']}
>>>>>> if task['startDate']:
>>>>>> query['m']['inv']['comp']['s'] = {'d': task['startDate']}
>>>>>> if task['endDate']:
>>>>>> query['m']['inv']['comp']['e'] = {'d': task['endDate']}
>>>>>> response, _ = self.client.invoke('urn:zimbraMail',
>>>>>> 'CreateTaskRequest', query)
>>>>>> response = self.get_message(response._getAttr(u'invId'))
>>>>>> task = self._taskFromGetMsgResponse(response)
>>>>>> return task
1: @refreshAuthToken def get_message(self, id): '''Returns a message (mail, task, etc), given its id.'''
>>>>>> query = {"_jsns": "urn:zimbraMail",
>>>>>> "m": {'id': id, 'html': 1, 'needExp': 1, 'max': 250000}}
>>>>>> response, attrs = self.client.invoke('urn:zimbraMail',
>>>>>> 'GetMsgRequest', query)
>>>>>> return response
1: @refreshAuthToken def get_all_tasks(self): '''Returns all the zimbra tasks of the authenticated user.'''
>>>>>> query = {'query': 'in:"tasks"', 'types': 'task', }
>>>>>> response, _ = self.client.invoke('urn:zimbraMail',
>>>>>> 'SearchRequest', query)
>>>>>> if type(response) != list:
>>>>>> response = [response]
>>>>>> return [self._taskFromSearchResponse(x) for x in response]
1: def _taskFromGetMsgResponse(self, response): '''Returns a ZimbraTask given a zimbra CreateTaskResponse.'''
>>>>>> id = response._getAttr('_orig_id')
>>>>>> title = response.inv.comp._getAttr('name')
>>>>>> body = getattr(response.inv.comp, 'fr', u'')
>>>>>> return ZimbraTask(id, title, self.server_url, body)
1: def _taskFromSearchResponse(self, response): '''Returns a ZImbraTask given a zimbra SearchResponse.'''
>>>>>> id = response._getAttr('invId')
>>>>>> title = response._getAttr('name')
>>>>>> body = getattr(response, 'fr', u'')
>>>>>> return ZimbraTask(id, title, self.server_url, body)
1: def _stringFromDate(self, date=None):
>>>>>> if not date:
>>>>>> return ''
>>>>>> return date.strftime('%Y%m%d')
2: class ZimbraTask: 1: def __init__(self, id, title, server_url, body):
>>>>>> self.id = id
>>>>>> self.title = title
>>>>>> self.server_url = server_url
>>>>>> self.url = ('{0}/zimbra/h/search?su=1&si=0&so=0&sc=4&st=task'
>>>>>> + '&id={1}&action=edittask').format(self.server_url, id)
>>>>>> self.body = body
1: def __eq__(self, other):
>>>>>> return (self.id == other.id) and (self.server_url == other.server_url)
1: def __repr__(self):
>>>>>> if len(self.body) < 10:
>>>>>> body = repr(self.body)
else:
>>>>>> body = repr(self.body[:10] + '...')
>>>>>> return 'ZimbraTask({0}, {1}, {2})'.format(repr(self.id),
>>>>>> repr(self.title), body)
1: zimbraUtilInstance = ZimbraUtil()