root/trunk/PresentationMaterial.py

Revision 3106, 12.9 kB (checked in by jukka, 1 year ago)

Made some pages a bit more robust for old objects

Line 
1 # Copyright 2006 by the LeMill Team (see AUTHORS)
2 #
3 # This file is part of LeMill.
4 #
5 # LeMill is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # LeMill is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with LeMill; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1
18
19
20 from AccessControl import ClassSecurityInfo, getSecurityManager
21 from Products.Archetypes.public import *
22 from Products.CMFCore.utils import getToolByName
23 from config import PROJECTNAME,SLIDESHARE_API_KEY,SLIDESHARE_SECRET_KEY
24 from FieldsWidgets import AudioField, ChapterField, AudioWidget, LeTextAreaWidget, SlideWidget, EmbedWidget
25 from Schemata import material_schema, community_editing_schema, draft_schema
26 from Material import Material
27 from types import ListType
28 from permissions import MODIFY_CONTENT
29 from persistent.mapping import PersistentMapping
30 from Products.LeMill import LeMillMessageFactory as _
31 from Products.CMFPlone.PloneBatch import Batch
32
33 from xml.dom.minidom import parse
34 import urllib, urllib2
35 import time, sha, calendar
36 import DateTime
37
38
39 presentation_schema= Schema((
40     AudioField('audio', # deprecates, won't be used by SlideShare presentations
41         accessor='getAudioFile',
42         mutator='setAudioFile',
43         widget=AudioWidget(label="Audio recording",
44             label_msgid="label_audio_recording",
45             description="An audio recording of the presentation",
46             description_msgid="help_presentation_audio_recording",
47             i18n_domain="lemill",
48             visible ={'edit':'invisible', 'view':'visible'}
49             ),
50         ),
51    StringField('description',
52         accessor="getDescription",
53         mutator = "setDescription",
54         index='ZCTextIndex',
55         schemata='default',
56         searchable = True,
57         widget=LeTextAreaWidget(label = "About the presentation",
58             label_msgid = "label_presentation_about",
59             description = "General information about the presentation such as the data, event and location.",
60             description_msgid = "help_presentation_about",
61             rows = 4,
62             i18n_domain = "lemill",
63             visible ={'edit':'visible', 'view':'visible'}
64             ),
65     ),
66     ChapterField('bodyText', # deprecates, won't be used by SlideShare presentations
67         accessor = 'getBodyText',
68         edit_accessor = 'getRawBodyText',
69         mutator = "setBodyText",
70         copied_in_translation=True,
71         index='ZCTextIndex',
72         index_method = 'getOnlyText',
73         searchable = True,
74         allowable_content_types = ['text/html',],
75         allow_file_upload = False,
76         default_output_type = 'text/x-html-captioned',
77         default_content_type = 'text/html',
78         default=[],
79         deleteEmptyChapters = False,
80         widget=SlideWidget(label = "Slides and captions",
81             label_msgid = "label_slides_and_captions",
82             i18n_domain = "lemill",
83             ),
84     ),
85     StringField('ss_id',
86         searchable = False,
87         widget = StringWidget(
88             visible = {'view':'invisible', 'edit':'invisible'},
89             ),
90     ),
91     StringField('permalink',
92         searchable = False,
93         widget = StringWidget(
94             visible = {'view':'visible', 'edit':'invisible'},
95             ),
96     ),
97     StringField('thumbnail',
98         searchable = False,
99         widget = StringWidget(
100             visible = {'view':'invisible', 'edit':'invisible'},
101             ),
102     ),
103     StringField('embedCode',
104         searchable = False,
105         widget = EmbedWidget(
106             visible = {'view':'visible', 'edit':'visible'},
107             ),
108     ),
109
110 ))
111
112 schema = material_schema + community_editing_schema + presentation_schema
113
114 schema = schema.copy()
115 schema.moveField('rights', pos='bottom')
116 schema['title'].required = True
117 schema['tags'].schemata='default'
118 schema.moveField('embedCode', before='description')
119
120 SIZES = (('small', (120, 120)), ('edit', (500, 500)), ('large', (700, 525)))
121
122 class PresentationMaterial(Material):
123     """ Presentation """
124
125     schema = schema
126
127     meta_type = "PresentationMaterial"
128     archetype_name = "PresentationMaterial"
129     default_location = 'content/presentations'
130
131     security = ClassSecurityInfo()
132     security.declareObjectPublic()
133
134     aliases = {
135         '(Default)' : 'slideshow_view',
136         'view'      : 'base_view',
137         'edit'      : 'base_edit'
138     }
139
140     def manage_afterAdd(self, item, container):
141         if not hasattr(self, 'temp_data'):
142             print 'no temp_data, creating empty dict'           
143             self.temp_data = {} # this has to be persistent just to get this to work.
144         Material.manage_afterAdd(self, item, container)
145
146     def hasComplexWorkflow(self):
147         """ Can have drafts or versions """
148         return False
149
150     def hasEditableCoverImage(self):
151         """ Cover Image is not created automatically """
152         return False
153
154     def getOnlyText(self):
155         field=self.getField('bodyText')
156         values = field.get(self)
157         if not values:
158             return ''
159         if type(values[0])==tuple:
160             dump= '\n'.join([x[0] for x in values if x[1]=='caption'])
161         else:
162             dump= '\n'.join([x['text'] for x in values if x['text']])
163         if dump.isspace():
164             return ''
165         else:
166             return dump
167
168     def getOnlyRawText(self):
169         field=self.getField('bodyText')
170         values = field.getRaw(self)
171         if values:
172             return '\n'.join([x[0] for x in values if x[1]=='caption'])
173         return ''
174
175     def getSlidesAsTuples(self):
176         """ Helper method for slideshows, returns (slide_src, thumb_src , caption) -tuples """
177         portal_url = getToolByName(self, 'portal_url')
178         thelist=[]
179         caption=slide_src=thumb_src=''
180         for (chapter,chapter_type) in self.getRawBodyText():
181             if chapter_type=='caption':
182                 thelist.append((slide_src, thumb_src, chapter))
183             elif chapter_type=='image_piece' and self.isUid(chapter):
184                 piece=self.getObjectByUID(chapter)
185                 if piece and hasattr(piece, 'image_large') and hasattr(piece, 'image_small'):
186                     slide_src='%s/image_large' % piece.absolute_url()
187                     thumb_src='%s/image_small' % piece.absolute_url()
188                 else:
189                     slide_src=''
190                     thumb_src=''                       
191             else:
192                 slide_src=''
193                 thumb_src=''
194         return thelist
195
196     def deleteResource(self, reason=''):
197         pieces_to_delete = []
198         for chapter in self.getRawBodyText():
199             if chapter['type']=='image_piece':
200                 piece=self.getObjectByUID(chapter['uid'])
201                 if piece and len(piece.getResourcesUsingPiece())==1:
202                     pieces_to_delete.append(piece)
203         Material.deleteResource(self)
204         for piece in pieces_to_delete:
205             piece.deleteResource()
206
207     # New, SlideShare related methods
208
209     security.declareProtected(MODIFY_CONTENT, 'fetchAllPresentations')
210     def fetchAllPresentations(self):
211         """ dictionary of SlideSharePresentations for current users """
212         lutool=getToolByName(self, 'lemill_usertool')
213         ss_user=lutool.getMemberFolder().getSlideshare_username()
214         if not ss_user:
215             return {}
216         data=self.getSlideshowsByUser(username_for=ss_user)
217         self.temp_data=self.parseSlideshareXML(data)
218
219     def getBatchOfPresentations(self,b_start=0, b_size=10):
220         """ Returns importable presentations in sorted and batched sets """       
221         if not getattr(self, 'temp_data', {}):
222             self.fetchAllPresentations()
223         list_of_p=[(x['date'], x) for x in self.temp_data.values()]
224         list_of_p.sort(reverse=True)
225         batchbase=[value for (date, value) in list_of_p]
226         batch=Batch(batchbase, b_size, int(b_start), orphan=0)
227         return batch
228
229     def uploadedPresentations(self):
230         """ Returns a list of slideshare ids that the user has already imported """
231         return []
232
233     security.declareProtected(MODIFY_CONTENT, 'injectPresentationFromSlideShare')
234     def injectPresentationFromSlideShare(self):
235         """ modifies the current presentation with data from slideshare """
236         REQUEST=self.REQUEST
237         key=REQUEST.form.get('slideshare_id','')
238         cancel=REQUEST.form.get('form.button.cancel','')
239         if cancel:
240             if hasattr(self, 'temp_data'):
241                 del self.temp_data
242             portal_url=getToolByName(self,'portal_url')
243             lt=getToolByName(self,'lemill_tool')
244             lt.addPortalMessage('Resource cancelled.')
245             self.aq_parent.manage_delObjects([self.id])
246             return REQUEST.RESPONSE.redirect(portal_url()+'/content')
247         if not key:
248             return REQUEST.RESPONSE.redirect(self.absolute_url()+'/import_presentation')
249         if not hasattr(self, 'temp_data'):
250             lutool=getToolByName(self, 'lemill_usertool')
251             ss_user=lutool.getMemberFolder().getSlideshare_username()
252             self.temp_data=self.parseSlideshareXML(self.getSlideshowsByUser(ss_user))
253         data=self.temp_data.get(key, None)       
254         if not data:
255             raise 'SlideShare id %s not found' % str(key)
256             return REQUEST.RESPONSE.redirect(self.absolute_url()+'/import_presentation')
257         self.edit(**data)
258         # We need to get this particular slideshow by id to get new style (working) slideshow.
259         this_slideshow=self.parseSlideshareXML(self.getSlideshowById(slideshow_id=key))
260         if this_slideshow:
261             self.setEmbedCode(this_slideshow[key]['embedCode'])
262         thumbnail=self.getThumbnail()
263         if thumbnail:
264             coverImageFile=urllib2.urlopen(thumbnail).read()
265             if coverImageFile:
266                 self.setCoverImage(coverImageFile)
267         self.publish()
268         self.at_post_edit_script()
269         del self.temp_data       
270         return REQUEST.RESPONSE.redirect(self.absolute_url()+'/base_edit')       
271
272     security.declarePrivate('getSlideshowsByUser')
273     def getSlideshowsByUser(self, username_for=None):
274         """ Fetch XML-data from SlideShare """
275         print '*** Fetching from SlideShare ***'
276         ts = int(time.time())
277         params = {'api_key' : SLIDESHARE_API_KEY,'ts' : ts, 'hash' : sha.new(SLIDESHARE_SECRET_KEY + str(ts)).hexdigest(), 'username_for':username_for}
278         params = urllib.urlencode(params)
279         data=urllib2.urlopen('http://www.slideshare.net/api/1/get_slideshow_by_user', params)
280         return data   
281
282     security.declarePrivate('getSlideshowById')
283     def getSlideshowById(self, slideshow_id=None, slideshow_url=None):
284         """ Fetch XML-data from SlideShare """
285         ts = int(time.time())
286         params = {'api_key' : SLIDESHARE_API_KEY,'ts' : ts, 'hash' : sha.new(SLIDESHARE_SECRET_KEY + str(ts)).hexdigest(), 'slideshow_id':slideshow_id, 'slideshow_url':slideshow_url or 'blank'}
287         params = urllib.urlencode(params)
288         data=urllib2.urlopen('http://www.slideshare.net/api/2/get_slideshow', params)
289         return data
290    
291     def parseSlideshareXML(self, xml_data):   
292         """ builds a dict of useful LeMill data from SlideShare's XML """
293         def getTag(dom, tag):
294             content=dom.getElementsByTagName(tag)
295             if content:
296                 content=content[0].childNodes
297                 for node in content:
298                     if node.nodeType==node.TEXT_NODE:
299                         return node.data         
300             return ''
301         dom=parse(xml_data)
302         slideshows=dom.getElementsByTagName("Slideshow")
303         dict={}
304         for ss in slideshows:
305             obj={}
306             id=getTag(ss, 'ID')
307             obj['ss_id']=id
308             obj['title']=getTag(ss, 'Title')
309             obj['description']=getTag(ss, 'Description')
310             date=getTag(ss, 'Created')
311             if date:
312                 try:
313                     date=time.strptime(date, '%a %b %d %H:%M:%S %Z %Y')
314                     date=calendar.timegm(date)
315                     date=DateTime.DateTime(date)
316                 except ValueError:
317                     date=DateTime.DateTime()
318             obj['date']=date
319             tags=getTag(ss, 'Tags')
320             if tags:
321                 tags=', '.join(tags.split(' '))
322             obj['tags']=tags
323             obj['permalink']=getTag(ss, 'Permalink')
324             obj['thumbnail']=getTag(ss, 'Thumbnail')
325             obj['embedCode']=getTag(ss,'Embed') or getTag(ss, 'EmbedCode')
326             dict[id]=obj
327         dom.unlink()
328         return dict
329
330
331 registerType(PresentationMaterial, PROJECTNAME)
Note: See TracBrowser for help on using the browser.