def reindexIndexes(context):
    """Reindex some indexes.

    Indexes that are added in the catalog.xml file get cleared
    everytime the GenericSetup profile is applied.  So we need to
    reindex them.

    Since we are forced to do that, we might as well make sure that
    these get reindexed in the correct order.
    """
    if isNotECAssignmentBoxProfile(context):
        return

    site = context.getSite()

    pc = getToolByName(site, "portal_catalog")
    indexes = [
        "isAssignmentBoxType",
        "isAssignmentType",
        "getRawAssignment_reference",
        "getRawRelatedItems",
        "review_state",
    ]

    # Don't reindex an index if it isn't actually in the catalog.
    # Should not happen, but cannot do any harm.
    ids = [id for id in indexes if id in pc.indexes()]
    if ids:
        pc.manage_reindexIndex(ids=ids)

    LOG.info("Indexes %s re-indexed." % indexes)
    def sendEmail(self, addresses, subject, text):
        """
        Send an e-mail message to the specified list of addresses.
        """

        if not addresses:
            return

        portal_url  = getToolByName(self, 'portal_url')
        #plone_utils = getToolByName(self, 'plone_utils')

        portal      = portal_url.getPortalObject()
        fromAddress = portal.getProperty('email_from_address', None)

        #mailHost    = plone_utils.getMailHost()
        #charset     = plone_utils.getSiteEncoding()
        mailHost = getToolByName(portal, 'MailHost') #self.MailHost
        charset = portal.getProperty('email_charset', 'UTF-8')


        if fromAddress is None:
            LOG.error('Cannot send email: address or name is %s' % fromAddress)
            return

        try:
            if (type(text) == unicode):
                msg = MIMEText(text.encode(charset), 'plain', charset)
            else:
                msg = MIMEText(text, 'plain', charset)
        except Exception, e:
            LOG.error('Cannot send notification email: %s' % e)
            return
def hideToolsFromNavigation(context):
    """Hide auto-installed tool instances from navigation
    """
    if isNotECAssignmentBoxProfile(context):
        return

    # this tools will be uncataloged
    tool_id = "ecab_utils"

    site = context.getSite()
    portal = getToolByName(site, "portal_url").getPortalObject()

    portalProperties = getToolByName(site, "portal_properties")
    navtreeProperties = getattr(portalProperties, "navtree_properties")

    if navtreeProperties.hasProperty("idsNotToList"):
        # get IDs of all unlisted items
        current = list(navtreeProperties.getProperty("idsNotToList") or [])

        # add our tools to list of unlisted items
        if tool_id not in current:
            current.append(tool_id)
            kwargs = {"idsNotToList": current}
            navtreeProperties.manage_changeProperties(**kwargs)

        # unindex our tools
        try:
            portal[tool_id].unindexObject()
        except:
            LOG.warn("Could not unindex object: %s" % tool_id)
Exemple #4
0
def reindexIndexes(context):
    """Reindex some indexes.

    Indexes that are added in the catalog.xml file get cleared
    everytime the GenericSetup profile is applied.  So we need to
    reindex them.

    Since we are forced to do that, we might as well make sure that
    these get reindexed in the correct order.
    """
    if isNotECAssignmentBoxProfile(context): return

    site = context.getSite()

    pc = getToolByName(site, 'portal_catalog')
    indexes = [
        'isAssignmentBoxType',
        'isAssignmentType',
        'getRawAssignment_reference',
        'getRawRelatedItems',
        'review_state',
    ]

    # Don't reindex an index if it isn't actually in the catalog.
    # Should not happen, but cannot do any harm.
    ids = [id for id in indexes if id in pc.indexes()]
    if ids:
        pc.manage_reindexIndex(ids=ids)

    LOG.info('Indexes %s re-indexed.' % indexes)
