source: trunk/LargeSectionFolder.py @ 1376

Revision 1376, 40.7 KB checked in by szabolcs, 13 years ago (diff)

ref #1152 spent 20m

Not closing yet as lemill should report 'No results' instead of just showing an empty box

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 config import *
20from Products.Archetypes.public import *
21from Products.ATContentTypes.content.folder import ATFolder, ATBTreeFolderSchema, ATBTreeFolder
22from Products.Archetypes.public import registerType
23from Products.CMFCore.utils import getToolByName
24from ZPublisher.HTTPRequest import FileUpload
25from DocumentTemplate import sequence
26from random import sample
27from DateTime import DateTime
28import re, datetime, urllib
29from AccessControl import ClassSecurityInfo
30from permissions import MODIFY_CONTENT, ADD_CONTENT_PERMISSION
31
32communityschema= ATBTreeFolderSchema + Schema((
33    LinesField('collaboration_proposals',
34        default= [],
35        widget = LinesWidget(
36            visible = {'view':'invisible', 'edit':'invisible'},
37            )
38        )
39
40))
41
42
43
44class LargeSectionFolder(ATBTreeFolder):
45    """Section Folder"""
46       
47    archetype_name = "Large Section Folder"
48    meta_type = "Large Section Folder"
49    security = ClassSecurityInfo()
50    isAnObjectManager = 1
51    global_allow= 1
52
53    def getAllContentTypes(self):
54        """ returns a list of all content types """
55        return ALL_CONTENT_TYPES
56
57    def getMaterialTypes(self):
58        """ returns a list of material types """
59        return MATERIAL_TYPES
60
61    def getContentTypes(self):
62        """ returns a list of material types """
63        return CONTENT_TYPES
64
65    def getActivityTypes(self):
66        """ returns a list of activity types """
67        return ACTIVITY_TYPES
68
69    def getToolsTypes(self):
70        """ returns a list of activity types """
71        return TOOLS_TYPES
72
73    def getFeaturedTypes(self):
74        """ returns a list of featured types """
75        return MATERIAL_TYPES + ACTIVITY_TYPES + TOOLS_TYPES
76
77    # Override initializeArchetype to turn on syndication by default
78    security.declarePrivate('initializeArchetype')
79    def initializeArchetype(self, **kwargs):
80        ret_val = ATBTreeFolder.initializeArchetype(self, **kwargs)
81        # Enable topic syndication by default
82        syn_tool = getToolByName(self, 'portal_syndication', None)
83        if syn_tool is not None:
84            if syn_tool.isSiteSyndicationAllowed():
85                try:
86                    syn_tool.enableSyndication(self)
87                except: # might get 'Syndication Information Exists'
88                    pass
89        return ret_val
90
91    # private
92    def _lemill_invokeFactory(self, container, meta_type, id=None, title=''):
93        """ add new object, edit it's title and invoke _renameAfterCreation """
94        if id is None:
95            id = self.generateUniqueId(meta_type)
96        new_id = container.invokeFactory(meta_type, id)
97        new = getattr(container, new_id)
98        new.edit(title = title)
99        renamed = new._renameAfterCreation()
100        if not renamed:
101            renamed = new_id
102        obj = getattr(container, renamed)
103        return obj
104
105
106    security.declareProtected(ADD_CONTENT_PERMISSION,'start_translation')
107    def start_translation(self, REQUEST=None, objId=None):
108        """
109        Start a new translation of an object. This is done by creating new object and
110        then, based on schema, some data is copyied from an object to new object.
111        objId - relative URL to object like /activities/demo_activity
112                or /activities/remote/<remote_server_address>/activities/demo_activity
113        """
114        if objId is None:
115            raise 'object id is None'
116        portal_url = getToolByName(self, 'portal_url')
117        mtool = getToolByName(self, 'portal_membership')
118        base_obj = self.restrictedTraverse(objId)
119        meta_type = base_obj.meta_type
120        lang=''
121        lif=LANGUAGE_INDEPENDENT_FIELDS       
122        if REQUEST:
123            if REQUEST.form.has_key('translanguage'):
124                lang = REQUEST.form['translanguage']
125        new = self._lemill_invokeFactory(self, meta_type, id=meta_type.lower()+str(id(base_obj)))
126        import copy
127        for k in base_obj.schema.keys():
128            # list all fields here that shouldn't be copyied to new object
129            if k in lif:
130                #print 'disqualified %s' % k
131                continue
132            #print 'good %s' % k
133            old_accessor = base_obj.schema[k].getEditAccessor(base_obj)
134            new_mutator = new.schema[k].getMutator(new)
135            val = old_accessor()
136            copied_val = None
137            try:
138                copied_val = copy.copy(val)
139            except TypeError:
140                copied_val = copy.copy(val.aq_base)
141            new_mutator(copied_val)
142            if 'DictField' in base_obj.schema[k].getType():
143                # DictField too has its own way of doing things..
144                source_f=base_obj.schema[k]
145                target_f=new.schema[k]
146                for chap in source_f.getKeys(base_obj):
147                    target_f.setValue(new, chap, source_f.getValue(base_obj, chap))           
148
149
150
151        trans_list = base_obj.getTranslations()
152        trans_list.append(new.UID())
153        base_obj.setTranslations(trans_list)
154        new.setTranslation_of(base_obj.UID())
155        new.setLanguage(lang)
156        new.setCreators([mtool.getAuthenticatedMember().getId()])
157        # give points for original author
158        authid=base_obj.getAuthorsNames()
159        memberfolder=mtool.getHomeFolder(authid[0])
160        if memberfolder!=None:
161            memberfolder.note_action(base_obj.UID(), base_obj.portal_type, 'new translation')
162       
163        mess = self.translate('Translation template has been created',domain='lemill')
164        if REQUEST:
165            REQUEST.set('portal_status_message', mess)
166            return REQUEST.RESPONSE.redirect(new.absolute_url()+'/base_translate?portal_status_message='+mess)
167        else:
168            return new.getId()
169
170
171    def analyzeRequest(self, REQUEST):
172        """ Digs searchterms and content filters out of request, returns dictionary """
173        ltool = getToolByName(self, 'lemill_tool')
174        queries=REQUEST.form
175        # HUGE kludge - no other ideas on how to fix the mysterious "-c" appearing
176        toremove=[]
177        for key in queries.keys():
178            if key.startswith('-'):
179                toremove.append(key)
180        for rem in toremove:
181            del queries[rem]
182       
183        fmds=FIELD_METHODS_DISPLAY_STRINGS
184        if queries.has_key('filter'):
185            filter=queries.pop('filter')
186        else:
187            filter=''
188        if queries.has_key('b_start'):
189            batch_start=queries.pop('b_start')
190        search_url=''
191        for (key,value) in queries.items():
192            if type(value) == list or type(value) == tuple:
193                for y in value:
194                    search_url='%s&%s=%s' % (search_url, key, y)               
195            else:
196                search_url='%s&%s=%s' % (search_url, key, value)       
197        if search_url!='':
198            cont_url=''.join(('?',search_url,'&'))
199        else:
200            cont_url=''.join((search_url,'?'))
201        searchterm_nice={}
202        value_nice={}
203        is_plural={}
204        for (key, value) in queries.items():           
205            if type(value) == list or type(value) == tuple:               
206            # Show materials where *tags* *are* *nature*, *tree*
207                if fmds.has_key(key):
208                    searchterm_nice[key]=fmds[key][1]
209                else:
210                    searchterm_nice[key]=key
211                is_plural[key]=True
212                if key=='Language' or key=='getLanguage_skills':
213                    value_nice=', '.join([lemill_tool.getPrettyLanguage(x) for x in value])                                       
214                else:
215                    value_nice=', '.join(value)                                       
216            else:
217            # Show materials where *tag* *is* *nature*
218                if fmds.has_key(key):
219                    searchterm_nice[key]=fmds[key][0]
220                else:
221                    searchterm_nice[key]=key
222                is_plural[key]=False
223                if key=='Language' or key=='getLanguage_skills':
224                    value_nice[key]=ltool.getPrettyLanguage(value)                                       
225                else:
226                    value_nice[key]=value                                       
227
228        dict={'searchterms':queries, # dictionary of searchterms got from url attributes {'searchterm' : 'value', ...}
229            'search_url':search_url,  # searchterms in url string form '&searchterm=value'
230            'cont_url':cont_url,  #searchterms in url string beginning with '?' and ending with '&'
231            'searchterm_nice':searchterm_nice, # dictionary of tuples for each searchterm, contains displayed form of searchterm f.ex 'getTags': (tag, tags)
232            'is_plural':is_plural, # dictionary of booleans, if certain searchterm has multiple values
233            'value_nice':value_nice, # dictionary of strings, if searchterm is language contains full names of languages otherwise just values for keys {'language':'Finnish'}
234            'filter':filter} # if materials / pieces filter is activated
235        return dict
236
237    def fullResultCount(self,  REQUEST=None, topic_name=None, getIndexMethod=None, request_opened=None, **kw):
238        """ Does a full catalog search with criteria from Topic (called from lemill_browse_results) """
239
240        # if the same search has just been done, return it instead of going through all of this
241        if hasattr(REQUEST, 'SESSION'):       
242            if REQUEST.SESSION.get('latest_st')== request_opened['searchterms']:
243                return REQUEST.SESSION.get('results_n_dict')
244
245        pcatalog = getToolByName(self, 'portal_catalog')
246        mtool = getToolByName(self, 'portal_membership')
247
248        if request_opened.has_key('searchterms'):
249            kw=request_opened['searchterms']       
250
251        if topic_name=='published': # some topic criteria cannot be drawn from given variables and must be hardcoded
252            kw['Creator']=mtool.getAuthenticatedMember().getId()
253            kw['review_state']='public'
254        elif topic_name=='draft':
255            return {} # this shouldn't have happened
256
257        if kw=={}: return {} # don't try to display results if there isn't proper search
258
259        results = pcatalog.searchResults(REQUEST, **kw)
260
261        if topic_name=='published':
262            del kw['review_state'] # this kw would just mess up the results
263       
264        rc={}
265        for t in SEARCHABLE_TYPES:
266            rc[t]=0
267        for r in results:
268            rpt=r.portal_type
269            if rpt in SEARCHABLE_TYPES and r.review_state != 'deleted':
270                rc[rpt]=rc[rpt]+1
271        rc['Learning resource']= sum([rc[k] for k in MATERIAL_TYPES])
272        rc['Content']=rc['Learning resource']+rc['Piece']+rc['LeMillReference']
273        for k in MATERIAL_TYPES: del rc[k]
274       
275        if hasattr(REQUEST, 'SESSION'):       
276            REQUEST.SESSION.set('latest_st', request_opened['searchterms'])
277            REQUEST.SESSION.set('results_n_dict', rc)
278
279        return rc
280
281    def prettyMethodNameDictionary(self):
282        """ Helper method for finding displayable names for search fields """
283        # better to do this in config..
284        return FIELD_METHODS_DISPLAY_STRINGS                     
285
286    def getBrowsedStuff(self, topic_name):
287        """ returns nice name for currently browsed content type"""
288        return self.getId()
289
290    def getNameOfResourceType(self,restype):
291        """Get human-readable name of resource - first try TYPE_NAMES, then TEMPLATES"""
292        if restype in TYPE_NAMES.keys():
293            return TYPE_NAMES[restype][0].lower()
294        else:
295            for t in TEMPLATES.values():
296                if t['meta_type'] == restype:
297                    if t['title'].isupper():
298                        return t['title']
299                    else:
300                        return t['title'].lower()
301        return ""
302
303    def getSectionFolder(self):
304        """ return this """
305        return self
306       
307
308    def getTopicLinks(self, topic, here_url, rfilter, search_url):
309        """ Figures out what links should be displayed in this topic page """       
310               
311        # these dictionaries define what kinds of links there are in legend tabs (up) and to other resource types (down).
312        # type_name_key : (location of link, path of link, filter)
313        # dictionary keys should match those of TYPE_NAMES so that displayed names for links can be fetched from there
314
315        # show all major categories
316        if topic=='published':           
317            dict={'Piece':('up','content/published','pieces'),
318            'LeMillReference':('up','content/published','references'),
319            'Learning resource':('up','content/published','resources'),
320            'Activity':('down','activities/published',''),
321            'Tool':('down','tools/published','')}
322
323        # recent changes needs link to show all, because there isn't any link back to original state otherwise
324        elif topic=='recent':           
325            dict={'All':('up','here',''),
326            'Piece':('up','here','pieces'),
327            'LeMillReference':('up','here','references'),
328            'Learning resource':('up','here','resources'),
329            'Activity':('down','here','activities'),
330            'Tool':('down','here','tools'),
331            }
332
333        # only resources can be drafts, so show nothing
334        elif topic=='draft':
335            dict={}
336
337        # almost everything has tags
338        elif topic=='tags':
339            dict={'Piece':('up','here','pieces'),
340            'LeMillReference':('up','here','references'),
341            'Learning resource':('up','here','resources'),
342            'Content':('down','content/tags','resources'),
343            'Activity':('down','activities/tags',''),
344            'Tool':('down','tools/tags',''),
345            'GroupBlog':('down','community/tags','')}
346
347        # almost everything has language (except pieces)
348        elif topic=='language' or topic=='group_language':
349            dict={'LeMillReference':('up','here','references'),
350            'Learning resource':('up','here','resources'),
351            'Content':('down', 'content/language','resources'),
352            'Activity':('down','activities/language',''),
353            'Tool':('down','tools/language',''),
354            'GroupBlog':('down','community/group_language',''),
355            'MemberFolder':('down','community/language','')}
356
357        # only references and resources have these
358        elif topic=='subject_area' or topic=='target_group':
359            dict={'LeMillReference':('up','here','references'),
360            'Learning resource':('up','here','resources')}
361       
362        # portfolio should show all stuff
363        elif topic=='portfolio':
364            dict={'Piece':('up','here','pieces'),
365            'LeMillReference':('up','here','references'),
366            'Learning resource':('up','here','resources'),
367            'Content':('down','here','resources'),
368            'Activity':('down','here','activities'),
369            'Tool':('down','here','tools'),
370            #'Collection':('down','here','collections'), <-- I think these should be included, but will require some extra work, I'll wait for comments
371            #'Story':('down','here','tipsforuse')
372            }
373       
374        # these should show nothing except themselves
375        elif topic in ['activities','tools','groups','members','country','skills','interests']:
376            dict={}                   
377        else:
378            dict={}
379
380        if dict=={}:
381            return ({},{})
382
383
384        # filter conversion table - this is stupid, but has to be done.
385        # if you're using filter, you want to disable the link to that filter, how do you know which one is it?
386        filter_conversion={'pieces':'Piece',
387        'references':'LeMillReference',
388        'resources':'Learning resource',
389        'activities':'Activity',
390        'tools':'Tool',
391        'collections':'Collection',
392        'tipsforuse':'Story',
393        }
394
395        # mark current page disabled
396        if rfilter:
397            current_page=filter_conversion[rfilter]
398            if current_page in dict.keys():
399                (place, path, lfilter)=dict[current_page]
400                dict[current_page]=(place,'disabled', lfilter)
401
402        portal_url = getToolByName(self, 'portal_url')
403        up_dict={}
404        down_dict={}
405        base_url = self.portal_url()
406       
407        # create better dicts:
408        # find display labels from TYPE_NAMES dict,
409        # replace path with real url with filters and searchterms
410        # if linked page is current page, set link to ''
411        # example:
412        # 'Piece':(('Piece','Pieces'), 'http://www.lemill.net/content/tags?filter=pieces')
413        for (key, value) in dict.items():
414            labels=TYPE_NAMES[key]
415            linkplace=value[0]
416            path=value[1]
417            lfilter=value[2]
418            if path=='here':
419                url=here_url
420            else:
421                url='/'.join((base_url, path))
422                if url==here_url and rfilter=='':
423                    path='disabled'
424            if key=='Content' and rfilter in ['references','resources','pieces']:
425                path='disabled'
426            if key=='All' and not rfilter:
427                path='disabled'
428            if path=='disabled':
429                url=''
430            else:
431                if search_url=='' and lfilter!='':
432                  url='%s?filter=%s' % (url, lfilter)
433                elif search_url!='' and lfilter!='':
434                  url='%s?%s&filter=%s' % (url, search_url[1:], lfilter)
435                elif search_url!='' and lfilter=='':
436                  url='%s?%s' % (url, search_url[1:])
437           
438            if linkplace=='up':
439                # add variable 'order' to dictionary value tuple, so sorting can be based on something
440                order=9               
441                for c in range(len(FILTER_LINK_ORDER)):
442                    if FILTER_LINK_ORDER[c]==key:
443                        order=c
444                        continue
445                up_dict[key]=(order,labels, url)
446            elif linkplace=='down':
447                down_dict[key]=(labels, url)
448        uplinks=up_dict.values()
449        uplinks.sort()
450        return (uplinks, down_dict)
451
452    def getMetadataFieldsToShowInEditor(self, object):
453        """ gets fields which are shown in metadata edit area """
454        type = object.meta_type
455        shownFieldsList = SHOW_METADATA_FIELDS[type]
456        shownFields = []
457        fields = object.Schemata()['metadata'].fields()
458        # At this point, the method can return a list of all metadata
459        if 'all' in shownFieldsList:
460            return fields
461        else:
462            for field in fields:
463                if field.getName() in shownFieldsList:
464                    shownFields.append(field)
465            return shownFields
466
467    def amIManager(self):
468        """Check whether I'm a manager."""
469        return 'Manager' in self.portal_membership.getAuthenticatedMember().getRoles()
470
471    def canIModerate(self):
472        roles = self.portal_membership.getAuthenticatedMember().getRolesInContext(self)
473        return 'Manager' in roles or 'Reviewer' in roles
474
475    def whoami(self):
476        return self.portal_membership.getAuthenticatedMember().getId()       
477
478    def getMember(self,uname=None):
479        if not uname:
480            uname=self.whoami()
481        try:
482            return getattr(self.community,uname)
483        except AttributeError:
484            return None
485
486    def getOtherMember(self, uname):
487        try:
488            return getattr(self.community,uname)
489        except AttributeError:
490            return None
491        except TypeError:
492            return None
493
494    def getSamples(self, search_results):
495        """ Pick three random objects from search results that have non-default images to display in folders front pages. """
496        pic_results = [x for x in search_results if x.meta_type in FEATURED_TYPES and x.getHasCoverImage and x.review_state=='public' and x.Title]
497        n=min(3,len(pic_results))
498        samples=sample(pic_results,n)
499        return samples
500       
501    def getTopResults(self, search_results, index_type):
502        """ Should return top three populated subgroups of search results in given index  """
503        pc = getToolByName(self, 'portal_catalog')
504        if index_type in pc.indexes() and index_type in pc.schema():
505            uniques = pc.uniqueValuesFor(index_type)
506            if uniques == ():
507                return []
508            hits={}
509            for a in uniques:
510                hits[a]=0
511            for counter in search_results:
512                if counter.review_state!='deleted':   
513                    values=getattr(counter, index_type)
514                    if isinstance(values,str):
515                         hits[values]=hits[values]+1
516                    else:
517                        try:
518                            for a in values:
519                                hits[a]=hits[a]+1
520                        except TypeError:
521                            pass # something wrong with data - let's continue without it
522            topthree= [(x[1],x[0]) for x in hits.items() if x[1]>0 and x[0]!='']
523            topthree.sort()
524            topthree.reverse()
525            topthree= topthree[:min(3,len(topthree))]
526            topthree=[x[1] for x in topthree]
527           
528            return topthree
529        else:
530            return []
531
532    def url_quote(self,word):
533        return urllib.quote(word)
534
535    def tagcloud_type(self,topic_name):
536        """ Other than community/tool/activity titles count tag cloud weights by their popularity, aka hits """
537        return 'hits'
538
539    def getTitleCloud(self, search_results, browse_type):
540        """ Simplified version of getUniques that doesn't try to weigh results, used for equal-worth ordering like with titles """
541        # uniquetuplelist contains result metadata reordered: (sort_title, count, url, indexvalue, title)
542        from math import log
543        rc=getToolByName(self, 'reference_catalog')
544        uc=getToolByName(self, 'uid_catalog')
545        pc = getToolByName(self, 'portal_catalog')
546        if browse_type=='group_titles':
547            grouptool = getToolByName(self, 'portal_groups')
548
549        def getTypeForReferenceSource(ref_catalog_item):
550            return uc({'UID':ref_catalog_item.sourceUID})[0].portal_type
551
552        def adjust(i):
553            # helper method to adjust hit count of this tag to relative size (1,...,8)
554            (a,b,c,d,e)=i
555            b=int((8*log(b,2))/log(maxscore,2))
556            if b==0:
557                b=1
558            i=(a,b,c,d,e)
559            return i       
560           
561        def calc_piece(x):
562            res=rc({'targetUID':x.UID})
563            score=len(res)
564            return score
565           
566        def calc_activity(x):
567            res=rc({'targetUID':x.UID})
568            score=0
569            scores={'Collection':1,'Story':10}
570            for r in res:
571                typ = getTypeForReferenceSource(r)
572                if typ in scores.keys():
573                    score+=scores[typ]
574            return score
575        calc_content=calc_activity
576        calc_tool=calc_activity
577        calc_reference=calc_activity
578        calc_material=calc_activity
579
580        def calc_member(x):
581            created=pc({'Creator':x.id})
582            score=0
583            scores={'Piece':1, 'PILOTMaterial':10, 'PresentationMaterial':10, 'MultimediaMaterial':10, 'Activity':10, 'Tool':10,'Story':10, 'BlogPost':1}
584            for c in created:
585                typ=c.portal_type
586                if typ in scores.keys():
587                    score+=scores[typ]
588            contacts=rc({'relationship':'is contact of', 'sourceUID':x.UID})
589            score+=len(contacts)
590            return score
591
592        def calc_group(x):
593            # slow!
594            score=0
595            materials=pc({'getGroupsShared':x.id})
596            blog_posts=x.getObject().objectValues('BlogPost')
597            group=grouptool.getGroupById(x.id)
598            members=group.getGroupMemberIds()
599            score=len(materials)+len(blog_posts)+len(members)   
600            return score         
601       
602        func = eval('calc_%s' % browse_type.split('_')[0])
603        popularity =[(func(x)+1, x.sortable_title, x) for x in search_results]
604        popularity.sort(cmp=lambda t2,t1: cmp(t1[0],t2[0]))
605        popularity=popularity[:100]
606        if browse_type=='member_titles':
607            titlecloud=[(x.getSortable_nicename,pop,x.getURL(),s_title, x.getNicename) for (pop, s_title, x) in popularity]       
608        else:
609            titlecloud=[(s_title,pop,x.getURL(),s_title, x.Title) for (pop, s_title, x) in popularity if x.Title!='']
610        titlecloud.sort()
611        maxscore=max([x[1] for x in titlecloud])
612        if maxscore>1:
613            titlecloud=map(adjust, titlecloud)
614        return titlecloud
615
616    def getUniques(self, search_results, index_type='Date', browse_type='hits'):
617        """ Should return unique values of search results in given index, results are list of index-metadata-like tuples in alphabetical order """
618
619        if search_results==[] or search_results==None:
620            return []
621        elif browse_type.endswith('_titles'):
622            return self.getTitleCloud(search_results, browse_type)
623        elif browse_type=='hits':
624            return self.getTagCloud(search_results, index_type, browse_type)
625
626
627    def getTagCloud(self, search_results, index_type, browse_type):
628        lemill_tool = getToolByName(self, 'lemill_tool')
629        pc = getToolByName(self, 'portal_catalog')
630        from math import log
631        resultlist=[]
632        maxcount=0
633        uniquevalues=[]
634
635        def adjust(i):
636            # helper method to adjust hit count of this tag to relative size (1,...,8)
637            (a,b,c,d,e)=i
638            b=int((8*log(b,2))/log(maxcount,2))
639            if b==0:
640                b=1
641            i=(a,b,c,d,e)
642            return i
643
644        # -- Step 1 -- : Make list of unique values for this index
645        uniques = pc.uniqueValuesFor(index_type)           
646        if uniques == []:
647            return []
648        hits={}
649        # -- Step 2 -- : Use that list to make a dictionary. Values of list are keys.
650        for a in uniques:
651            hits[a]=0
652        # -- Step 3 -- : Go through the search_results and every time a certain key is found from selected index, add a hit to counter under that key.
653        spent_urls=[]
654        for c_obj in search_results:
655            if c_obj.review_state!='deleted':
656                values=getattr(c_obj, index_type)
657                if values!=None:
658                    if type(values)==str or type(values)==int:
659                        hits[values]=hits[values]+1
660                    elif type(values)==list or type(values)==tuple:
661                        for a in list(values):
662                            hits[a]=hits[a]+1               
663
664        # -- Step 4 -- : Build a list from previous dictionary.
665        if hits.has_key(''):
666            del hits['']
667        resultlist=[(x[1], x[0]) for x in hits.items() if x[1]>0]
668        if not resultlist:
669            return []
670        resultlist.sort()
671        resultlist.reverse()
672        maxcount=resultlist[0][0]
673        # if the first cut score for tag is x, we want to cut off all of the tags with score x.
674        if len(resultlist)>100:
675            resultlist = resultlist[:[x[0] for x in result].index(resultlist[100])]
676        resultlist=[(x[1], x[0], '',x[1],x[1]) for x in resultlist]
677
678        # adjust to 1-8. We don't have to worry about score 0, they're already removed.
679        if maxcount>1:
680            resultlist=map(adjust, resultlist)
681        # prettify language names
682        if index_type=='Language' or index_type=='getLanguage_skills':
683            resultlist=[(x[0],x[1],x[2],x[3],lemill_tool.getPrettyLanguage(x[4])) for x in resultlist]
684           
685        resultlist.sort()
686        return resultlist
687
688    def getTagURL(self,context,category,value,filter=None, insideMemberFolder=False):
689        value=to_unicode(value)
690
691        if filter:
692            filter=''.join(('&filter=',filter))
693        else:
694            filter=''
695
696        if insideMemberFolder:
697            begin='/'.join((insideMemberFolder.absolute_url(),context.getId()))
698            filter='&Creator=%s' % insideMemberFolder.getId()
699        else:
700            begin=context.absolute_url()
701       
702        return u"%s?%s=%s%s" % (begin,category,value, filter)
703
704    def getUrlInsideMemberFolder(self, memberfolder=None, topicid='', here_url=''):
705        """ When trying to get url for topics, absolute_url omits the memberfolder, this method puts it back in """
706        if memberfolder:
707            return '/'.join((memberfolder.absolute_url(),topicid))
708        else:
709            return here_url
710
711    def js_queryForPieces(self, keyword, audio=False):
712        """ javascript is querying for pieces that are images """
713        # when this method is called by javascript, all arguments are packed to string 'keyword'
714        # typical value for keyword: 'foobar,audio=False'
715        keywords=keyword.split(', ')
716        keyword=keywords[0]
717        audio='no'
718        for a in keywords[1:]:
719            if a=='audio=True':
720                audio='only'
721            elif a=='audio=accept':
722                audio='accept'
723
724        result = []
725        stool = getToolByName(self, 'lemill_search')
726        q = {'SearchableText': keyword,
727             'portal_type': ['Piece', ]
728        }
729        q_results = stool.local_search(q)
730        for r in q_results:
731            if r.review_state == 'deleted':
732                continue
733            if audio=='only':
734                if not r.getObject().isAudio(): continue
735            elif audio=='no':
736                if not r.getObject().isImage(): continue
737            tmp = [r.getObject().UID(), r.getId, to_unicode(r.Title).encode('iso-8859-15'), int(r.getObject().isAudio()), int(r.getHasCoverImage)]
738            result.append(tmp)
739        return str(result)
740
741    security.declarePublic('public_getSortCriterion')
742    def public_getSortCriterion(self,topic):
743        """ Topics have this useful getSortCriterion -method, but it's available only if allowed to change content."""
744        if topic.hasSortCriterion():
745            return topic.getSortCriterion().field
746        else:
747            return False
748
749    def filterContent(self, results, show_what=''):
750        """ Currently only contents use this, other SectionFolders traverse here because stupid test(x,y,z) implementation """
751        return results
752
753    def getDefaultIcon(self, meta_type, obj=None):
754        """ general method for getting proper icon for object, used when only catalog-metadata is available """       
755        address=DEFAULT_ICONS[meta_type]
756        if address!='piece':
757            return address
758        else:
759            try:
760                obj=obj.getObject()
761                return obj.getDefaultIcon()
762            except AttributeError:
763                return DEFAULT_ICONS['Piece']
764
765class LargeContentFolder(LargeSectionFolder):
766
767    archetype_name = "Large Content Folder"
768    meta_type = "Large Content Folder"
769
770    allowed_content_types = CONTENT_TYPES +('Topic','Redirector')
771    default_view = ('lemill_content_view')
772    filter_content_types = True
773    security = ClassSecurityInfo()
774
775    security.declareProtected(ADD_CONTENT_PERMISSION,'uploadIt')
776    def uploadIt(self, REQUEST):
777        """ gets file from upload and makes new object.
778            also does some content-type whitelist checking here.
779        """
780        file = REQUEST.get('file')
781        if file==None or not getattr(file, 'headers',{}).has_key('Content-Type'):
782            return REQUEST.RESPONSE.redirect('lemill_explain_upload_fail')       
783        user_description = REQUEST.get('user_description')
784        content_type = file.headers['Content-Type']
785        type = ''
786        if content_type in MIMETYPE_WHITELIST:
787            type = 'Piece'
788       
789        if not type or type != 'Piece':
790            return REQUEST.RESPONSE.redirect('lemill_explain_upload_fail')
791       
792        new = self._lemill_invokeFactory(self, type, id=type+str(id(self)))
793        new.edit(description=user_description, file=file.read())
794        if type=='Piece':
795            new.edit(language='')
796        new_id = new.getId()
797        return REQUEST.RESPONSE.redirect(new.absolute_url()+'/piece_edit')
798        #return REQUEST.RESPONSE.redirect(self.absolute_url()+'/lemill_check_content?id='+new_id+'&type='+type)
799
800    def getTemplates(self, aslist=False):
801        if not aslist:
802            return TEMPLATES
803        else:           
804            # as list = ordered list of dictionaries, original key is under key 'keyname'
805            rl=[(value['order'], key, value) for (key,value) in TEMPLATES.items()]
806            rl.sort()
807            resl=[]
808            for (order, key, value) in rl:
809                value['keyname']=key
810                resl.append(value)
811            return resl
812
813
814    def getTemplate(self, template_id):
815        return TEMPLATES.get(template_id, None)
816
817    def filterContent(self, results, show_what='resources'):
818        if show_what=='content':
819            allowed=CONTENT_TYPES
820        elif show_what=='activities':
821            allowed=('Activity',)
822        elif show_what=='tools':
823            allowed=('Tool',)
824        elif show_what=='resources':
825            allowed=MATERIAL_TYPES
826        elif show_what=='pieces':
827            allowed=('Piece',)
828        elif show_what=='references':
829            allowed=('LeMillReference',)
830
831        else: return results
832        return filter(lambda x: x.portal_type in allowed, results)
833
834
835
836    def tagcloud_type(self,topic_name):
837        """ There are content tag clouds by titles """
838        if topic_name=='pieces': return 'piece_titles'
839        elif topic_name=='materials': return 'material_titles'
840        elif topic_name=='references': return 'reference_titles' # I'm not sure if these are used
841        elif topic_name=='content': return 'content_titles'
842        else: return 'hits'
843
844    security.declareProtected(ADD_CONTENT_PERMISSION,'lemidlet_post')
845    def lemidlet_post(self, REQUEST):
846        """ LeMidlet will post image here...."""
847        #print REQUEST.file.read()
848        file = REQUEST.get('file')
849        if file==None:
850            return 'file not found'       
851        description = REQUEST.get('description')
852        type = 'Piece'
853
854        new = self._lemill_invokeFactory(self, type, id=type+str(id(self)))
855        new.edit(description=description, file=file.read())
856        new.edit(language='')
857        new.edit(title=REQUEST.get('title'))
858        new.edit(tags=REQUEST.get('tags'))
859        new_id = new.getId()
860        return 0
861
862       
863class LargeActivityFolder(LargeSectionFolder):
864
865    archetype_name = "Large Activity Folder"
866    meta_type = "Large Activity Folder"
867
868    allowed_content_types = ('Activity','KB', 'Topic','Redirector')
869    default_view = ('lemill_activities_view')
870    filter_content_types = True
871
872    def tagcloud_type(self,topic_name):
873        """ Other than community tag clouds count tags by their popularity, except hits """
874        if topic_name=='activities': return 'activity_titles'
875        else: return 'hits'
876   
877class LargeToolFolder(LargeSectionFolder):
878
879    archetype_name = "Large Tool Folder"
880    meta_type = "Large Tool Folder"
881
882    allowed_content_types = ('Tool', 'Topic','Redirector')
883    default_view = ('lemill_tools_view')
884    filter_content_types = True
885
886    def tagcloud_type(self,topic_name):
887        """ Other than community tag clouds count tags by their popularity, aka hits """
888        if topic_name=='tools': return 'tool_titles'
889        else: return 'hits'
890
891
892class LargeCommunityFolder(LargeSectionFolder):
893
894    archetype_name = "Large Community Folder"
895    meta_type = "Large Community Folder"
896
897    allowed_content_types = ('Topic','Redirector','MemberFolder','GroupBlog')
898    default_view = ('lemill_community_view')
899    filter_content_types = True
900    security = ClassSecurityInfo()
901
902    schema=communityschema
903
904    ### If MemberFolder for logged in user does not exist, it is created here
905   
906    def my_page(self):
907        """ Checks if user has MemberFolder and creates one if not. Returns the folder url."""
908        mtool = getToolByName(self, "portal_membership")
909        member=mtool.getAuthenticatedMember()
910        if not member: return
911        if member.getHomeFolder()==None:
912            member.createMemberarea()           
913        folder=member.getHomeFolder()
914        if not hasattr(folder.aq_base,'collections'):
915            folder.invokeFactory('CollectionsFolder', id='collections')
916        if not hasattr(folder.aq_base,'stories'):
917            folder.invokeFactory('StoryFolder', id='stories')               
918        return folder.absolute_url()   
919
920    def tagcloud_type(self,topic_name):
921        """ Community tag clouds can use people's activities or group activities as base """
922        if topic_name=='members': return 'member_titles'
923        elif topic_name=='groups': return 'group_titles'
924        else: return 'hits'
925       
926
927    def getCollaboration_proposals(self):
928        """ Because I prefer lists, not tuples """
929        return list(self.getField('collaboration_proposals').get(self))
930       
931    security.declareProtected(ADD_CONTENT_PERMISSION,'addCollaboration_proposal')
932    def addCollaboration_proposal(self, obj_uid):
933        """ Collaboration proposals are stored as list of UID:s, because then we don't have to care about group path when finding them """
934        uid_cat = getToolByName(self, "uid_catalog")
935
936        def post_date(uid):
937            post=uid_cat(UID=uid)
938            post=post[0].getObject()
939            return post.creation_date                       
940
941        current_date = DateTime()
942        cp= self.getCollaboration_proposals()
943        if obj_uid not in cp:
944            cp=[obj_uid]+cp
945        # pop out old collaboration proposals from tail of the list
946        while post_date(cp[-1])< (current_date-31):
947            cp.pop()
948        cp=cp[:100]
949        cp_field=self.getField('collaboration_proposals')
950        cp_field.set(self, cp)
951
952    security.declareProtected(ADD_CONTENT_PERMISSION,'removeCollaboration_proposal')
953    def removeCollaboration_proposal(self, obj_uid):
954        cp= self.getCollaboration_proposals()
955        if obj_uid in cp:
956            cp.remove(obj_uid)
957        cp_field=self.getField('collaboration_proposals')
958        cp_field.set(self, cp)
959
960    def mergeLatestPostsInMyGroups(self):
961        mtool = getToolByName(self, "portal_membership")
962        gtool = getToolByName(self, "portal_groups")
963        member=mtool.getAuthenticatedMember()
964        memberid=member.getId()
965        glist = self.lemill_usertool.getGroupsList(memberid);
966        recents=[]
967        for group in glist:
968            gname= group.getGroupName()
969            garea= gtool.getGroupareaFolder(gname)
970            grecent= garea.getRecent_posts()
971            for postid in grecent:
972                try:
973                    post=garea._getOb(postid)
974                    recents.append((post.Date,post))
975                except AttributeError:
976                    # do some cleaning:
977                    garea.removeRecent_post(postid)
978        recents.sort()
979        recents = [x[1] for x in recents]
980        return recents[:5]
981                           
982    def getBrowsedStuff(self, topic_name):
983        """ returns nice name for currently browsed content type"""
984        if BROWSING_TITLE_FROM_LOCATION.has_key(topic_name):           
985            return BROWSING_TITLE_FROM_LOCATION[topic_name]
986        else:
987            return self.getId()
988       
989       
990    def getCollections(self, obj_uid):
991        """ Show collections where object is used."""
992        res = []
993        q = { 'targetUID': obj_uid }
994        qres = self.reference_catalog(q)
995        for q in qres:
996            v = self.reference_catalog.lookupObject(q.UID)
997            source = v.getSourceObject()
998            if source.meta_type == 'Collection':
999                res.append(source)
1000        return res
1001
1002    def filterContent(self, results, show_what='resources'):
1003        if show_what=='content':
1004            allowed=CONTENT_TYPES
1005        elif show_what=='activities':
1006            allowed=('Activity',)
1007        elif show_what=='tools':
1008            allowed=('Tool',)
1009        elif show_what=='resources':
1010            allowed=MATERIAL_TYPES
1011        elif show_what=='pieces':
1012            allowed=('Piece',)
1013        elif show_what=='references':
1014            allowed=('LeMillReference',)
1015
1016        else: return results
1017        return filter(lambda x: x.portal_type in allowed, results)
1018
1019       
1020registerType(LargeContentFolder, PROJECTNAME)
1021registerType(LargeActivityFolder, PROJECTNAME)
1022registerType(LargeToolFolder, PROJECTNAME)
1023registerType(LargeCommunityFolder, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.