Changeset 1907


Ignore:
Timestamp:
07/30/07 14:21:50 (12 years ago)
Author:
jukka
Message:

Closed #1476, spent 20h. I'm allowing editing and deleting resource discussions like any other forum posts: if the discussion is deleted, new one will be created next time someone tries discussion. The default discussion post bodytext is i18n:translated, but once someone changes it, it won't try to translate it anymore.

Location:
trunk
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/BlogPost.py

    r1833 r1907  
    5151        ), 
    5252    ), 
     53    BooleanField( 
     54        name="is_discussion", 
     55        default=False, 
     56        widget=ComputedWidget( 
     57            visible={'edit':'invisible', 'view':'invisible'} 
     58            ), 
     59        ), 
    5360)) 
    5461schema = schema.copy() 
     
    223230        return lt.split_at_p_or_br(self.getBlog(),min_len=50, max_len=200); 
    224231 
     232    def getDiscussedResource(self): 
     233        """ if this is related to some resource, get the resource """ 
     234        reftool= getToolByName(self, 'reference_catalog') 
     235        obj_uid = self.UID() 
     236        found = [] 
     237        ref_query = { 'sourceUID': obj_uid, 'type': 'is_discussion_about' } 
     238        refresults = reftool(ref_query) 
     239        for q in refresults: 
     240            refobject = reftool.lookupObject(q.UID) 
     241            target = refobject.getTargetObject() 
     242            if target:  
     243                return target 
     244        return None  
     245 
    225246 
    226247registerType(BlogPost, PROJECTNAME) 
  • trunk/ConfigurationMethods.py

    r1818 r1907  
    508508    faq.reindexObject() 
    509509         
     510def setupUnassignedDiscussionsGroup(self, portal): 
     511    # Create empty group to hold discussions for items not assigned to any group. 
     512    if not hasattr(portal, 'community'): 
     513        return 1  
     514    if hasattr(portal.community, 'unassigned_discussions'): 
     515        return 1 
     516    parent=portal.community 
     517    # We force our way through stupid allowed-content-types-limitations 
     518    if 'Large Plone Folder' not in parent.allowed_content_types: 
     519        parent.allowed_content_types=parent.allowed_content_types+('Large Plone Folder',) 
     520    if parent.filter_content_types==True: 
     521        parent.filter_content_types=False 
     522    addObject(parent, 'unassigned_discussions', 'Large Plone Folder', 'Discussions for resources not assigned to groups')  
     523    obj=parent.unassigned_discussions 
     524    syn_tool = getToolByName(portal, 'portal_syndication', None) 
     525    syn_tool.enableSyndication(obj) 
     526    obj.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)  
     527    obj.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1) 
     528 
     529     
    510530         
    511531 
  • trunk/LargeSectionFolder.py

    r1896 r1907  
    826826    meta_type = "Large Community Folder" 
    827827 
    828     allowed_content_types = ('Topic','Redirector','MemberFolder','GroupBlog') 
     828    allowed_content_types = ('Topic','Redirector','MemberFolder','GroupBlog','ATBTreeFolder','Large Plone Folder') 
    829829    default_view = ('lemill_community_view') 
    830     filter_content_types = True 
     830    filter_content_types = False 
    831831    security = ClassSecurityInfo() 
    832832 
  • trunk/Resources.py

    r1903 r1907  
    566566                changedFields = [x for x in set(changedFields + prev_changes) if x[0] != '_'] 
    567567            self.storeInHistory(changedFields) 
     568 
     569    def isID(self, s): 
     570        """ Stupid heuristic to decide s is an id or not. """ 
     571        if len(s) != 32: 
     572            return False 
     573        for i in range(len(s)): 
     574            if s[i] not in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']: 
     575                return False 
     576        return True                 
     577 
     578    def correctReferences(self, oldBodyText, newBodyText): 
     579        """ Delete unused references after restore. """ 
     580        oldIDs = [x for x in oldBodyText if self.isID(x)] 
     581        newIDs = [x for x in newBodyText if self.isID(x)] 
     582        real_newIDs = [x for x in newIDs if x not in oldIDs] 
     583        real_oldIDs = [x for x in oldIDs if x not in newIDs] 
     584        tool = getToolByName(self, 'reference_catalog') 
     585        for x in real_oldIDs: 
     586             tool.deleteReference(self, x, 'uses')     
    568587 
    569588    security.declareProtected(MODIFY_CONTENT, 'restoreAVersion') 
     
    953972    def setGroupsShared(self, value): 
    954973        """ share a material/resource with a group(s) """ 
    955         # adjust security to members of portal 
     974        gtool = getToolByName(self, 'portal_groups') 
     975        reftool= getToolByName(self, 'reference_catalog') 
    956976        create_new = self.REQUEST.get('new_group_name', '') 
     977        blog=None 
    957978        if create_new and value=='__new_group': 
    958979            # create a new group here 
    959980            from Products.CMFPlone.utils import normalizeString 
    960981            new_group_id = normalizeString(create_new, context=self) 
    961             gtool = getToolByName(self, 'portal_groups') 
    962982            try: 
    963983                gtool.addGroup(new_group_id, (), ()) 
     
    969989            blog.setProperties(id=new_group_id, title=create_new, description="") 
    970990            value = new_group_id 
     991            discussion=self.getDiscussion(do_create=False) 
     992            if discussion: 
     993                self.moveDiscussion(discussion, blog)                 
     994 
    971995        if value == '__new_group': 
    972996            return 
    973997        f = self.getField('groups') 
    974998        old_value = f.get(self) 
     999        destination=None 
    9751000        if old_value: 
    9761001            if old_value!='no_group': 
     
    9791004            if value!='no_group': 
    9801005                self.manage_setLocalRoles(value, ('CoAuthor',)) 
     1006                destination = gtool.getGroupareaFolder(value) 
    9811007            else: 
    9821008                # make sure that all CoAuthors are deleted 
     
    9841010                for (key,dvalue) in roles.items(): 
    9851011                    if not 'Owner' in dvalue: self.manage_delLocalRoles((key,)) 
     1012                destination=self.community.unassigned_discussions 
     1013 
    9861014            f.set(self, value) 
     1015            discussion=self.getDiscussion(do_create=False) 
     1016            if discussion and destination: 
     1017                self.moveDiscussion(discussion, destination) 
     1018 
     1019    ######################### 
     1020    ###    Discussions    ### 
     1021    ######################### 
     1022 
     1023    def moveDiscussion(self, discussion, destination): 
     1024        """ moves a discussion from one group to another, called when resource changes groups """ 
     1025        reftool= getToolByName(self, 'reference_catalog') 
     1026        source=discussion.aq_parent 
     1027        reftool.deleteReference(discussion, self,  'is_discussion_about') 
     1028        destination.manage_pasteObjects(source.manage_cutObjects(discussion.id)) 
     1029        discussion=getattr(destination, discussion.id) 
     1030        reftool.addReference(discussion, self, 'is_discussion_about') 
     1031 
     1032 
     1033    def getDiscussion(self, do_create=True): 
     1034        """get discussion object or create one """ 
     1035        # If discussion exists, find it 
     1036        reftool= getToolByName(self, 'reference_catalog') 
     1037        obj_uid = self.UID() 
     1038        found = [] 
     1039        ref_query = { 'targetUID': obj_uid, 'type': 'is_discussion_about' } 
     1040        refresults = reftool(ref_query) 
     1041        for q in refresults: 
     1042            refobject = reftool.lookupObject(q.UID) 
     1043            source = refobject.getSourceObject() 
     1044            if source.meta_type == 'BlogPost': 
     1045                 found.append(source) 
     1046        if found: 
     1047            return found[0] 
     1048        elif not do_create: 
     1049            return None             
     1050        # If no discussion found and we do_create, then we create one 
     1051        gtool = getToolByName(self, 'portal_groups') 
     1052        group=self.getGroupsEditing() 
     1053        if group: 
     1054            group = getattr(self.community, str(group), None) 
     1055        else: 
     1056            group=self.community.unassigned_discussions 
     1057 
     1058        body=self.defaultDiscussionMessage() 
     1059        title="Discussion about %s" % self.Title() 
     1060        post_id = self.generateUniqueId('BlogPost') 
     1061        post_id=group.invokeFactory('BlogPost',post_id) 
     1062        post=getattr(group, post_id, None) 
     1063        post.edit(bodyText=body, is_discussion=True, title=title) 
     1064        post._renameAfterCreation() 
     1065        reftool.addReference(post, self, 'is_discussion_about') 
     1066        return post 
     1067 
     1068    def defaultDiscussionMessage(self, bodytext=None): 
     1069        """ return bodytext to default message or compare it with given bodytext 
     1070         (if they match we can put i18n:tags around it)""" 
     1071        body="""Here you can discuss about <a href="%s/view">%s</a>.""" % (self.absolute_url(), self.Title()) 
     1072        if bodytext: 
     1073            return body==bodytext 
     1074        else: 
     1075            return body       
    9871076 
    9881077 
  • trunk/config.py

    r1862 r1907  
    4040# Must match the folder in Products/ where this product is installed 
    4141PROJECTNAME = "LeMill" 
     42 
     43 
     44# If you want to enable Flickr-search for pieces, you must have a flickr api key. 
     45# You can get one from http://www.flickr.com/services/  
     46FLICKR_API_KEY = "774a1f64011ec6166e85def00ec641f6" 
     47#FLICKR_API_KEY = "" 
    4248 
    4349# 
  • trunk/skins/lemill/ForumRSS.pt

    r1649 r1907  
    1313    define=" 
    1414                 syn context/portal_syndication;  
    15                  objectList python:context.getFullForumRSS();                  
     15                 objectList context/getFullForumRSS; 
    1616                 "> 
    1717 
  • trunk/skins/lemill/blogpost_view.pt

    r1570 r1907  
    1919        <metal:body define-macro="body"> 
    2020                 
    21     <p> 
    22     <metal:fieldMacro use-macro="python:here.widget('bodyText',mode='view')"/> 
     21 
     22    <p tal:condition="not:here/getIs_discussion"> 
     23        <metal:fieldMacro use-macro="python:here.widget('bodyText',mode='view')"/> 
    2324    </p> 
    24  
     25    <tal:resource_discussion tal:condition="here/getIs_discussion"> 
     26        <tal:defs define="obj here/getDiscussedResource;" condition="obj"> 
     27            <p tal:condition="python:obj.defaultDiscussionMessage(here.getBodyText())" i18n:translate="discussion_explanation">Here you can discuss about <a i18n:name="resource_name" tal:attributes="href string:${obj/absolute_url}/view" href="" tal:content="obj/Title">title</a>.</p> 
     28            <p tal:condition="python:not obj.defaultDiscussionMessage(here.getBodyText())"> 
     29                <metal:fieldMacro use-macro="python:here.widget('bodyText',mode='view')"/> 
     30            </p> 
     31        </tal:defs> 
     32    </tal:resource_discussion> 
    2533 
    2634        <metal:discussion use-macro="here/viewThreadsAtBottom/macros/discussionView" /> 
  • trunk/skins/lemill/discussion_reply.cpy

    r1676 r1907  
    66##bind state=state 
    77##bind subpath=traverse_subpath 
    8 ##parameters=body_text 
     8##parameters=body_text, origin 
    99##title=Reply to content 
    1010 
     
    3333 
    3434# return to the discussable object. 
    35 redirect_target = context.plone_utils.getDiscussionThread(tb)[0] 
    36 view = redirect_target.getTypeInfo().getActionById('view') 
    3735anchor = reply.id 
     36 
     37if origin: 
     38    redirect_target = origin 
     39    target = '%s/discussion#%s' % (redirect_target, anchor) 
     40 
     41else: 
     42    redirect_target = context.plone_utils.getDiscussionThread(tb)[0] 
     43    view = redirect_target.getTypeInfo().getActionById('view') 
     44    target = '%s/%s#%s' % (redirect_target.absolute_url(), view, anchor) 
    3845 
    3946transaction_note('Added comment to %s at %s' % (parent.title_or_id(), reply.absolute_url())) 
     
    4249context.plone_utils.addPortalMessage(msg) 
    4350 
    44 target = '%s/%s#%s' % (redirect_target.absolute_url(), view, anchor) 
    4551 
    4652return req.RESPONSE.redirect(target) 
  • trunk/skins/lemill/document_byline.pt

    r1544 r1907  
    1515         timeString python:toLocalizedTime(test(showCreationTime,target.CreationDate(),target.ModificationDate()),long_format=1); 
    1616         wf_state target/review_state|python: wtool.getInfoFor(target, 'review_state', '');"> 
    17         <img src="" alt="" 
    18            title="This document is locked." 
    19            tal:define="locked portal_object/lock_icon.gif; 
    20                         lockable python:hasattr(target, 'wl_isLocked');" 
    21            tal:condition="python:lockable and target.wl_isLocked()" 
    22            tal:replace="structure python:locked.tag(title='Locked')" 
    23            i18n:attributes="title label_document_locked;" 
    24            /> 
    2517 
    2618        <tal:creatornames tal:condition="python:creators and wf_state=='public'"> 
  • trunk/skins/lemill/portlet_material_actions.pt

    r1863 r1907  
    6868        </li> 
    6969        <li><a href="" i18n:translate="label_view_history" tal:attributes="href string:${here_url}/history_view">History</a></li> 
     70        <li><a href="" i18n:translate="label_discussion" tal:attributes="href string:${here_url}/discussion">Discussion</a></li> 
    7071        <!--li tal:condition="python:(context.amIOwner() or here.canIModerate()) and here.amIMaterial() and not no_edit_links"><a href="TODO"><tal:block i18n:translate="label_transfer_authorship">Transfer authorship</tal:block>...</a></li--> 
    7172        <li metal:define-macro="delete_action" tal:condition="python:is_owner or can_moderate"> 
  • trunk/skins/lemill/viewThreadsAtBottom.pt

    r1797 r1907  
    6666                         i18n:attributes="value label_add_reply;" 
    6767                         /> 
     68                  <input type="hidden" value="" name="origin"> 
    6869            </form> 
    6970            <form tal:condition="python:isAnon and not userHasReplyPermission and isDiscussionAllowed" 
Note: See TracChangeset for help on using the changeset viewer.