Exemple #5
0
def hideToolsFromNavigation(context):
    """Hide auto-installed tool instances from navigation
    """
    if isNotECAssignmentBoxProfile(context): return

    # this tools will be uncataloged
    tool_id = 'ecab_utils'

    site = context.getSite()
    portal = getToolByName(site, 'portal_url').getPortalObject()

    portalProperties = getToolByName(site, 'portal_properties')
    navtreeProperties = getattr(portalProperties, 'navtree_properties')

    if navtreeProperties.hasProperty('idsNotToList'):
        # get IDs of all unlisted items
        current = list(navtreeProperties.getProperty('idsNotToList') or [])

        # add our tools to list of unlisted items
        if tool_id not in current:
            current.append(tool_id)
            kwargs = {'idsNotToList': current}
            navtreeProperties.manage_changeProperties(**kwargs)

        # unindex our tools
        try:
            portal[tool_id].unindexObject()
        except:
            LOG.warn('Could not unindex object: %s' % tool_id)
    def summarize(self):
        """
        Returns an dictionary containing summarized states of all assignments 
        for current user - or all users if manager - in all subfolders.
        
        Only users with roles owner, reviewer or manager will see 
        summarized states of all users.
        
        @return a dictionary containing user-id as key and summarized states
                as value
        """
        result = {}

        # get current uses's id
        currentUser = self.portal_membership.getAuthenticatedMember()
        # check if current user is owner of this folder
        isOwner = currentUser.has_role(['Owner', 'Reviewer', 'Manager'], self)

        catalog = getToolByName(self, 'portal_catalog')

        if isOwner:
            brains = catalog.searchResults(
                path={
                    'query': '/'.join(self.getPhysicalPath()),
                    'depth': 100,
                },
                isAssignmentType=True,
            )
        else:
            brains = catalog.searchResults(
                path={
                    'query': '/'.join(self.getPhysicalPath()),
                    'depth': 100,
                },
                Creator=currentUser.getId(),
                isAssignmentType=True,
            )

        wf_states = self.getWfStates()

        #LOG.debug('wf_states: %s' % wf_states)

        n_states = len(wf_states)

        for brain in brains:
            key = brain.Creator
            reviewState = brain.review_state

            if key and reviewState:
                #LOG.debug('key: %s' % key)
                #LOG.debug('reviewState: %s' % reviewState)

                if not result.has_key(key):
                    result[key] = [0 for i in range(n_states)]

                LOG.debug('result: %s' % result)

                result[key][wf_states.index(brain.review_state)] += 1

        return result
    def sendEmail(self, addresses, subject, text):
        """
        Send an e-mail message to the specified list of addresses.
        """

        if not addresses:
            return

        portal_url = getToolByName(self, 'portal_url')
        #plone_utils = getToolByName(self, 'plone_utils')

        portal = portal_url.getPortalObject()
        fromAddress = portal.getProperty('email_from_address', None)

        #mailHost    = plone_utils.getMailHost()
        #charset     = plone_utils.getSiteEncoding()
        mailHost = getToolByName(portal, 'MailHost')  #self.MailHost
        charset = portal.getProperty('email_charset', 'UTF-8')

        if fromAddress is None:
            LOG.error('Cannot send email: address or name is %s' % fromAddress)
            return

        try:
            if (type(text) == unicode):
                msg = MIMEText(text.encode(charset), 'plain', charset)
            else:
                msg = MIMEText(text, 'plain', charset)
        except Exception, e:
            LOG.error('Cannot send notification email: %s' % e)
            return
 def getWfStates(self):
     """
     @deprecated use getWfStates in ecab_utils directly
     """
     ecab_utils = getToolByName(self, 'ecab_utils', None)
     
     if (ecab_utils != None):
         return ecab_utils.getWfStates(config.ECA_WORKFLOW_ID)
     else:
         LOG.warn("Could not get tool by name: '%s'" % 'ecab_utils')
         return ()
    def getWfStates(self):
        """
        @deprecated use getWfStates in ecab_utils directly
        """
        ecab_utils = getToolByName(self, 'ecab_utils', None)

        if (ecab_utils != None):
            return ecab_utils.getWfStates(config.ECA_WORKFLOW_ID)
        else:
            LOG.warn("Could not get tool by name: '%s'" % 'ecab_utils')
            return ()
    def summarize(self):
        """
        Returns an dictionary containing summarized states of all assignments 
        for current user - or all users if manager - in all subfolders.
        
        Only users with roles owner, reviewer or manager will see 
        summarized states of all users.
        
        @return a dictionary containing user-id as key and summarized states
                as value
        """
        result = {}
        
        # get current uses's id
        currentUser = self.portal_membership.getAuthenticatedMember()
        # check if current user is owner of this folder
        isOwner = currentUser.has_role(['Owner', 'Reviewer', 'Manager'], self)
        
        catalog = getToolByName(self, 'portal_catalog')

        if isOwner:
            brains = catalog.searchResults(path = {'query':'/'.join(self.getPhysicalPath()), 'depth':100, },
                                   isAssignmentType = True,
                                   )
        else:
            brains = catalog.searchResults(path = {'query':'/'.join(self.getPhysicalPath()), 'depth':100, },
                                   Creator = currentUser.getId(), 
                                   isAssignmentType = True,
                                   )

        wf_states = self.getWfStates()
        
        #LOG.debug('wf_states: %s' % wf_states)
        
        n_states = len(wf_states)
    
        for brain in brains:
            key = brain.Creator
            reviewState = brain.review_state
            
            if key and reviewState: 
                #LOG.debug('key: %s' % key)
                #LOG.debug('reviewState: %s' % reviewState)
                
                if not result.has_key(key):
                    result[key] = [0 for i in range(n_states)]
                    
                LOG.debug('result: %s' % result)
                
                result[key][wf_states.index(brain.review_state)] += 1

        return result
