source: trunk/MemberFolder.py @ 3128

Revision 3128, 30.2 KB checked in by jukka, 9 years ago (diff)

Fixed #1991. Contact emails lead to contact initiator.

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 Products.Archetypes.public import *
20from Products.ATContentTypes.content.folder import ATFolder
21from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
22from Products.CMFCore.permissions import ModifyPortalContent
23from Products.Archetypes.public import BaseFolder, BaseFolderSchema, registerType
24from Products.Archetypes.atapi import DisplayList
25from Globals import InitializeClass
26from Products.CMFCore.utils import getToolByName
27from AccessControl import ClassSecurityInfo, Unauthorized
28from config import *
29from Schemata import coverImage, score, latest_edit_schema, state
30from permissions import ModerateContent, MODIFY_CONTENT, ACCESS_CONTENT, VIEW
31from Products.PloneLanguageTool.availablelanguages import countries
32from FieldsWidgets import HTMLLinkWidget
33try:
34    from Products.PloneLanguageTool.availablelanguages import languages_english
35except ImportError:
36    from Products.PloneLanguageTool.availablelanguages import languages
37    languages_english = dict([(key, val['english']) for (key, val) in languages.iteritems()])
38    del languages
39
40from messagefactory_ import i18nme as _
41from FieldsWidgets import TagsField, TagsWidget, MessengerWidget, MobileWidget, LeTextAreaWidget, TwoColumnMultiSelectionWidget
42from CommonMixIn import CommonMixIn, CoverImageMixIn
43from LargeSectionFolder import LeMillFolder
44from Acquisition import ImplicitAcquisitionWrapper
45from DateTime import DateTime
46import datetime, time
47import random
48
49### MemberFolders should be created automatically. If users get their account from other authentication scheme, their folders can be created with methods at LargeCommunityFolder (my_page -method is run, if top-right-corner link to memberpage fails)
50
51messenger_vocabulary = [(x,x) for x in INSTANT_MESSENGERS]
52
53# if it is plausible that just this field is searched somewhere, then field can have its own index. Otherwise it should be just 'searchable=True'. Those are all kept in one big text index.
54
55memberfolder_schema = Schema((
56    StringField('title',
57        mode ='r',
58        # default_method is called only once, when first needed; after that, getXxx is used
59        widget=StringWidget(
60            label_msgid='label_title',
61            visible={'edit' : 'invisible'},           
62        ),
63    ),
64    StringField('firstname',
65        searchable = True,
66        required = True,
67        widget = StringWidget(
68             label = 'First name',
69             label_msgid = 'label_firstname',
70             i18n_domain = "lemill"
71             )
72        ),
73    StringField('lastname',
74        searchable = True,
75        required = True,
76        widget = StringWidget(
77             label = 'Last name',
78             label_msgid = 'label_lastname',
79             i18n_domain = "lemill"
80             )
81        ),
82    StringField('full_name',
83        searchable = True,
84        widget = StringWidget(
85             visible = {'view':'invisible', 'edit':'invisible'},
86             )
87        ),
88    ComputedField('nicename', # so that displayed name can be pulled from catalog metadata
89        index= 'FieldIndex:schema',
90        expression = 'here.getNicename()',
91        ),
92       
93    StringField('email',
94        searchable = True,
95        required = True,
96        index = 'FieldIndex:schema',
97        validators = 'isEmail',
98        widget = StringWidget(
99             label = 'Email address',
100             label_msgid = 'label_email',
101             i18n_domain = "lemill"
102             )
103        ),
104
105    StringField('mobile',
106        widget = MobileWidget(
107            label = 'Phone',
108            label_msgid = 'label_phone',
109            description = 'Check the box if you approve community members sending text messages.',
110            description_msgid = 'help_mobile',
111            visible = {'view':'invisible', 'edit':'invisible'},
112            )
113    ),         
114
115    StringField('messenger1',
116        vocabulary = DisplayList(messenger_vocabulary),
117        widget = MessengerWidget(
118             label = 'Instant messengers',
119             label_msgid = 'label_messenger',
120             i18n_domain = "lemill"
121             )
122        ),
123    StringField('messenger2',
124        vocabulary = DisplayList(messenger_vocabulary),
125        widget = MessengerWidget(
126             label = ' ',
127             )
128        ),
129    StringField('messenger3',
130        vocabulary = DisplayList(messenger_vocabulary),
131        widget = MessengerWidget(
132             label = ' ',
133             )
134        ),
135    StringField('slideshare_username',
136        widget = StringWidget(
137            label = 'Slideshare user name',
138            label_msgid ='label_slideshare_user',
139            description = 'If you want to upload presentations from Slideshare, LeMill needs to know where to look for them. Username is not visible for other users in LeMill. We will never ask your password.',
140            description_msgid = 'help_slideshare_user',
141            visible = {'view':'invisible', 'edit':'invisible'},
142            )
143        ),
144    StringField('location_country',
145        index = 'FieldIndex:schema',
146        searchable = True,
147        vocabulary = 'getCountrylist',
148        widget = SelectionWidget(
149             label = 'Country',
150             label_msgid = 'label_country',
151             i18n_domain = "lemill"
152             )
153        ),       
154    StringField('location_area',
155        searchable = True,
156        widget = StringWidget(
157             label = 'City or area',
158             label_msgid = 'label_area',
159             i18n_domain = "lemill"
160             )
161        ),
162    StringField('home_page',
163        widget = HTMLLinkWidget(
164             label = 'Homepage',
165             label_msgid = 'label_home_page',
166             i18n_domain = "lemill",
167             validators = 'isURL'
168             )
169        ),
170    LinesField('language_skills',
171        default = [],
172        index = 'KeywordIndex:schema',
173        vocabulary = 'getLanguagelist',
174        widget = PicklistWidget(           
175             label = 'Languages',
176             label_msgid = 'label_language_skills',
177             description = "",
178             i18n_domain = "lemill"
179             )
180        ),       
181    TagsField('skills',
182        index = 'KeywordIndex:schema',
183        widget = TagsWidget(           
184             label = 'Skills',
185             label_msgid = 'label_skills',
186             description = "Enter a list of your skills separated by commas.",
187             description_msgid = 'help_skills',
188             visible = {'view':'invisible', 'edit':'invisible'},
189             )
190        ),
191    TagsField('interests',
192        index = 'KeywordIndex:schema',
193        widget = TagsWidget(
194             label = 'Interests',
195             label_msgid = 'label_interests',
196             description = "Enter a list of your interests separated by commas.",
197             description_msgid = 'help_interests',
198             visible = {'view':'invisible', 'edit':'invisible'},
199             )
200        ),
201    LinesField('subject_area',
202        vocabulary = DisplayList([(x,x) for x in SUBJECT_AREAS]),
203        index = "KeywordIndex:schema",
204        multivalued=True,
205        searchable=True,
206        widget=TwoColumnMultiSelectionWidget(
207            format="checkbox",
208            label="Subject area",
209            label_msgid="label_member_subject_area",
210            description="Choose subject areas that you are teaching.",
211            description_msgid="description_member_subject_area",
212            i18n_domain="lemill"
213            )
214        ),
215    ComputedField('tags',
216        index = 'KeywordIndex:schema',
217        expression = 'here.getTags()',
218        ),
219
220    StringField('biography',
221        searchable = True,
222        widget = LeTextAreaWidget(
223            label = 'About me',
224            label_msgid = 'label_about_me',
225            description = "Any background information about yourself that you wish to share with others.",
226            description_msgid = 'help_your_biography',
227            i18n_domain = "lemill"
228            )
229        ),
230
231    StringField('wysiwyg_editor',
232            default='kupu',
233            mode = 'r',
234            widget = StringWidget(
235                visible = {'view':'invisible', 'edit':'invisible'},
236                ),
237            ),
238    ReferenceField('listOfContacts',
239        required = False,
240        searchable = False,
241        relationship = 'is contact of',
242        accessor = 'getListOfContacts',
243        mutator = 'addListOfContacts',
244        multiValued = True,
245        widget = ReferenceWidget(
246            visible = {'view':'invisible', 'edit':'invisible'},
247            ),
248        ),
249    LinesField('notification_properties',
250        vocabulary = DisplayList((
251            ("resource_edited", "Someone edited your resource"),
252            ("resource_added_to_collection", "Someone added your resource to a collection"),
253            ("resource_discussion_note", "Someone wrote a discussion note about your resource"),
254            ("contact_added", "Someone added you as a contact"),
255            ("contact_published_resource", "Your contact published a new resource"),
256            ("group_joined", "Someone joined your group"),
257            ("group_message_posted", "Someone posted a message in group forum"),
258            )),
259        multivalued = True,
260        default = ('resource_edited', 'resource_added_to_collection', 'resource_discussion_note', 'contact_added', 'contact_published_resource', 'group_joined', 'group_message_posted'),
261        widget = MultiSelectionWidget(
262            format = "checkbox",
263            visible = {'view':'invisible','edit':'visible'},
264            label = "E-mail announcements about changes in LeMill",
265            label_msgid = "label_notification_properties",
266            description = "The system will automatically send e-mail messages to you for all the checked events.",
267            description_msgid = "description_notification properties",
268            i18n_domain = "lemill",
269        ),
270    ),
271
272))
273
274schema = BaseFolderSchema + coverImage + score + latest_edit_schema + state + memberfolder_schema
275
276schema = schema.copy()
277schema['coverImage'].original_size=(140,120)
278
279class MemberFolder(CoverImageMixIn,CommonMixIn, BaseFolder):
280    """Member folder"""
281
282    meta_type = "MemberFolder"
283    archetype_name = "MemberFolder" 
284    typeDescription="Member folder"
285    typeDescMsgId='description_memberfolder'
286    global_allow = 1
287    portlet = 'here/portlet_member/macros/portlet'
288    default_location = 'community/people'
289
290    allowed_content_types = ('CollectionsFolder', 'Topic')
291    default_view = ('member_view')
292    filter_content_types = True
293    security = ClassSecurityInfo()
294    schema = schema
295
296    actions = (
297        {'id':'view',
298         'name':'View',
299         'action':"string:${object_url}/member_view",
300         'permission':(VIEW,),
301        },
302        {'id':'edit',
303         'name':'Edit',
304         'action':"string:${object_url}/personalize_form",
305         'permission':(MODIFY_CONTENT,),
306        },
307    )   
308    aliases = {
309        '(Default)': '',
310        'edit': 'personalize_form',
311        'view':'member_view'
312        }
313
314    def manage_afterAdd(self, item, container):
315        BaseFolder.manage_afterAdd(self, item, container)
316        # Handle case when logged in user is authenticated from an
317        # external source for the first time
318        try:
319            # This is not very nicely done, should use API methods to access what I need
320            uinfo = self.acl_users.source_users.getUserInfo(self.Creator())
321        except KeyError: # Doesn't exist yet - create
322            self.acl_users.source_users.addUser(self.Creator(),self.Creator(),'')
323            self.acl_users.portal_role_manager.assignRolesToPrincipal(('Member',),self.Creator())
324        # If we've done external authentication, then the user isn't really yet
325        # properly authenticated, so we can't create
326        # the collections and resources folders.
327        self.reindexObject()
328
329    def setPermissions(self):
330        # Setting View permission
331        self.manage_permission(VIEW, ('Manager','Owner','Member','Authenticated','Anonymous'), acquire=0)
332        # Setting Edit permission
333        self.manage_permission(MODIFY_CONTENT, ('Manager','Owner'), acquire=0)
334        # Setting Review permission
335        self.manage_permission(ModerateContent, ('Manager','Owner','Reviewer'), acquire=0)
336        # Setting Access permission
337        self.manage_permission(ACCESS_CONTENT, ('Manager','Owner','Member','Authenticated','Anonymous'), acquire=0)
338
339    def getMessages(self):
340        """ Memberfolder messages should remind about missing country and language """
341        messages=CommonMixIn.getMessages(self)
342        if self.canIEdit() and not (self.getLanguage_skills() and self.getLocation_country() and self.getLocation_country()!='No country specified'):
343            messages.append('missing_member_info')           
344        return messages
345
346    def setFullname(self, value):
347        """ had to rename fullname-field, but its set method is still widely used """ 
348        self.setFull_name(value)
349
350    def getMemberId(self):
351        """ return user's id """
352        return self.Creator()
353
354    def getMetaDescription(self):
355        """ Biography is a good description, but if not filled, then skills, interests or subject areas  """
356        return self.getBiography() or ', '.join(self.getTags()) or ', '.join(self.getSubject_area())
357
358    def getLocation_country(self):
359        """ a getter to fix problem with wrapped values """
360        value= self.getField('location_country').get(self)
361        if type(value)==ImplicitAcquisitionWrapper:
362            value=value()
363        return value
364
365    def getMemberFolder(self):
366        """ return the member, useful for collections, topics etc. subobjects """
367        return self
368
369    def getLatestEditDate(self):
370        """Returns creation date, we don't want to notify about every edit"""
371        return DateTime(self.CreationDate())
372
373    def getCollectionsFolder(self):
374        """..."""
375        if not hasattr(self.aq_base, 'collections'):
376            self.invokeFactory('CollectionsFolder', id='collections')
377        return self.collections
378
379    def getCollectionsNumber(self):
380        """..."""
381        dest = self.getCollectionsFolder()
382        collections = dest.objectIds('Collection')
383        return len(collections)
384   
385    def getCollections(self, obj_id=None, sort=True, col_uid=None):
386        """Return list of user's collections."""
387        if obj_id:
388            return self.aq_parent.getCollections(obj_id)
389        collections = self.getCollectionsFolder().objectValues('Collection')
390        if col_uid:
391            collections = [c for c in collections if c.UID()!=col_uid]
392        if not sort:
393            return collections
394        sortable_collections = [(x.Title(), x) for x in collections]
395        sortable_collections.sort()
396        return [x[1] for x in sortable_collections]
397
398    security.declareProtected(MODIFY_CONTENT,'delCollection')
399    def delCollection(self, obj_id):
400        obj=self.collections.get(obj_id)
401        if obj.amIOwner():       
402            collection_resources = obj.getRelatedContent() + obj.getRelatedMethods() + obj.getRelatedTools()
403            self.collections._delObject(obj_id)
404            # when deleting collection we need to recalculate scores for collection resources
405            for r in collection_resources:
406                r.recalculateScore()
407                r.reindexObject(['getScore'])
408            msg=_(u'Collection deleted')
409        else:
410            msg=_(u'You are not allowed to delete this collection')
411        return (self.collections, msg)     
412   
413    def getCountrylist(self):
414        """ We don't need short country codes, so we make a list where fancyname=fancyname and give that as DisplayList """
415        countries_root = [('No country specified', 'No country specified')]
416        countries_list = [(x[1],x[1]) for x in countries.items()]
417        countries_list.sort()
418        countries_root= countries_root + countries_list
419        return DisplayList(tuple(countries_root)) # not sure, but DisplayList might require tuples not lists.
420
421
422
423    security.declareProtected(MODIFY_CONTENT, 'updateCountry')
424    def updateCountry(self,country):
425        """ Just change country, called from javascript """
426        self.setLocation_country(country)
427        self.at_post_edit_script()
428        lt=getToolByName(self, 'lemill_tool')
429        lt.addPortalMessage(_('Thank you!'))
430        return self.REQUEST.RESPONSE.redirect(self.absolute_url())
431   
432    def getLanguagelist(self):
433        return DisplayList(LANGUAGES[1:]) # Cut out the first, 'no language specified'-option
434
435
436    def getPortrait(self, author=None):
437        """ Gets portrait"""
438        if not author:
439            return self.getCoverImage()
440        else:
441            return self.getMemberFolderById(author).getCoverImage()
442
443    def getPortraitURL(self,author=None):
444        """ Gets portrait URL"""
445        return self.getCoverImageURL()
446
447    def getNicename(self):
448        """ First try full_name, then userid """
449        return self.getFull_name() or self.Creator()
450
451    def sortable_title(self):
452        lastname= self.getLastname()
453        #if type(lastname)== ImplicitAcquisitionWrapper:
454        #    lastname=lastname()
455        if lastname:
456            try:
457                lastname=lastname.lower()
458            except:
459                lastname=lastname()
460            return lastname.lower()
461        else:
462            return self.Creator().lower()
463
464    def prefill_title(self):
465        lutool = getToolByName(self, 'lemill_usertool')
466        return lutool.getAuthenticatedId()
467
468    def getFull_name(self):
469        full= self.getField('full_name').get(self)
470        if full:           
471            return full
472        else:
473            first=self.getField('firstname').get(self)
474            last=self.getField('lastname').get(self)
475            if first and last:
476                self.getField('full_name').set(self, ' '.join((first, last)))
477                return ' '.join((first, last))
478            else:
479                return ''
480
481    def setLastname(self, value):
482        self.getField('lastname').set(self, value)
483        first=self.getField('firstname').get(self)
484        if callable(first):
485            first=first()
486        if value:
487            self.getField('full_name').set(self, ' '.join((first, value)))
488       
489    def setFirstname(self, value):
490        self.getField('firstname').set(self, value)
491        last=self.getField('lastname').get(self)
492        if callable(last):
493            last=last()
494        if value:
495            self.getField('full_name').set(self, ' '.join((value, last)))
496       
497    security.declareProtected(MODIFY_CONTENT,'setCoverImage')
498    def setCoverImage(self, value, **kwargs):
499        cover=self.getField('coverImage')
500        cover.set(self,value,**kwargs)
501        has_cover=self.getField('hasCoverImage')
502        if value==None:
503            has_cover.set(self,False)
504        else:
505            has_cover.set(self,True)
506
507       
508    def getHasCoverImage(self):
509        if self.getCoverImage():
510            return True
511        return False
512
513    security.declarePrivate('at_post_edit_script')
514    def at_post_edit_script(self):
515        self.recalculateScore()
516        fullname = self.getField('full_name').get(self)
517        if fullname and fullname!=self.Title():
518            self.setTitle(fullname)
519        self.reindexObject()
520
521    def getTags(self):
522        lst = self.getField('interests').get(self) + self.getField('skills').get(self)
523        return list(lst)
524
525    def canNotify(self, prop):
526        """ checks if notification preferences allow this kind of message """
527        return prop in self.getNotification_properties()
528
529    def userPortfolioInfo(self):
530        """ """
531        amounts_dict = self.getResources(self.Creator(), n=True, as_dict=True, private_materials=False);
532        text = '<div id="portfolio_content" style="background-color: #ffffff; padding:5px; vertical-align:top;">'
533       
534        # display random user resource image if has any
535        pc = getToolByName(self, 'portal_catalog')
536        meta_types = MATERIAL_TYPES + ACTIVITY_TYPES + TOOLS_TYPES
537        results = pc({'Creator': self.Creator(), 'meta_type': meta_types, 'getState':['public', 'draft'], 'getHasCoverImage': True})
538        if results:
539            obj = random.choice(results).getObject()
540            if obj:
541                text += '<div style="display: table-cell;text-align: center;vertical-align: middle;width: 130px;height: 100px;border: 1px solid #cccccc;"><img src="%s" alt=""></img></div>' % obj.getCoverImageURL()
542       
543        here_url = self.absolute_url()
544        portal_url = getToolByName(self, 'portal_url')
545        portal_url = portal_url()
546        text += '<ul style="line-height: 1.5em;margin: 0.5em 0 0 1.5em;padding: 0;list-style-image: url(%s);list-style-type: square;font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size: 13px;">' % (portal_url + '/bullet.gif')
547        text += '<li><a href="%s" target="_blank" style="color:#2299bb;">Content</a> (%s)</li>' % (here_url + '/portfolio?type=resource', amounts_dict.get('Content'))
548        text += '<li><a href="%s" target="_blank" style="color:#2299bb;">Methods</a> (%s)</li>' % (here_url + '/portfolio?type=Activity', amounts_dict.get('Activities'))
549        text += '<li><a href="%s" target="_blank" style="color:#2299bb;">Tools</a> (%s)</li>' % (here_url + '/portfolio?type=Tool', amounts_dict.get('Tools'))
550        text += '<li><a href="%s" target="_blank" style="color:#2299bb;">Collections</a> (%s)</li>' % (here_url + '/collections', amounts_dict.get('Collections'))
551        text += '<li><a href="%s" target="_blank" style="color:#2299bb;">Tag cloud</a></li>' % (here_url + '/portfolio')
552        text += '</ul></div>'
553        return text
554
555    def userPortfolio(self):
556        """ """
557        url = self.absolute_url() + '/userPortfolioInfo'
558        iframe_text = '<iframe src="%s" width="100%%" height="220px" frameborder="0" scrolling="no"></iframe>' % url
559        return iframe_text
560
561
562    def getGroups(self, objects=False):
563        """ Gets groups where member belongs"""
564        pc=getToolByName(self, 'portal_catalog')
565        objlist=pc({'getGroupMembers':self.getMemberId(), 'portal_type':'GroupBlog'})
566        if objects:
567            # getObject verified
568            return [o.getObject() for o in objlist]
569        else:
570            return objlist
571
572
573    def getSamples(self, n=4):
574        """ get n number of samples """
575        my_id=self.getMemberId()
576        pc=getToolByName(self, 'portal_catalog')
577        results = pc({'getState':'public', 'meta_type': self.getFeaturedTypes(), 'getHasCoverImage':True, 'Creator': my_id})
578        if len(results)<n:
579            results = pc({'getState':'public', 'meta_type': list(self.getFeaturedTypes())+['Piece'], 'getHasCoverImage':True, 'Creator': my_id})
580        indexes=range(len(results))
581        choices=[]
582        while indexes and len(choices)<n:
583            choices.append(indexes.pop(random.randint(0,len(indexes)-1)))
584        good_results=[results[i] for i in choices]
585        return good_results
586       
587
588    def getDefaultIcon(self, meta_type='', obj=None):
589        """ general method for getting proper icon for object, used when only catalog-metadata is available """
590        # this combines folderish getDefaultIcon(for-this-type, object) and resource-specific object.getDefaultIcon()
591        # folderish behaviour is needed because members have these created resources-pages. 
592        if meta_type=='':
593            return  DEFAULT_ICONS['MemberFolder']
594        else:     
595            address=DEFAULT_ICONS[meta_type]
596            if address!='piece':
597                return address
598            else:
599                # getObject verified
600                obj=obj.getObject()
601                return obj.getDefaultIcon()
602   
603    def verifyMessengers(self, array):
604        """ check if there are some instant messengers to show
605            takes an array and if there is content then returns True
606        """
607        for x in array:
608            if x: return True
609        return False
610
611
612    security.declareProtected(MODIFY_CONTENT,'addToContacts')
613    def addToContacts(self,uid=None):
614        """ Add person to contacts """
615        field=self.getField('listOfContacts')
616        uidlist=field.getRaw(self)
617        if uid not in uidlist:
618            uidlist.append(uid)
619            field.set(self, uidlist)
620            lt=getToolByName(self, 'lemill_tool')
621            mf = lt.getObjectByUID(uid)
622            mf.notifyAddedAsContact()
623       
624    security.declareProtected(MODIFY_CONTENT,'removeFromContacts')
625    def removeFromContacts(self,uid=None):
626        """ Remove person from contacts """
627        field=self.getField('listOfContacts')
628        uidlist=field.getRaw(self)       
629        if uid in uidlist:
630            uidlist.remove(uid)
631            field.set(self, uidlist)
632
633    def showRemoveContactLink(self):
634        """ Determines if we show the remove link for user this is still done in reverse """
635        lutool = getToolByName(self, "lemill_usertool")
636        home=lutool.getMemberFolder()
637        field = home.getField('listOfContacts')
638        return self.UID() in field.getRaw(home)
639
640    def giveSortedListOfContacts(self):
641        """ Sorts list of contacts by sortable nicename """
642        return self.portal_catalog(UID=self.getRawListOfContacts(), sort_on='sortable_title')
643
644    def getRelatedContacts(self, size_only=False):
645        """ Returns all related contacts """
646        obj_uid = self.UID()
647        res = []
648        q = { 'targetUID': obj_uid }
649        qres = self.reference_catalog(q)
650        if size_only:
651            return len(qres)
652        for q in qres:
653            sourceUID= self.reference_catalog.lookupObject(q.UID).sourceUID
654            sres = self.portal_catalog({'UID':sourceUID})
655            if sres and sres[0].portal_type == 'MemberFolder':
656                res.append(sres[0])
657        return res
658
659    security.declareProtected(MODIFY_CONTENT,'updateSlideshare_username')
660    def updateSlideshare_username(self, REQUEST):
661        """ """
662        new_username=REQUEST.get('new_username','')
663        if new_username:
664            self.setSlideshare_username(new_username)
665        lt=getToolByName(self, 'lemill_tool')
666        lt.addPortalMessage(_('Saved SlideShare username.'))
667        return REQUEST.RESPONSE.redirect(self.content.absolute_url()+'/add_presentation')
668
669    def recalculateScore(self):
670        """ Recalculates score for MemberFolder according to specifications """
671        score = 0
672        member = self.getMemberId()
673        pc=getToolByName(self, 'portal_catalog')
674        # Get pieces and filter out References
675        pieces=pc(Creator=member, portal_type='Piece', getState='public')
676        # Get Material types, Methods and Tools
677        main_resources = pc(Creator=member, portal_type=['Activity','Tool','PresentationMaterial', 'MultimediaMaterial', 'PILOTMaterial', 'ExerciseMaterial','LessonPlan', 'SchoolProjectMaterial'], getState='public')
678        # Get collections and see which ones are complete
679        collections = pc(Creator=member, portal_type='Collection', getState='public')
680        stories = pc(Creator=member, portal_type='Collection', getGoodStory=True, getState='public')
681        # Get all posts by member
682        posts = pc(Creator=member, portal_type='BlogPost', getState='public')
683
684        # Get people that have this member as contact
685        contacts = self.getRelatedContacts(size_only=True)
686
687        score += len(pieces) # 1 point for each piece
688        score += len(main_resources) * 10 # 10 points for each learning resource, method and tool
689        score += len(stories) * 10 # 10 points for each storie
690        score += len(posts) # 1 point for each post
691        score += contacts # 1 point for each contact
692
693        # Make sure that score is at least 1
694        if score<1:
695            score = 1
696        self.setScore(score)
697
698    def portfolioFilter(self):
699        """ Used for filtering member portfolio """
700        return ('Creator',self.getMemberId())
701
702    ################ Notifications ##############################
703    security.declarePrivate('notifyAddedAsContact')
704    def notifyAddedAsContact(self):
705        ltool = getToolByName(self, 'lemill_tool')
706        lutool = getToolByName(self, 'lemill_usertool')
707        auth_mf=lutool.getMemberFolder()
708        if self.canNotify('contact_added'):
709            language=lutool.getCommunicationLanguage(self)
710            dict={'name':to_unicode(auth_mf.getNicename()),
711                'url':to_unicode(auth_mf.absolute_url())}               
712            msg = self.translate("%(name)s has added you as a contact: %(url)s", domain="lemill", target_language=language) % dict
713            ltool.mailNotification(msg, recipient=self.getEmail(), language=language)   
714
715    def sendInvitationMail(self, message, invited, inviter_name):
716        utool=getToolByName(self,'portal_url')
717        lutool = getToolByName(self, 'lemill_usertool')   
718        language=lutool.getCommunicationLanguage(invited.getId())
719        dict = {'invited':to_unicode(invited.getNicename()),
720            'inviter_name':to_unicode(inviter_name),
721            'message':to_unicode(message)}
722        msg = self.translate(u"""Dear %(invited)s,
723
724%(inviter_name)s is inviting you to join the following groups in LeMill:
725
726%(message)s
727
728Best regards,
729
730LeMill
731
732--
733Do not reply to this message. You can find this person's contact information from LeMill.""", domain="lemill", target_language=language) %  dict
734       
735        try:
736            mhost=self.MailHost
737            mhost.secureSend(msg.encode('utf-8'),
738                mto=invited.getEmail(),
739                mfrom="LeMill <no-reply@lemill.net>",
740                subject="Invitation to group in %s (do not reply)" % (utool.Title()),
741                charset='utf-8')
742        except:
743            print 'Something is wrong with outgoing email. Sent message was:'
744            try:
745                print msg
746            except:
747                print '(Probably UnicodeEncodeError preventing displaying this message)'
748
749       
750registerType(MemberFolder, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.