root/SimpleBlog/trunk/MetaWeblogAPI.py

Revision 790 (checked in by mylan, 2 years ago)

Clear blogging APIs modules, up version.

  • 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         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 browser.