Exemple #11
0
def installQIDependencies(context):
    """Install dependencies"""
    if isNotECAssignmentBoxProfile(context): return

    site = context.getSite()

    portal = getToolByName(site, 'portal_url').getPortalObject()
    quickinstaller = portal.portal_quickinstaller
    for dependency in config.DEPENDENCIES:
        if quickinstaller.isProductInstalled(dependency):
            LOG.info('Reinstalling dependency %s:' % dependency)
            quickinstaller.reinstallProducts([dependency])
            transaction.savepoint()
        else:
            LOG.info('Installing dependency %s:' % dependency)
            quickinstaller.installProduct(dependency)
            transaction.savepoint()
def installQIDependencies(context):
    """Install dependencies"""
    if isNotECAssignmentBoxProfile(context):
        return

    site = context.getSite()

    portal = getToolByName(site, "portal_url").getPortalObject()
    quickinstaller = portal.portal_quickinstaller
    for dependency in config.DEPENDENCIES:
        if quickinstaller.isProductInstalled(dependency):
            LOG.info("Reinstalling dependency %s:" % dependency)
            quickinstaller.reinstallProducts([dependency])
            transaction.savepoint()
        else:
            LOG.info("Installing dependency %s:" % dependency)
            quickinstaller.installProduct(dependency)
            transaction.savepoint()
            LOG.error('Cannot send notification email: %s' % e)
            return

        msg['Subject'] = subjHeader
        msg['From'] = fromAddress
        msg['Subject'] = subject

        # This is a hack to suppress deprecation messages about send()
        # in SecureMailHost; the proposed alternative, secureSend(),
        # sucks.
        mailHost._v_send = 1
        
        for address in addresses:
            if address:
                try:
                    LOG.info("Sending email to %r" % address)

                    msg['To'] = address
                    
                    mailHost.send(msg.as_string())
                    
                except ConflictError, ce:
                    LOG.error('Failed sending email: %s' % ce)
                    raise
                except Exception, e:
                    LOG.error('Failed sending email from %s to %s' % 
                              (fromAddress, address))
                    LOG.error("Reason: %s: %r" % (e.__class__.__name__, str(e)))
            # end if
        # end for
