root/SimpleBlog/branches/plone-2.5/MetaWeblogAPI.py

Revision 583 (checked in by chervol, 2 years ago)

blog tool merged APIs added

  • Property svn:eol-style set to native
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
24 from OFS.SimpleItem import SimpleItem
25 from Products.CMFCore.utils import getToolByName
26 from Products.CMFDefault.utils import parseHeadersBody
27 from AccessControl import ClassSecurityInfo, getSecurityManager
28 from AccessControl.SecurityManagement import setSecurityManager, newSecurityManager
29
30 import DateTime
31 import re
32 import xmlrpclib
33 import random
34
35 authMethods = [
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
46 def genericMetaWeblogAuth(args):
47     return args[1], args[2], args
48
49
50 class 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        
67         self.plone_log('metaWeblog/newPost')
68         print 'metaWeblog/newPost'
69        
70         sbtool = getToolByName(self, 'simpleblog_tool')
71
72         blog = sbtool.getByUID(blogid)
73
74         body  = struct.get('description', struct.get('Description'))
75         title = struct.get('title', struct.get('Title'))
76         description = struct.get('mt_excerpt', '')
77         allow_comments = struct.get('mt_allow_comments', 1)
78        
79         id = sbtool.idFromTitle(title)
80
81         blog.invokeFactory('BlogEntry', id = id, title = title)
82         entry = getattr(blog, id)
83
84         entry.setBody(body, mimetype='text/html')
85         entry.setDescription(description)
86
87         # The workflow moves the entry, so get the UID now
88         entry_uid = entry.UID()
89
90         wf_tool = getToolByName(self, 'portal_workflow')
91         if publish:
92             state = sbtool.getPublishedState()
93             entry.setEffectiveDate(DateTime.DateTime())
94            
95             # todo xxxxxxxxxx
96             wf_tool.doActionFor(entry, 'publish', None)
97
98         return entry_uid
99
100     security.declarePublic('editPost')
101     def editPost(self, postid, username, password, struct, publish):
102         """Some stuff"""
103         self.plone_log('metaWeblog/editPost')
104         print 'metaWeblog/editPost'
105         sbtool = getToolByName(self, 'simpleblog_tool')
106        
107         entry = sbtool.getByUID(postid)
108
109         body  = struct.get('description', struct.get('Description'))   
110         title = struct.get('title', struct.get('Title'))
111         description = struct.get('mt_excerpt', '')
112         allow_comments = struct.get('mt_allow_comments', 1)
113        
114         entry.setBody(body, mimetype='text/html')
115         entry.setTitle(title)
116         entry.setDescription(description)
117         disc_tool = getToolByName(self, 'portal_discussion')
118        
119         #if allow_comments:
120             #disc_tool.overrideDiscussionFor(entry, 1)
121         #else:
122             #disc_tool.overrideDiscussionFor(entry, 0)
123  
124         #  portal.portal_workflow.getInfoFor(here,'review_state',None)   (from folder_contents.pt)
125         wf_tool=getToolByName(self, 'portal_workflow')
126         wf_state = wf_tool.getInfoFor(entry, 'review_state', '')
127         if publish and wf_state != 'published':  # todo!!!!
128             wf_tool.doActionFor(entry, 'publish')
129
130         entry.reindexObject()
131                    
132         return True
133        
134     security.declarePublic('getPost')
135     def getPost(self, postid, username, password):
136         "Return a post I suppose"
137         self.plone_log('metaWeblog/getPost')
138         print 'metaWeblog/getPost'
139         sbtool = getToolByName(self, 'simpleblog_tool')
140        
141         post = sbtool.getByUID(postid)
142         disc_tool = getToolByName(self, 'portal_discussion')
143         res = {}
144         if post:
145             res['postid'] = post.UID()
146             res['title'] = post.Title()
147             res['link'] = post.absolute_url()
148             res['category'] = post.listCategories()
149             res['categories'] = post.listCategories()
150             res['description'] = post.getBody()
151             res['mt_excerpt'] = post.Description()
152             res['mt_text_more']=post.getBody()
153             res['mt_allow_comments']=disc_tool.isDiscussionAllowedFor(post)
154                
155             return res
156         else:
157             raise AttributeError, "Post %s was not found" % postid
158
159         return res
160        
161     security.declarePublic('getCategories')
162     def getCategories(self, blogid, username, password):
163         "Returns a struct containing description, htmlUrl and rssUrl"
164         self.plone_log('metaWeblog/getCategories')
165         print 'metaWeblog/getCategories'
166         sbtool = getToolByName(self, 'simpleblog_tool')
167        
168         blog = sbtool.getByUID(blogid)
169        
170         cats = blog.listCategories()
171        
172         categories = []
173         for cat in cats:
174             categories.append(
175                 {'categoryName': cat, 'description' : cat,
176                 'htmlUrl' : blog.absolute_url() + ',/SimpleBlogCatSearch?category=' + cat,
177                 'rssUrl' : blog.absolute_url() + ',/SimpleBlogCatSearch?category=' + cat
178                 })
179                
180         self.plone_log('metaWeblog/getCategories: returning ', categories)
181         return categories
182
183     security.declarePublic('deletePost')
184     def deletePost(self, postid, username, password, publish):
185         "Returns true on success, fault on failure"
186         self.plone_log('metaWeblog/deletePost')
187         print 'metaWeblog/deletePost'
188         sbtool = getToolByName(self, 'simpleblog_tool')
189        
190         entry = sbtool.getByUID(postid)
191
192         entry.aq_inner.aq_parent.manage_delObjects(entry.getId())
193
194         return True
195
196     security.declarePublic('getRecentPosts')
197     def getRecentPosts(self, blogid, username, password, num):
198         """Return 'num' recent posts to specified blog, returns a struct:
199          The three basic elements are title, link and description.
200          For blogging tools that don't support titles and links, the description element holds what the Blogger API refers to as 'content'."""
201
202         self.plone_log('metaWeblog/getRecentPosts')
203         print 'metaWeblog/getRecentPosts'
204         sbtool = getToolByName(self, 'simpleblog_tool')
205         blog = sbtool.getByUID(blogid)
206
207         entries = blog.getFolderListingFolderContents(contentFilter={'portal_type': 'BlogEntry'},)       
208         # todo: what if entries are in subfolders?
209        
210         posts = []
211         for entry in entries:
212             posts.append( { 'dateCreated':entry.created()
213                             , 'userid':entry.Creator()
214                             , 'postid':entry.UID()
215                             , 'title':entry.Title()
216                             , 'description':entry.getBody()
217                             , 'excerpt':entry.Description()
218                               })           
219            
220         if num is not None:
221             return posts[:int(num)]
222         return posts
223    
224     security.declarePublic('getUsersBlogs')
225     def getUsersBlogs(self, username, password):
226         """ Return all the blogs the user has access and write permission to """
227
228         self.plone_log('metaWeblog/getUsersBlogs')
229         print 'metaWeblog/getUsersBlogs'
230         catalog = getToolByName(self, 'portal_catalog')
231         results = catalog(meta_type='Blog')
232
233         blogs = []
234         for item in results:
235             o = item.getObject()
236             if o.portal_membership.checkPermission('Modify portal content', o):
237                 blogs.append(
238                         {'url': o.absolute_url(),
239                          'blogid' : o.UID(),
240                          'blogName' : o.title_or_id()}
241                         )
242
243         return blogs
244
245     security.declarePublic('getUserInfo')
246     def getUserInfo(self, appkey, username, password):
247         """metaWeblog.getUserInfo returns a struct containing user's
248         userid, firstname, lastname, nickname, email, and url."""
249         self.plone_log('metaWeblog/getUserInfo')
250         print 'metaWeblog/getUserInfo'
251
252         membership=getToolByName(self, 'portal_membership')
253         info={'name':'no name','email':'no email','userid':'no user id'
254                ,'firstname':'no first name','lastname':'no last name'
255                ,'url':'no url'}
256         member=membership.getAuthenticatedMember()
257         if member:
258             for key,value in info.items():
259                 info[key] = getattr(member,key,None) or value
260         return info
261
262
263     security.declarePublic('newMediaObject')
264     def newMediaObject(self, blogid, username, password, struct):
265         """Create media object and return it's URL or exception"""
266        
267         self.plone_log('metaWeblog/newMediaObject')
268         print 'metaWeblog/newMediaObject'
269        
270         sbtool = getToolByName(self, 'simpleblog_tool')
271         blog = sbtool.getByUID(blogid)
272        
273         media_name = struct.get('name', None)
274         mime_type = struct.get('type', None)
275         data = struct.get('bits', '')
276
277         if not media_name or media_name.startswith('.'):
278             raise AttributeError, "No 'name' of media object supply or starts with '.'"
279         if not mime_type:
280             raise AttributeError, "No 'type' of media object supply"
281         if not (mime_type.startswith('image') or mime_type.startswith('application')):
282             raise AttributeError, "'%s' - not supported mime tipe." % mime_type
283
284         if not 'images' in blog.objectIds():
285             blog.invokeFactory('BlogFolder', id = 'images', title='Container for images')
286             images = getattr(blog, 'images')
287         else:
288             images = blog.images
289
290         id = re.sub('[^A-Za-z0-9_.]', '', re.sub(' ', '_', media_name)).lower()
291         while id in images.objectIds():
292             index = id.rfind('.')
293             if index > -1:
294                 front = id[:index]
295                 ext = id[index:]
296             else:
297                 front = id
298                 ext = ''
299             id = front + str(random.randint(1,100)) + ext
300
301         images.invokeFactory('Image', id=id, title=media_name, file=str(data))
302         image = getattr(images, id)
303
304         return {'url':image.absolute_url()}
Note: See TracBrowser for help on using the browser.