Contact as Person and Organization object, callable using lxml
[treecutter.git] / xinclude / contact.py
index e7e0ab32820a0127f7344fd8b88b310cde60e5c1..c6d8034344fb903216239eed4c889f7bded73e02 100755 (executable)
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from vobject import readComponents
 import sys
-from address import Address
+
+from vobject import readComponents
 from geohash import encode
+from urlparse import urlparse
+from getpass import getpass
+from lxml import etree
+from lxml.builder import ElementMaker
 
-for arg in sys.argv[1:]:
-  al = arg.split("=")
-  if al[0] == "lang":
-    lang = al[1]
-  if al[0] == "xptr":
-    argument = al[1]
-
-(cards,query) = argument.split('?')
-(key, name) = query.split(':')
-with open(cards, 'r') as f:
-  card_data = f.read()
-f.closed
-
-# Scan for the correct card
-found = None
-out = u''
-for card in readComponents(card_data):
-# card.prettyPrint()
-  if key in card.contents.keys():
-    if name.decode('utf-8') == card.contents[key][0].value[0]:
-      found = card
-  if key == 'firstname':
-    if name.decode('utf-8') == card.n.value.given:
-      found = card
-  if key == 'surname':
-    if name.decode('utf-8') == card.n.value.family:
-      found = card
-
-if not found:
-  print query+' failed in '+cards
-  exit(2)
-# when card is found parse it to docbook.
-pn = ''
-
-if 'n' in found.contents.keys():
-  n = found.n.value
-  empty = n.prefix == '' and n.given == '' and \
-      n.additional =='' and n.family ==''  and n.suffix == ''
-  if not empty:
-    pn += '<personname>'
-    if n.prefix != '':
-      pn += '<honorific>'+n.prefix+'</honorific> '
-    if n.given != '':
-      pn += '<firstname>'+n.given+'</firstname> '
-    if n.additional != '':
-      pn += '<othername>'+n.additional+'</othername> '
-    if n.family != '':
-      pn += '<surname>'+n.family+'</surname> '
-    if n.suffix != '':
-      pn += '<lineage>'+n.suffix+'</lineage> '
-    pn += '</personname>'
-
-ad = ''
-if 'adr' in found.contents.keys():
-  for a, t in zip(found.contents['adr'],found.contents['tel']):
-    ad += '\n<address type="'+a.type_param+'"> '
-    if a.value.street != '':
-      ad += '<street>'+a.value.street+'</street>'
-    if a.value.code != '':
-      ad += '<postcode>'+a.value.code+'</postcode> '
-    if a.value.city != '':
-      ad += '<city>'+a.value.city+'</city>'
-    if a.value.country != '':
-      ad += '<country>'+a.value.country+'</country>'
-    if t.value != '':
-      ad += '<phone>'+t.value+'</phone>'
-    ad += '</address>'
-    geostr = u''+a.value.street+', '+a.value.city+', '+a.value.country
-    (lat,lon) = geocode(geostr.encode('utf-8'))
-    mapimage([(float(lat),float(lon))])
-    ad += maplink(lat,lon)
-
-o = ''
-if 'org' in found.contents.keys():
-  o = '''
-      <org>
-        <orgname>'''+found.org.value[0]+'''</orgname>
-        '''+ad+'''
-        </org>'''
-
-
-url = ''
-if 'url' in found.contents.keys():
-  url += '<uri type="website"><link xlink:href="'+found.url.value+'"/></uri> '
-
-geo = ''
-#if 'geo' in found.contents.keys():
-#  (lat,lon) = found.geo.value.split(';')
-#  mapimage([(float(lat),float(lon))])
-#  # create picture
-#  geo += maplink(lat,lon)
-
-
-# Turn off email for now
-email = ''
-#if 'email' in found.contents.keys():
-#  email += '<email>'+found.email.value+'</email>'
-
-if empty:
-  content = pn+o+url+geo+email
-else:
-  if o == '':
-    content = '<person>'+pn+ad+url+geo+email+'</person>'
-  else:
-    content = '<person>'+pn+'<affiliation>'+o+'</affiliation>'+url+geo+email+ \
-        '</person>'
-out = '''
-<para xmlns="http://docbook.org/ns/docbook"
-      xmlns:xlink="http://www.w3.org/1999/xlink">
-  '''+content+'''
-</para>
-'''
-
-ex ='''
-    <address>
-      <street>Street</street>
-      <postcode>Postcode</postcode> <city>City</city>
-      <country>Country</country>
-      <phone>+1 123 456 789</phone>
-    </address>
-    <affiliation>
-      <jobtitle>Occupation</jobtitle>
-      <org>
-        <orgname>Organization</orgname>
-        <address>
-          <street>Street</street>
-          <postcode>Postcode</postcode> <city>City</city>
-          <country>Country</country>
-          <phone>+1 123 456 789</phone>
-        </address>
-      </org>
-    </affiliation>
-  </person>
-</para>
-'''
-
-sys.stdout.write(out.encode('utf-8'))
+from address import Address
+from treecutter import constants as const
+
+class Contacts(object):
+    def __init__(self, uri):
+        self.uri = uri
+        self.card_data = None
+        if uri.scheme == 'file':
+            with open(self.uri.path, 'r') as f:
+                self.card_data = f.read()
+            f.closed
+        if uri.scheme == 'http':
+            pw = getpass()
+            print "http not yet implemented"
+        if uri.scheme == 'https':
+            print "https not yet implemented"
+
+    def filter(self,query):
+        (key, name) = query.split(':')
+        card = None
+        for c in readComponents(self.card_data):
+            if key in c.contents.keys():
+                if name.decode('utf-8') == c.contents[key][0].value[0]:
+                    card = c
+            if key == 'firstname':
+                if name.decode('utf-8') == c.n.value.given:
+                    card = c
+            if key == 'surname':
+                if name.decode('utf-8') == c.n.value.family:
+                    card = c
+        return Contact(card)
+
+class Contact(object):
+    def __init__(self,card):
+        self.card = card
+        self.person = None
+        self.organization = Organization('')
+        self.address = []
+        self.phone = ''
+        self.jobtitle = ''
+        self.url = ''
+        self.email = ''
+        self.parsecard()
+
+    def parsecard(self):
+        if 'n' in self.card.contents.keys():
+            n = self.card.n.value
+            empty = n.prefix == '' and n.given == '' and \
+                n.additional =='' and n.family ==''  and n.suffix == ''
+        if not empty:
+            self.person = Person(n.given,n.family,
+                                 n.prefix,n.additional,n.suffix)
+        if 'title' in self.card.contents.keys():
+            self.jobtitle = self.card.title.value
+
+        if 'org' in self.card.contents.keys():
+            self.organization = Organization(self.card.org.value[0])
+
+        for av in self.card.contents['adr']:
+            a = av.value
+            addr = Address(a.street,a.code,a.city,a.country)
+            if av.type_param == 'work':
+                self.organization.add_address(addr)
+            if av.type_param == 'home':
+                self.address.append(addr)
+            addr.geocode()
+
+        for i,t in enumerate(self.card.contents['tel']):
+            if av.type_param == 'cell':  # Does not exist ?
+                self.phone = t.value
+            if av.type_param == 'work':
+                self.organization.add_phone(i,t.value)
+            if av.type_param == 'home':
+                self.address[i].add_phone(t.value)
+
+        if 'url' in self.card.contents.keys():
+            self.url = self.card.url.value
+
+#        if 'email' in self.card.contents.keys():
+#            self.email = self.card.email.value
+
+
+    def db_xml(self):
+        db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP)
+        if self.person:
+            pers = db.person(self.person.db_xml(),db.phone(self.phone))
+            for a in self.address:
+                pers.append(a.db_xml())
+            pers.append(db.affiliation(db.jobtitle(self.jobtitle),
+                                       self.organization.db_xml()))
+            pers.append(db.email(self.email))
+        else:
+            pers = self.organization.db_xml()
+        pers.append(db.uri(db.link(self.url,**{const.XLINK+"href": self.url}),
+                           type='website'))
+        return pers
+
+class Person(object):
+    def __init__(self,firstname,surname,honorific,othername,linage):
+        self.honorific = honorific
+        self.firstname = firstname
+        self.othername = othername
+        self.surname = surname
+        self.linage = linage
+
+    def db_xml(self):
+        db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP)
+        p = db.personname(
+          db.honorific(self.honorific),
+          db.firstname(self.firstname),
+          db.othername(self.othername),
+          db.surname(self.surname),
+          db.linage(self.linage)
+          )
+        return p
+
+class Organization(object):
+    def __init__(self,orgname):
+        self.orgname = orgname
+        self.address = []
+
+    def add_address(self,addr):
+        addr.set_name(self.orgname)
+        self.address.append(addr)
+
+    def add_phone(self, i, phone):
+        # Quick fix for when an address has two phone numbers : FIXME
+        try:
+            self.address[i].add_phone(phone)
+        except IndexError, e:
+            pass
+
+    def db_xml(self):
+        db = ElementMaker(namespace=const.DB_NS, nsmap=const.NSMAP)
+        org = db.org(db.orgname(self.orgname))
+        for a in self.address:
+            org.append(a.db_xml())
+        return org
+
+def recursively_empty(e):
+    if e.text or e.tag == const.DB+'imagedata':
+        return False
+    return all((recursively_empty(c) for c in e.iterchildren()))
+
+def clean_db(xml):
+    context = etree.iterwalk(xml)
+    for action, elem in context:
+        parent = elem.getparent()
+        if recursively_empty(elem):
+            parent.remove(elem)
+
+
+if __name__ == "__main__":
+    for arg in sys.argv[1:]:
+        al = arg.split("=",1)
+        if al[0] == "lang":
+            lang = al[1]
+        if al[0] == "xptr":
+            argument = al[1]
+
+    (uristr,query) = argument.split('|')
+    uri = urlparse(uristr)
+    contact = Contacts(uri).filter(query)
+    cxml = contact.db_xml()
+    clean_db(cxml)
+
+    #print(etree.tostring(cxml, pretty_print=True))
+    #sys.stdout.write(out.encode('utf-8'))
+    sys.stdout.write(etree.tostring(cxml,encoding='UTF-8',pretty_print=False))