class ECABTool(UniqueObject, BaseContent, BrowserDefaultMixin):
    """
    """
    security = ClassSecurityInfo()
    implements(IECABTool)
    meta_type = 'ECABTool'
    plone_tool = True
    _at_rename_after_creation = True

    schema = ECABTool_schema

    def __init__(self, id=None):
        """
        Tool-constructors have no id argument, the id is fixed
        """
        BaseContent.__init__(self, 'ecab_utils')
        self.setTitle('')

    def at_post_edit_script(self):
        """
        Tool should not appear in portal_catalog
        """
        self.unindexObject()

    # -- Methods --------------------------------------------------------------
    #security.declarePrivate('getWfStates')
    def getWfStates(self, wfName=config.ECA_WORKFLOW_ID):
        """
        @return a list containing all state keys in assignment's workflow
        """
        wtool = self.portal_workflow
        return wtool.getWorkflowById(wfName).states.keys()

    #security.declarePublic('getWfStatesDisplayList')
    def getWfStatesDisplayList(self, wfName=config.ECA_WORKFLOW_ID):
        """
        @return a DisplayList containing all state keys and state titles in 
                assignment's workflow
        """
        #LOG.info('xxx: getWfStatesDisplayList')

        dl = DisplayList(())

        wtool = self.portal_workflow
        wf = wtool.getWorkflowById(wfName)
        stateKeys = self.getWfStates(wfName)

        for key in stateKeys:
            dl.add(key, wf.states[key].title)

        #return dl.sortedByValue()
        return dl

    #security.declarePrivate('getWfTransitions')
    def getWfTransitions(self, wfName=config.ECA_WORKFLOW_ID):
        """
        @return all transitions for the given workflow
        """

        result = {}

        wtool = self.portal_workflow
        wf = wtool.getWorkflowById(wfName)

        for tid in wf.transitions.keys():
            tdef = wf.transitions.get(tid, None)
            if tdef is not None and \
               tdef.trigger_type == TRIGGER_USER_ACTION and \
               tdef.actbox_name and \
               not result.has_key(tdef.id):
                result[tdef.id] = {
                    'id': tdef.id,
                    'title': tdef.title,
                    'title_or_id': tdef.title_or_id(),
                    'description': tdef.description,
                    'name': tdef.actbox_name
                }

        return tuple(result.values())

    #security.declarePrivate('getWfTransitionsDisplayList')
    def getWfTransitionsDisplayList(self, wfName=config.ECA_WORKFLOW_ID):
        """
        @return a DisplayList containing all transition keys and titles in 
                assignment's workflow
        """
        dl = DisplayList(())

        #wtool = self.portal_workflow
        #wf = wtool.getWorkflowById(wfName)

        for transition in self.getWfTransitions():
            # FIXME: not sure if this works with the result
            # from getWfTransitions
            dl.add(transition.id, transition.actbox_name)

        return dl.sortedByValue()

    #security.declarePublic('localizeNumber')
    def localizeNumber(self, format, value):
        """
        A simple method for localized formatting of decimal numbers,
        similar to locale.format().
        """

        #LOG.info('format: %s' % format)
        #LOG.info('value: %s' % value)

        if not value: return None

        result = format % value
        fields = result.split(".")
        decimalSeparator = self.translate(msgid='decimal_separator',
                                          domain=config.I18N_DOMAIN,
                                          default='.')
        if len(fields) == 2:
            result = fields[0] + decimalSeparator + fields[1]
        elif len(fields) == 1:
            result = fields[0]
        else:
            raise ValueError, "Too many decimal points in result string"

        return result

    #security.declarePublic('getFullNameById')
    def getFullNameById(self, id):
        """
        Returns the full name of a user by the given ID.  If full name is
        devided into given and last name, we return it in the format
        Doo, John; otherwise we will return 'fullname' as provided by Plone. 
        """
        #LOG.debug('Here we are in ECABTool#getFullNameById')

        mtool = self.portal_membership
        member = mtool.getMemberById(id)
        error = False

        if not member:
            return id

        try:
            sn = member.getProperty('sn', None)
            givenName = member.getProperty('givenName', None)

        except:
            error = True

        #LOG.info('xdebug: sn, givenName: %s, %s' % (type(sn), type(givenName)))
        #LOG.info('xdebug: sn, givenName: %s, %s' % (sn, givenName))

        if error or (not sn) or (not givenName):
            fullname = member.getProperty('fullname', '')

            if fullname == '':
                return id
            else:
                return fullname

            #if fullname.find(' ') == -1:
            #    return fullname
            #
            #sn = fullname[fullname.rfind(' ') + 1:]
            #givenName = fullname[0:fullname.find(' ')]

        else:
            #return sn + ', ' + givenName
            # print 'givenName, sn: %s, %s' % (givenName, sn, )
            return '%s, %s' % (sn, givenName)

    security.declarePublic('getUserPropertyById')

    def getUserPropertyById(self, userId, property, fallback=None):
        """
        @return: Value for 'property' or None
        """

        #LOG.info('xdebug: %s, %s, %s' % (userId, property, fallback, ))

        membership = getToolByName(self, 'portal_membership')
        member = membership.getMemberById(userId)

        try:
            return member.getProperty(property, fallback)
        except:
            return fallback

    #security.declarePublic('testAssignmentBoxType')
    def testAssignmentBoxType(self, item=None):
        """
        Returns True if item has an attribut 'isAssignmentBoxType' or - in case
        item is a catalog brain- index 'isAssignmentBoxType' is True
        """

        #LOG.debug('Here we are in ECABTool#testAssignmentBoxType: %s' % item)

        result = None

        if (item and hasattr(item, 'isAssignmentBoxType')):
            result = item.isAssignmentBoxType

            # dirty hack
            if repr(result) == 'Missing.Value':
                result = False

        else:
            result = False

        #LOG.info('result: %s' % repr(result))

        return result

    #security.declarePublic('isGrader')
    def isGrader(self, item, id=None):
        """
        Returns True if the user given by id has permission to grade the
        assignment given by item; otherwise False.

        If id is None, the check will be done for the current user.

        @param item an assignment
        @param id a user id
        """
        mtool = self.portal_membership

        if not id:
            member = mtool.getAuthenticatedMember()
        else:
            member = mtool.getMemberById(id)

        return member.checkPermission(config.GradeAssignments, item)

    #security.declarePublic('getStatesToShow')
    def getStatesToShow(self, showSuperseded=False, state=None):
        """
        Returns a list of state names which will be used as a filter
        for showing assignments.
        """

        # FIXME: states are static names but they shoul better be taken from
        #        workflow_tool for the given object
        result = (
            'submitted',
            'pending',
            'accepted',
            'rejected',
            'graded',
        )

        if state is not None:
            if type(state) not in [tuple, list]:
                state = (state, )
            result = [s for s in state if s in result]

        if showSuperseded:
            result += ('superseded', )

        return result

    #security.declarePublic('findAssignments')
    def findAssignments(self, context, id):
        """
        """
        ct = getToolByName(self, 'portal_catalog')
        ntp = getToolByName(self, 'portal_properties').navtree_properties
        currentPath = None
        query = {}

        if context == self:
            currentPath = getToolByName(self, 'portal_url').getPortalPath()
            query['path'] = {
                'query': currentPath,
                'depth': ntp.getProperty('sitemapDepth', 2)
            }
        else:
            currentPath = '/'.join(context.getPhysicalPath())
            query['path'] = {'query': currentPath, 'navtree': 1}

        query['portal_type'] = ('ECAssignment', )
        #rawresult = ct(**query)
        rawresult = ct(path=currentPath,
                       portal_type='ECAssignment',
                       Creator=id)
        return rawresult

    #security.declarePublic('calculateMean')
    def calculateMean(self, list):
        """
        """
        try:
            stats = Statistics(map((float), list))
        #except Exception, e:
        #    LOG.warn("calculateMean: %s: %s" % (sys.exc_info()[0], e))
        except:
            return None

        return stats.mean

    #security.declarePublic('calculateMedian')
    def calculateMedian(self, list):
        """
        """
        try:
            stats = Statistics(map((float), list))
        #except Exception, e:
        #    LOG.warn("calculateMedian: %s: %s" % (sys.exc_info()[0], e))
        except:
            return None

        return stats.median

    #security.declarePublic('normalizeURL')
    def normalizeURL(self, url):
        """
        Takes a URL (as returned by absolute_url(), for example) and
        replaces the hostname with the actual, fully-qualified
        hostname.
        """
        url_parts = urlsplit(url)
        hostpart = url_parts[1]
        port = ''

        if hostpart.find(':') != -1:
            (hostname, port) = split(hostpart, ':')
        else:
            hostname = hostpart

        if hostname == 'localhost' or hostname == '127.0.0.1':
            hostname = getfqdn(gethostname())
        else:
            hostname = getfqdn(hostname)

        if port:
            hostpart = join((hostname, port), ':')

        url = urlunsplit((url_parts[0], hostpart, \
                          url_parts[2], url_parts[3], url_parts[4]))
        return url

    #security.declarePublic('urlencode')
    def urlencode(self, *args, **kwargs):
        """
        """
        return urllib.urlencode(*args, **kwargs)

    #security.declarePublic('parseQueryString')
    def parseQueryString(self, *args, **kwargs):
        """
        """
        return cgi.parse_qs(*args, **kwargs)

    #security.declarePrivate('sendEmail')
    def sendEmail(self, addresses, subject, text):
        """
        Send an e-mail message to the specified list of addresses.
        """

        if not addresses:
            return

        portal_url = getToolByName(self, 'portal_url')
        #plone_utils = getToolByName(self, 'plone_utils')

        portal = portal_url.getPortalObject()
        fromAddress = portal.getProperty('email_from_address', None)

        #mailHost    = plone_utils.getMailHost()
        #charset     = plone_utils.getSiteEncoding()
        mailHost = getToolByName(portal, 'MailHost')  #self.MailHost
        charset = portal.getProperty('email_charset', 'UTF-8')

        if fromAddress is None:
            LOG.error('Cannot send email: address or name is %s' % fromAddress)
            return

        try:
            if (type(text) == unicode):
                msg = MIMEText(text.encode(charset), 'plain', charset)
            else:
                msg = MIMEText(text, 'plain', charset)
        except Exception, e:
            LOG.error('Cannot send notification email: %s' % e)
            return

        try:
            if (type(subject) == unicode):
                subjHeader = Header(subject.encode(charset), charset)
            else:
                subjHeader = Header(subject, charset)
        except Exception, e:
            LOG.error('Cannot send notification email: %s' % e)
            return
            LOG.error('Cannot send notification email: %s' % e)
            return

        msg['Subject'] = subjHeader
        msg['From'] = fromAddress
        msg['Subject'] = subject

        # This is a hack to suppress deprecation messages about send()
        # in SecureMailHost; the proposed alternative, secureSend(),
        # sucks.
        mailHost._v_send = 1

        for address in addresses:
            if address:
                try:
                    LOG.info("Sending email to %r" % address)

                    msg['To'] = address

                    mailHost.send(msg.as_string())

                except ConflictError, ce:
                    LOG.error('Failed sending email: %s' % ce)
                    raise
                except Exception, e:
                    LOG.error('Failed sending email from %s to %s' %
                              (fromAddress, address))
                    LOG.error("Reason: %s: %r" %
                              (e.__class__.__name__, str(e)))
            # end if
        # end for