Package amplee :: Package atompub :: Module service
[hide private]
[frames] | no frames]

Source Code for Module amplee.atompub.service

  1  # -*- coding: utf-8 -*- 
  2  __docformat__ = 'epytext'  
  3  __doc__ = """Represents an Atom Publisging Protocol service entity. 
  4  """ 
  5   
  6  import amara 
  7  from amplee.utils import ATOM10_NS, ATOM10_PREFIX, ATOMPUB_PREFIX, \ 
  8       ATOMPUB_NS, XML_PREFIX, XML_NS, XMLNS_PREFIX, XMLNS_NS 
  9  from amplee.utils import generate_uuid_uri, get_isodate, qname 
 10  from amplee.comparer import app_edited_comparer 
 11  from amplee.error import UnknownResource 
 12   
 13  __all__ = ['AtomPubService'] 
 14   
15 -class AtomPubService(object):
16 - def __init__(self, store, xml_attrs=None):
17 """Atom Publisging Protocol service entity. 18 19 @type store: L{AtomPubStore} 20 @param store: L{AtomPubStore} instance or C{None} 21 @type xml_attrs: dict 22 @param xml_attrs: allows for XML attributes to be provided: lang, base 23 """ 24 self.store = store 25 self.xml_attrs = xml_attrs or {} 26 27 # List of workspace instances belonging to 28 # this service instance 29 self.workspaces = [] 30 31 self.xslt_path = None
32
33 - def set_xslt(self, path):
34 self.xslt_path = path
35
36 - def get_workspace(self, name_or_id):
37 """Returns a workspace per its identifier. 38 39 @type name_or_id: string 40 @param name_or_id: matches the workspace attribute of the 41 same name. 42 """ 43 for workspace in self.workspaces: 44 if workspace.name_or_id == name_or_id: 45 return workspace
46
47 - def get_collections(self):
48 """Returns all the collections belonging to workspaces 49 of this service. 50 51 @rtype: list 52 @return: the list of L{AtomPubCollection} belonging 53 to this service. 54 """ 55 collections = [] 56 for workspace in self.workspaces: 57 collections.extend(workspace.collections) 58 return collections
59
60 - def get_collection(self, name_or_id):
61 """Returns a collection identified by C{name_or_id} 62 63 @type name_or_id: string 64 @param name_or_id: identifier for the collection to be looked up 65 @rtype: L{AtomPubCollection} 66 @return: collection associated with the provided identifier 67 """ 68 for workspace in self.workspaces: 69 for collection in workspace.collections: 70 if collection.name_or_id == name_or_id: 71 return collection
72
73 - def get_collection_by_uri(self, uri):
74 """Returns a collection identified by its URI. 75 76 @type uri: string 77 @param uri: absolute URI of the collection. 78 @rtype: L{AtomPubCollection} 79 @return: collection associated with the provided identifier 80 """ 81 for workspace in self.workspaces: 82 for collection in workspace.collections: 83 if collection.get_base_edit_uri() == uri: 84 return collection
85 86
87 - def to_service(self, prefix=ATOMPUB_PREFIX, namespace=ATOMPUB_NS, include_workspace_id=False):
88 """Generates and returns a L{amara} instance of the service 89 document and its workspaces. 90 91 @type prefix: string 92 @param prefix: XML prefix to use 93 94 @type namespace: string 95 @param namespace: namespace associated with the service document 96 97 @type include_workspace_id: bool 98 @param include_workspace_id: if you want the C{name_or_id} attribute value as C{xml:id} 99 of the {app:workspace} element, set this to C{True}. 100 101 @rtype: L{amara.root_base} 102 @return: amara instance of the service document 103 """ 104 d = amara.create_document(prefixes={ATOM10_PREFIX: ATOM10_NS}) 105 if self.xslt_path: 106 pi = amara.bindery.pi_base(u"xml-stylesheet", u'href="%s" type="text/xsl"' % self.xslt_path) 107 d.xml_append(pi) 108 109 attrs = {} 110 if self.xml_attrs is not None: 111 for attr in self.xml_attrs: 112 attrs[(qname(attr, XML_PREFIX), XML_NS)] = self.xml_attrs[attr] 113 114 service = d.xml_append(d.xml_create_element(qname(u"service", prefix), 115 ns=namespace, attributes=attrs)) 116 117 for workspace in self.workspaces: 118 w = workspace.to_workspace(prefix=prefix, namespace=namespace, 119 include_id=include_workspace_id) 120 service.xml_append(w.rootNode) 121 122 return d
123
124 - def make_feed(self, items, entry_processor=None, 125 id=None, title=None, xslt_path=None, 126 member_comparer=app_edited_comparer):
127 """ 128 Generates a new atom feed from the passed items dictionnary. 129 130 @type items: dict 131 @param items: C{{collection_name: [member_ids,]}} as returned for instance 132 by the L{Store.list_members} method. 133 134 @type entry_processor: callable 135 @param entry_processor: callable that takes a 136 member instance as parameter and returns a L{amara.root_base} representing 137 the entry after being processed. Useful for instance to transform 138 the entry into a more public face. 139 140 @type id: string 141 @param id: id of the feed and if not provided a urn:uuid will be generated. 142 143 @type xslt_path: string 144 @param xslt_path: if provided it will be inserted as a processing 145 instruction. 146 147 @type member_comparer: callable 148 @param member_comparer: used to 149 compare two entries when they are sorted within. By default 150 they are sorted by app:edited element. 151 152 @rtype: L{amara.root_base} 153 @return: an amara instance representing the Atom feed. 154 """ 155 d = amara.create_document() 156 if xslt_path: 157 pi = amara.bindery.pi_base(u"xml-stylesheet", u'href="%s" type="text/xsl"' % xslt_path) 158 d.xml_append(pi) 159 160 feed = d.xml_create_element(qname(u"feed", ATOM10_PREFIX), ns=ATOM10_NS) 161 d.xml_append(feed) 162 163 uuid = id or generate_uuid_uri() 164 feed.xml_append(d.xml_create_element(qname(u"id", ATOM10_PREFIX), 165 ns=ATOM10_NS, content=uuid)) 166 feed.xml_append(d.xml_create_element(qname(u"updated", ATOM10_PREFIX), 167 ns=ATOM10_NS, content=get_isodate())) 168 feed.xml_append(d.xml_create_element(qname(u"title", ATOM10_PREFIX), ns=ATOM10_NS, 169 attributes={u'type': u'text'}, content=title)) 170 171 xml_base = self.xml_attrs.get('base', None) 172 if xml_base: 173 feed.xml_set_attribute((qname(u'base', XML_PREFIX), XML_NS), xml_base) 174 175 xml_lang = self.xml_attrs.get('lang', None) 176 if xml_lang: 177 feed.xml_set_attribute((qname(u'lang', XML_PREFIX), XML_NS), xml_lang) 178 179 if not callable(entry_processor): 180 # avoids a "if callable(entry_processor)" 181 # in the inner loop below. 182 entry_processor = lambda m: m.atom 183 184 entries = [] 185 for collection_name in items: 186 c = self.get_collection(collection_name) 187 for member_id in items[collection_name]: 188 try: 189 member = c.load_member(member_id) 190 entry = entry_processor(member) 191 entries.append(entry.childNodes[0]) 192 except UnknownResource: 193 pass 194 195 entries.sort(cmp=member_comparer) 196 197 for entry in entries: 198 feed.xml_append(entry) 199 200 return d
201