source: trunk/LeMillTool.py @ 1370

Revision 1370, 9.0 KB checked in by jukka, 13 years ago (diff)

Worked on #1146. Search for suitable existing story is done and stories can be written. Must find out why portal_factory decides to keep stories, if user cancels or wanders off from story creation. Also the search for existing stories is tricky. Current way isn't fast, but I don't know if it can be done any faster -- and it's our front page, will get lots of hits.

Well, one way would be to combine stories' uids to one superuid and try to match that. We'll see..

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-1301  USA
18
19from OFS.SimpleItem import SimpleItem
20from OFS.PropertyManager import PropertyManager
21from Products.CMFCore.utils import UniqueObject
22from Globals import InitializeClass
23from AccessControl import ClassSecurityInfo
24from Products.CMFCore.utils import getToolByName
25from config import SEARCHABLE_TYPES, CONTENT_TYPES, COMMUNITY_TYPES, TOOLS_TYPES, ACTIVITY_TYPES, MATERIAL_TYPES
26from permissions import MANAGE_PORTAL
27from itertools import chain
28from Products.LeMill.Resources import Resource
29from random import choice
30
31
32import re
33
34class LeMillTool(PropertyManager, UniqueObject, SimpleItem):
35    """ Tool for miscallenous methods """
36
37    id = 'lemill_tool'
38    meta_type = 'LeMillTool'
39    security = ClassSecurityInfo()
40    plone_tool = 1
41    toolicon = 'skins/lemill/tool.gif'
42    __allow_access_to_unprotected_subobjects__ = 1
43
44
45    security.declarePublic('createUniqueGroupId')
46    def createUniqueGroupId(self, basename):
47        #Groups should always use titles for display, but urls use ids so lets make ids understandable & unique.
48        # basename should be user's id or material's id, we add _group+numbers after that.
49        basename=str(basename)
50        grouptool=getToolByName(self, 'portal_groups')
51        folder=grouptool.getGroupWorkspacesFolder()
52        name=basename+'_group'
53        number=1
54        while name in folder.objectIds():
55            name=basename+'_group'+str(number)
56            number=number+1
57        return name
58   
59    security.declarePublic('render')
60    def render(self,body):
61 
62        body="\n\n%s\n\n" % str(body)
63       
64        lf1 = re.compile('\r\n')
65        lf2 = re.compile('\r')
66        body = lf1.sub('\n',body)
67        body = lf2.sub('\n',body)
68
69        body = re.sub(r'\n\n\*\s', r'\n\n<ul><li>', body)
70        body = re.sub(r'\n\*\s(.*)\n\n', r'</li><li>\1</li></ul>\n\n', body)
71        body = re.sub(r'\n\*\s', r'</li><li>', body)
72
73        body = re.sub(r'\n\n\#\s', r'\n\n<ol><li>', body)
74        body = re.sub(r'\n\#\s(.*)\n\n', r'</li><li>\1</li></ol>\n\n', body)
75        body = re.sub(r'\n\#\s', r'</li><li>', body)
76
77        body = re.sub('\n\n<ul>',"</p><ul>",body)
78        body = re.sub('</ul>\n\n',"</ul><p>",body)
79        body = re.sub('\n\n<ol>',"</p><ol>",body)
80        body = re.sub('</ol>\n\n',"</ol><p>",body)
81        body = re.sub('\n\n',"</p><p>",body)
82        body = re.sub('\n',"<br/>",body)
83   
84        body = re.sub(r'\A</p>', '', body)
85        body = re.sub(r'<p>\Z', '', body)
86
87        body = re.sub(r'\[(\S+?)\s(.*?)\]', r'<a href="\1">\2</a>', body)
88       
89        #raise 'FOO', str(body)
90        body=re.sub(r'([\W>])\*(\S.*?\S)\*([\W<])', r'\1<b>\2</b>\3',body)
91        body=re.sub(r'([\W>])_(\S.*?\S)_([\W<])', r'\1<i>\2</i>\3',body)
92        body = re.sub(r'\A\s(.*)\s\Z',r'<p>\1</p>',body)
93        return body
94
95    security.declarePublic('listrender')
96    def listrender(self, body):
97        # like render, but without all of the stuff related to new lines
98        body = re.sub(r'\[(\S+?)\s(.*?)\]', r'<a href="\1">\2</a>', body)       
99        body=re.sub(r'([\W>])\*(\S.*?\S)\*([\W<])', r'\1<b>\2</b>\3',body)
100        body=re.sub(r'([\W>])_(\S.*?\S)_([\W<])', r'\1<i>\2</i>\3',body)
101        body = re.sub(r'\A\s(.*)\s\Z',r'<p>\1</p>',body)
102        body = re.sub(r'<?p>','', body)
103        return body
104
105    security.declarePublic('searchable_types')
106    def searchable_types(self):
107        return list(SEARCHABLE_TYPES)
108
109    def resize_image(self, image, to_width=120, to_height=120, format="PNG"):
110        # resize image to given width and height. StringIO, im will be returned
111        try:
112            from PIL import Image
113        except ImportError:
114            return None, image
115        import cStringIO
116        val = None
117        # attempt to get pure binary data
118        try:
119            val = image.read()
120        except AttributeError: # no read method
121            val = image
122        if hasattr(image, 'data'):
123            val = image.data
124            if not isinstance(val, type('')):
125                val = val.aq_base
126                from OFS.Image import Pdata
127                if isinstance(val, Pdata):
128                    #print "this is Pdata"
129                    val = str(val)
130        s = cStringIO.StringIO(val)
131        s.seek(0)
132        im = Image.open(s)
133        (width, height) = im.size
134        if width > to_width:
135            mod = float(to_width)/float(width)
136            width = width*mod
137            height = height*mod
138            im = im.resize((int(width),int(height)), Image.ANTIALIAS)
139        if height > to_height:
140            u_w = float(to_height)/float(height)
141            width = width*u_w
142            height = height*u_w
143            im = im.resize((int(width),int(height)), Image.ANTIALIAS)
144        s = cStringIO.StringIO()
145        im.save(s, "PNG")
146        s.seek(0)
147        return s, im
148
149    def getPrettyLanguage(self, lang_code):
150        if len(str(lang_code))<3:       
151            ts=getToolByName(self,'translation_service')
152            languages = ts.availableLanguages()
153            if dict(languages).has_key(lang_code):
154                return dict(languages)[lang_code]
155            else:
156                return lang_code
157        else:
158            return lang_code
159
160    def savePiece(self, uid, values):
161        # Edit one piece
162        piece=self.uid_catalog(UID=uid)
163        piece=piece[0].getObject()
164        piece.edit(**values)
165        piece.at_post_edit_script()
166
167    def giveLanguageLink(self, REQUEST, lang, url, param):
168        """ Changes the language and redirects to the needed link """
169        self.portal_languages.setLanguageCookie(lang, REQUEST, None)
170        if param:
171            param = re.sub('_and_', '&', param)
172            return REQUEST.RESPONSE.redirect(url+'?'+param)
173        return REQUEST.RESPONSE.redirect(url)
174
175    def testLinkParameters(self, REQUEST):
176        """ Tests the query string for the language change """
177        stri = REQUEST.get('QUERY_STRING')
178        stri = stri.replace('&', '_and_')
179        return stri
180
181    def getStoryCandidate(self, only_with_story=False):
182        """ Random pick for one content, method and tool """
183        pc=getToolByName(self, 'portal_catalog')
184        rc=getToolByName(self, 'reference_catalog')       
185        full_results=pc({'review_state':'public','getHasCoverImage':True})
186        content=[x for x in full_results if x.meta_type in MATERIAL_TYPES]
187        method=[x for x in full_results if x.meta_type=='Activity']
188        tool=[x for x in full_results if x.meta_type=='Tool']
189        if content:
190            content=choice(content).getObject()
191        if method:
192            method=choice(method).getObject()
193        if tool:
194            tool=choice(tool).getObject()
195        if content and method and tool:
196            story=None
197            relations_to_this_content=rc({'relationship':'relatesToContent', 'targetUID':content.UID()})
198            stories=[x.sourceUID for x in relations_to_this_content]
199            good_stories=[]
200            for storc in stories:
201                if rc({'sourceUID':storc, 'relationship':'relatesToMethods', 'targetUID':method.UID()}) and rc({'sourceUID':storc, 'relationship':'relatesToTools', 'targetUID':tool.UID()}):
202                    good_stories.append(storc)
203            if good_stories:
204                story=choice(good_stories)
205                story=self.uid_catalog(UID=story)[0].getObject()
206             
207        else:
208            story=None
209        candidate = {'chcontent':content, 'method':method, 'tool':tool, 'story':story}
210        print candidate
211        return candidate
212       
213       
214
215    security.declareProtected(MANAGE_PORTAL, 'manage_cleanAfterSchemaUpdate')
216    def manage_cleanAfterSchemaUpdate(self, admin=''):
217        """ Archetype update rewrites fields for objects
218        and so user running the update gets to be author.
219        We fix that by running update authors for all objects with special request to
220        ignore modifications this user in last hour. """
221        if not admin:
222            mtool = getToolByName(self, 'portal_membership')
223            admin = mtool.getAuthenticatedMember()
224            admin = admin.getId()
225        for x in chain(self.content.objectValues(CONTENT_TYPES),
226                        self.tools.objectValues(TOOLS_TYPES),
227                        self.activities.objectValues(ACTIVITY_TYPES)):
228            if isinstance(x, Resource):
229                x.recalculateAuthors(removeAdmin=admin)
230       
231
232
233InitializeClass(LeMillTool)
Note: See TracBrowser for help on using the repository browser.