source: trunk/SectionFolder.py @ 1241

Revision 1241, 35.5 KB checked in by jukka, 13 years ago (diff)

Fixed #1051, spent 2h. Also went through all topics and checked they are ok.

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, ATFolderSchema
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
30
31
32communityschema= ATFolderSchema + Schema((
33    LinesField('collaboration_proposals',
34        default= [],
35        widget = LinesWidget(
36            visible = {'view':'invisible', 'edit':'invisible'},
37            )
38        )
39
40))
41
42
43
44class SectionFolder(ATFolder):
45    """Section Folder"""
46       
47    archetype_name = "Section Folder"
48    meta_type = "Section Folder"
49    security = ClassSecurityInfo()
50   
51    def getAllContentTypes(self):
52        """ returns a list of all content types """
53        return ALL_CONTENT_TYPES
54
55    def getMaterialTypes(self):
56        """ returns a list of material types """
57        return MATERIAL_TYPES
58
59    def getContentTypes(self):
60        """ returns a list of material types """
61        return CONTENT_TYPES
62
63    def getActivityTypes(self):
64        """ returns a list of activity types """
65        return ACTIVITY_TYPES
66
67    def getToolsTypes(self):
68        """ returns a list of activity types """
69        return TOOLS_TYPES
70
71    def getFeaturedTypes(self):
72        """ returns a list of featured types """
73        return MATERIAL_TYPES + ACTIVITY_TYPES + TOOLS_TYPES
74
75    # Override initializeArchetype to turn on syndication by default
76    def initializeArchetype(self, **kwargs):
77        ret_val = ATFolder.initializeArchetype(self, **kwargs)
78        # Enable topic syndication by default
79        syn_tool = getToolByName(self, 'portal_syndication', None)
80        if syn_tool is not None:
81            if syn_tool.isSiteSyndicationAllowed():
82                try:
83                    syn_tool.enableSyndication(self)
84                except: # might get 'Syndication Information Exists'
85                    pass
86        return ret_val
87
88    def _lemill_invokeFactory(self, container, meta_type, id=None, title=''):
89        """ add new object, edit it's title and invoke _renameAfterCreation """
90        if id is None:
91            id = self.generateUniqueId(meta_type)
92        new_id = container.invokeFactory(meta_type, id)
93        new = getattr(container, new_id)
94        new.edit(title = title)
95        renamed = new._renameAfterCreation()
96        if not renamed:
97            renamed = new_id
98        obj = getattr(container, renamed)
99        return obj
100
101
102   
103    def start_new_version(self, REQUEST=None, objId=None):
104        """
105        FEATURE REMOVED for v1.4 Start a new version of an object. This is done by creating new object and
106        then, based on schema, all data is copyied from an object to new object.
107        """
108        if objId is None:
109            raise 'object id is None'
110        portal_url = getToolByName(self, 'portal_url')
111        base_obj = self.restrictedTraverse(objId)
112        meta_type = base_obj.meta_type
113        lang=''
114        new = self._lemill_invokeFactory(self, meta_type, id=meta_type.lower()+str(id(base_obj)), title=base_obj.Title())
115        import copy
116        for k in base_obj.schema.keys():
117            # list all fields here that shouldn't be copyied to new object
118            if k in ['id', 'effectiveDate', 'expirationDate', 'creation_date', 'modification_date', 'versions', 'parentVersion', 'translation_of','translations']:
119                continue           
120            old_accessor = base_obj.schema[k].getEditAccessor(base_obj)
121            new_mutator = new.schema[k].getMutator(new)
122            val = old_accessor()
123            copied_val = None
124            try:
125                copied_val = copy.copy(val)
126            except TypeError:
127                copied_val = copy.copy(val.aq_base)
128            new_mutator(copied_val)
129            if 'DictField' in base_obj.schema[k].getType():
130                # DictField too has its own way of doing things..
131                source_f=base_obj.schema[k]
132                target_f=new.schema[k]
133                for chap in source_f.getKeys(base_obj):
134                    target_f.setValue(new, chap, source_f.getValue(base_obj, chap))           
135
136
137        vers_list = base_obj.getVersions()
138        vers_list.append(new.UID())
139        base_obj.setVersions(vers_list)
140        new.setParentVersion(base_obj.UID())
141        if REQUEST:
142            return REQUEST.RESPONSE.redirect(new.absolute_url()+'/base_edit')
143        else:
144            return new.getId()
145
146
147    def start_translation(self, REQUEST=None, objId=None):
148        """
149        Start a new translation of an object. This is done by creating new object and
150        then, based on schema, some data is copyied from an object to new object.
151        objId - relative URL to object like /activities/demo_activity
152                or /activities/remote/<remote_server_address>/activities/demo_activity
153        """
154        if objId is None:
155            raise 'object id is None'
156        portal_url = getToolByName(self, 'portal_url')
157        base_obj = self.restrictedTraverse(objId)
158        meta_type = base_obj.meta_type
159        lang=''
160        lif=LANGUAGE_INDEPENDENT_FIELDS       
161        if REQUEST:
162            if REQUEST.form.has_key('translanguage'):
163                lang = REQUEST.form['translanguage']
164        new = self._lemill_invokeFactory(self, meta_type, id=meta_type.lower()+str(id(base_obj)))
165        import copy
166        for k in base_obj.schema.keys():
167            # list all fields here that shouldn't be copyied to new object
168            if k in lif:
169                #print 'disqualified %s' % k
170                continue
171            #print 'good %s' % k
172            old_accessor = base_obj.schema[k].getEditAccessor(base_obj)
173            new_mutator = new.schema[k].getMutator(new)
174            val = old_accessor()
175            copied_val = None
176            try:
177                copied_val = copy.copy(val)
178            except TypeError:
179                copied_val = copy.copy(val.aq_base)
180            new_mutator(copied_val)
181            if 'DictField' in base_obj.schema[k].getType():
182                # DictField too has its own way of doing things..
183                source_f=base_obj.schema[k]
184                target_f=new.schema[k]
185                for chap in source_f.getKeys(base_obj):
186                    target_f.setValue(new, chap, source_f.getValue(base_obj, chap))           
187
188
189
190        trans_list = base_obj.getTranslations()
191        trans_list.append(new.UID())
192        base_obj.setTranslations(trans_list)
193        new.setTranslation_of(base_obj.UID())
194        new.setLanguage(lang)
195        mess = self.translate('Translation template has been created',domain='lemill')
196        if REQUEST:
197            REQUEST.set('portal_status_message', mess)
198            return REQUEST.RESPONSE.redirect(new.absolute_url()+'/base_translate?portal_status_message='+mess)
199        else:
200            return new.getId()
201
202
203    def analyzeRequest(self, REQUEST):
204        """ Digs searchterms and content filters out of request, returns dictionary """
205        ltool = getToolByName(self, 'lemill_tool')
206        queries=REQUEST.form
207        # HUGE kludge - no other ideas on how to fix the mysterious "-c" appearing
208        toremove=[]
209        for key in queries.keys():
210            if key.startswith('-'):
211                toremove.append(key)
212        for rem in toremove:
213            del queries[rem]
214       
215        fmds=FIELD_METHODS_DISPLAY_STRINGS
216        if queries.has_key('filter'):
217            filter=queries.pop('filter')
218        else:
219            filter=''
220        if queries.has_key('b_start'):
221            batch_start=queries.pop('b_start')
222        search_url=''
223        for (key,value) in queries.items():
224            if type(value) == list or type(value) == tuple:
225                for y in value:
226                    search_url='%s&%s=%s' % (search_url, key, y)               
227            else:
228                search_url='%s&%s=%s' % (search_url, key, value)       
229        if search_url!='':
230            cont_url=''.join(('?',search_url,'&'))
231        else:
232            cont_url=''.join((search_url,'?'))
233        searchterm_nice={}
234        value_nice={}
235        is_plural={}
236        for (key, value) in queries.items():           
237            if type(value) == list or type(value) == tuple:               
238            # Show materials where *tags* *are* *nature*, *tree*
239                if fmds.has_key(key):
240                    searchterm_nice[key]=fmds[key][1]
241                else:
242                    searchterm_nice[key]=key
243                is_plural[key]=True
244                if key=='Language' or key=='getLanguage_skills':
245                    value_nice=', '.join([lemill_tool.getPrettyLanguage(x) for x in value])                                       
246                else:
247                    value_nice=', '.join(value)                                       
248            else:
249            # Show materials where *tag* *is* *nature*
250                if fmds.has_key(key):
251                    searchterm_nice[key]=fmds[key][0]
252                else:
253                    searchterm_nice[key]=key
254                is_plural[key]=False
255                if key=='Language' or key=='getLanguage_skills':
256                    value_nice[key]=ltool.getPrettyLanguage(value)                                       
257                else:
258                    value_nice[key]=value                                       
259
260        dict={'searchterms':queries, # dictionary of searchterms got from url attributes {'searchterm' : 'value', ...}
261            'search_url':search_url,  # searchterms in url string form '&searchterm=value'
262            'cont_url':cont_url,  #searchterms in url string beginning with '?' and ending with '&'
263            'searchterm_nice':searchterm_nice, # dictionary of tuples for each searchterm, contains displayed form of searchterm f.ex 'getTags': (tag, tags)
264            'is_plural':is_plural, # dictionary of booleans, if certain searchterm has multiple values
265            'value_nice':value_nice, # dictionary of strings, if searchterm is language contains full names of languages otherwise just values for keys {'language':'Finnish'}
266            'filter':filter} # if materials / pieces filter is activated
267        return dict
268
269    def fullResultCount(self,  REQUEST=None, topic_name=None, getIndexMethod=None, request_opened=None, **kw):
270        """ Does a full catalog search with criteria from Topic (called from lemill_browse_results) """
271
272        # if the same search has just been done, return it instead of going through all of this
273        if hasattr(REQUEST, 'SESSION'):       
274            if REQUEST.SESSION.get('latest_st')== request_opened['searchterms']:
275                return REQUEST.SESSION.get('results_n_dict')
276
277        pcatalog = getToolByName(self, 'portal_catalog')
278        mtool = getToolByName(self, 'portal_membership')
279
280        if request_opened.has_key('searchterms'):
281            kw=request_opened['searchterms']       
282
283        if topic_name=='published': # some topic criteria cannot be drawn from given variables and must be hardcoded
284            kw['Creator']=mtool.getAuthenticatedMember().getId()
285            kw['review_state']='public'
286        elif topic_name=='draft':
287            return {} # this shouldn't have happened
288
289        if kw=={}: return {} # don't try to display results if there isn't proper search
290
291        results = pcatalog.searchResults(REQUEST, **kw)
292
293        if topic_name=='published':
294            del kw['review_state'] # this kw would just mess up the results
295       
296        rc={}
297        for t in SEARCHABLE_TYPES:
298            rc[t]=0
299        for r in results:
300            rpt=r.portal_type
301            if rpt in SEARCHABLE_TYPES and r.review_state != 'deleted':
302                rc[rpt]=rc[rpt]+1
303        rc['Learning resource']= sum([rc[k] for k in MATERIAL_TYPES])
304        for k in MATERIAL_TYPES: del rc[k]
305
306       
307        if hasattr(REQUEST, 'SESSION'):       
308            REQUEST.SESSION.set('latest_st', request_opened['searchterms'])
309            REQUEST.SESSION.set('results_n_dict', rc)
310        return rc
311
312    def prettyMethodNameDictionary(self):
313        """ Helper method for finding displayable names for search fields """
314        # better to do this in config..
315        return FIELD_METHODS_DISPLAY_STRINGS                     
316
317    def getBrowsedStuff(self, topic_name):
318        """ returns nice name for currently browsed content type"""
319        return self.getId()
320
321    def getNameOfResourceType(self,restype):
322        """Get human-readable name of resource - first try TYPE_NAMES, then TEMPLATES"""
323        if restype in TYPE_NAMES.keys():
324            return TYPE_NAMES[restype][0].lower()
325        else:
326            for t in TEMPLATES.values():
327                if t['meta_type'] == restype:
328                    if t['title'].isupper():
329                        return t['title']
330                    else:
331                        return t['title'].lower()
332        return ""
333
334    def whatResourceWhereDictionary(self):
335        """ Helper method for finding correct sections for different resource types """       
336        dict=TYPE_NAMES
337        ww=TYPE_LOCATIONS
338        # adds path information to type_names dictionary and returns it
339        for (key, value) in dict.items():
340            if ww.has_key(key):
341                if key=='Piece':
342                    add_filter='&filter=pieces'
343                elif key=='LeMillReference':
344                    add_filter='&filter=references'
345                elif key=='Material' or key=='Learning resource':
346                    add_filter='&filter=resources'
347                else:
348                    add_filter=''
349                dict[key]=(value[0], value[1], ww[key], eval('self.%s.absolute_url()' % ww[key]), add_filter)
350            else:
351                del dict[key]
352        return dict
353
354    def getMetadataFieldsToShowInEditor(self, object):
355        """ gets fields which are shown in metadata edit area """
356        type = object.meta_type
357        shownFieldsList = SHOW_METADATA_FIELDS[type]
358        shownFields = []
359        fields = object.Schemata()['metadata'].fields()
360        # At this point, the method can return a list of all metadata
361        if 'all' in shownFieldsList:
362            return fields
363        else:
364            for field in fields:
365                if field.getName() in shownFieldsList:
366                    shownFields.append(field)
367            return shownFields
368
369    #def getFolder(self):
370    #    return self
371
372    def amIManager(self):
373        """Check whether I'm a manager."""
374        return 'Manager' in self.portal_membership.getAuthenticatedMember().getRoles()
375
376    def canIModerate(self):
377        roles = self.portal_membership.getAuthenticatedMember().getRolesInContext(self)
378        return 'Manager' in roles or 'Reviewer' in roles
379
380    def whoami(self):
381        return self.portal_membership.getAuthenticatedMember().getId()       
382
383    def getMember(self,uname=None):
384        if not uname:
385            uname=self.whoami()
386        try:
387            return getattr(self.community,uname)
388        except AttributeError:
389            return None
390
391    def getOtherMember(self, uname):
392        try:
393            return getattr(self.community,uname)
394        except AttributeError:
395            return None
396        except TypeError:
397            return None
398
399    def getSamples(self, search_results):
400        """ Pick three random objects from search results that have non-default images to display in folders front pages. """
401        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]
402        n=min(3,len(pic_results))
403        samples=sample(pic_results,n)
404        return samples
405       
406    def getTopResults(self, search_results, index_type):
407        """ Should return top three populated subgroups of search results in given index  """
408        pc = getToolByName(self, 'portal_catalog')
409        if index_type in pc.indexes() and index_type in pc.schema():
410            uniques = pc.uniqueValuesFor(index_type)
411            if uniques == ():
412                return []
413            hits={}
414            for a in uniques:
415                hits[a]=0
416            for counter in search_results:
417                if counter.review_state!='deleted':   
418                    values=getattr(counter, index_type)
419                    if isinstance(values,str):
420                         hits[values]=hits[values]+1
421                    else:
422                        try:
423                            for a in values:
424                                hits[a]=hits[a]+1
425                        except TypeError:
426                            pass # something wrong with data - let's continue without it
427            topthree= [(x[1],x[0]) for x in hits.items() if x[1]>0 and x[0]!='']
428            topthree.sort()
429            topthree.reverse()
430            topthree= topthree[:min(3,len(topthree))]
431            topthree=[x[1] for x in topthree]
432           
433            return topthree
434        else:
435            return []
436
437    def url_quote(self,word):
438        """..."""
439        return urllib.quote(word)
440
441    def tagcloud_type(self,topic_name):
442        """ Other than community/tool/activity titles count tag cloud weights by their popularity, aka hits """
443        return 'hits'
444
445    def getSimpleUniques(self, search_results):
446        """ Simplified version of getUniques that doesn't try to weigh results, used for equal-worth ordering like with titles """
447        # uniquetuplelist contains result metadata reordered: (sort_title, count, url, indexvalue, title)
448        uniquetuplelist=[(x.sortable_title,2,x.getURL(),x.sortable_title, x.Title) for x in search_results if x.Title!='']
449        uniquetuplelist.sort()
450        return uniquetuplelist
451
452    def getUniques(self, search_results, index_type='Date', browse_type='hits'):
453        """ Should return unique values of search results in given index, results are list of index-metadata-like tuples in alphabetical order """
454
455        if browse_type in ['reference_titles', 'piece_titles', 'material_titles', 'activity_titles', 'tool_titles', 'content_titles']: # only activity_titles and tool_titles are actually used
456            return self.getSimpleUniques(search_results)
457
458        lemill_tool = getToolByName(self, 'lemill_tool')
459        pc = getToolByName(self, 'portal_catalog')
460        uniquetuplelist=[]
461        maxcount=0
462        uniques=[]
463
464        def adjust(i):
465            # helper method to adjust hit count of this tag to relative size (1,...,8)
466            (a,b,c,d,e)=i
467            if type(b)==int:
468                if b>1:
469                    b=int((8*b)/maxcount)
470                i=(a,b,c,d,e)
471            else:
472                print 'Broken MemberFolder: (%s,%s,%s,%s,%s)' % (a,b,c,d,e)
473            return i
474
475        # -- Step 1 -- : Make list of unique values for this index. For members and groups this is time to collect their urls and title.
476        if browse_type=='hits':
477            uniques = pc.uniqueValuesFor(index_type)           
478        elif browse_type=='active_people':
479            people = pc.searchResults(portal_type='MemberFolder')
480            uniques = [x.id for x in people]
481        elif browse_type=='active_groups':
482            groups = pc.searchResults(portal_type='GroupBlog')
483            uniques = [x.id for x in groups]
484
485        if uniques == []:
486            return []
487        hits={}
488
489        # -- Step 2 -- : Use list to make a dictionary. Values of list are keys.
490        for a in uniques:
491            hits[a]=(0,'','','') # value : (hits, objectURL, sort_title, title)
492
493        # -- 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. With people and group names the counter gets hits from different sources.
494        if browse_type=='active_groups':
495            # Just get activity score from group metadata
496            for group in groups:
497                hits[group.id]=(max(1, group.getActivity_score), group.getURL(), group.sortable_title, group.Title)
498               
499        elif browse_type=="active_people":
500            # Just get activity score from member metadata
501            for member in people:
502                hits[member.id]=(max(1, member.getActivity_score), member.getURL(), member.getSortable_nicename, member.getNicename)
503
504        elif browse_type=="unique_hits":
505            for counter in search_results:
506                if counter.review_state!='deleted':
507                    value=getattr(counter, index_type)
508                    hits[value]=(0, counter.getURL(), value, counter.Title)
509        else:
510            # Vanilla hits counter
511            spent_urls=[]
512            for counter in search_results:
513                c_url=counter.getURL()
514                if counter.review_state!='deleted' and not c_url in spent_urls:
515                    values=getattr(counter, index_type)
516                    if values!=None:
517                        if type(values)==str or type(values)==int:
518                            hits[values]=(hits[values][0]+1, c_url, values, values)
519                        elif type(values)==list or type(values)==tuple:
520                            for a in list(values):
521                                hits[a]=(hits[a][0]+1, c_url, a, a)
522                    spent_urls.append(c_url)
523        # OK, the story so far: hits = dictionary, where keys are the distinct values of current index, or memberid:s
524        # values of this dictionary are tuples, where:
525        # value[0]= n of objects that have this value,
526        # value[1]= url-of-object that has this value (sensible only if there is one object with this value, like names for users),
527        # value[2]= title, nicer representation of key's name (title for group names and nicename for member names)
528        # value[3]= another_title, because sortable_nicename already takes the title place for members. ugly...
529
530        # -- Step 4 -- : Build a list from previous dictionary. Objects in list are tuples. Order list alphabetically.
531        # This dictionary should be ordered alphabetically by title.
532        if hits.has_key(''):
533            del hits['']
534        uniquetuplelist=[(x[1][2],x[1][0],x[1][1],x[0],x[1][3]) for x in hits.items() if x[1][0]>0]       
535        # uniquetuplelist now contains dictionary reordered: (sort_title, count, url, indexvalue, title)
536        if uniquetuplelist==[]:
537            return uniquetuplelist
538        if browse_type in ('hits','active_people','active_groups') and len(uniquetuplelist)>100:
539            # order by activity/usage
540            tmplist = [(x[1], x) for x in uniquetuplelist]
541            tmplist.sort()
542            tmplist.reverse()
543            uniquetuplelist = [x for (key, x) in tmplist]
544            # select value at cut point
545            maxcount=uniquetuplelist[0][1]
546            smallest=uniquetuplelist[100][1]
547            cutpoint=99
548            small_value=uniquetuplelist[cutpoint][1]
549            # keep going down the list as long as the values are equal
550            while small_value==smallest:
551                cutpoint=cutpoint-1
552                small_value=uniquetuplelist[cutpoint][1]
553            uniquetuplelist=uniquetuplelist[:cutpoint+1]
554
555        else:
556            maxcount=max(map(lambda x: x[1], uniquetuplelist))
557        uniquetuplelist.sort()
558        uniquetuplelist=map(adjust, uniquetuplelist)
559         
560        # prettify language names
561        if index_type=='Language' or index_type=='getLanguage_skills':
562            uniquetuplelist=[(x[0],x[1],x[2],x[3],lemill_tool.getPrettyLanguage(x[4])) for x in uniquetuplelist]
563        return uniquetuplelist
564
565    def getTagURL(self,context,category,value,filter=None, insideMemberFolder=False):
566        value=to_unicode(value)
567
568        if filter:
569            filter=''.join(('&filter=',filter))
570        else:
571            filter=''
572
573        if insideMemberFolder:
574            begin='/'.join((insideMemberFolder.absolute_url(),context.getId()))
575            filter='&Creator=%s' % insideMemberFolder.getId()
576        else:
577            begin=context.absolute_url()
578       
579        return u"%s?%s=%s%s" % (begin,category,value, filter)
580
581    def getUrlInsideMemberFolder(self, memberfolder=None, topicid='', here_url=''):
582        """ When trying to get url for topics, absolute_url omits the memberfolder, this method puts it back in """
583        if memberfolder:
584            return '/'.join((memberfolder.absolute_url(),topicid))
585        else:
586            return here_url
587
588    def js_queryForPieces(self, keyword, audio=False):
589        """ javascript is querying for pieces that are images """
590        # when this method is called by javascript, all arguments are packed to string 'keyword'
591        # typical value for keyword: 'foobar,audio=False'
592        keywords=keyword.split(', ')
593        keyword=keywords[0]
594        audio='no'
595        for a in keywords[1:]:
596            if a=='audio=True':
597                audio='only'
598            elif a=='audio=accept':
599                audio='accept'
600
601        result = []
602        stool = getToolByName(self, 'lemill_search')
603        q = {'SearchableText': keyword,
604             'portal_type': ['Piece', ]
605        }
606        q_results = stool.local_search(q)
607        for r in q_results:
608            if r.review_state == 'deleted':
609                continue
610            if audio=='only':
611                if not r.getObject().isAudio(): continue
612            elif audio=='no':
613                if not r.getObject().isImage(): continue
614            tmp = [r.getObject().UID(), r.getId, to_unicode(r.Title).encode('iso-8859-15'), int(r.getObject().isAudio()), int(r.getHasCoverImage)]
615            result.append(tmp)
616        return str(result)
617
618    security.declarePublic('public_getSortCriterion')
619    def public_getSortCriterion(self,topic):
620        """ Topics have this useful getSortCriterion -method, but it's available only if allowed to change content."""
621        if topic.hasSortCriterion():
622            return topic.getSortCriterion().field
623        else:
624            return False
625
626    def filterContent(self, results, show_what=''):
627        """ Currently only contents use this, other SectionFolders traverse here because stupid test(x,y,z) implementation """
628        return results
629
630    def getDefaultIcon(self, meta_type, obj=None):
631        """ general method for getting proper icon for object, used when only catalog-metadata is available """       
632        address=DEFAULT_ICONS[meta_type]
633        if address!='piece':
634            return address
635        else:
636            try:
637                obj=obj.getObject()
638                return obj.getDefaultIcon()
639            except AttributeError:
640                return DEFAULT_ICONS['Piece']
641
642class ContentFolder(SectionFolder):
643
644    archetype_name = "Content Folder"
645    meta_type = "Content Folder"
646
647    allowed_content_types = CONTENT_TYPES +('Topic',)
648    default_view = ('lemill_content_view')
649    filter_content_types = True
650
651    def uploadIt(self, REQUEST):
652        """ gets file from upload and makes new object.
653            also does some content-type whitelist checking here.
654        """
655        file = REQUEST.get('file')
656        if file==None:
657            return REQUEST.RESPONSE.redirect('lemill_explain_upload_fail')       
658        user_description = REQUEST.get('user_description')
659        content_type = file.headers['Content-Type']
660        type = ''
661        if content_type in MIMETYPE_WHITELIST:
662            type = 'Piece'
663       
664        if not type or type != 'Piece':
665            return REQUEST.RESPONSE.redirect('lemill_explain_upload_fail')
666       
667        new = self._lemill_invokeFactory(self, type, id=type+str(id(self)))
668        new.edit(description=user_description, file=file.read())
669        if type=='Piece':
670            new.edit(language='')
671        new_id = new.getId()
672        return REQUEST.RESPONSE.redirect(new.absolute_url()+'/piece_edit')
673        #return REQUEST.RESPONSE.redirect(self.absolute_url()+'/lemill_check_content?id='+new_id+'&type='+type)
674
675    def getTemplates(self, aslist=False):
676        if not aslist:
677            return TEMPLATES
678        else:           
679            # as list = ordered list of dictionaries, original key is under key 'keyname'
680            rl=[(value['order'], key, value) for (key,value) in TEMPLATES.items()]
681            rl.sort()
682            resl=[]
683            for (order, key, value) in rl:
684                value['keyname']=key
685                resl.append(value)
686            return resl
687
688
689    def getTemplate(self, template_id):
690        return TEMPLATES.get(template_id, None)
691
692    def filterContent(self, results, show_what='resources'):
693        if show_what=='resources':
694            allowed=MATERIAL_TYPES
695        elif show_what=='pieces':
696            allowed=('Piece',)
697        elif show_what=='references':
698            allowed=('LeMillReference',)
699        else: return results
700        return filter(lambda x: x.portal_type in allowed, results)
701
702    def tagcloud_type(self,topic_name):
703        """ There are content tag clouds by titles """
704        if topic_name=='pieces': return 'piece_titles'
705        elif topic_name=='materials': return 'material_titles'
706        elif topic_name=='references': return 'reference_titles' # I'm not sure if these are used
707        elif topic_name=='content': return 'content_titles'
708        else: return 'hits'
709
710    def lemidlet_post(self, REQUEST):
711        """ LeMidlet will post image here...."""
712        #print REQUEST.file.read()
713        file = REQUEST.get('file')
714        if file==None:
715            return 'file not found'       
716        description = REQUEST.get('description')
717        type = 'Piece'
718
719        new = self._lemill_invokeFactory(self, type, id=type+str(id(self)))
720        new.edit(description=description, file=file.read())
721        new.edit(language='')
722        new.edit(title=REQUEST.get('title'))
723        new.edit(tags=REQUEST.get('tags'))
724        new_id = new.getId()
725        return 0
726
727       
728class ActivityFolder(SectionFolder):
729
730    archetype_name = "Activity Folder"
731    meta_type = "Activity Folder"
732
733    allowed_content_types = ('Activity','KB', 'Topic')
734    default_view = ('lemill_activities_view')
735    filter_content_types = True
736
737    def tagcloud_type(self,topic_name):
738        """ Other than community tag clouds count tags by their popularity, except hits """
739        if topic_name=='activities': return 'activity_titles'
740        else: return 'hits'
741   
742class ToolFolder(SectionFolder):
743
744    archetype_name = "Tool Folder"
745    meta_type = "Tool Folder"
746
747    allowed_content_types = ('Tool', 'Topic')
748    default_view = ('lemill_tools_view')
749    filter_content_types = True
750
751    def tagcloud_type(self,topic_name):
752        """ Other than community tag clouds count tags by their popularity, aka hits """
753        if topic_name=='tools': return 'tool_titles'
754        else: return 'hits'
755
756
757class CommunityFolder(SectionFolder):
758
759    archetype_name = "Community Folder"
760    meta_type = "Community Folder"
761
762    allowed_content_types = ('Topic',)
763    default_view = ('lemill_community_view')
764    filter_content_types = True
765
766    schema=communityschema
767   
768    def my_page(self):
769        """ Checks if user has MemberFolder and creates one if not. Returns the folder url."""
770        mtool = getToolByName(self, "portal_membership")
771        member=mtool.getAuthenticatedMember()
772        if member.getHomeFolder()==None:
773            member.createMemberarea()
774        folder=member.getHomeFolder()   
775        return folder.absolute_url()   
776
777    def tagcloud_type(self,topic_name):
778        """ Community tag clouds can use people's activities or group activities as base """
779        if topic_name=='members': return 'active_people'
780        elif topic_name=='groups': return 'active_groups'
781        else: return 'hits'
782       
783
784    def getCollaboration_proposals(self):
785        """ Because I prefer lists, not tuples """
786        return list(self.getField('collaboration_proposals').get(self))
787       
788    def addCollaboration_proposal(self, obj_uid):
789        """ Collaboration proposals are stored as list of UID:s, because then we don't have to care about group path when finding them """
790        uid_cat = getToolByName(self, "uid_catalog")
791
792        def post_date(uid):
793            post=uid_cat(UID=uid)
794            post=post[0].getObject()
795            return post.creation_date                       
796
797        current_date = DateTime()
798        cp= self.getCollaboration_proposals()
799        if obj_uid not in cp:
800            cp=[obj_uid]+cp
801        # pop out old collaboration proposals from tail of the list
802        while post_date(cp[-1])< (current_date-31):
803            cp.pop()
804        cp=cp[:100]
805        cp_field=self.getField('collaboration_proposals')
806        cp_field.set(self, cp)
807
808    def removeCollaboration_proposal(self, obj_uid):
809        cp= self.getCollaboration_proposals()
810        if obj_uid in cp:
811            cp.remove(obj_uid)
812        cp_field=self.getField('collaboration_proposals')
813        cp_field.set(self, cp)
814
815    def mergeLatestPostsInMyGroups(self):
816        mtool = getToolByName(self, "portal_membership")
817        gtool = getToolByName(self, "portal_groups")
818        member=mtool.getAuthenticatedMember()
819        memberid=member.getId()
820        glist = self.lemill_usertool.getGroupsList(memberid);
821        recents=[]
822        for group in glist:
823            gname= group.getGroupName()
824            garea= gtool.getGroupareaFolder(gname)
825            grecent= garea.getRecent_posts()
826            for postid in grecent:
827                try:
828                    post=garea._getOb(postid)
829                    recents.append((post.Date,post))
830                except AttributeError:
831                    # do some cleaning:
832                    garea.removeRecent_post(postid)
833        recents.sort()
834        recents = [x[1] for x in recents]
835        return recents[:5]
836                           
837    def getBrowsedStuff(self, topic_name):
838        """ returns nice name for currently browsed content type"""
839        if BROWSING_TITLE_FROM_LOCATION.has_key(topic_name):           
840            return BROWSING_TITLE_FROM_LOCATION[topic_name]
841        else:
842            return self.getId()
843       
844       
845    def getCollections(self, obj_uid):
846        """ Show collections where object is used."""
847        res = []
848        q = { 'targetUID': obj_uid }
849        qres = self.reference_catalog(q)
850        for q in qres:
851            v = self.reference_catalog.lookupObject(q.UID)
852            source = v.getSourceObject()
853            if source.meta_type == 'Collection':
854                res.append(source)
855        return res
856
857    def filterContent(self, results, show_what='resources'):
858        if show_what=='content':
859            allowed=CONTENT_TYPES
860        elif show_what=='activities':
861            allowed=('Activity',)
862        elif show_what=='tools':
863            allowed=('Tool',)
864        elif show_what=='resources':
865            allowed=MATERIAL_TYPES
866        elif show_what=='pieces':
867            allowed=('Piece',)
868        elif show_what=='references':
869            allowed=('LeMillReference',)
870
871        else: return results
872        return filter(lambda x: x.portal_type in allowed, results)
873
874       
875registerType(ContentFolder, PROJECTNAME)
876registerType(ActivityFolder, PROJECTNAME)
877registerType(ToolFolder, PROJECTNAME)
878registerType(CommunityFolder, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.