source: products/SimpleBlog/trunk/MetaWeblogAPI.py

Last change on this file was 1, checked in by myroslav, 14 years ago

Building directory structure

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1#
2# Authors: Tom von Schwerdtner <tvon@etria.com>
3#          Brian Skahan <bskahan@etria.com>
4#
5# Copyright 2004, Etria, LLP
6#
7# This file is part of Quills
8#
9# Quills is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# Foobar is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with Quills; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
23
24from OFS.SimpleItem import SimpleItem
25from Products.CMFCore.utils import getToolByName
26from Products.CMFDefault.utils import parseHeadersBody
27from AccessControl import ClassSecurityInfo, getSecurityManager
28from AccessControl.SecurityManagement import setSecurityManager, newSecurityManager
29
30import DateTime
31import re
32import xmlrpclib
33import random
34
35authMethods = [
36    'metaWeblog/getPost',
37    'metaWeblog/deletePost',
38    'metaWeblog/editPost',
39    'metaWeblog/newPost',
40    'metaWeblog/getRecentPosts',
41    'metaWeblog/getUsersBlogs',
42    'metaWeblog/getCategories',
43    'metaWeblog/newMediaObject'
44    ]
45
46def genericMetaWeblogAuth(args):
47    return args[1], args[2], args
48
49
50class MetaWeblogAPI(SimpleItem):
51    """http://www.metaWeblog.com/developers/api/1_docs/"""
52    security = ClassSecurityInfo()
53
54    def __init__(self, RPCAuth = None):
55        ""
56        if RPCAuth:
57            self.setupRPCAuth(RPCAuth)
58
59    security.declarePublic('setupRPCAuth')
60    def setupRPCAuth(self, RPCAuth):
61        RPCAuth.addAuthProvider(authMethods, genericMetaWeblogAuth)
62
63    security.declarePublic('newPost')
64    def newPost(self, blogid, username, password, struct, publish):
65        """Some Stuff"""
66        self.plone_log('metaWeblog/newPost')
67
68        sbtool = getToolByName(self, 'simpleblog_tool')
69        blog = sbtool.getByUID(blogid)
70
71        body  = struct.get('description', struct.get('Description'))
72        title = struct.get('title', struct.get('Title'))
73        description = struct.get('mt_excerpt', '')
74        allow_comments = struct.get('mt_allow_comments', 1)
75        id = sbtool.idFromTitle(title)
76
77        blog.invokeFactory('BlogEntry', id = id, title = title)
78        entry = getattr(blog, id)
79
80        entry.setBody(body, mimetype='text/html')
81        entry.setDescription(description)
82
83        # The workflow moves the entry, so get the UID now
84        entry_uid = entry.UID()
85
86        wf_tool = getToolByName(self, 'portal_workflow')
87        if publish:
88            state = sbtool.getPublishedState()
89            entry.setEffectiveDate(DateTime.DateTime())
90            # todo xxxxxxxxxx
91            wf_tool.doActionFor(entry, 'publish', None)
92
93        return entry_uid
94
95    security.declarePublic('editPost')
96    def editPost(self, postid, username, password, struct, publish):
97        """Some stuff"""
98        self.plone_log('metaWeblog/editPost')
99        sbtool = getToolByName(self, 'simpleblog_tool')
100        entry = sbtool.getByUID(postid)
101        body  = struct.get('description', struct.get('Description'))   
102        title = struct.get('title', struct.get('Title'))
103        description = struct.get('mt_excerpt', '')
104        allow_comments = struct.get('mt_allow_comments', 1)
105
106        entry.setBody(body, mimetype='text/html')
107        entry.setTitle(title)
108        entry.setDescription(description)
109        disc_tool = getToolByName(self, 'portal_discussion')
110
111        #if allow_comments:
112            #disc_tool.overrideDiscussionFor(entry, 1)
113        #else:
114            #disc_tool.overrideDiscussionFor(entry, 0)
115 
116        #  portal.portal_workflow.getInfoFor(here,'review_state',None)   (from folder_contents.pt)
117        wf_tool=getToolByName(self, 'portal_workflow')
118        wf_state = wf_tool.getInfoFor(entry, 'review_state', '')
119        if publish and wf_state != 'published':  # todo!!!!
120            wf_tool.doActionFor(entry, 'publish')
121
122        entry.reindexObject()
123
124        return True
125
126    security.declarePublic('getPost')
127    def getPost(self, postid, username, password):
128        "Return a post I suppose"
129        self.plone_log('metaWeblog/getPost')
130        sbtool = getToolByName(self, 'simpleblog_tool')
131
132        post = sbtool.getByUID(postid)
133        disc_tool = getToolByName(self, 'portal_discussion')
134        res = {}
135        if post:
136            res['postid'] = post.UID()
137            res['title'] = post.Title()
138            res['link'] = post.absolute_url()
139            res['category'] = post.listCategories()
140            res['categories'] = post.listCategories()
141            res['description'] = post.getBody()
142            res['mt_excerpt'] = post.Description()
143            res['mt_text_more']=post.getBody()
144            res['mt_allow_comments']=disc_tool.isDiscussionAllowedFor(post)
145
146            return res
147        else:
148            raise AttributeError, "Post %s was not found" % postid
149
150        return res
151
152    security.declarePublic('getCategories')
153    def getCategories(self, blogid, username, password):
154        "Returns a struct containing description, htmlUrl and rssUrl"
155        self.plone_log('metaWeblog/getCategories')
156        sbtool = getToolByName(self, 'simpleblog_tool')
157        blog = sbtool.getByUID(blogid)
158
159        cats = blog.listCategories()
160        categories = []
161        for cat in cats:
162            categories.append(
163                {'categoryName': cat, 'description' : cat,
164                'htmlUrl' : blog.absolute_url() + ',/SimpleBlogCatSearch?category=' + cat,
165                'rssUrl' : blog.absolute_url() + ',/SimpleBlogCatSearch?category=' + cat
166                })
167
168        return categories
169
170    security.declarePublic('deletePost')
171    def deletePost(self, postid, username, password, publish):
172        "Returns true on success, fault on failure"
173        self.plone_log('metaWeblog/deletePost')
174        sbtool = getToolByName(self, 'simpleblog_tool')
175
176        entry = sbtool.getByUID(postid)
177        entry.aq_inner.aq_parent.manage_delObjects(entry.getId())
178
179        return True
180
181    security.declarePublic('getRecentPosts')
182    def getRecentPosts(self, blogid, username, password, num):
183        """Return 'num' recent posts to specified blog, returns a struct:
184         The three basic elements are title, link and description.
185         For blogging tools that don't support titles and links, the description element holds what the Blogger API refers to as 'content'."""
186        self.plone_log('metaWeblog/getRecentPosts')
187        sbtool = getToolByName(self, 'simpleblog_tool')
188        blog = sbtool.getByUID(blogid)
189
190        brains = blog.getFolderContents(contentFilter={'portal_type': 'BlogEntry'},)
191        # todo: what if entries are in subfolders?
192        posts = []
193        for b in brains:
194            entry = b.getObject()
195            posts.append( { 'dateCreated':b.created
196                            , 'userid':b.Creator
197                            , 'postid':entry.UID()
198                            , 'title':b.Title
199                            , 'description':entry.getBody()
200                            , 'excerpt':b.Description
201                              })
202        if num is not None:
203            return posts[:int(num)]
204
205        return posts
206
207    security.declarePublic('getUsersBlogs')
208    def getUsersBlogs(self, username, password):
209        """ Return all the blogs the user has access and write permission to """
210        self.plone_log('metaWeblog/getUsersBlogs')
211        catalog = getToolByName(self, 'portal_catalog')
212        results = catalog(meta_type='Blog')
213
214        blogs = []
215        for item in results:
216            o = item.getObject()
217            if o.portal_membership.checkPermission('Modify portal content', o):
218                blogs.append(
219                        {'url': o.absolute_url(),
220                         'blogid' : o.UID(),
221                         'blogName' : o.title_or_id()}
222                        )
223
224        return blogs
225
226    security.declarePublic('getUserInfo')
227    def getUserInfo(self, appkey, username, password):
228        """metaWeblog.getUserInfo returns a struct containing user's
229        userid, firstname, lastname, nickname, email, and url."""
230        self.plone_log('metaWeblog/getUserInfo')
231
232        membership=getToolByName(self, 'portal_membership')
233        info={'name':'no name','email':'no email','userid':'no user id'
234               ,'firstname':'no first name','lastname':'no last name'
235               ,'url':'no url'}
236        member=membership.getAuthenticatedMember()
237        if member:
238            for key,value in info.items():
239                info[key] = getattr(member,key,None) or value
240
241        return info
242
243
244    security.declarePublic('newMediaObject')
245    def newMediaObject(self, blogid, username, password, struct):
246        """Create media object and return it's URL or exception"""
247        self.plone_log('metaWeblog/newMediaObject')
248        sbtool = getToolByName(self, 'simpleblog_tool')
249        blog = sbtool.getByUID(blogid)
250
251        media_name = struct.get('name', None)
252        mime_type = struct.get('type', None)
253        data = struct.get('bits', '')
254
255        if not media_name or media_name.startswith('.'):
256            raise AttributeError, "No 'name' of media object supply or starts with '.'"
257        if not mime_type:
258            raise AttributeError, "No 'type' of media object supply"
259        if not (mime_type.startswith('image') or mime_type.startswith('application')):
260            raise AttributeError, "'%s' - not supported mime tipe." % mime_type
261
262        if not 'images' in blog.objectIds():
263            blog.invokeFactory('BlogFolder', id = 'images', title='Container for images')
264            images = getattr(blog, 'images')
265        else:
266            images = blog.images
267
268        id = re.sub('[^A-Za-z0-9_.]', '', re.sub(' ', '_', media_name)).lower()
269        while id in images.objectIds():
270            index = id.rfind('.')
271            if index > -1:
272                front = id[:index]
273                ext = id[index:]
274            else:
275                front = id
276                ext = ''
277            id = front + str(random.randint(1,100)) + ext
278
279        images.invokeFactory('Image', id=id, title=media_name, file=str(data)) 
280        image = getattr(images, id)
281
282        return {'url':image.absolute_url()}
Note: See TracBrowser for help on using the repository browser.