475 lines
12 KiB
Python
475 lines
12 KiB
Python
|
#!/usr/bin/env python
|
||
|
#
|
||
|
# Copyright (C) 2009 Google Inc.
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
"""Data model classes for parsing and generating XML for the Contacts API."""
|
||
|
|
||
|
|
||
|
__author__ = 'vinces1979@gmail.com (Vince Spicer)'
|
||
|
|
||
|
|
||
|
import atom.core
|
||
|
import gdata
|
||
|
import gdata.data
|
||
|
|
||
|
|
||
|
PHOTO_LINK_REL = 'http://schemas.google.com/contacts/2008/rel#photo'
|
||
|
PHOTO_EDIT_LINK_REL = 'http://schemas.google.com/contacts/2008/rel#edit-photo'
|
||
|
|
||
|
EXTERNAL_ID_ORGANIZATION = 'organization'
|
||
|
|
||
|
RELATION_MANAGER = 'manager'
|
||
|
|
||
|
CONTACTS_NAMESPACE = 'http://schemas.google.com/contact/2008'
|
||
|
CONTACTS_TEMPLATE = '{%s}%%s' % CONTACTS_NAMESPACE
|
||
|
|
||
|
|
||
|
class BillingInformation(atom.core.XmlElement):
|
||
|
"""
|
||
|
gContact:billingInformation
|
||
|
Specifies billing information of the entity represented by the contact. The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'billingInformation'
|
||
|
|
||
|
|
||
|
class Birthday(atom.core.XmlElement):
|
||
|
"""
|
||
|
Stores birthday date of the person represented by the contact. The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'birthday'
|
||
|
when = 'when'
|
||
|
|
||
|
|
||
|
class CalendarLink(atom.core.XmlElement):
|
||
|
"""
|
||
|
Storage for URL of the contact's calendar. The element can be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'calendarLink'
|
||
|
rel = 'rel'
|
||
|
label = 'label'
|
||
|
primary = 'primary'
|
||
|
href = 'href'
|
||
|
|
||
|
|
||
|
class DirectoryServer(atom.core.XmlElement):
|
||
|
"""
|
||
|
A directory server associated with this contact.
|
||
|
May not be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'directoryServer'
|
||
|
|
||
|
|
||
|
class Event(atom.core.XmlElement):
|
||
|
"""
|
||
|
These elements describe events associated with a contact.
|
||
|
They may be repeated
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'event'
|
||
|
label = 'label'
|
||
|
rel = 'rel'
|
||
|
when = gdata.data.When
|
||
|
|
||
|
|
||
|
class ExternalId(atom.core.XmlElement):
|
||
|
"""
|
||
|
Describes an ID of the contact in an external system of some kind.
|
||
|
This element may be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'externalId'
|
||
|
|
||
|
|
||
|
def ExternalIdFromString(xml_string):
|
||
|
return atom.core.parse(ExternalId, xml_string)
|
||
|
|
||
|
|
||
|
class Gender(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies the gender of the person represented by the contact.
|
||
|
The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'directoryServer'
|
||
|
value = 'value'
|
||
|
|
||
|
|
||
|
class Hobby(atom.core.XmlElement):
|
||
|
"""
|
||
|
Describes an ID of the contact in an external system of some kind.
|
||
|
This element may be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'hobby'
|
||
|
|
||
|
|
||
|
class Initials(atom.core.XmlElement):
|
||
|
""" Specifies the initials of the person represented by the contact. The
|
||
|
element cannot be repeated. """
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'initials'
|
||
|
|
||
|
|
||
|
class Jot(atom.core.XmlElement):
|
||
|
"""
|
||
|
Storage for arbitrary pieces of information about the contact. Each jot
|
||
|
has a type specified by the rel attribute and a text value.
|
||
|
The element can be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'jot'
|
||
|
rel = 'rel'
|
||
|
|
||
|
|
||
|
class Language(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies the preferred languages of the contact.
|
||
|
The element can be repeated.
|
||
|
|
||
|
The language must be specified using one of two mutually exclusive methods:
|
||
|
using the freeform @label attribute, or using the @code attribute, whose value
|
||
|
must conform to the IETF BCP 47 specification.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'language'
|
||
|
code = 'code'
|
||
|
label = 'label'
|
||
|
|
||
|
|
||
|
class MaidenName(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies maiden name of the person represented by the contact.
|
||
|
The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'maidenName'
|
||
|
|
||
|
|
||
|
class Mileage(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies the mileage for the entity represented by the contact.
|
||
|
Can be used for example to document distance needed for reimbursement
|
||
|
purposes. The value is not interpreted. The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'mileage'
|
||
|
|
||
|
|
||
|
class NickName(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies the nickname of the person represented by the contact.
|
||
|
The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'nickname'
|
||
|
|
||
|
|
||
|
class Occupation(atom.core.XmlElement):
|
||
|
"""
|
||
|
Specifies the occupation/profession of the person specified by the contact.
|
||
|
The element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'occupation'
|
||
|
|
||
|
|
||
|
class Priority(atom.core.XmlElement):
|
||
|
"""
|
||
|
Classifies importance of the contact into 3 categories:
|
||
|
* Low
|
||
|
* Normal
|
||
|
* High
|
||
|
|
||
|
The priority element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'priority'
|
||
|
|
||
|
|
||
|
class Relation(atom.core.XmlElement):
|
||
|
"""
|
||
|
This element describe another entity (usually a person) that is in a
|
||
|
relation of some kind with the contact.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'relation'
|
||
|
rel = 'rel'
|
||
|
label = 'label'
|
||
|
|
||
|
|
||
|
class Sensitivity(atom.core.XmlElement):
|
||
|
"""
|
||
|
Classifies sensitivity of the contact into the following categories:
|
||
|
* Confidential
|
||
|
* Normal
|
||
|
* Personal
|
||
|
* Private
|
||
|
|
||
|
The sensitivity element cannot be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'sensitivity'
|
||
|
rel = 'rel'
|
||
|
|
||
|
|
||
|
class UserDefinedField(atom.core.XmlElement):
|
||
|
"""
|
||
|
Represents an arbitrary key-value pair attached to the contact.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'userDefinedField'
|
||
|
key = 'key'
|
||
|
value = 'value'
|
||
|
|
||
|
|
||
|
def UserDefinedFieldFromString(xml_string):
|
||
|
return atom.core.parse(UserDefinedField, xml_string)
|
||
|
|
||
|
|
||
|
class Website(atom.core.XmlElement):
|
||
|
"""
|
||
|
Describes websites associated with the contact, including links.
|
||
|
May be repeated.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'website'
|
||
|
|
||
|
href = 'href'
|
||
|
label = 'label'
|
||
|
primary = 'primary'
|
||
|
rel = 'rel'
|
||
|
|
||
|
|
||
|
def WebsiteFromString(xml_string):
|
||
|
return atom.core.parse(Website, xml_string)
|
||
|
|
||
|
|
||
|
class HouseName(atom.core.XmlElement):
|
||
|
"""
|
||
|
Used in places where houses or buildings have names (and
|
||
|
not necessarily numbers), eg. "The Pillars".
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'housename'
|
||
|
|
||
|
|
||
|
class Street(atom.core.XmlElement):
|
||
|
"""
|
||
|
Can be street, avenue, road, etc. This element also includes the house
|
||
|
number and room/apartment/flat/floor number.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'street'
|
||
|
|
||
|
|
||
|
class POBox(atom.core.XmlElement):
|
||
|
"""
|
||
|
Covers actual P.O. boxes, drawers, locked bags, etc. This is usually but not
|
||
|
always mutually exclusive with street
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'pobox'
|
||
|
|
||
|
|
||
|
class Neighborhood(atom.core.XmlElement):
|
||
|
"""
|
||
|
This is used to disambiguate a street address when a city contains more than
|
||
|
one street with the same name, or to specify a small place whose mail is
|
||
|
routed through a larger postal town. In China it could be a county or a
|
||
|
minor city.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'neighborhood'
|
||
|
|
||
|
|
||
|
class City(atom.core.XmlElement):
|
||
|
"""
|
||
|
Can be city, village, town, borough, etc. This is the postal town and not
|
||
|
necessarily the place of residence or place of business.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'city'
|
||
|
|
||
|
|
||
|
class SubRegion(atom.core.XmlElement):
|
||
|
"""
|
||
|
Handles administrative districts such as U.S. or U.K. counties that are not
|
||
|
used for mail addressing purposes. Subregion is not intended for
|
||
|
delivery addresses.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'subregion'
|
||
|
|
||
|
|
||
|
class Region(atom.core.XmlElement):
|
||
|
"""
|
||
|
A state, province, county (in Ireland), Land (in Germany),
|
||
|
departement (in France), etc.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'region'
|
||
|
|
||
|
|
||
|
class PostalCode(atom.core.XmlElement):
|
||
|
"""
|
||
|
Postal code. Usually country-wide, but sometimes specific to the
|
||
|
city (e.g. "2" in "Dublin 2, Ireland" addresses).
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'postcode'
|
||
|
|
||
|
|
||
|
class Country(atom.core.XmlElement):
|
||
|
""" The name or code of the country. """
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'country'
|
||
|
|
||
|
|
||
|
class PersonEntry(gdata.data.BatchEntry):
|
||
|
"""Represents a google contact"""
|
||
|
|
||
|
billing_information = BillingInformation
|
||
|
birthday = Birthday
|
||
|
calendar_link = [CalendarLink]
|
||
|
directory_server = DirectoryServer
|
||
|
event = [Event]
|
||
|
external_id = [ExternalId]
|
||
|
gender = Gender
|
||
|
hobby = [Hobby]
|
||
|
initals = Initials
|
||
|
jot = [Jot]
|
||
|
language= [Language]
|
||
|
maiden_name = MaidenName
|
||
|
mileage = Mileage
|
||
|
nickname = NickName
|
||
|
occupation = Occupation
|
||
|
priority = Priority
|
||
|
relation = [Relation]
|
||
|
sensitivity = Sensitivity
|
||
|
user_defined_field = [UserDefinedField]
|
||
|
website = [Website]
|
||
|
|
||
|
name = gdata.data.Name
|
||
|
phone_number = [gdata.data.PhoneNumber]
|
||
|
organization = gdata.data.Organization
|
||
|
postal_address = [gdata.data.PostalAddress]
|
||
|
email = [gdata.data.Email]
|
||
|
im = [gdata.data.Im]
|
||
|
structured_postal_address = [gdata.data.StructuredPostalAddress]
|
||
|
extended_property = [gdata.data.ExtendedProperty]
|
||
|
|
||
|
|
||
|
class Deleted(atom.core.XmlElement):
|
||
|
"""If present, indicates that this contact has been deleted."""
|
||
|
_qname = gdata.GDATA_TEMPLATE % 'deleted'
|
||
|
|
||
|
|
||
|
class GroupMembershipInfo(atom.core.XmlElement):
|
||
|
"""
|
||
|
Identifies the group to which the contact belongs or belonged.
|
||
|
The group is referenced by its id.
|
||
|
"""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'groupMembershipInfo'
|
||
|
|
||
|
href = 'href'
|
||
|
deleted = 'deleted'
|
||
|
|
||
|
|
||
|
class ContactEntry(PersonEntry):
|
||
|
"""A Google Contacts flavor of an Atom Entry."""
|
||
|
|
||
|
deleted = Deleted
|
||
|
group_membership_info = [GroupMembershipInfo]
|
||
|
organization = gdata.data.Organization
|
||
|
|
||
|
def GetPhotoLink(self):
|
||
|
for a_link in self.link:
|
||
|
if a_link.rel == PHOTO_LINK_REL:
|
||
|
return a_link
|
||
|
return None
|
||
|
|
||
|
def GetPhotoEditLink(self):
|
||
|
for a_link in self.link:
|
||
|
if a_link.rel == PHOTO_EDIT_LINK_REL:
|
||
|
return a_link
|
||
|
return None
|
||
|
|
||
|
|
||
|
class ContactsFeed(gdata.data.BatchFeed):
|
||
|
"""A collection of Contacts."""
|
||
|
entry = [ContactEntry]
|
||
|
|
||
|
|
||
|
class SystemGroup(atom.core.XmlElement):
|
||
|
"""The contacts systemGroup element.
|
||
|
|
||
|
When used within a contact group entry, indicates that the group in
|
||
|
question is one of the predefined system groups."""
|
||
|
|
||
|
_qname = CONTACTS_TEMPLATE % 'systemGroup'
|
||
|
id = 'id'
|
||
|
|
||
|
|
||
|
class GroupEntry(gdata.data.BatchEntry):
|
||
|
"""Represents a contact group."""
|
||
|
extended_property = [gdata.data.ExtendedProperty]
|
||
|
system_group = SystemGroup
|
||
|
|
||
|
|
||
|
class GroupsFeed(gdata.data.BatchFeed):
|
||
|
"""A Google contact groups feed flavor of an Atom Feed."""
|
||
|
entry = [GroupEntry]
|
||
|
|
||
|
|
||
|
class ProfileEntry(PersonEntry):
|
||
|
"""A Google Profiles flavor of an Atom Entry."""
|
||
|
|
||
|
|
||
|
def ProfileEntryFromString(xml_string):
|
||
|
"""Converts an XML string into a ProfileEntry object.
|
||
|
|
||
|
Args:
|
||
|
xml_string: string The XML describing a Profile entry.
|
||
|
|
||
|
Returns:
|
||
|
A ProfileEntry object corresponding to the given XML.
|
||
|
"""
|
||
|
return atom.core.parse(ProfileEntry, xml_string)
|
||
|
|
||
|
|
||
|
class ProfilesFeed(gdata.data.BatchFeed):
|
||
|
"""A Google Profiles feed flavor of an Atom Feed."""
|
||
|
_qname = atom.data.ATOM_TEMPLATE % 'feed'
|
||
|
entry = [ProfileEntry]
|
||
|
|
||
|
|
||
|
def ProfilesFeedFromString(xml_string):
|
||
|
"""Converts an XML string into a ProfilesFeed object.
|
||
|
|
||
|
Args:
|
||
|
xml_string: string The XML describing a Profiles feed.
|
||
|
|
||
|
Returns:
|
||
|
A ProfilesFeed object corresponding to the given XML.
|
||
|
"""
|
||
|
return atom.core.parse(ProfilesFeed, xml_string)
|
||
|
|
||
|
|