class Federations(SimpleItem):
    def __init__(self):
        self.federations = PersistentMapping()

    def getUserId(self, nameIdentifier):
        return self.federations.get(nameIdentifier, {}).get('user_id')

    def getIdentityDump(self, nameIdentifier):
        return self.federations.get(nameIdentifier, {}).get('identity_dump')

    def setFederation(self, nameIdentifier, userId, identityDump):
        self.federations[nameIdentifier] = {'user_id': userId, 'identity_dump': identityDump}

    def removeFederation(self, nameIdentifier):
        if self.federations.has_key(nameIdentifier):
            del self.federations[nameIdentifier]
Exemplo n.º 2
0
class Resource(Persistent):
    security = ClassSecurityInfo()

    def __init__(self, id, **kwargs):
        self._data = PersistentMapping()
        self._data['id'] = id
        self._data['expression'] = kwargs.get('expression', '')
        self._data['enabled'] = kwargs.get('enabled', True)
        self._data['cookable'] = kwargs.get('cookable', True)
        self._data['cacheable'] = kwargs.get('cacheable', True)

    def copy(self):
        result = self.__class__(self.getId())
        for key, value in self._data.items():
            if key != 'id':
                result._data[key] = value
        return result

    security.declarePublic('getId')
    def getId(self):
        return self._data['id']

    def _setId(self, id):
        self._data['id'] = id

    security.declarePublic('getExpression')
    def getExpression(self):
        return self._data['expression']

    security.declareProtected(permissions.ManagePortal, 'setExpression')
    def setExpression(self, expression):
        self._data['expression'] = expression

    security.declarePublic('getEnabled')
    def getEnabled(self):
        return bool(self._data['enabled'])

    security.declareProtected(permissions.ManagePortal, 'setEnabled')
    def setEnabled(self, enabled):
        self._data['enabled'] = enabled

    security.declarePublic('getCookable')
    def getCookable(self):
        return self._data['cookable']

    security.declareProtected(permissions.ManagePortal, 'setCookable')
    def setCookable(self, cookable):
        self._data['cookable'] = cookable

    security.declarePublic('getCacheable')
    def getCacheable(self):
        # as this is a new property, old instance might not have that value, so
        # return True as default
        return self._data.get('cacheable', True)

    security.declareProtected(permissions.ManagePortal, 'setCacheable')
    def setCacheable(self, cacheable):
        self._data['cacheable'] = cacheable
Exemplo n.º 3
0
class ContentTypeRegistry(SimpleItem):
    """
        Registry for rules which map PUT args to a CMF Type Object.
    """

    implements(IContentTypeRegistry)
    __implements__ = z2IContentTypeRegistry

    meta_type = 'Content Type Registry'
    id = 'content_type_registry'

    manage_options = ({
        'label': 'Predicates',
        'action': 'manage_predicates'
    }, {
        'label': 'Test',
        'action': 'manage_testRegistry'
    }) + SimpleItem.manage_options

    security = ClassSecurityInfo()

    def __init__(self):
        self.predicate_ids = ()
        self.predicates = PersistentMapping()

    #
    #   ZMI
    #
    security.declarePublic('listPredicateTypes')

    def listPredicateTypes(self):
        """
        """
        return map(lambda x: x[0], _predicate_types)

    security.declareProtected(ManagePortal, 'manage_predicates')
    manage_predicates = DTMLFile('registryPredList', _dtmldir)

    security.declareProtected(ManagePortal, 'doAddPredicate')

    def doAddPredicate(self, predicate_id, predicate_type, REQUEST):
        """
        """
        self.addPredicate(predicate_id, predicate_type)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+added.')

    security.declareProtected(ManagePortal, 'doUpdatePredicate')

    def doUpdatePredicate(self, predicate_id, predicate, typeObjectName,
                          REQUEST):
        """
        """
        self.updatePredicate(predicate_id, predicate, typeObjectName)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+updated.')

    security.declareProtected(ManagePortal, 'doMovePredicateUp')

    def doMovePredicateUp(self, predicate_id, REQUEST):
        """
        """
        predicate_ids = list(self.predicate_ids)
        ndx = predicate_ids.index(predicate_id)
        if ndx == 0:
            msg = "Predicate+already+first."
        else:
            self.reorderPredicate(predicate_id, ndx - 1)
            msg = "Predicate+moved."
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'doMovePredicateDown')

    def doMovePredicateDown(self, predicate_id, REQUEST):
        """
        """
        predicate_ids = list(self.predicate_ids)
        ndx = predicate_ids.index(predicate_id)
        if ndx == len(predicate_ids) - 1:
            msg = "Predicate+already+last."
        else:
            self.reorderPredicate(predicate_id, ndx + 1)
            msg = "Predicate+moved."
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'doRemovePredicate')

    def doRemovePredicate(self, predicate_id, REQUEST):
        """
        """
        self.removePredicate(predicate_id)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+removed.')

    security.declareProtected(ManagePortal, 'manage_testRegistry')
    manage_testRegistry = DTMLFile('registryTest', _dtmldir)

    security.declareProtected(ManagePortal, 'doTestRegistry')

    def doTestRegistry(self, name, content_type, body, REQUEST):
        """
        """
        typeName = self.findTypeName(name, content_type, body)
        if typeName is None:
            typeName = '<unknown>'
        else:
            types_tool = getToolByName(self, 'portal_types')
            typeName = types_tool.getTypeInfo(typeName).Title()
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_testRegistry' +
                                     '?testResults=Type:+%s' %
                                     urllib.quote(typeName))

    #
    #   Predicate manipulation
    #
    security.declarePublic('getPredicate')

    def getPredicate(self, predicate_id):
        """
            Find the predicate whose id is 'id';  return the predicate
            object, if found, or else None.
        """
        return self.predicates.get(predicate_id, (None, None))[0]

    security.declarePublic('listPredicates')

    def listPredicates(self):
        """List '(id, (predicate, typeObjectName))' tuples for all predicates.
        """
        return tuple([(id, self.predicates[id]) for id in self.predicate_ids])

    security.declarePublic('getTypeObjectName')

    def getTypeObjectName(self, predicate_id):
        """
            Find the predicate whose id is 'id';  return the name of
            the type object, if found, or else None.
        """
        return self.predicates.get(predicate_id, (None, None))[1]

    security.declareProtected(ManagePortal, 'addPredicate')

    def addPredicate(self, predicate_id, predicate_type):
        """
            Add a predicate to this element of type 'typ' to the registry.
        """
        if predicate_id in self.predicate_ids:
            raise ValueError, "Existing predicate: %s" % predicate_id

        klass = None
        for key, value in _predicate_types:
            if key == predicate_type:
                klass = value

        if klass is None:
            raise ValueError, "Unknown predicate type: %s" % predicate_type

        self.predicates[predicate_id] = (klass(predicate_id), None)
        self.predicate_ids = self.predicate_ids + (predicate_id, )

    security.declareProtected(ManagePortal, 'updatePredicate')

    def updatePredicate(self, predicate_id, predicate, typeObjectName):
        """
            Update a predicate in this element.
        """
        if not predicate_id in self.predicate_ids:
            raise ValueError, "Unknown predicate: %s" % predicate_id

        predObj = self.predicates[predicate_id][0]
        mapply(predObj.edit, (), predicate.__dict__)
        self.assignTypeName(predicate_id, typeObjectName)

    security.declareProtected(ManagePortal, 'removePredicate')

    def removePredicate(self, predicate_id):
        """
            Remove a predicate from the registry.
        """
        del self.predicates[predicate_id]
        idlist = list(self.predicate_ids)
        ndx = idlist.index(predicate_id)
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        self.predicate_ids = tuple(idlist)

    security.declareProtected(ManagePortal, 'reorderPredicate')

    def reorderPredicate(self, predicate_id, newIndex):
        """
            Move a given predicate to a new location in the list.
        """
        idlist = list(self.predicate_ids)
        ndx = idlist.index(predicate_id)
        pred = idlist[ndx]
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        idlist.insert(newIndex, pred)
        self.predicate_ids = tuple(idlist)

    security.declareProtected(ManagePortal, 'assignTypeName')

    def assignTypeName(self, predicate_id, typeObjectName):
        """
            Bind the given predicate to a particular type object.
        """
        pred, oldTypeObjName = self.predicates[predicate_id]
        self.predicates[predicate_id] = (pred, typeObjectName)

    #
    #   ContentTypeRegistry interface
    #
    def findTypeName(self, name, typ, body):
        """
            Perform a lookup over a collection of rules, returning the
            the name of the Type object corresponding to name/typ/body.
            Return None if no match found.
        """
        for predicate_id in self.predicate_ids:
            pred, typeObjectName = self.predicates[predicate_id]
            if pred(name, typ, body):
                return typeObjectName

        return None
Exemplo n.º 4
0
class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
    """
    Stores messages and their translations...
    """

    meta_type = 'MessageCatalog'

    security = ClassSecurityInfo()


    def __init__(self, id, title, sourcelang, languages):
        self.id = id

        self.title = title

        # Language Manager data
        self._languages = tuple(languages)
        self._default_language = sourcelang

        # Here the message translations are stored
        self._messages = PersistentMapping()

        # Data for the PO files headers
        self._po_headers = PersistentMapping()
        for lang in self._languages:
            self._po_headers[lang] = empty_po_header


    #######################################################################
    # Public API
    #######################################################################
    security.declarePublic('message_encode')
    def message_encode(self, message):
        """
        Encodes a message to an ASCII string.
        To be used in the user interface, to avoid problems with the
        encodings, HTML entities, etc..
        """
        if type(message) is UnicodeType:
            msg = 'u' + message.encode('utf8')
        else:
            msg = 'n' + message

        return base64.encodestring(msg)


    security.declarePublic('message_decode')
    def message_decode(self, message):
        """
        Decodes a message from an ASCII string.
        To be used in the user interface, to avoid problems with the
        encodings, HTML entities, etc..
        """
        message = base64.decodestring(message)
        type = message[0]
        message = message[1:]
        if type == 'u':
            return unicode(message, 'utf8')
        return message


    security.declarePublic('message_exists')
    def message_exists(self, message):
        """ """
        return self._messages.has_key(message)


    security.declareProtected('Manage messages', 'message_edit')
    def message_edit(self, message, language, translation, note):
        """ """
        self._messages[message][language] = translation
        self._messages[message]['note'] = note


    security.declareProtected('Manage messages', 'message_del')
    def message_del(self, message):
        """ """
        del self._messages[message]


    security.declarePublic('gettext')
    def gettext(self, message, lang=None, add=1, default=_marker):
        """Returns the message translation from the database if available.

        If add=1, add any unknown message to the database.
        If a default is provided, use it instead of the message id
        as a translation for unknown messages.
        """

        if type(message) not in (StringType, UnicodeType):
            raise TypeError, 'only strings can be translated.'

        message = message.strip()

        if default is _marker:
            default = message

        # Add it if it's not in the dictionary
        if add and not self._messages.has_key(message) and message:
            self._messages[message] = PersistentMapping()

        # Get the string
        if self._messages.has_key(message):
            m = self._messages[message]

            if lang is None:
                # Builds the list of available languages
                # should the empty translations be filtered?
                available_languages = list(self._languages)

                # Imagine that the default language is 'en'. There is no
                # translation from 'en' to 'en' in the message catalog
                # The user has the preferences 'en' and 'nl' in that order
                # The next two lines make certain 'en' is shown, not 'nl'
                if not self._default_language in available_languages:
                    available_languages.append(self._default_language)

                # Get the language!
                lang = lang_negotiator(available_languages)

                # Is it None? use the default
                if lang is None:
                    lang = self._default_language

            if lang is not None:
                return m.get(lang) or default

        return default


    __call__ = gettext


    def translate(self, domain, msgid, *args, **kw):
        """
        This method is required to get the i18n namespace from ZPT working.
        """
        return self.gettext(msgid)


    #######################################################################
    # Management screens
    #######################################################################
    def manage_options(self):
        """ """
        options = (
            {'label': N_('Messages'), 'action': 'manage_messages',
             'help': ('Localizer', 'MC_messages.stx')},
            {'label': N_('Properties'), 'action': 'manage_propertiesForm'},
            {'label': N_('Import/Export'), 'action': 'manage_importExport',
             'help': ('Localizer', 'MC_importExport.stx')},
            {'label': N_('TMX'), 'action': 'manage_tmx'}) \
            + LanguageManager.manage_options \
            + SimpleItem.manage_options

        r = []
        for option in options:
            option = option.copy()
            option['label'] = _(option['label'])
            r.append(option)

        return r


    #######################################################################
    # Management screens -- Messages
    #######################################################################
    security.declareProtected('Manage messages', 'manage_messages')
    manage_messages = LocalDTMLFile('ui/MC_messages', globals())


    security.declareProtected('Manage messages', 'get_translations')
    def get_translations(self, message):
        """ """
        return self._messages[message]


    security.declarePublic('get_url')
    def get_url(self, url, batch_start, batch_size, regex, lang, empty, **kw):
        """ """
        params = []
        for key, value in kw.items():
            if value is not None:
                params.append('%s=%s' % (key, quote(value)))

        params.extend(['batch_start:int=%d' % batch_start,
                       'batch_size:int=%d' % batch_size,
                       'regex=%s' % quote(regex),
                       'empty=%s' % (empty and 'on' or '')])

        if lang:
            params.append('lang=%s' % lang)

        return url + '?' + '&amp;'.join(params)

    def to_unicode(self, x):
        """
        In Zope the ISO-8859-1 encoding has an special status, normal strings
        are considered to be in this encoding by default.
        """
        if type(x) is StringType:
            x = unicode(x, 'iso-8859-1')
        return x


    def filter_sort(self, x, y):
        x = self.to_unicode(x)
        y = self.to_unicode(y)
        return cmp(x, y)


    security.declarePublic('filter')
    def filter(self, message, lang, empty, regex, batch_start, batch_size=15):
        """
        For the management interface, allows to filter the messages to show.
        """
        # Filter the messages
        regex = regex.strip()

        try:
            regex = re.compile(regex)
        except:
            regex = re.compile('')

        messages = []
        for m, t in self._messages.items():
            if regex.search(m) and (not empty or not t.get(lang, '').strip()):
                messages.append(m)
        messages.sort(self.filter_sort)

        # How many messages
        n = len(messages)

        # Calculate the start
        while batch_start >= n:
            batch_start = batch_start - batch_size

        if batch_start < 0:
            batch_start = 0

        # Select the batch to show
        batch_end = batch_start + batch_size
        messages = messages[batch_start:batch_end]

        # Get the message
        message_encoded = None
        if message is None:
            if messages:
                message = messages[0]
                message_encoded = self.message_encode(message)
        else:
            message_encoded = message
            message = self.message_decode(message)

        # Calculate the current message
        aux = []
        for x in messages:
            current = type(x) is type(message) \
                      and self.to_unicode(x) == self.to_unicode(message)
            aux.append({'message': x, 'current': current})

        return {'messages': aux,
                'n_messages': n,
                'batch_start': batch_start,
                'message': message,
                'message_encoded': message_encoded}


    security.declareProtected('Manage messages', 'manage_editMessage')
    def manage_editMessage(self, message, language, translation, note,
                           REQUEST, RESPONSE):
        """Modifies a message."""
        message_encoded = message
        message = self.message_decode(message_encoded)
        self.message_edit(message, language, translation, note)

        url = self.get_url(REQUEST.URL1 + '/manage_messages',
                           REQUEST['batch_start'], REQUEST['batch_size'],
                           REQUEST['regex'], REQUEST.get('lang', ''),
                           REQUEST.get('empty', 0),
                           msg=message_encoded,
                           manage_tabs_message=_('Saved changes.'))
        RESPONSE.redirect(url)


    security.declareProtected('Manage messages', 'manage_delMessage')
    def manage_delMessage(self, message, REQUEST, RESPONSE):
        """ """
        message = self.message_decode(message)
        self.message_del(message)

        url = self.get_url(REQUEST.URL1 + '/manage_messages',
                           REQUEST['batch_start'], REQUEST['batch_size'],
                           REQUEST['regex'], REQUEST.get('lang', ''),
                           REQUEST.get('empty', 0),
                           manage_tabs_message=_('Saved changes.'))
        RESPONSE.redirect(url)



    #######################################################################
    # Management screens -- Properties
    # Management screens -- Import/Export
    # FTP access
    #######################################################################
    security.declareProtected('View management screens',
                              'manage_propertiesForm')
    manage_propertiesForm = LocalDTMLFile('ui/MC_properties', globals())


    security.declareProtected('View management screens', 'manage_properties')
    def manage_properties(self, title, REQUEST=None, RESPONSE=None):
        """Change the Message Catalog properties."""
        self.title = title

        if RESPONSE is not None:
            RESPONSE.redirect('manage_propertiesForm')


    # Properties management screen
    security.declareProtected('View management screens', 'get_po_header')
    def get_po_header(self, lang):
        """ """
        # For backwards compatibility
        if not hasattr(aq_base(self), '_po_headers'):
            self._po_headers = PersistentMapping()

        return self._po_headers.get(lang, empty_po_header)


    security.declareProtected('View management screens', 'update_po_header')
    def update_po_header(self, lang,
                         last_translator_name=None,
                         last_translator_email=None,
                         language_team=None,
                         charset=None,
                         REQUEST=None, RESPONSE=None):
        """ """
        header = self.get_po_header(lang)

        if last_translator_name is None:
            last_translator_name = header['last_translator_name']

        if last_translator_email is None:
            last_translator_email = header['last_translator_email']

        if language_team is None:
            language_team = header['language_team']

        if charset is None:
            charset = header['charset']

        header = {'last_translator_name': last_translator_name,
                  'last_translator_email': last_translator_email,
                  'language_team': language_team,
                  'charset': charset}

        self._po_headers[lang] = header

        if RESPONSE is not None:
            RESPONSE.redirect('manage_propertiesForm')



    security.declareProtected('View management screens', 'manage_importExport')
    manage_importExport = LocalDTMLFile('ui/MC_importExport', globals())


    security.declarePublic('get_charsets')
    def get_charsets(self):
        """ """
        return charsets[:]


    security.declarePublic('manage_export')
    def manage_export(self, x, REQUEST=None, RESPONSE=None):
        """
        Exports the content of the message catalog either to a template
        file (locale.pot) or to an language specific PO file (<x>.po).
        """
        # Get the PO header info
        header = self.get_po_header(x)
        last_translator_name = header['last_translator_name']
        last_translator_email = header['last_translator_email']
        language_team = header['language_team']
        charset = header['charset']

        # PO file header, empty message.
        po_revision_date = time.strftime('%Y-%m-%d %H:%m+%Z',
                                         time.gmtime(time.time()))
        pot_creation_date = po_revision_date
        last_translator = '%s <%s>' % (last_translator_name,
                                       last_translator_email)

        if x == 'locale.pot':
            language_team = 'LANGUAGE <*****@*****.**>'
        else:
            language_team = '%s <%s>' % (x, language_team)

        r = ['msgid ""',
             'msgstr "Project-Id-Version: %s\\n"' % self.title,
             '"POT-Creation-Date: %s\\n"' % pot_creation_date,
             '"PO-Revision-Date: %s\\n"' % po_revision_date,
             '"Last-Translator: %s\\n"' % last_translator,
             '"Language-Team: %s\\n"' % language_team,
             '"MIME-Version: 1.0\\n"',
             '"Content-Type: text/plain; charset=%s\\n"' % charset,
             '"Content-Transfer-Encoding: 8bit\\n"',
             '', '']


        # Get the messages, and perhaps its translations.
        d = {}
        if x == 'locale.pot':
            filename = x
            for k in self._messages.keys():
                d[k] = ""
        else:
            filename = '%s.po' % x
            for k, v in self._messages.items():
                try:
                    d[k] = v[x]
                except KeyError:
                    d[k] = ""

        # Generate the file
        def backslashescape(x):
            quote_esc = re.compile(r'"')
            x = quote_esc.sub('\\"', x)

            trans = [('\n', '\\n'), ('\r', '\\r'), ('\t', '\\t')]
            for a, b in trans:
                x = x.replace(a, b)

            return x

        # Generate sorted msgids to simplify diffs
        dkeys = d.keys()
        dkeys.sort()
        for k in dkeys:
            r.append('msgid "%s"' % backslashescape(k))
            v = d[k]
            r.append('msgstr "%s"' % backslashescape(v))
            r.append('')

        if RESPONSE is not None:
            RESPONSE.setHeader('Content-type','application/data')
            RESPONSE.setHeader('Content-Disposition',
                               'inline;filename=%s' % filename)

        r2 = []
        for x in r:
            if type(x) is UnicodeType:
                r2.append(x.encode(charset))
            else:
                r2.append(x)

        return '\n'.join(r2)


    security.declareProtected('Manage messages', 'po_import')
    def po_import(self, lang, data):
        """ """
        messages = self._messages

        resource = memory.File(data)
        po = PO.PO(resource)

        # Load the data
        for msgid in po.get_msgids():
            if msgid:
                msgstr = po.get_msgstr(msgid) or ''
                if not messages.has_key(msgid):
                    messages[msgid] = PersistentMapping()
                messages[msgid][lang] = msgstr

        # Set the encoding (the full header should be loaded XXX)
        self.update_po_header(lang, charset=po.get_encoding())


    security.declareProtected('Manage messages', 'manage_import')
    def manage_import(self, lang, file, REQUEST=None, RESPONSE=None):
        """ """
        # XXX For backwards compatibility only, use "po_import" instead.
        if isinstance(file, str):
            content = file
        else:
            content = file.read()

        self.po_import(lang, content)

        if RESPONSE is not None:
            RESPONSE.redirect('manage_messages')


    def objectItems(self, spec=None):
        """ """
        for lang in self._languages:
            if not hasattr(aq_base(self), lang):
                self._setObject(lang, POFile(lang))

        r = MessageCatalog.inheritedAttribute('objectItems')(self, spec)
        return r


    #######################################################################
    # TMX support
    security.declareProtected('View management screens', 'manage_tmx')
    manage_tmx = LocalDTMLFile('ui/MC_tmx', globals())


    security.declareProtected('Manage messages', 'tmx_export')
    def tmx_export(self, REQUEST, RESPONSE=None):
        """
        Exports the content of the message catalog to a TMX file
        """
        orglang = self._default_language
#       orglang = orglang.lower()

        # Get the header info
        header = self.get_po_header(orglang)
        charset = header['charset']

        r = []

        # Generate the TMX file header
        r.append('<?xml version="1.0" encoding="utf-8"?>')
        r.append('<!DOCTYPE tmx SYSTEM "http://www.lisa.org/tmx/tmx14.dtd">')
        r.append('<tmx version="1.4">')
        r.append('<header')
        r.append('creationtool="Localizer"')
        r.append('creationtoolversion="1.x"')
        r.append('datatype="plaintext"')
        r.append('segtype="paragraph"')
        r.append('adminlang="%s"' % orglang)
        r.append('srclang="%s"' % orglang)
        r.append('o-encoding="%s"' % charset.lower())

        r.append('>')
        r.append('</header>')
        r.append('')

        # Get the messages, and perhaps its translations.
        d = {}
        filename = '%s.tmx' % self.id
        for msgkey, transunit in self._messages.items():
            try:
                d[msgkey] = transunit[orglang]
            except KeyError:
                d[msgkey] = ""

        # Generate sorted msgids to simplify diffs
        dkeys = d.keys()
        dkeys.sort()
        r.append('<body>')
        for msgkey in dkeys:
            r.append('<tu>')
            transunit = self._messages.get(msgkey)
            if transunit.has_key('note') and transunit['note']:
                r.append('<note>%s</note>' % escape(transunit['note']))
            r.append('<tuv xml:lang="%s">' % orglang)
            # The key is the message
            r.append('<seg>%s</seg></tuv>' % escape(msgkey))

            for tlang in self._languages:
                if tlang != orglang:
                    v = transunit.get(tlang,'')
                    v = escape(v)
                    r.append('<tuv xml:lang="%s">' % tlang)
                    r.append('<seg>%s</seg></tuv>' % v)

            r.append('</tu>')
            r.append('')

        r.append('</body>')
        r.append('</tmx>')

        if RESPONSE is not None:
            RESPONSE.setHeader('Content-type','application/data')
            RESPONSE.setHeader('Content-Disposition',
                               'attachment; filename="%s"' % filename)

        r2 = []
        for x in r:
            if type(x) is UnicodeType:
                r2.append(x.encode('utf-8'))
            else:
                r2.append(x)

        return '\r\n'.join(r2)

    def _normalize_lang(self,langcode):
        """ Get the core language (The part before the '-') and return it
            in lowercase. If there is a local part, return it in uppercase.
        """
        dash = langcode.find('-')
        if dash == -1:
            la = langcode.lower()
            return (la,la)
        else:
            la = langcode[:dash].lower()
            lo = langcode[dash+1:].upper()
            return (la+'-'+lo,la)

    def _tmx_header(self, attrs):
        """ Works on a header (<header>)
        """
        if attrs.has_key('srclang'):
            self._v_srclang = attrs['srclang']

    def _tmx_tu(self, unit):
        """ Works on a translation unit (<tu>)
        """
        src_lang = self._default_language
        # We look up the message for the language we have chosen to be our
        # working language
        if unit.has_key(self._default_language):
            src_lang = self._default_language
        else:
            # This MUST exist. Otherwise the TMX file is bad
            src_lang = self._v_srclang
        key = unit[src_lang]
        if key == u'':
            return # Don't add empty messages
        keysum = md5text(key) # For future indexing on md5 sums

        messages = self._messages
        languages = list(self._languages)
        if not messages.has_key(key):
            if self._v_howmuch == 'clear' or self._v_howmuch == 'all':
                messages[key] = PersistentMapping()
            else:
                return # Don't add unknown messages

        self._v_num_translations = self._v_num_translations + 1

        for lang in unit.keys():
            # Since the messagecatalog's default language overrides our
            # source language anyway, we handle "*all*" correctly already.
            # In the test below "*all*" should not be allowed.
            # Languages that start with '_' are other properties
            if lang == '_note':
                messages[key]['note'] = unit[lang]
                self._v_num_notes = self._v_num_notes + 1
                continue
            if lang[0] == '_':  # Unknown special property
                continue
            if lang == '*all*' or lang == '*none*':
                lang = self._v_srclang
            (target_lang, core_lang) = self._normalize_lang(lang)
            # If the core language is not seen before then add it
            if core_lang != src_lang and core_lang not in languages:
                languages.append(core_lang)
            # If the language+locality is not seen before then add it
            if target_lang != src_lang and target_lang not in languages:
                languages.append(target_lang)
            # Add message for language+locality
            if target_lang != src_lang:
                messages[key][target_lang] = unit[target_lang]
            # Add message for core language
            if not (unit.has_key(core_lang) or core_lang == src_lang):
                messages[key][core_lang] = unit[target_lang]

        self._languages = tuple(languages)
        self._messages = messages

    security.declareProtected('Manage messages', 'tmx_import')
    def tmx_import(self, howmuch, file, REQUEST=None, RESPONSE=None):
        """ Imports a TMX level 1 file.
            We use the SAX parser. It has the benefit that it internally
            converts everything to python unicode strings.
        """
        if howmuch == 'clear':
            # Clear the message catalogue prior to import
            self._messages = {}
            self._languages = ()

        self._v_howmuch = howmuch
        self._v_srclang = self._default_language
        self._v_num_translations = 0
        self._v_num_notes = 0
        # Create a parser
        parser = make_parser()
        chandler = HandleTMXParsing(self._tmx_tu, self._tmx_header)
        # Tell the parser to use our handler
        parser.setContentHandler(chandler)
        # Don't load the DTD from the Internet
        parser.setFeature(handler.feature_external_ges, 0)
        inputsrc = InputSource()

        if type(file) is StringType:
            inputsrc.setByteStream(StringIO(file))
        else:
            content = file.read()
            inputsrc.setByteStream(StringIO(content))
        parser.parse(inputsrc)

        num_translations = self._v_num_translations
        num_notes = self._v_num_notes
        del self._v_srclang
        del self._v_howmuch
        del self._v_num_translations
        del self._v_num_notes

        if REQUEST is not None:
            return MessageDialog(
                title = _('Messages imported'),
                message = _('Imported %d messages and %d notes')
                          % (num_translations, num_notes),
                action = 'manage_messages')


    #######################################################################
    # Backwards compatibility (XXX)
    #######################################################################

    hasmsg = message_exists
    hasLS = message_exists  # CMFLocalizer uses it

    security.declareProtected('Manage messages', 'xliff_export')
    def xliff_export(self, x, export_all=1, REQUEST=None, RESPONSE=None):
        """ Exports the content of the message catalog to an XLIFF file
        """
        orglang = self._default_language
        from DateTime import DateTime
        r = []
        # alias for append function. For optimization purposes
        r_append = r.append
        # Generate the XLIFF file header
        RESPONSE.setHeader('Content-Type', 'text/xml; charset=UTF-8')
        RESPONSE.setHeader('Content-Disposition',
                           'attachment; filename="%s_%s_%s.xlf"' % (self.id,
                                                                    orglang,
                                                                    x))

        r_append('<?xml version="1.0" encoding="UTF-8"?>')
        # Version 1.1 of the DTD is not yet available - use version 1.0
        r_append('<!DOCTYPE xliff SYSTEM "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd">')
        # Force a UTF-8 char in the start
        r_append(u'<!-- XLIFF Format Copyright \xa9 OASIS Open 2001-2003 -->')
        r_append('<xliff version="1.0">')
        r_append('<file')
        r_append('original="/%s"' % self.absolute_url(1))
        r_append('product-name="Localizer"')
        r_append('product-version="1.1.x"')
        r_append('datatype="plaintext"')
        r_append('source-language="%s"' % orglang)
        r_append('target-language="%s"' % x)
        r_append('date="%s"' % DateTime().HTML4())
        r_append('>')
        r_append('<header>')
#       r_append('<phase-group>')
#       r_append('<phase ')
#       r_append('phase-name="%s"' % REQUEST.get('phase_name', ''))
#       r_append('process-name="Export"')
#       r_append('tool="Localizer"')
#       r_append('date="%s"' % DateTime().HTML4())
#       r_append('company-name="%s"' % REQUEST.get('company_name', ''))
#       r_append('job-id="%s"' % REQUEST.get('job_id', ''))
#       r_append('contact-name="%s"' % REQUEST.get('contact_name', ''))
#       r_append('contact-email="%s"' % REQUEST.get('contact_email', ''))
#       r_append('/>')
#       r_append('</phase-group>')
        r_append('</header>')
        r_append('<body>')

        # Get the messages, and perhaps its translations.
        d = {}
        for msgkey, transunit in self._messages.items():
            try:
                # if export_all=1 export all messages otherwise export
                # only untranslated messages
                if int(export_all) == 1 \
                       or (int(export_all) == 0 and transunit[x] == ''):
                    d[msgkey] = transunit[x]
            except KeyError:
                d[msgkey] = ""
            if d[msgkey] == "":
                d[msgkey] = msgkey
        # Generate sorted msgids to simplify diffs
        dkeys = d.keys()
        dkeys.sort()
        for msgkey in dkeys:
            transunit = self._messages[msgkey]
            r_append('<trans-unit id="%s">' % md5text(msgkey))
            r_append(' <source>%s</source>' % escape(msgkey))
            r_append(' <target>%s</target>' % escape(d[msgkey]))
            if transunit.has_key('note') and transunit['note']:
                r_append(' <note>%s</note>' % escape(transunit['note']))
            r_append('</trans-unit>')

        r_append('</body>')
        r_append('</file>')
        r_append('</xliff>')

        r2 = []
        for x in r:
            if type(x) is UnicodeType:
                r2.append(x.encode('utf-8'))
            else:
                r2.append(x)

        return '\r\n'.join(r2)

    security.declareProtected('Manage messages', 'xliff_import')
    def xliff_import(self, file, REQUEST=None):
        """ XLIFF is the XML Localization Interchange File Format
            designed by a group of software providers.
            It is specified by www.oasis-open.org
        """

        messages = self._messages

        # Build a table of messages hashed on the md5 sum of the message
        # This is because sometimes the xliff file has the sources translated,
        # not the targets
        md5hash = {}
        for mes in messages.keys():
            hash = md5text(mes)
            md5hash[hash] = mes

        parser = HandleXliffParsing()

        # parse the xliff information
        chandler = parser.parseXLIFFFile(file)
        if chandler is None:
            return MessageDialog(title = 'Parse error',
             message = 'Unable to parse XLIFF file' ,
             action = 'manage_main',)

        header_info = chandler.getFileTag()
        #get the target language
        lang = [x for x in header_info if x[0]=='target-language'][0][1]
        (targetlang, core_lang) = self._normalize_lang(lang)

        # return a dictionary {id: (source, target)}
        body_info = chandler.getBody()

        num_notes = 0
        num_translations = 0
        # load the data
        for msgkey, transunit in body_info.items():
            # If message is not in catalog, then it is new in xliff file
            # -- not legal
            if md5hash.has_key(msgkey):
                # Normal add
                srcmsg = md5hash[msgkey]
                if transunit['note'] != messages[srcmsg].get('note',u''):
                    messages[srcmsg]['note'] = transunit['note']
                    num_notes = num_notes + 1
                if srcmsg == transunit['target']:
                    # No translation was done
                    continue
                num_translations = num_translations + 1
                if transunit['target'] == u'' and transunit['source'] != srcmsg:
                # The source was translated. Happens sometimes
                    messages[srcmsg][targetlang] = transunit['source']
                else:
                    messages[srcmsg][targetlang] = transunit['target']

        if REQUEST is not None:
            return MessageDialog(title = _('Messages imported'),
             message = _('Imported %d messages and %d notes to %s') % \
                (num_translations, num_notes, targetlang) ,
             action = 'manage_messages',)
Exemplo n.º 5
0
class UserFolder(BasicUserFolder):
    """Standard UserFolder object

    A UserFolder holds User objects which contain information
    about users including name, password domain, and roles.
    UserFolders function chiefly to control access by authenticating
    users and binding them to a collection of roles."""

    meta_type='User Folder'
    id       ='acl_users'
    title    ='User Folder'
    icon     ='p_/UserFolder'

    def __init__(self):
        self.data=PersistentMapping()

    def getUserNames(self):
        """Return a list of usernames"""
        names=self.data.keys()
        names.sort()
        return names

    def getUsers(self):
        """Return a list of user objects"""
        data=self.data
        names=data.keys()
        names.sort()
        users=[]
        f=users.append
        for n in names:
            f(data[n])
        return users

    def getUser(self, name):
        """Return the named user object or None"""
        return self.data.get(name, None)

    def _doAddUser(self, name, password, roles, domains, **kw):
        """Create a new user"""
        if password is not None and self.encrypt_passwords:
            password = self._encryptPassword(password)
        self.data[name]=User(name,password,roles,domains)

    def _doChangeUser(self, name, password, roles, domains, **kw):
        user=self.data[name]
        if password is not None:
            if self.encrypt_passwords and not self._isPasswordEncrypted(pw):
                password = self._encryptPassword(password)
            user.__=password
        user.roles=roles
        user.domains=domains

    def _doDelUsers(self, names):
        for name in names:
            del self.data[name]

    def _createInitialUser(self):
        """
        If there are no users or only one user in this user folder,
        populates from the 'inituser' file in INSTANCE_HOME.
        We have to do this even when there is already a user
        just in case the initial user ignored the setup messages.
        We don't do it for more than one user to avoid
        abuse of this mechanism.
        Called only by OFS.Application.initialize().
        """
        if len(self.data) <= 1:
            info = readUserAccessFile('inituser')
            if info:
                name, password, domains, remote_user_mode = info
                self._doDelUsers(self.getUserNames())
                self._doAddUser(name, password, ('Manager',), domains)
                try:
                    os.remove(os.path.join(INSTANCE_HOME, 'inituser'))
                except:
                    pass
Exemplo n.º 6
0
class MembershipTool(UniqueObject, Folder, ActionProviderBase):

    """ This tool accesses member data through an acl_users object.

    It can be replaced with something that accesses member data in a
    different way.
    """

    implements(IMembershipTool)
    __implements__ = (z2IMembershipTool, ActionProviderBase.__implements__)

    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'
    memberareaCreationFlag = 1

    security = ClassSecurityInfo()

    manage_options=( ({ 'label' : 'Configuration'
                     , 'action' : 'manage_mapRoles'
                     },) +
                     ActionProviderBase.manage_options +
                   ( { 'label' : 'Overview'
                     , 'action' : 'manage_overview'
                     },
                   ) + Folder.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile( 'explainMembershipTool', _dtmldir )

    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir )

    security.declareProtected(SetOwnPassword, 'setPassword')
    def setPassword(self, password, domains=None):
        '''Allows the authenticated member to set his/her own password.
        '''
        registration = getToolByName(self, 'portal_registration', None)
        if not self.isAnonymousUser():
            member = self.getAuthenticatedMember()
            if registration:
                failMessage = registration.testPasswordValidity(password)
                if failMessage is not None:
                    raise BadRequest(failMessage)
            member.setSecurityProfile(password=password, domains=domains)
        else:
            raise BadRequest('Not logged in.')

    security.declarePublic('getAuthenticatedMember')
    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')
    def wrapUser(self, u, wrap_anon=0):
        """ Set up the correct acquisition wrappers for a user object.

        Provides an opportunity for a portal_memberdata tool to retrieve and
        store member data independently of the user object.
        """
        b = getattr(u, 'aq_base', None)
        if b is None:
            # u isn't wrapped at all.  Wrap it in self.acl_users.
            b = u
            u = u.__of__(self.acl_users)
        if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'):
            # This user is either not recognized by acl_users or it is
            # already registered with something that implements the
            # member data tool at least partially.
            return u

        # Apply any role mapping if we have it
        if hasattr(self, 'role_map'):
            for portal_role in self.role_map.keys():
                if (self.role_map.get(portal_role) in u.roles and
                        portal_role not in u.roles):
                    u.roles.append(portal_role)

        mdtool = getToolByName(self, 'portal_memberdata', None)
        if mdtool is not None:
            try:
                u = mdtool.wrapUser(u)
            except ConflictError:
                raise
            except:
                logging.exception('CMFCore.MembershipTool',
                                  'Error during wrapUser')
        return u

    security.declareProtected(ManagePortal, 'getPortalRoles')
    def getPortalRoles(self):
        """
        Return all local roles defined by the portal itself,
        which means roles that are useful and understood
        by the portal object
        """
        parent = self.aq_inner.aq_parent
        roles = list( parent.userdefined_roles() )

        # This is *not* a local role in the portal but used by it
        roles.append('Manager')
        roles.append('Owner')

        return roles

    security.declareProtected(ManagePortal, 'setRoleMapping')
    def setRoleMapping(self, portal_role, userfolder_role):
        """
        set the mapping of roles between roles understood by
        the portal and roles coming from outside user sources
        """
        if not hasattr(self, 'role_map'): self.role_map = PersistentMapping()

        if len(userfolder_role) < 1:
            del self.role_map[portal_role]
        else:
            self.role_map[portal_role] = userfolder_role

        return MessageDialog(
               title  ='Mapping updated',
               message='The Role mappings have been updated',
               action ='manage_mapRoles')

    security.declareProtected(ManagePortal, 'getMappedRole')
    def getMappedRole(self, portal_role):
        """
        returns a role name if the portal role is mapped to
        something else or an empty string if it is not
        """
        if hasattr(self, 'role_map'):
            return self.role_map.get(portal_role, '')
        else:
            return ''

    security.declarePublic('getMembersFolder')
    def getMembersFolder(self):
        """ Get the members folder object.
        """
        parent = aq_parent( aq_inner(self) )
        members = getattr(parent, 'Members', None)
        return members

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')
    def getMemberareaCreationFlag(self):
        """
        Returns the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        return self.memberareaCreationFlag

    security.declareProtected(ManagePortal, 'setMemberareaCreationFlag')
    def setMemberareaCreationFlag(self):
        """
        sets the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        if self.memberareaCreationFlag == 0:
            self.memberareaCreationFlag = 1
        else:
            self.memberareaCreationFlag = 0

        return MessageDialog(
               title  ='Member area creation flag changed',
               message='Member area creation flag has been updated',
               action ='manage_mapRoles')

    security.declarePublic('createMemberArea')
    def createMemberArea(self, member_id=''):
        """ Create a member area for 'member_id' or authenticated user.
        """
        if not self.getMemberareaCreationFlag():
            return None
        members = self.getMembersFolder()
        if not members:
            return None
        if self.isAnonymousUser():
            return None
        # Note: We can't use getAuthenticatedMember() and getMemberById()
        # because they might be wrapped by MemberDataTool.
        user = _getAuthenticatedUser(self)
        user_id = user.getId()
        if member_id in ('', user_id):
            member = user
            member_id = user_id
        else:
            if _checkPermission(ManageUsers, self):
                member = self.acl_users.getUserById(member_id, None)
                if member:
                    member = member.__of__(self.acl_users)
                else:
                    raise ValueError('Member %s does not exist' % member_id)
            else:
                return None
        if hasattr( aq_base(members), member_id ):
            return None
        else:
            f_title = "%s's Home" % member_id
            members.manage_addPortalFolder( id=member_id, title=f_title )
            f=getattr(members, member_id)

            f.manage_permission(View,
                                ['Owner','Manager','Reviewer'], 0)
            f.manage_permission(AccessContentsInformation,
                                ['Owner','Manager','Reviewer'], 0)

            # Grant Ownership and Owner role to Member
            f.changeOwnership(member)
            f.__ac_local_roles__ = None
            f.manage_setLocalRoles(member_id, ['Owner'])
        return f

    security.declarePublic('createMemberarea')
    createMemberarea = createMemberArea

    security.declareProtected(ManageUsers, 'deleteMemberArea')
    def deleteMemberArea(self, member_id):
        """ Delete member area of member specified by member_id.
        """
        members = self.getMembersFolder()
        if not members:
            return 0
        if hasattr( aq_base(members), member_id ):
            members.manage_delObjects(member_id)
            return 1
        else:
            return 0

    security.declarePublic('isAnonymousUser')
    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')
    def checkPermission(self, permissionName, object, subobjectName=None):
        '''
        Checks whether the current user has the given permission on
        the given object or subobject.
        '''
        if subobjectName is not None:
            object = getattr(object, subobjectName)
        return _checkPermission(permissionName, object)

    security.declarePublic('credentialsChanged')
    def credentialsChanged(self, password):
        '''
        Notifies the authentication mechanism that this user has changed
        passwords.  This can be used to update the authentication cookie.
        Note that this call should *not* cause any change at all to user
        databases.
        '''
        if not self.isAnonymousUser():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            name = user.getUserName()
            # this really does need to be the user name, and not the user id,
            # because we're dealing with authentication credentials
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, name, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, name, password)

    security.declareProtected(ManageUsers, 'getMemberById')
    def getMemberById(self, id):
        '''
        Returns the given member.
        '''
        user = self._huntUser(id, self)
        if user is not None:
            user = self.wrapUser(user)
        return user

    def _huntUser(self, username, context):
        """Find user in the hierarchy starting from bottom level 'start'.
        """
        uf = context.acl_users
        while uf is not None:
            user = uf.getUserById(username)
            if user is not None:
                return user
            container = aq_parent(aq_inner(uf))
            parent = aq_parent(aq_inner(container))
            uf = getattr(parent, 'acl_users', None)
        return None

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManageUsers, 'listMemberIds')
    def listMemberIds(self):
        '''Lists the ids of all members.  This may eventually be
        replaced with a set of methods for querying pieces of the
        list rather than the entire list at once.
        '''
        user_folder = self.__getPUS()
        return [ x.getId() for x in user_folder.getUsers() ]

    security.declareProtected(ManageUsers, 'listMembers')
    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declareProtected(ListPortalMembers, 'searchMembers')
    def searchMembers( self, search_param, search_term ):
        """ Search the membership """
        md = getToolByName( self, 'portal_memberdata' )

        return md.searchMemberData( search_param, search_term )

    security.declareProtected(View, 'getCandidateLocalRoles')
    def getCandidateLocalRoles(self, obj):
        """ What local roles can I assign?
        """
        member = self.getAuthenticatedMember()
        member_roles = member.getRolesInContext(obj)
        if _checkPermission(ManageUsers, obj):
            local_roles = self.getPortalRoles()
            if 'Manager' not in member_roles:
                 local_roles.remove('Manager')
        else:
            local_roles = [ role for role in member_roles
                            if role not in ('Member', 'Authenticated') ]
        local_roles.sort()
        return tuple(local_roles)

    security.declareProtected(View, 'setLocalRoles')
    def setLocalRoles(self, obj, member_ids, member_role, reindex=1):
        """ Add local roles on an item.
        """
        if ( _checkPermission(ChangeLocalRoles, obj)
             and member_role in self.getCandidateLocalRoles(obj) ):
            for member_id in member_ids:
                roles = list(obj.get_local_roles_for_userid( userid=member_id ))

                if member_role not in roles:
                    roles.append( member_role )
                    obj.manage_setLocalRoles( member_id, roles )

        if reindex:
            # It is assumed that all objects have the method
            # reindexObjectSecurity, which is in CMFCatalogAware and
            # thus PortalContent and PortalFolder.
            obj.reindexObjectSecurity()

    security.declareProtected(View, 'deleteLocalRoles')
    def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0):
        """ Delete local roles of specified members.
        """
        if _checkPermission(ChangeLocalRoles, obj):
            for member_id in member_ids:
                if obj.get_local_roles_for_userid(userid=member_id):
                    obj.manage_delLocalRoles(userids=member_ids)
                    break

        if recursive and hasattr( aq_base(obj), 'contentValues' ):
            for subobj in obj.contentValues():
                self.deleteLocalRoles(subobj, member_ids, 0, 1)

        if reindex:
            # reindexObjectSecurity is always recursive
            obj.reindexObjectSecurity()

    security.declarePrivate('addMember')
    def addMember(self, id, password, roles, domains, properties=None):
        '''Adds a new member to the user folder.  Security checks will have
        already been performed.  Called by portal_registration.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_doAddUser'):
            acl_users._doAddUser(id, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            member = self.getMemberById(id)
            member.setMemberProperties(properties)

    security.declareProtected(ManageUsers, 'deleteMembers')
    def deleteMembers(self, member_ids, delete_memberareas=1,
                      delete_localroles=1):
        """ Delete members specified by member_ids.
        """

        # Delete members in acl_users.
        acl_users = self.acl_users
        if _checkPermission(ManageUsers, acl_users):
            if isinstance(member_ids, basestring):
                member_ids = (member_ids,)
            member_ids = list(member_ids)
            for member_id in member_ids[:]:
                if not acl_users.getUserById(member_id, None):
                    member_ids.remove(member_id)
            try:
                acl_users.userFolderDelUsers(member_ids)
            except (NotImplementedError, 'NotImplemented'):
                raise NotImplementedError('The underlying User Folder '
                                         'doesn\'t support deleting members.')
        else:
            raise AccessControl_Unauthorized('You need the \'Manage users\' '
                                 'permission for the underlying User Folder.')

        # Delete member data in portal_memberdata.
        mdtool = getToolByName(self, 'portal_memberdata', None)
        if mdtool is not None:
            for member_id in member_ids:
                mdtool.deleteMemberData(member_id)

        # Delete members' home folders including all content items.
        if delete_memberareas:
            for member_id in member_ids:
                 self.deleteMemberArea(member_id)

        # Delete members' local roles.
        if delete_localroles:
            utool = getToolByName(self, 'portal_url', None)
            self.deleteLocalRoles( utool.getPortalObject(), member_ids,
                                   reindex=1, recursive=1 )

        return tuple(member_ids)

    security.declarePublic('getHomeFolder')
    def getHomeFolder(self, id=None, verifyPermission=0):
        """Returns a member's home folder object or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None

    security.declarePublic('getHomeUrl')
    def getHomeUrl(self, id=None, verifyPermission=0):
        """Returns the URL to a member's home folder or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
Exemplo n.º 7
0
class DiscussionItemContainer( Persistent, Implicit, Traversable ):
    """
        Store DiscussionItem objects. Discussable content that
        has DiscussionItems associated with it will have an
        instance of DiscussionItemContainer injected into it to
        hold the discussion threads.
    """

    __implements__ = Discussable

    # for the security machinery to allow traversal
    #__roles__ = None

    security = ClassSecurityInfo()

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()

    security.declareProtected(View, 'getId')
    def getId( self ):
        return self.id

    security.declareProtected(View, 'getReply')
    def getReply( self, reply_id ):
        """
            Return a discussion item, given its ID;  raise KeyError
            if not found.
        """
        return self._container.get( reply_id ).__of__(self)

    # Is this right?
    security.declareProtected(View, '__bobo_traverse__')
    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target

        else:
            try:
                return self.getReply(name)
            except:
                parent = aq_parent( aq_inner( self ) )
                if parent.getId() == name:
                    return parent
                else:
                    REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    security.declarePrivate('manage_afterAdd')
    def manage_afterAdd(self, item, container):
        """
            We have juste been added or moved.
            Add the contained items to the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__(self).manage_afterAdd(item, container)

    security.declarePrivate('manage_afterClone')
    def manage_afterClone(self, item):
        """
            We have just been cloned.
            Notify the workflow about the contained items.
        """
        for obj in self.objectValues():
            obj.__of__(self).manage_afterClone(item)

    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
        """
            Remove the contained items from the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__( self ).manage_beforeDelete( item, container )

    #
    #   OFS.ObjectManager query interface.
    #
    security.declareProtected(AccessContentsInformation, 'objectIds')
    def objectIds( self, spec=None ):
        """
            Return a list of the ids of our DiscussionItems.
        """
        if spec and spec is not DiscussionItem.meta_type:
            return []
        return self._container.keys()


    security.declareProtected(AccessContentsInformation, 'objectItems')
    def objectItems(self, spec=None):
        """
            Return a list of (id, subobject) tuples for our DiscussionItems.
        """
        r=[]
        a=r.append
        g=self._container.get
        for id in self.objectIds(spec):
            a( (id, g( id ) ) )
        return r


    security.declareProtected(AccessContentsInformation, 'objectValues')
    def objectValues(self):
        """
            Return a list of our DiscussionItems.
        """
        return self._container.values()

    #
    #   Discussable interface
    #
    security.declareProtected(ReplyToItem, 'createReply')
    def createReply( self, title, text, Creator=None, text_format='structured-text' ):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while self._container.get( str(id), None ) is not None:
            id = id + 1
        id = str( id )

        item = DiscussionItem( id, title=title, description=title )
        item._edit( text_format=text_format, text=text )
        item.__of__(self).addCreator(Creator)
        item.__of__(self).indexObject()

        item.setReplyTo( self._getDiscussable() )
        item.__of__(self).notifyWorkflowCreated()

        self._container[ id ] = item

        return id

    security.declareProtected(ManagePortal, 'deleteReply')
    def deleteReply( self, reply_id ):
        """ Remove a reply from this container """
        if self._container.has_key( reply_id ):
            reply = self._container.get( reply_id ).__of__( self )
            my_replies = reply.talkback.getReplies()
            for my_reply in my_replies:
                my_reply_id = my_reply.getId()
                if hasattr( my_reply, 'unindexObject' ):
                    my_reply.unindexObject()

                del self._container[my_reply_id]

            if hasattr( reply, 'unindexObject' ):
                reply.unindexObject()

            del self._container[reply_id]


    security.declareProtected(View, 'hasReplies')
    def hasReplies( self, content_obj ):
        """
            Test to see if there are any dicussion items
        """
        outer = self._getDiscussable( outer=1 )
        if content_obj == outer:
            return not not len( self._container )
        else:
            return not not len( content_obj.talkback._getReplyResults() )

    security.declareProtected(View, 'replyCount')
    def replyCount( self, content_obj ):
        """ How many replies do i have? """
        outer = self._getDiscussable( outer=1 )
        if content_obj == outer:
            return len( self._container )
        else:
            replies = content_obj.talkback.getReplies()
            return self._repcount( replies )

    security.declarePrivate('_repcount')
    def _repcount( self, replies ):
        """  counts the total number of replies by recursing thru the various levels
        """
        count = 0

        for reply in replies:
            count = count + 1

            #if there is at least one reply to this reply
            replies = reply.talkback.getReplies()
            if replies:
                count = count + self._repcount( replies )

        return count

    security.declareProtected(View, 'getReplies')
    def getReplies( self ):
        """
            Return a sequence of the DiscussionResponse objects which are
            associated with this Discussable
        """
        objects = []
        a = objects.append
        result_ids = self._getReplyResults()

        for id in result_ids:
            a( self._container.get( id ).__of__( self ) )

        return objects

    security.declareProtected(View, 'quotedContents')
    def quotedContents(self):
        """
            Return this object's contents in a form suitable for inclusion
            as a quote in a response.
        """

        return ""

    #
    #   Utility methods
    #
    security.declarePrivate( '_getReplyParent' )
    def _getReplyParent( self, in_reply_to ):
        """
            Return the object indicated by the 'in_reply_to', where
            'None' represents the "outer" content object.
        """
        outer = self._getDiscussable( outer=1 )
        if in_reply_to is None:
            return outer
        parent = self._container[ in_reply_to ].__of__( aq_inner( self ) )
        return parent.__of__( outer )

    security.declarePrivate( '_getDiscussable' )
    def _getDiscussable( self, outer=0 ):
        """
        """
        tb = outer and aq_inner( self ) or self
        return getattr( tb, 'aq_parent', None )

    security.declarePrivate( '_getReplyResults' )
    def _getReplyResults( self ):
        """
           Get a list of ids of DiscussionItems which are replies to
           our Discussable.
        """
        discussable = self._getDiscussable()
        outer = self._getDiscussable( outer=1 )

        if discussable == outer:
            in_reply_to = None
        else:
            in_reply_to = discussable.getId()

        result = []
        a = result.append
        for key, value in self._container.items():
            if value.in_reply_to == in_reply_to:
                a( ( key, value ) )

        result.sort( lambda a, b: cmp(a[1].creation_date, b[1].creation_date) )

        return [ x[0] for x in result ]
Exemplo n.º 8
0
class MembershipTool (UniqueObject, SimpleItem):
    # This tool accesses member data through an acl_users object.
    # It can be replaced with something that accesses member data in
    # a different way.
    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'

    security = ClassSecurityInfo()

    manage_options=( { 'label' : 'Overview'
                     , 'action' : 'manage_overview'
                     }
                   , { 'label' : 'Role Mapping'
                     , 'action' : 'manage_mapRoles'
                     }
                   ) + SimpleItem.manage_options

    #
    #   ZMI methods
    #
    security.declareProtected( CMFCorePermissions.ManagePortal
                             , 'manage_overview' )
    manage_overview = DTMLFile( 'explainMembershipTool', _dtmldir )
 
    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLFile('dtml/membershipRolemapping', _dtmldir )
 
    security.declarePublic('getAuthenticatedMember')
    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')
    def wrapUser(self, u, wrap_anon=0):
        '''
        Sets up the correct acquisition wrappers for a user
        object and provides an opportunity for a portal_memberdata
        tool to retrieve and store member data independently of
        the user object.
        '''
        b = getattr(u, 'aq_base', None)
        if b is None:
            # u isn't wrapped at all.  Wrap it in self.acl_users.
            b = u
            u = u.__of__(self.acl_users)
        if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'):
            # This user is either not recognized by acl_users or it is
            # already registered with something that implements the 
            # member data tool at least partially.
            return u
        
        parent = self.aq_inner.aq_parent
        base = getattr(parent, 'aq_base', None)
        if hasattr(base, 'portal_memberdata'):
            # Apply any role mapping if we have it
            if hasattr(self, 'role_map'):
                for portal_role in self.role_map.keys():
                    if (self.role_map.get(portal_role) in u.roles and
                            portal_role not in u.roles):
                        u.roles.append(portal_role)

            # Get portal_memberdata to do the wrapping.
            md = getToolByName(parent, 'portal_memberdata')
            try:
                portal_user = md.wrapUser(u)

                # Check for the member area creation flag and
                # take appropriate (non-) action
                if getattr(self, 'memberareaCreationFlag', 0) != 0:
                    if self.getHomeUrl(portal_user.getId()) is None:
                        self.createMemberarea(portal_user.getId())

                return portal_user

            except:
                # DEBUGGING CODE
                import traceback
                traceback.print_exc()
                pass
        # Failed.
        return u

    security.declareProtected(ManagePortal, 'getPortalRoles')
    def getPortalRoles(self):
        """
        Return all local roles defined by the portal itself,
        which means roles that are useful and understood 
        by the portal object
        """
        parent = self.aq_inner.aq_parent
        roles = list(parent.__ac_roles__)

        # This is *not* a local role in the portal but used by it
        roles.append('Manager')

        return roles

    security.declareProtected(ManagePortal, 'setRoleMapping')
    def setRoleMapping(self, portal_role, userfolder_role):
        """
        set the mapping of roles between roles understood by 
        the portal and roles coming from outside user sources
        """
        if not hasattr(self, 'role_map'): self.role_map = PersistentMapping()

        if len(userfolder_role) < 1:
            del self.role_map[portal_role]
        else:
            self.role_map[portal_role] = userfolder_role

        return MessageDialog(
               title  ='Mapping updated',
               message='The Role mappings have been updated',
               action ='manage_mapRoles')

    security.declareProtected(ManagePortal, 'getMappedRole')
    def getMappedRole(self, portal_role):
        """
        returns a role name if the portal role is mapped to
        something else or an empty string if it is not
        """
        if hasattr(self, 'role_map'):
            return self.role_map.get(portal_role, '')
        else:
            return ''

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')
    def getMemberareaCreationFlag(self):
        """
        Returns the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going 
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        return self.memberareaCreationFlag

    security.declareProtected(ManagePortal, 'setMemberareaCreationFlag')
    def setMemberareaCreationFlag(self):
        """
        sets the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        if self.memberareaCreationFlag == 0:
            self.memberareaCreationFlag = 1
        else:
            self.memberareaCreationFlag = 0

        return MessageDialog(
               title  ='Member area creation flag changed',
               message='Member area creation flag has been updated',
               action ='manage_mapRoles')

    security.declareProtected(ManagePortal, 'createMemberarea')
    def createMemberarea(self, member_id):
        """
        create a member area
        """
        parent = self.aq_inner.aq_parent
        members =  getattr(parent, 'Members', None)
        if members is not None:
            members.manage_addPortalFolder(member_id)
            f=getattr(members, member_id)
 
            f.manage_permission(CMFCorePermissions.View,
                                ['Owner','Manager','Reviewer'], 0)
            f.manage_permission(CMFCorePermissions.AccessContentsInformation,
                                ['Owner','Manager','Reviewer'], 0)  


    security.declarePublic('isAnonymousUser')
    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')
    def checkPermission(self, permissionName, object, subobjectName=None):
        '''
        Checks whether the current user has the given permission on
        the given object or subobject.
        '''
        if subobjectName is not None:
            object = getattr(object, subobjectName)
        return _checkPermission(permissionName, object)

    security.declarePublic('credentialsChanged')
    def credentialsChanged(self, password):
        '''
        Notifies the authentication mechanism that this user has changed
        passwords.  This can be used to update the authentication cookie.
        Note that this call should *not* cause any change at all to user
        databases.
        '''
        if not self.isAnonymousUser():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            id = user.getUserName()
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, id, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, id, password)

    security.declareProtected(ManagePortal, 'getMemberById')
    def getMemberById(self, id):
        '''
        Returns the given member.
        '''
        u = self.acl_users.getUser(id)
        if u is not None:
            u = self.wrapUser(u)
        return u

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManagePortal, 'listMemberIds')
    def listMemberIds(self):
        '''Lists the ids of all members.  This may eventually be
        replaced with a set of methods for querying pieces of the
        list rather than the entire list at once.
        '''
        return self.__getPUS().getUserNames()
    
    security.declareProtected(ManagePortal, 'listMembers')
    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declarePrivate('addMember')
    def addMember(self, id, password, roles, domains, properties=None):
        '''Adds a new member to the user folder.  Security checks will have
        already been performed.  Called by portal_registration.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_addUser'):
            acl_users._addUser(id, password, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
                    return
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            membership = getToolByName(self, 'portal_membership')
            member = membership.getMemberById(id)
            member.setMemberProperties(properties)


    security.declarePrivate('listActions')
    def listActions(self, info):
        return None

    security.declarePublic('getHomeFolder')
    def getHomeFolder(self, id=None, verifyPermission=0):
        """Returns a member's home folder object or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
        
    security.declarePublic('getHomeUrl')
    def getHomeUrl(self, id=None, verifyPermission=0):
        """Returns the URL to a member's home folder or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
Exemplo n.º 9
0
class DocAuthentication(BasicUserFolder, ObjectManager, session, CookieCrumbler):

    meta_type = 'User Folder'
    icon = 'misc_/Finshare/acl_users.gif'

    manage_options = (
        {'label' : 'Users', 'action' : 'manage_users_html'},
        {'label' : 'Permissions', 'action' : 'manage_permissions_html'},
    )

    security = ClassSecurityInfo()

    def __init__(self, id, title):
        self.id = id
        self.title = title
        self.data = PersistentMapping()

    ###########################
    #    PRIVATE METHODS      #
    ###########################


    security.declarePrivate('_doAddUser')
    def _doAddUser(self, name, password, roles, firstname, lastname, email, **kw):
        """Create a new user. The 'password' will be the
           original input password, unencrypted. This
           method is responsible for performing any needed encryption."""

        if password is not None and self.encrypt_passwords:
            password = self._encryptPassword(password)
        self.data[name] = User(name, password, roles, firstname, lastname, email)
        self._p_changed = 1


    security.declarePrivate('_doChangeUser')
    def _doChangeUser(self, name, password, roles, firstname, lastname, email, lastupdated, notifications, **kw):
        """Modify an existing user. The 'password' will be the
           original input password, unencrypted. The implementation of this
           method is responsible for performing any needed encryption."""

        user=self.data[name]
        if password is not None:
            if self.encrypt_passwords and not self._isPasswordEncrypted(password):
                password = self._encryptPassword(password)
            user.__ = password
        user.roles = roles
        user.firstname = firstname
        user.lastname = lastname
        user.email = email
        user.lastupdated = lastupdated
        user.notifications = notifications
        self._p_changed = 1


    security.declarePrivate('_doDelUsers')
    def _doDelUsers(self, names):
        """Delete one or more users."""
        for name in names:
            del self.data[name]
        self._p_changed = 1


    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_addUser')
    def manage_addUser(self, user='', pwd='', cpwd='', role='', fname='', 
        lname='', email='', REQUEST=None):
        """ """
        if REQUEST and REQUEST.has_key('CancelButton'):
            return REQUEST.RESPONSE.redirect(REQUEST['destination'])
        errors = []
        if not string.strip(user):
            errors.append(ERROR102)
        if not string.strip(fname):
            errors.append(ERROR100)
        if not string.strip(lname):
            errors.append(ERROR101)
        if not string.strip(email):
            errors.append(ERROR104)
        if not string.strip(pwd) or not string.strip(cpwd):
            errors.append(ERROR103)
        if self.getUser(user) or (self._emergency_user and
                                  user == self._emergency_user.getUserName()):
            errors.append(ERROR105)
        if (pwd or cpwd) and (pwd != cpwd):
            errors.append(ERROR106)
        users = self.getUserNames()
        for n in users:
            us = self.getUser(n)
            if email.strip() == us.email:
                errors.append(ERROR113)
                break
            if fname == us.firstname and lname == us.lastname:
                errors.append(ERROR114)
                break
        role = self.utConvertToList(role)
        #domains are not used for the moment
        #if domains and not self.domainSpecValidate(domains):
        #    errors.append(ERROR107)
        if len(errors):
            if REQUEST is not None: 
                #save form data to session
                self.setUserSession(user, role, fname, lname, email)
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        self._doAddUser(user, pwd, role, fname, lname, email)
        if REQUEST is not None and REQUEST.has_key('destination'): 
            return REQUEST.RESPONSE.redirect(REQUEST['destination'])


    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_changeUser')
    def manage_changeUser(self, user='', role='', fname='', lname='', email='', lastupdated='', REQUEST=None):
        """ """
        if REQUEST and REQUEST.has_key('CancelButton'):
            return REQUEST.RESPONSE.redirect(REQUEST['destination'])
        errors = []
        if not fname:
            errors.append(ERROR100)
        if not lname:
            errors.append(ERROR101)
        if not email:
            errors.append(ERROR104)
        user_ob = self.getUser(user)
        role = self.utConvertToList(role)
        if len(errors):
            if REQUEST is not None:
                #save form data to session
                self.setUserSession(user, role, fname, lname, email)
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        #domains are not used for the moment
        #if domains and not self.domainSpecValidate(domains):
        #    errors.append(ERROR107)
        lastupdated = time.strftime('%d %b %Y %H:%M:%S')
        self._doChangeUser(user, self.getUserPassword(user_ob), role, fname, lname, email, lastupdated, [])
        if REQUEST is not None and REQUEST.has_key('destination'): 
            return REQUEST.RESPONSE.redirect(REQUEST['destination'] + '?save=ok')


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'changeUserAccount')
    def changeUserAccount(self, user='', fname='', lname='', email='', REQUEST=None, RESPONSE=None):
        """ change user account information """
        errors = []
        if not fname:
            errors.append(ERROR100)
        if not lname:
            errors.append(ERROR101)
        if not email:
            errors.append(ERROR104)
        user_ob = self.getUser(user)
        if len(errors):
            if REQUEST is not None:
                #save form data to session
                self.setUserSession(user, '', fname, lname, email)
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        lastupdated = time.strftime('%d %b %Y %H:%M:%S')
        self._doChangeUser(user, self.getUserPassword(user_ob), self.getUserRoles(user_ob), fname, lname, email, lastupdated, [])
        if REQUEST is not None: 
            return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER + '?save=ok')


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'changeUserPassword')
    def changeUserPassword(self, user='', opass='', npass='', cpass='', REQUEST=None, RESPONSE=None):
        """ change user password """
        errors = []
        if not opass:
            errors.append(ERROR115)
        if (npass or cpass) and (npass != cpass):
            errors.append(ERROR106)
        if npass == cpass == '':
            errors.append(ERROR103)
        user_ob = self.getUser(user)
        if opass != self.getUserPassword(user_ob):
            errors.append(ERROR116)
        if len(errors):
            if REQUEST is not None:
                #save form data to session
                self.setUserSession(user, '', '', '', '')
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        lastupdated = time.strftime('%d %b %Y %H:%M:%S')
        self._doChangeUser(user, npass, self.getUserRoles(user_ob), self.getUserFirstName(user_ob), 
            self.getUserLastName(user_ob), self.getUserEmail(user_ob), lastupdated, [])
        self.credentialsChanged(user, npass)
        if REQUEST is not None: 
            return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER + '?save=ok')


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'changeUserNotifications')
    def changeUserNotifications(self, user='', newsletter=[], REQUEST=None, RESPONSE=None):
        """ change user notifications list """
        if newsletter:
            notifications = self.utConvertToList(newsletter)
        else:
            notifications = []
        user_ob = self.getUser(user)
        lastupdated = time.strftime('%d %b %Y %H:%M:%S')
        self._doChangeUser(user, self.getUserPassword(user_ob), self.getUserRoles(user_ob), 
            self.getUserFirstName(user_ob), self.getUserLastName(user_ob), 
            self.getUserEmail(user_ob), lastupdated, notifications)
        if REQUEST is not None: 
            return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER + '?save=ok')


    security.declarePublic('registerUser')
    def registerUser(self, user='', fname='', lname='', email='', npass='', 
                    cpass='', REQUEST=None, RESPONSE=None):
        """ register a new user """
        errors = []
        if not string.strip(user):
            errors.append(ERROR102)
        if not string.strip(fname):
            errors.append(ERROR100)
        if not string.strip(lname):
            errors.append(ERROR101)
        if not string.strip(email):
            errors.append(ERROR104)
        if not string.strip(npass) or not string.strip(cpass):
            errors.append(ERROR103)
        if self.getUser(user) or (self._emergency_user and
                                  user == self._emergency_user.getUserName()):
            errors.append(ERROR105)
        if (npass or cpass) and (npass != cpass):
            errors.append(ERROR106)
        users = self.getUserNames()
        for n in users:
            us = self.getUser(n)
            if email.strip() == us.email:
                errors.append(ERROR113)
                break
            if fname == us.firstname and lname == us.lastname:
                errors.append(ERROR114)
                break
        if len(errors):
            if REQUEST is not None: 
                #save form data to session
                self.setUserSession(user, '', fname, lname, email)
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        n = Notification()
        template_text = self.notification.register.document_src()
        template_html = self.notification.register_html.document_src()
        if self.notification.register.title:
            subject = self.notification.register.title
        elif self.notification.register_html.title:
            subject = self.notification.register_html.title
        else:
            subject = "finShare notifications"
        if self.webmaster:
            webmaster = self.webmaster
        else:
            webmaster = "*****@*****.**"
        n.send_registration(user, email, fname, lname, npass, webmaster, subject, template_text, template_html)
        if REQUEST is not None and REQUEST.has_key('destination'): 
            return REQUEST.RESPONSE.redirect(REQUEST['destination'] + '?save=ok')


    security.declarePublic('forgotPassword')
    def lostPassword(self, email='', REQUEST=None, RESPONSE=None):
        """ forgot password """
        errors = []
        if not string.strip(email):
            errors.append(ERROR104)
        pwd = fname = lname = accoount = None
        if email!='':
            for n in self.getUserNames():
                us = self.getUser(n)
                if email.strip() == us.email:
                    pwd = self.getUserPassword(us)
                    fname = self.getUserFirstName(us)
                    lname = self.getUserLastName(us)
                    account = self.getUserAccount(us)
                    break
            if pwd is None:
                errors.append(ERROR117)
        if len(errors):
            if REQUEST is not None: 
                #save form data to session
                self.setUserSession('', '', '', '', email)
                #save error to session
                self.setSessionErrors(errors)
                return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
            else:
                return errors
        n = Notification()
        template_text = self.notification.sendpassword.document_src()
        template_html = self.notification.sendpassword_html.document_src()
        if self.notification.sendpassword.title:
            subject = self.notification.sendpassword.title
        elif self.notification.sendpassword_html.title:
            subject = self.notification.sendpassword_html.title
        else:
            subject = "finShare notifications"
        if self.webmaster:
            webmaster = self.webmaster
        else:
            webmaster = "*****@*****.**"
        n.send_passwords(account, email, fname, lname, pwd, webmaster, subject, template_text, template_html)
        if REQUEST is not None and REQUEST.has_key('destination'): 
            return REQUEST.RESPONSE.redirect(REQUEST['destination'] + '?save=ok')


    security.declarePublic('sendFeedback')
    def sendFeedback(self, title, comments, REQUEST=None):
        """ send feedback """
        n = Notification()
        template_text = self.notification.feedback.document_src()
        template_html = self.notification.feedback_html.document_src()
        user = self.REQUEST.AUTHENTICATED_USER.getUserName()
        user_ob = self.getUser(user)
        fname = self.getUserFirstName(user_ob)
        lname = self.getUserLastName(user_ob)
        email = self.getUserEmail(user_ob)
        n.send_feedback(title, comments, fname, lname, email, self.getDocManagerURL(), '*****@*****.**', template_text, template_html)
        if REQUEST is not None and REQUEST.has_key('destination'): 
            return REQUEST.RESPONSE.redirect(REQUEST['destination'] + '?send=ok')

    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_delUsers')
    def manage_delUsers(self, users=[], REQUEST=None):
        """ """
        errors = []
        names = self.utConvertToList(users)
        if len(names) == 0:
            errors.append(ERROR108)
        if len(errors):
            #save error to session
            self.setSessionErrors(errors)
            return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER)
        self._doDelUsers(names)
        if REQUEST: return REQUEST.RESPONSE.redirect(REQUEST.HTTP_REFERER + '?save=ok')


    ###########################
    #       USER METHODS      #
    ###########################

    def getUserNames(self):
        """Return a list of usernames"""
        names=self.data.keys()
        names.sort()
        return names


    security.declareProtected(PERMISSION_EDIT_USERS, 'getUsersNames')
    def getUsersNames(self):
        """ return a list of usernames """
        return self.user_names()


    def getUsers(self):
        """Return a list of user objects"""
        data=self.data
        names=data.keys()
        names.sort()
        users=[]
        f=users.append
        for n in names:
            f(data[n])
        return users


    security.declarePublic('getUser') #xxx
    def getUser(self, name):
        """Return the named user object or None"""
        return self.data.get(name, None)


    def getUserAccount(self, user_obj):
        """ Return the username"""
        return user_obj.name


    def getUserPassword(self, user_obj):
        """ Return the password"""
        return user_obj.__


    def getUserFirstName(self, user_obj):
        """ Return the firstname"""
        return user_obj.firstname


    def getUserLastName(self, user_obj):
        """ Return the lastname"""
        return user_obj.lastname


    def getUserEmail(self, user_obj):
        """ Return the email """
        return user_obj.email


    def getUserRoles(self, user_obj):
        """ Return the user roles """
        return user_obj.roles


    def getUserHistory(self, user_obj):
        """ return the last login"""
        return user_obj.history


    def getUserCreatedDate(self, user_obj):
        """ Return the created date """
        return user_obj.created


    def getUserLastUpdated(self, user_obj):
        """ Return the lastupdated date"""
        return user_obj.lastupdated


    def getUserNotifications(self, user_obj):
        """ Return the lastupdated date"""
        return user_obj.notifications


    def forgotPassword(self, email, REQUEST=None, RESPONSE=None):
        """ retrieve user's password given the email """


    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_users_html')
    manage_users_html = PageTemplateFile('zpt/DocAuth/show_users.zpt', globals())


    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_addUser_html')
    manage_addUser_html = PageTemplateFile('zpt/DocAuth/add_user.zpt', globals())


    security.declareProtected(PERMISSION_EDIT_USERS, 'manage_editUser_html')
    manage_editUser_html = PageTemplateFile('zpt/DocAuth/edit_user.zpt', globals())


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'personal_html')
    personal_html = PageTemplateFile('zpt/DocAuth/personal.zpt', globals())


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'changepwd_html')
    changepwd_html = PageTemplateFile('zpt/DocAuth/changepwd.zpt', globals())


    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'newsletter_html')
    newsletter_html = PageTemplateFile('zpt/DocAuth/newsletter.zpt', globals())

    security.declareProtected(PERMISSION_VIEW_DMOBJECTS, 'feedback_html')
    feedback_html = PageTemplateFile('zpt/DocManager/DocManager_feedback', globals())
Exemplo n.º 10
0
class zodbAuthSource(Folder):
	""" Authenticate users against a ZODB dictionary"""

	meta_type='Authentication Source'
	title	 ='ZODB Authentication'
	icon ='misc_/exUserFolder/exUserFolderPlugin.gif'

	manage_properties=HTMLFile('properties', globals())

	manage_editForm=manage_editzodbAuthSourceForm
	manage_tabs=Acquisition.Acquired

	#
	# You can define this to go off and do the authentication instead of
	# using the basic one inside the User Object
	#
	remoteAuthMethod=None

	def __init__(self):
		self.id = 'zodbAuthSource'
		self.data=PersistentMapping()

	def cryptPassword_old(self, username, password):
			salt = username[:2]
			secret = crypt(password, salt)
			return secret

	def deleteUsers(self, userids):
		for name in userids:
			del self.data[name]

	def createUser(self, username, password, roles=[]):
		""" Add a Username """
		if type(roles) != type([]):
			if roles:
				roles=list(roles)
			else:
				roles=[]
			
			
		secret=self.cryptPassword(username, password)
		self.data[username]=PersistentMapping()
		self.data[username].update({ 
					'username': username,	
					'password': secret, 
					'roles': roles })

	def updateUser(self, username, password, roles):
		if type(roles) != type([]):
			if roles:
				roles=list(roles)
			else:
				roles=[]
		
		self.data[username]['roles'] = roles
		if password:
			secret = self.cryptPassword(username, password)
			self.data[username]['password'] = secret

	def listUserNames(self):
		return list(self.data.keys())

	def listUsers(self):
		""" return a list of user names or [] if no users exist"""
		return self.data.values()

	def listOneUser(self, username):
		users = []
		data = self.data.get(username)
		if data is not None:
			users.append(data)
		return users

	def postInitialisation(self, REQUEST):
		pass
Exemplo n.º 11
0
class DiscussionItemContainer(Persistent, Implicit):
    """
    This class stores DiscussionItem objects. Discussable 
    content that has DiscussionItems associated with it 
    will have an instance of DiscussionItemContainer 
    injected into it to hold the discussion threads.
    """

    # for the security machinery to allow traversal
    __roles__ = None
    __allow_access_to_unprotected_subobjects__ = 1   # legacy code


    __ac_permissions__ = ( ( 'Access contents information'
                           , ( 'objectIds'
                             , 'objectValues'
                             , 'objectItems'
                             )
                           )
                         , ( 'View'
                           , ( 'hasReplies'
                             , 'getReplies'
                             , '__bobo_traverse__'
                             )
                           )
                         , ( 'Reply to item'
                           , ( 'createReply'
                             ,
                             )
                           )
                         ) 

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()


    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target
        else:
            try:
                return self._container.get(name).__of__(self)
            except:
                REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    def objectIds(self, spec=None):
        """
        return a list of ids of DiscussionItems in
        this DiscussionItemContainer
        """
        return self._container.keys()

    def objectItems(self, spec=None):
        """
        Returns a list of (id, subobject) tuples of the current object.
        If 'spec' is specified, returns only objects whose meta_type
        match 'spec'
        """
        r=[]
        a=r.append
        g=self._container.get
        for id in self.objectIds(spec): a((id, g(id)))
        return r

    def objectValues(self):
        """
        return the list of objects stored in this
        DiscussionItemContainer
        """
        return self._container.values()

    def createReply(self, title, text, REQUEST, RESPONSE):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while getattr(self._container, `id`, None) is not None:
            id = id + 1

        item = DiscussionItem( `id` )
        item.title = title
        item.description = title
        item.text_format = 'structured-text'
        item.text = text

        if REQUEST.has_key( 'Creator' ):
            item.creator = REQUEST[ 'Creator' ]

        item.__of__(self).setReplyTo(self.aq_parent)
 
        item._parse()
        self._container[`id`] = item

        RESPONSE.redirect( self.aq_inner.aq_parent.absolute_url() + '/view' )
Exemplo n.º 12
0
class FriedCMSUserFolder(BasicUserFolder):
    """
    """
    meta_type = METATYPE_USERFOLDER
    id = 'acl_users'
    title = 'User Folder'

    security = ClassSecurityInfo()
    manage_options = ({ 'label' : 'Details', 'action' : 'tabUserFolderContents'},)+\
                   BasicUserFolder.manage_options[:1]+\
                   ({ 'label' : 'Local Roles', 'action' : 'tabLocalRoles'},)+\
                   BasicUserFolder.manage_options[1:]
     
    def __init__(self):
        self._users = PersistentMapping()
    
    security.declareProtected(PERMISSION_MANAGE_CONTENT,'index_html')
    def index_html(self, REQUEST=None):
        """ """
        if REQUEST:
            return self.http_redirect("viewUsers")


    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'countUsers')
    def countUsers(self):
        """ return integer of how many users there are in this user folder """
        return len(self._users)
    
        
    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'getUserNames')
    def getUserNames(self):
        """
        Return a list of usernames
        """
        names = self._users.keys()
        names.sort()
        return names

    def getAuthenticatedUser(self):
        authenticated = getSecurityManager().getUser()
        return authenticated
        
    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'getUsers')
    def getUsers(self):
        """
        Return a list of user objects, but only those who are
        defined below object to which current user has permissions.
        """
        result = self._users.keys()
        result.sort()
        users = [self._users[n] for n in result]
        return users
    
    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'getUser')
    def getUser(self, name):
        """
        Return the named user object or None
        """
        user = self._users.get(name, None)
        return user

    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'hasUsers')
    def hasUsers(self):
        """
        """
        if self._users:
            return True
        else:
            return False

    def _doAddUser(self, username, password, roles,
                   firstname='', lastname='',
                   email='', company='', **kw):
        """
        """
        parent = aq_parent(aq_inner(self))
        for role in roles:
            if role not in self.getAvailableRoles():
                parent._addRole(role)
                
        if password is not None and self.encrypt_passwords:
            password = self._encryptPassword(password)
        user = FriedCMSUser(username, password, roles,
                            firstname=firstname, lastname=lastname,
                            email=email, company=company, **kw)
        self._users[username] = user
        return True

    #deprecated
    def _doChangeUser(self, username, password, roles, domains, **kw):
        user = self._users[username]
        if password is not None:
            if (self.encrypt_passwords and not self._isPasswordEncrypted(password)):
                password = self._encryptPassword(password)
            user._setPassword(password)
        user.roles = roles

    def _doDelUsers(self, names):
        for username in names:
            del self._users[username]

    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'manage_addUser')
    def manage_addUser(self, username, password, repeat_password, roles=[],
                       firstname='', lastname='', new_role='',
                       email='', company='', REQUEST=None, **kw):
        """
        """
        msg = ""
        if not username:
            msg = "Usrename can not be empty."
        elif not password:
            msg = "Password can not be empty."
        elif password != repeat_password:
            msg = "Password does not match its confirmation."
        else:
            #No global roles for user, only local roles
            roles = [x.strip() for x in roles if x.strip()]
            if new_role.strip():
                roles.append(new_role)
            
            self._doAddUser(username, password, roles,
                            firstname=firstname, lastname=lastname,
                            email=email, company=company, **kw)
        if msg: #failed
            if REQUEST:
                REQUEST['msg'] = msg
                return self.addUserForm(self, REQUEST)
            else:
                return msg
        else:
            msg = "User added."
            if REQUEST:
                REQUEST['msg'] = msg
                return self.viewUsers(self, REQUEST)
            else:
                return msg
    
    security.declareProtected(PERMISSION_MANAGE_CONTENT,'getAvailableRoles')
    def getAvailableRoles(self):
        """
        """
        roles = []
        all_roles = self.valid_roles()
        for r in all_roles:
            #if r not in ('Authenticated','Anonymous','Manager','Owner'):
            if r not in ('Authenticated','Owner'):
                roles.append(r)
        return roles

    security.declareProtected(PERMISSION_MANAGE_CONTENT,'manage_editUser')
    def manage_editUser(self, username, password='', repeat_password='', roles=[],
                        firstname = '', lastname='',
                        email='', company='', REQUEST=None, **kw):
        """
        """
        msg = ""
        if not username:
            msg = "Usrename can not be empty."
        elif password != repeat_password:
            msg = "Password does not match its confirmation."
        else:
            user = self._users[username]      
            params = {'username':username, 
                      'roles':roles,
                      'firstname':firstname, 'lastname':lastname,
                      'email':email, 'company':company,
                      }
            user.editUser(**params)
            self._users[username] = user
            #If password is empty dont change it
            if password:
                if (self.encrypt_passwords and not self._isPasswordEncrypted(password)):
                    password = self._encryptPassword(password)
                user._setPassword(password)      
        if msg: #failed
            if REQUEST:
                REQUEST['msg'] = msg
                return self.editUserForm(self,REQUEST)
            else:
                return msg
        else:
            msg = "User data changed."
            if REQUEST:
                REQUEST['msg'] = msg
                return self.viewUsers(self,REQUEST)
            else:
                return msg
    
    security.declareProtected(PERMISSION_MANAGE_CONTENT, 'manage_deleteUsers')
    def manage_deleteUsers(self, usernames, REQUEST=None):
        """
        """
        if not usernames:
            msg = "No users selected"
        else:
            if type(usernames) == type(''):
                usernames = [usernames]
                #remove user objects
                self._doDelUsers(usernames)
            msg = "%d user(s) deleted."%len(usernames)
        if REQUEST:
            url = "%s/%s"%(self.absolute_url(),"viewUsers")
            self.http_redirect(url,msg=msg)
        else:
            return msg
    
        
    security.declareProtected(VMS, 'manage_getLocalRoles')
    def manage_getLocalRoles(self):
        """
        Check all site objects for local roles
        """
        result = []
        parent = self.aq_parent
        self.getLocalRolesForObject(1, parent, result)
        return result
        
    def getLocalRolesForObject(self,level,object,result):
        """
        """
        record = {}
        objects = object.objectValues()
        raw_roles = object.get_local_roles()
        roles = []
        #omitt 'Owner' role
        for r in raw_roles:
            if 'Owner' not in r[1]:
                roles.append(r)
        record['level'] = level
        record['roles'] = roles
        record['title'] = object.title_or_id()
        record['url'] = object.absolute_url()
        record['icon'] = object.icon
        #return only objects with roles
        if roles:
            result.append(record)
        for ob in objects:
            self.getLocalRolesForObject(level+1,ob,result)
        
    def canAuthenticatedAccessUser(self, user):
        """
        Method used in templates to check if particular user
        can be accesed by logged in user. In general yes, but
        this function can be overriden in inheriting classes
        to check morer conditions
        """
        auth = self.getAuthenticatedUser()
        if auth.has_permission(MANAGE_CONTENT_PERMISSIONS,self):
            return True
        else:
            return False
Exemplo n.º 13
0
class TransformTool(UniqueObject, ActionProviderBase, Folder):

    id = 'portal_transforms'
    meta_type = id.title().replace('_', ' ')
    isPrincipiaFolderish = 1 # Show up in the ZMI

    __implements__ = iengine
    implements(IPortalTransformsTool)

    meta_types = all_meta_types = (
        { 'name'   : 'Transform',
          'action' : 'manage_addTransformForm'},
        { 'name'   : 'TransformsChain',
          'action' : 'manage_addTransformsChainForm'},
        )

    manage_addTransformForm = PageTemplateFile('addTransform', _www)
    manage_addTransformsChainForm = PageTemplateFile('addTransformsChain', _www)
    manage_cacheForm = PageTemplateFile('setCacheTime', _www)
    manage_editTransformationPolicyForm = PageTemplateFile('editTransformationPolicy', _www)
    manage_reloadAllTransforms = PageTemplateFile('reloadAllTransforms', _www)

    manage_options = ((Folder.manage_options[0],) + Folder.manage_options[2:] +
                      (
        { 'label'   : 'Caches',
          'action' : 'manage_cacheForm'},
        { 'label'   : 'Policy',
          'action' : 'manage_editTransformationPolicyForm'},
        { 'label'   : 'Reload transforms',
          'action' : 'manage_reloadAllTransforms'},
        )
                      )

    security = ClassSecurityInfo()

    def __init__(self, policies=None, max_sec_in_cache=3600):
        self._mtmap = PersistentMapping()
        self._policies = policies or PersistentMapping()
        self.max_sec_in_cache = max_sec_in_cache
        self._new_style_pt = 1

    # mimetype oriented conversions (iengine interface) ########################

    def unregisterTransform(self, name):
        """ unregister a transform
        name is the name of a registered transform
        """
        self._unmapTransform(getattr(self, name))
        if name in self.objectIds():
            self._delObject(name)


    def convertTo(self, target_mimetype, orig, data=None, object=None,
                  usedby=None, context=None, **kwargs):
        """Convert orig to a given mimetype

        * orig is an encoded string

        * data an optional idatastream object. If None a new datastream will be
        created and returned

        * optional object argument is the object on which is bound the data.
        If present that object will be used by the engine to bound cached data.

        * additional arguments (kwargs) will be passed to the transformations.
        Some usual arguments are : filename, mimetype, encoding

        return an object implementing idatastream or None if no path has been
        found.
        """
        target_mimetype = str(target_mimetype)

        if object is not None:
            cache = Cache(object)
            data = cache.getCache(target_mimetype)
            if data is not None:
                time, data = data
                if self.max_sec_in_cache == 0 or time < self.max_sec_in_cache:
                    return data

        if data is None:
            data = self._wrap(target_mimetype)

        registry = getToolByName(self, 'mimetypes_registry')

        if not getattr(aq_base(registry), 'classify', None):
            # avoid problems when importing a site with an old mimetype registry
            # XXX return None or orig?
            return None

        orig_mt = registry.classify(orig,
                                    mimetype=kwargs.get('mimetype'),
                                    filename=kwargs.get('filename'))
        orig_mt = str(orig_mt)
        if not orig_mt:
            log('Unable to guess input mime type (filename=%s, mimetype=%s)' %(
                kwargs.get('mimetype'), kwargs.get('filename')), severity=DEBUG)
            return None

        target_mt = registry.lookup(target_mimetype)
        if target_mt:
            target_mt = target_mt[0]
        else:
            log('Unable to match target mime type %s'% str(target_mimetype),
                severity=DEBUG)
            return None

        ## fastpath
        # If orig_mt and target_mt are the same, we only allow
        # a one-hop transform, a.k.a. filter.
        # XXX disabled filtering for now
        filter_only = False
        if orig_mt == str(target_mt):
            filter_only = True
            data.setData(orig)
            md = data.getMetadata()
            md['mimetype'] = str(orig_mt)
            if object is not None:
                cache.setCache(str(target_mimetype), data)
            return data

        ## get a path to output mime type
        requirements = self._policies.get(str(target_mt), [])
        path = self._findPath(orig_mt, target_mt, list(requirements))
        if not path and requirements:
            log('Unable to satisfy requirements %s' % ', '.join(requirements),
                severity=DEBUG)
            path = self._findPath(orig_mt, target_mt)

        if not path:
            log('NO PATH FROM %s TO %s : %s' % (orig_mt, target_mimetype, path),
                severity=DEBUG)
            return None #XXX raise TransformError

        if len(path) > 1:
            ## create a chain on the fly (sly)
            transform = chain()
            for t in path:
                transform.registerTransform(t)
        else:
            transform = path[0]

        result = transform.convert(orig, data, context=context, usedby=usedby, **kwargs)
        assert(idatastream.isImplementedBy(result),
               'result doesn\'t implemented idatastream')
        self._setMetaData(result, transform)

        # set cache if possible
        if object is not None and result.isCacheable():
            cache.setCache(str(target_mimetype), result)

        # return idatastream object
        return result

    security.declarePublic('convertToData')
    def convertToData(self, target_mimetype, orig, data=None, object=None,
                      usedby=None, context=None, **kwargs):
        """Convert to a given mimetype and return the raw data
        ignoring subobjects. see convertTo for more information
        """
        data =self.convertTo(target_mimetype, orig, data, object, usedby,
                       context, **kwargs)
        if data:
            return data.getData()
        return None

    security.declarePublic('convert')
    def convert(self, name, orig, data=None, context=None, **kwargs):
        """run a tranform of a given name on data

        * name is the name of a registered transform

        see convertTo docstring for more info
        """
        if not data:
            data = self._wrap(name)
        try:
            transform = getattr(self, name)
        except AttributeError:
            raise Exception('No such transform "%s"' % name)
        data = transform.convert(orig, data, context=context, **kwargs)
        self._setMetaData(data, transform)
        return data


    def __call__(self, name, orig, data=None, context=None, **kwargs):
        """run a transform by its name, returning the raw data product

        * name is the name of a registered transform.

        return an encoded string.
        see convert docstring for more info on additional arguments.
        """
        data = self.convert(name, orig, data, context, **kwargs)
        return data.getData()


    # utilities ###############################################################

    def _setMetaData(self, datastream, transform):
        """set metadata on datastream according to the given transform
        (mime type and optionaly encoding)
        """
        md = datastream.getMetadata()
        if hasattr(transform, 'output_encoding'):
            md['encoding'] = transform.output_encoding
        md['mimetype'] = transform.output

    def _wrap(self, name):
        """wrap a data object in an icache"""
        return datastream(name)

    def _unwrap(self, data):
        """unwrap data from an icache"""
        if idatastream.isImplementedBy(data):
            data = data.getData()
        return data

    def _mapTransform(self, transform):
        """map transform to internal structures"""
        registry = getToolByName(self, 'mimetypes_registry')
        inputs = getattr(transform, 'inputs', None)
        if not inputs:
            raise TransformException('Bad transform %s : no input MIME type' %
                                     (transform))
        for i in inputs:
            mts = registry.lookup(i)
            if not mts:
                msg = 'Input MIME type %r for transform %s is not registered '\
                      'in the MIME types registry' % (i, transform.name())
                raise TransformException(msg)
            for mti in mts:
                for mt in mti.mimetypes:
                    mt_in = self._mtmap.setdefault(mt, PersistentMapping())
                    output = getattr(transform, 'output', None)
                    if not output:
                        msg = 'Bad transform %s : no output MIME type'
                        raise TransformException(msg % transform.name())
                    mto = registry.lookup(output)
                    if not mto:
                        msg = 'Output MIME type %r for transform %s is not '\
                              'registered in the MIME types registry' % \
                              (output, transform.name())
                        raise TransformException(msg)
                    if len(mto) > 1:
                        msg = 'Wildcarding not allowed in transform\'s output '\
                              'MIME type'
                        raise TransformException(msg)

                    for mt2 in mto[0].mimetypes:
                        try:
                            if not transform in mt_in[mt2]:
                                mt_in[mt2].append(transform)
                        except KeyError:
                            mt_in[mt2] = PersistentList([transform])

    def _unmapTransform(self, transform):
        """unmap transform from internal structures"""
        registry = getToolByName(self, 'mimetypes_registry')
        for i in transform.inputs:
            for mti in registry.lookup(i):
                for mt in mti.mimetypes:
                    mt_in = self._mtmap.get(mt, {})
                    output = transform.output
                    mto = registry.lookup(output)
                    for mt2 in mto[0].mimetypes:
                        l = mt_in[mt2]
                        for i in range(len(l)):
                            if transform.name() == l[i].name():
                                l.pop(i)
                                break
                        else:
                            log('Can\'t find transform %s from %s to %s' % (
                                transform.name(), mti, mt),
                                severity=DEBUG)

    def _findPath(self, orig, target, required_transforms=()):
        """return the shortest path for transformation from orig mimetype to
        target mimetype
        """
        path = []

        if not self._mtmap:
            return None

        # naive algorithm :
        #  find all possible paths with required transforms
        #  take the shortest
        #
        # it should be enough since we should not have so much possible paths
        shortest, winner = 9999, None
        for path in self._getPaths(str(orig), str(target), required_transforms):
            if len(path) < shortest:
                winner = path
                shortest = len(path)

        return winner

    def _getPaths(self, orig, target, requirements, path=None, result=None):
        """return a all path for transformation from orig mimetype to
        target mimetype
        """
        if path is None:
            result = []
            path = []
            requirements = list(requirements)
        outputs = self._mtmap.get(orig)
        if outputs is None:
            return result
        path.append(None)
        for o_mt, transforms in outputs.items():
            for transform in transforms:
                required = 0
                name = transform.name()
                if name in requirements:
                    requirements.remove(name)
                    required = 1
                if transform in path:
                    # avoid infinite loop...
                    continue
                path[-1] = transform
                if o_mt == target:
                    if not requirements:
                        result.append(path[:])
                else:
                    self._getPaths(o_mt, target, requirements, path, result)
                if required:
                    requirements.append(name)
        path.pop()

        return result

    security.declarePrivate('manage_afterAdd')
    def manage_afterAdd(self, item, container):
        """ overload manage_afterAdd to finish initialization when the
        transform tool is added
        """
        Folder.manage_afterAdd(self, item, container)
        transforms.initialize(self)
        # XXX required?
        #try:
        #    # first initialization
        #    transforms.initialize(self)
        #except:
        #    # may fail on copy
        #    pass

    security.declareProtected(ManagePortal, 'manage_addTransform')
    def manage_addTransform(self, id, module, REQUEST=None):
        """ add a new transform to the tool """
        transform = Transform(id, module)
        self._setObject(id, transform)
        self._mapTransform(transform)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

    security.declareProtected(ManagePortal, 'manage_addTransform')
    def manage_addTransformsChain(self, id, description, REQUEST=None):
        """ add a new transform to the tool """
        transform = TransformsChain(id, description)
        self._setObject(id, transform)
        self._mapTransform(transform)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

    security.declareProtected(ManagePortal, 'manage_addTransform')
    def manage_setCacheValidityTime(self, seconds, REQUEST=None):
        """set  the lifetime of cached data in seconds"""
        self.max_sec_in_cache = int(seconds)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

    security.declareProtected(ManagePortal, 'reloadTransforms')
    def reloadTransforms(self, ids=()):
        """ reload transforms with the given ids
        if no ids, reload all registered transforms

        return a list of (transform_id, transform_module) describing reloaded
        transforms
        """
        if not ids:
            ids = self.objectIds()
        reloaded = []
        for id in ids:
            o = getattr(self, id)
            o.reload()
            reloaded.append((id, o.module))
        return reloaded

    # Policy handling methods #################################################

    def manage_addPolicy(self, output_mimetype, required_transforms, REQUEST=None):
        """ add a policy for a given output mime types"""
        registry = getToolByName(self, 'mimetypes_registry')
        if not registry.lookup(output_mimetype):
            raise TransformException('Unknown MIME type')
        if self._policies.has_key(output_mimetype):
            msg = 'A policy for output %s is yet defined' % output_mimetype
            raise TransformException(msg)

        required_transforms = tuple(required_transforms)
        self._policies[output_mimetype] = required_transforms
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_editTransformationPolicyForm')

    def manage_delPolicies(self, outputs, REQUEST=None):
        """ remove policies for given output mime types"""
        for mimetype in outputs:
            del self._policies[mimetype]
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_editTransformationPolicyForm')

    def listPolicies(self):
        """ return the list of defined policies

        a policy is a 2-uple (output_mime_type, [list of required transforms])
        """
        # XXXFIXME: backward compat, should be removed latter
        if not hasattr(self, '_policies'):
            self._policies = PersistentMapping()
        return self._policies.items()

    # mimetype oriented conversions (iengine interface) ########################

    def registerTransform(self, transform):
        """register a new transform

        transform isn't a Zope Transform (the wrapper) but the wrapped transform
        the persistence wrapper will be created here
        """
        # needed when call from transform.transforms.initialize which
        # register non zope transform
        module = str(transform.__module__)
        transform = Transform(transform.name(), module, transform)
        if not itransform.isImplementedBy(transform):
            raise TransformException('%s does not implement itransform' % transform)
        name = transform.name()
        __traceback_info__ = (name, transform)
        if name not in self.objectIds():
            self._setObject(name, transform)
            self._mapTransform(transform)

    security.declareProtected(ManagePortal, 'ZopeFind')
    def ZopeFind(self, *args, **kwargs):
        """Don't break ZopeFind feature when a transform can't be loaded
        """
        try:
            return Folder.ZopeFind(self, *args, **kwargs)
        except MissingBinary:
            log('ZopeFind: catched MissingBinary exception')

    security.declareProtected(View, 'objectItems')
    def objectItems(self, *args, **kwargs):
        """Don't break ZopeFind feature when a transform can't be loaded
        """
        try:
            return Folder.objectItems(self, *args, **kwargs)
        except MissingBinary:
            log('objectItems: catched MissingBinary exception')
            return []

    # available mimetypes ####################################################
    def listAvailableTextInputs(self):
        """ Returns a list of mimetypes that can be used as input for textfields
            by building a list of the inputs beginning with "text/" of all transforms.
        """
        available_types = []
        candidate_transforms = [object[1] for object in self.objectItems()]
        for candidate in candidate_transforms:
            for input in candidate.inputs:
                if input.startswith("text/") and input not in available_types:
                    available_types.append(input)
        return available_types
Exemplo n.º 14
0
class DiscussionItemContainer( Persistent, Implicit, Traversable ):
    """
        Store DiscussionItem objects. Discussable content that
        has DiscussionItems associated with it will have an
        instance of DiscussionItemContainer injected into it to
        hold the discussion threads.
    """

    # for the security machinery to allow traversal
    #__roles__ = None

    security = ClassSecurityInfo()

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()

    security.declareProtected( CMFCorePermissions.View, 'getId' )
    def getId( self ):
        return self.id

    # Is this right?
    security.declareProtected( CMFCorePermissions.View, '__bobo_traverse__' )
    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target
        else:
            try:
                return self._container.get(name).__of__(self)
            except:
                REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
        """
            Remove the contained items from the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__( self ).manage_beforeDelete( item, container )

    #
    #   OFS.ObjectManager query interface.
    #
    security.declareProtected( CMFCorePermissions.AccessContentsInformation
                             , 'objectIds' )
    def objectIds( self, spec=None ):
        """
            Return a list of the ids of our DiscussionItems.
        """
        if spec and spec is not DiscussionItem.meta_type:
            return []
        return self._container.keys()


    security.declareProtected( CMFCorePermissions.AccessContentsInformation
                             , 'objectItems' )
    def objectItems(self, spec=None):
        """
            Return a list of (id, subobject) tuples for our DiscussionItems.
        """
        r=[]
        a=r.append
        g=self._container.get
        for id in self.objectIds(spec):
            a( (id, g( id ) ) )
        return r


    security.declareProtected( CMFCorePermissions.AccessContentsInformation
                             , 'objectValues' )
    def objectValues(self):
        """
            Return a list of our DiscussionItems.
        """
        return self._container.values()

    #
    #   Discussable interface
    #
    security.declareProtected( CMFCorePermissions.ReplyToItem, 'createReply' )
    def createReply( self, title, text, Creator=None ):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while self._container.get( str(id), None ) is not None:
            id = id + 1
        id = str( id )

        item = DiscussionItem( id, title=title, description=title )
        item._edit( text_format='structured-text', text=text )

        if Creator:
            item.creator = Creator

        item.__of__( self ).indexObject()

        item.setReplyTo( self._getDiscussable() )
 
        self._container[ id ] = item

        return id

    security.declareProtected( CMFCorePermissions.View, 'hasReplies' )
    def hasReplies( self ):
        """
            Test to see if there are any dicussion items
        """
        if len(self._container) == 0:
            return 0

        return len( self._getReplyResults() )

    security.declareProtected( CMFCorePermissions.View, 'getReplies' )
    def getReplies( self ):
        """
            Return a sequence of the DiscussionResponse objects which are
            associated with this Discussable
        """
        objects = []
        a = objects.append
        result_ids = self._getReplyResults()

        for id in result_ids:
            a( self._container.get( id ).__of__( self ) )

        return objects

    security.declareProtected( CMFCorePermissions.View, 'quotedContents' )
    def quotedContents(self):
        """
            Return this object's contents in a form suitable for inclusion
            as a quote in a response.
        """
 
        return ""
    
    #
    #   Utility methods
    #
    security.declarePrivate( '_getReplyParent' )
    def _getReplyParent( self, in_reply_to ):
        """
            Return the object indicated by the 'in_reply_to', where
            'None' represents the "outer" content object.
        """
        outer = self._getDiscussable( outer=1 )
        if in_reply_to is None:
            return outer
        parent = self._container[ in_reply_to ].__of__( aq_inner( self ) )
        return parent.__of__( outer )
        

    security.declarePrivate( '_getDiscussable' )
    def _getDiscussable( self, outer=0 ):
        """
        """
        tb = outer and aq_inner( self ) or self
        return getattr( tb, 'aq_parent', None )

    security.declarePrivate( '_getReplyResults' )
    def _getReplyResults( self ):
        """
           Get a list of ids of DiscussionItems which are replies to
           our Discussable.
        """
        discussable = self._getDiscussable()
        outer = self._getDiscussable( outer=1 )

        if discussable == outer:
            in_reply_to = None
        else:
            in_reply_to = discussable.getId()

        result = []
        a = result.append
        for key, value in self._container.items():
            if value.in_reply_to == in_reply_to:
                a( key )

        return result
Exemplo n.º 15
0
class AuthenticationTool(BasicUserFolder, Role, ObjectManager, session_manager,
                         file_utils, plugins_tool, PropertyManager):

    meta_type = METATYPE_AUTHENTICATIONTOOL
    icon = 'misc_/NaayaCore/AuthenticationTool.gif'

    manage_options = (
        {'label': 'Users', 'action': 'manage_users_html'},
        {'label': 'Roles', 'action': 'manage_roles_html'},
        {'label': 'Permissions', 'action': 'manage_permissions_html'},
        {'label': 'Other sources', 'action': 'manage_sources_html'},
        {'label': 'Properties', 'action': 'manage_propertiesForm',
         'help': ('OFSP','Properties.stx')},
    )

    _properties = (
        {'id': 'title', 'type': 'string', 'mode': 'w',
         'label': 'Title'},
        {'id': 'encrypt_passwords', 'type': 'boolean', 'mode': 'w',
         'label': 'Encrypt users passwords'},
        {'id': 'email_expression', 'type': 'string', 'mode': 'w',
         'label': 'E-mail should match this regular expression'},
        {'id': 'email_confirmation', 'type': 'boolean', 'mode': 'w',
         'label': 'Ask for email confirmation before add user '},
    )

    security = ClassSecurityInfo()
    #
    # Properties
    #
    encrypt_passwords = False
    email_expression = '^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$'
    email_confirmation = False

    def __init__(self, id, title):
        self.id = id
        self.title = title
        self.data = PersistentMapping()
        Role.__dict__['__init__'](self)
        plugins_tool.__dict__['__init__'](self)

    security.declarePrivate('loadDefaultData')
    def loadDefaultData(self):
        #load default stuff
        pass

    security.declarePrivate('_doAddTempUser')
    def _doAddTempUser(self, **kwargs):
        """Generate a confirmation string, add it to temp users list,
           and return it.
        """
        text = object2string(kwargs)
        if not hasattr(self, '_temp_users'):
            self._temp_users = []
        if text in self._temp_users:
            raise Exception, 'User already request access roles.'
        self._temp_users.append(text)
        self._p_changed = 1
        return text

    security.declarePrivate('_doAddUser')
    def _doAddUser(self, name, password, roles, domains, firstname, lastname, email, **kw):
        """Create a new user. The 'password' will be the
           original input password, unencrypted. This
           method is responsible for performing any needed encryption."""

        if password is not None and self.encrypt_passwords:
            password = self._encryptPassword(password)
        self.data[name] = User(name, password, roles, domains, firstname, lastname, email)
        self._p_changed = 1
        return name

    security.declarePrivate('_doChangeUser')
    def _doChangeUser(self, name, password, roles, domains, firstname, lastname, email, lastupdated, **kw):
        """Modify an existing user. The 'password' will be the
           original input password, unencrypted. The implementation of this
           method is responsible for performing any needed encryption."""

        user=self.data[name]
        if password is not None:
            if self.encrypt_passwords and not self._isPasswordEncrypted(password):
                password = self._encryptPassword(password)
            user.__ = password
        user.roles = roles
        user.domains = domains
        user.firstname = firstname
        user.lastname = lastname
        user.email = email
        user.lastupdated = lastupdated
        self._p_changed = 1

    security.declarePublic('changeLastLogin')
    def changeLastLogin(self, name):
        user=self.data.get(name, None)
        if user:
            user.lastlogin = time.strftime('%d %b %Y %H:%M:%S')
            self._p_changed = 1

    security.declarePublic('changeLastPost')
    def changeLastPost(self, name):
        user=self.data.get(name, None)
        if user:
            user.lastpost = time.strftime('%d %b %Y %H:%M:%S')
            self._p_changed = 1

    security.declareProtected(manage_users, 'getUserPass')
    def getUserPass(self):
        """Return a list of usernames"""
        temp = {}
        names=self.data.keys()
        for name in names:
            temp[name] = self.getUser(name).__
        return temp

    security.declarePrivate('_doChangeUserRoles')
    def _doChangeUserRoles(self, name, roles, **kw):
        """ """
        user=self.data[name]
        user.roles = roles
        self._p_changed = 1

    security.declarePrivate('_doDelUserRoles')
    def _doDelUserRoles(self, name, **kw):
        """ """
        for user in name:
            user_obj = self.data[user]
            user_obj.roles = []
        self._p_changed = 1

    security.declarePrivate('_doDelUsers')
    def _doDelUsers(self, names):
        """Delete one or more users."""

        for name in names:
            del self.data[name]
        self._p_changed = 1

    #zmi actions
    security.declareProtected(manage_users, 'manage_confirmUser')
    def manage_confirmUser(self, key='', REQUEST=None):
        """ Add user from key
        """
        if key not in getattr(self, '_temp_users', []):
            raise Exception, 'Invalid activation key !'
        try:
            res = string2object(key)
        except InvalidStringError, err:
            raise Exception, 'Invalid activation key !'
        else:
Exemplo n.º 16
0
class ArchetypeTool(UniqueObject, ActionProviderBase, \
                    SQLStorageConfig, Folder):
    """Archetypes tool, manage aspects of Archetype instances.
    """
    id = TOOL_NAME
    meta_type = TOOL_NAME.title().replace('_', ' ')

    implements(IArchetypeTool)

    isPrincipiaFolderish = True # Show up in the ZMI

    security = ClassSecurityInfo()

    meta_types = all_meta_types = ()

    manage_options = (
        (
        { 'label'  : 'Types',
          'action' : 'manage_debugForm',
          },

        {  'label'  : 'Catalogs',
           'action' : 'manage_catalogs',
           },

        { 'label'  : 'Templates',
          'action' : 'manage_templateForm',
          },

        {  'label'  : 'UIDs',
           'action' : 'manage_uids',
           },

        { 'label'  : 'Update Schema',
          'action' : 'manage_updateSchemaForm',
          },

        { 'label'  : 'Migration',
          'action' : 'manage_migrationForm',
          },

        ) + SQLStorageConfig.manage_options
        )

    security.declareProtected(permissions.ManagePortal,
                              'manage_uids')
    manage_uids = PageTemplateFile('viewContents', _www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_templateForm')
    manage_templateForm = PageTemplateFile('manageTemplates',_www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_debugForm')
    manage_debugForm = PageTemplateFile('generateDebug', _www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_updateSchemaForm')
    manage_updateSchemaForm = PageTemplateFile('updateSchemaForm', _www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_migrationForm')
    manage_migrationForm = PageTemplateFile('migrationForm', _www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_dumpSchemaForm')
    manage_dumpSchemaForm = PageTemplateFile('schema', _www)
    security.declareProtected(permissions.ManagePortal,
                              'manage_catalogs')
    manage_catalogs = PageTemplateFile('manage_catalogs', _www)


    def __init__(self):
        self._schemas = PersistentMapping()
        self._templates = PersistentMapping()
        self._registeredTemplates = PersistentMapping()
        # meta_type -> [names of CatalogTools]
        self.catalog_map = PersistentMapping()
        self.catalog_map['Reference'] = [] # References not in portal_catalog
        # DM (avoid persistency bug): "_types" now maps known schemas to signatures
        self._types = {}

    security.declareProtected(permissions.ManagePortal,
                              'manage_dumpSchema')
    def manage_dumpSchema(self, REQUEST=None):
        """XML Dump Schema of passed in class.
        """
        from Products.Archetypes.Schema import getSchemata
        package = REQUEST.get('package', '')
        type_name = REQUEST.get('type_name', '')
        spec = self.getTypeSpec(package, type_name)
        type = self.lookupType(package, type_name)
        options = {}
        options['classname'] = spec
        options['schematas'] = getSchemata(type['klass'])
        REQUEST.RESPONSE.setHeader('Content-Type', 'text/xml')
        return self.manage_dumpSchemaForm(**options)

    # Template Management
    # Views can be pretty generic by iterating the schema so we don't
    # register by type anymore, we just create per site selection
    # lists
    #
    # We keep two lists, all register templates and their
    # names/titles and the mapping of type to template bindings both
    # are persistent
    security.declareProtected(permissions.ManagePortal,
                              'registerTemplate')
    def registerTemplate(self, template, name=None):
        # Lookup the template by name
        if not name:
            obj = self.unrestrictedTraverse(template, None)
            try:
                name = obj.title_or_id()
            except:
                name = template

        self._registeredTemplates[template] = name


    security.declareProtected(permissions.View, 'lookupTemplates')
    def lookupTemplates(self, instance_or_portaltype=None):
        """Lookup templates by giving an instance or a portal_type.

        Returns a DisplayList.
        """
        results = []
        if not isinstance(instance_or_portaltype, basestring):
            portal_type = instance_or_portaltype.getTypeInfo().getId()
        else:
            portal_type = instance_or_portaltype
        try:
            templates = self._templates[portal_type]
        except KeyError:
            return DisplayList()
            # XXX Look this up in the types tool later
            # self._templates[instance] = ['base_view',]
            # templates = self._templates[instance]
        for t in templates:
            results.append((t, self._registeredTemplates[t]))            

        return DisplayList(results).sortedByValue()

    security.declareProtected(permissions.View, 'listTemplates')
    def listTemplates(self):
        """Lists all the templates.
        """
        return DisplayList(self._registeredTemplates.items()).sortedByValue()

    security.declareProtected(permissions.ManagePortal, 'bindTemplate')
    def bindTemplate(self, portal_type, templateList):
        """Creates binding between a type and its associated views.
        """
        self._templates[portal_type] = templateList

    security.declareProtected(permissions.ManagePortal,
                              'manage_templates')
    def manage_templates(self, REQUEST=None):
        """Sets all the template/type mappings.
        """
        prefix = 'template_names_'
        for key in REQUEST.form.keys():
            if key.startswith(prefix):
                k = key[len(prefix):]
                v = REQUEST.form.get(key)
                self.bindTemplate(k, v)

        add = REQUEST.get('addTemplate')
        name = REQUEST.get('newTemplate')
        if add and name:
            self.registerTemplate(name)

        return REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_templateForm')
    
    security.declareProtected(permissions.View, 'typeImplementsInterfaces')
    def typeImplementsInterfaces(self, type, interfaces):
        """Checks if an type uses one of the given interfaces.
        """
        if isinstance(type, dict) and type.has_key('klass'):
            type = type['klass']
        for iface in interfaces:
            res = iface.isImplementedByInstancesOf(type)
            if res:
                return True
        return False
    
    security.declareProtected(permissions.View, 'isTemplateEnabled')
    def isTemplateEnabled(self, type):
        """Checks if an type uses ITemplateMixin.
        """
        return self.typeImplementsInterfaces(type, [ITemplateMixin])
        
    security.declareProtected(permissions.View, 'listTemplateEnabledPortalTypes')
    def listTemplateEnabledPortalTypes(self):
        """Return a list of portal_types with ITemplateMixin
        """
        return self.listPortalTypesWithInterfaces([ITemplateMixin])
        
    security.declareProtected(permissions.View, 'listPortalTypesWithInterfaces')
    def listPortalTypesWithInterfaces(self, ifaces):
        """Returns a list of ftis of which the types implement one of
        the given interfaces.  Only returns AT types.

        Get a list of FTIs of types implementing IReferenceable:
        >>> tool = getToolByName(self.portal, TOOL_NAME)
        >>> meth = tool.listPortalTypesWithInterfaces
        >>> ftis = tool.listPortalTypesWithInterfaces([IReferenceable])
        
        Sort the type ids and print them:
        >>> type_ids = [fti.getId() for fti in ftis]
        >>> type_ids.sort()
        >>> type_ids
        ['ATBIFolder', 'ComplexType', ...]
        """
        pt = getToolByName(self, 'portal_types')
        value = []
        for data in listTypes():
            klass = data['klass']
            for iface in ifaces:
                if iface.isImplementedByInstancesOf(klass):
                    ti = pt.getTypeInfo(data['portal_type'])
                    if ti is not None:
                        value.append(ti)
        return value

    # Type/Schema Management
    security.declareProtected(permissions.View, 'listRegisteredTypes')
    def listRegisteredTypes(self, inProject=False, portalTypes=False):
        """Return the list of sorted types.
        """

        def type_sort(a, b):
            v = cmp(a['package'], b['package'])
            if v != False: return v
            c = cmp(a['klass'].__class__.__name__,
                    b['klass'].__class__.__name__)

            if c == False:
                return cmp(a['package'], b['package'])
            return c

        values = listTypes()
        values.sort(type_sort)

        if inProject:
            # portal_type can change (as it does after ATCT-migration), so we
            # need to check against the content_meta_type of each type-info
            ttool = getToolByName(self, 'portal_types')
            types = [ti.Metatype() for ti in ttool.listTypeInfo()]
	    if portalTypes:
                values = [v for v in values if v['portal_type'] in types]
            else:
                values = [v for v in values if v['meta_type'] in types]

        return values

    security.declareProtected(permissions.View, 'getTypeSpec')
    def getTypeSpec(self, package, type):
        t = self.lookupType(package, type)
        module = t['klass'].__module__
        klass = t['name']
        return '%s.%s' % (module, klass)

    security.declareProtected(permissions.View, 'listTypes')
    def listTypes(self, package=None, type=None):
        """Just the class.
        """
        if type is None:
            return [t['klass'] for t in listTypes(package)]
        else:
            return [getType(type, package)['klass']]

    security.declareProtected(permissions.View, 'lookupType')
    def lookupType(self, package, type):
        types = self.listRegisteredTypes()
        for t in types:
            if t['package'] != package:
                continue
            if t['meta_type'] == type:
                # We have to return the schema wrapped into the acquisition of
                # something to allow access. Otherwise we will end up with:
                # Your user account is defined outside the context of the object
                # being accessed.
                t['schema'] = ImplicitAcquisitionWrapper(t['schema'], self)
                return t
        return None

    security.declareProtected(permissions.ManagePortal,
                              'manage_installType')
    def manage_installType(self, typeName, package=None,
                           uninstall=None, REQUEST=None):
        """Un/Install a type TTW.
        """
        typesTool = getToolByName(self, 'portal_types')
        try:
            typesTool._delObject(typeName)
        except (ConflictError, KeyboardInterrupt):
            raise
        except: # XXX bare exception
            pass
        if uninstall is not None:
            if REQUEST:
                return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                                 '/manage_debugForm')
            return

        typeinfo_name = '%s: %s' % (package, typeName)

        # We want to run the process/modify_fti code which might not
        # have been called
        typeDesc = getType(typeName, package)
        process_types([typeDesc], package)
        klass = typeDesc['klass']
        
        # get the meta type of the FTI from the class, use the default FTI as default
        fti_meta_type = getattr(klass, '_at_fti_meta_type', None)
        if fti_meta_type in (None, 'simple item'):
            fti_meta_type = FactoryTypeInformation.meta_type

        typesTool.manage_addTypeInformation(fti_meta_type,
                                            id=typeName,
                                            typeinfo_name=typeinfo_name)
        t = getattr(typesTool, typeName, None)
        if t:
            t.title = getattr(klass, 'archetype_name',
                              typeDesc['portal_type'])

        # and update the actions as needed
        fixActionsForType(klass, typesTool)

        if REQUEST:
            return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                             '/manage_debugForm')

    security.declarePublic('getSearchWidgets')
    def getSearchWidgets(self, package=None, type=None,
                         context=None, nosort=None):
        """Empty widgets for searching.
        """
        return self.getWidgets(package=package, type=type,
                               context=context, mode='search', nosort=nosort)

    security.declarePublic('getWidgets')
    def getWidgets(self, instance=None,
                   package=None, type=None,
                   context=None, mode='edit',
                   fields=None, schemata=None, nosort=None):
        """Empty widgets for standalone rendering.
        """
        widgets = []
        w_keys = {}
        context = context is not None and context or self
        instances = instance is not None and [instance] or []
        f_names = fields
        if not instances:
            for t in self.listTypes(package, type):
                instance = t('fake_instance')
                instance._at_is_fake_instance = True
                wrapped = instance.__of__(context)
                wrapped.initializeArchetype()
                instances.append(wrapped)
        for instance in instances:
            if schemata is not None:
                schema = instance.Schemata()[schemata].copy()
            else:
                schema = instance.Schema().copy()
            fields = schema.fields()
            if mode == 'search':
                # Include only fields which have an index
                # XXX duplicate fieldnames may break this,
                # as different widgets with the same name
                # on different schemas means only the first
                # one found will be used
                indexes=self.portal_catalog.indexes()
                fields = [f for f in fields
                          if (f.accessor and
                              not w_keys.has_key(f.accessor)
                              and f.accessor in indexes)]
            if f_names is not None:
                fields = filter(lambda f: f.getName() in f_names, fields)
            for field in fields:
                widget = field.widget
                field_name = field.getName()
                accessor = field.getAccessor(instance)
                if mode == 'search':
                    field.required = False
                    field.addable = False # for ReferenceField
                    if not isinstance(field.vocabulary, DisplayList):
                        field.vocabulary = field.Vocabulary(instance)
                    if '' not in field.vocabulary.keys():
                        field.vocabulary = DisplayList([('', _(u'at_search_any', default=u'<any>'))]) + \
                                           field.vocabulary
                    widget.populate = False
                    field_name = field.accessor
                    # accessor must be a method which doesn't take an argument
                    # this lambda is facking an accessor
                    accessor = lambda: field.getDefault(instance)

                w_keys[field_name] = None
                widgets.append((field_name, WidgetWrapper(
                    field_name=field_name,
                    mode=mode,
                    widget=widget,
                    instance=instance,
                    field=field,
                    accessor=accessor)))
        if mode == 'search' and nosort == None:
            widgets.sort()
        return [widget for name, widget in widgets]

    security.declarePrivate('_rawEnum')
    def _rawEnum(self, callback, *args, **kwargs):
        """Finds all object to check if they are 'referenceable'.
        """
        catalog = getToolByName(self, 'portal_catalog')
        brains = catalog(id=[])
        for b in brains:
            o = b.getObject()
            if o is not None:
                if IBaseObject.isImplementedBy(o):
                    callback(o, *args, **kwargs)
            else:
                log('no object for brain: %s:%s' % (b,b.getURL()))


    security.declareProtected(permissions.View, 'enum')
    def enum(self, callback, *args, **kwargs):
        catalog = getToolByName(self, UID_CATALOG)
        keys = catalog.uniqueValuesFor('UID')
        for uid in keys:
            o = self.getObject(uid)
            if o:
                callback(o, *args, **kwargs)
            else:
                log('No object for %s' % uid)


    security.declareProtected(permissions.View, 'Content')
    def Content(self):
        """Return a list of all the content ids.
        """
        catalog = getToolByName(self, UID_CATALOG)
        keys = catalog.uniqueValuesFor('UID')
        results = catalog(UID=keys)
        return results


    ## Management Forms
    security.declareProtected(permissions.ManagePortal,
                              'manage_doGenerate')
    def manage_doGenerate(self, sids=(), REQUEST=None):
        """(Re)generate types.
        """
        schemas = []
        for sid in sids:
            schemas.append(self.getSchema(sid))

        for s in schemas:
            s.generate()

        if REQUEST:
            return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                             '/manage_workspace')

    security.declareProtected(permissions.ManagePortal,
                              'manage_inspect')
    def manage_inspect(self, UID, REQUEST=None):
        """Dump some things about an object hook in the debugger for now.
        """
        object = self.getObject(UID)
        log(object, object.Schema(), dir(object))

        return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                         '/manage_uids')

    security.declareProtected(permissions.ManagePortal,
                              'manage_reindex')
    def manage_reindex(self, REQUEST=None):
        """Assign UIDs to all basecontent objects.
        """

        def _index(object, archetype_tool):
            archetype_tool.registerContent(object)

        self._rawEnum(_index, self)

        return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                         '/manage_uids')

    security.declareProtected(permissions.ManagePortal, 'index')
    index = manage_reindex

    def _listAllTypes(self):
        """List all types -- either currently known or known to us.
        """
        allTypes = _types.copy(); allTypes.update(self._types)
        return allTypes.keys()

    security.declareProtected(permissions.ManagePortal,
                              'getChangedSchema')
    def getChangedSchema(self):
        """Returns a list of tuples indicating which schema have changed.

        Tuples have the form (schema, changed).
        """
        list = []
        currentTypes = _types
        ourTypes = self._types
        modified = False
        keys = self._listAllTypes()
        keys.sort()
        for t in keys:
            if t not in ourTypes:
                # Add it
                ourTypes[t] = currentTypes[t]['signature']
                modified = True
                list.append((t, 0))
            elif t not in currentTypes:
                # Huh: what shall we do? We remove it -- this might be wrong!
                del ourTypes[t]
                modified = True
                # We do not add an entry because we cannot update
                # these objects (having no longer type information for them)
            else:
                list.append((t, ourTypes[t] != currentTypes[t]['signature']))
        if modified:
            self._p_changed = True
        return list


    security.declareProtected(permissions.ManagePortal,
                              'manage_updateSchema')
    def manage_updateSchema(self, REQUEST=None, update_all=None,
                            remove_instance_schemas=None):
        """Make sure all objects' schema are up to date.
        """
        out = StringIO()
        print >> out, 'Updating schema...'

        update_types = []
        if REQUEST is None:
            # DM (avoid persistency bug): avoid code duplication
            update_types = [ti[0] for ti in self.getChangedSchema() if ti[1]]
        else:
            # DM (avoid persistency bug):
            for t in self._listAllTypes():
                if REQUEST.form.get(t, False):
                    update_types.append(t)
            update_all = REQUEST.form.get('update_all', False)
            remove_instance_schemas = REQUEST.form.get(
                'remove_instance_schemas', False)

        # XXX: Enter this block only when there are types to update!
        if update_types:
            # Use the catalog's ZopeFindAndApply method to walk through
            # all objects in the portal.  This works much better than
            # relying on the catalog to find objects, because an object
            # may be uncatalogable because of its schema, and then you
            # can't update it if you require that it be in the catalog.
            catalog = getToolByName(self, 'portal_catalog')
            portal = getToolByName(self, 'portal_url').getPortalObject()
            meta_types = [_types[t]['meta_type'] for t in update_types]
            if remove_instance_schemas:
                func_update_changed = self._removeSchemaAndUpdateChangedObject
                func_update_all = self._removeSchemaAndUpdateObject
            else:
                func_update_changed = self._updateChangedObject
                func_update_all = self._updateObject
            if update_all:
                catalog.ZopeFindAndApply(portal, obj_metatypes=meta_types,
                    search_sub=True, apply_func=func_update_all)
            else:
                catalog.ZopeFindAndApply(portal, obj_metatypes=meta_types,
                    search_sub=True, apply_func=func_update_changed)
            for t in update_types:
                self._types[t] = _types[t]['signature']
            self._p_changed = True

        print >> out, 'Done.'
        return out.getvalue()

    # A counter to ensure that in a given interval a subtransaction
    # commit is done.
    subtransactioncounter = 0

    def _updateObject(self, o, path, remove_instance_schemas=None):
        o._updateSchema(remove_instance_schemas=remove_instance_schemas)
        # Subtransactions to avoid eating up RAM when used inside a
        # 'ZopeFindAndApply' like in manage_updateSchema
        self.subtransactioncounter += 1
        # Only every 250 objects a sub-commit, otherwise it eats up all diskspace
        if not self.subtransactioncounter % 250:
            transaction.savepoint(optimistic=True)

    def _updateChangedObject(self, o, path):
        if not o._isSchemaCurrent():
            self._updateObject(o, path)

    def _removeSchemaAndUpdateObject(self, o, path):
        self._updateObject(o, path, remove_instance_schemas=True)

    def _removeSchemaAndUpdateChangedObject(self, o, path):
        if not o._isSchemaCurrent():
            self._removeSchemaAndUpdateObject(o, path)

    security.declareProtected(permissions.ManagePortal,
                              'manage_updateSchema')
    def manage_migrate(self, REQUEST=None):
        """Run Extensions.migrations.migrate.
        """
        from Products.Archetypes.Extensions.migrations import migrate
        out = migrate(self)
        self.manage_updateSchema()
        return out

    # Catalog management
    security.declareProtected(permissions.View,
                              'listCatalogs')
    def listCatalogs(self):
        """Show the catalog mapping.
        """
        return self.catalog_map

    security.declareProtected(permissions.ManagePortal,
                              'manage_updateCatalogs')
    def manage_updateCatalogs(self, REQUEST=None):
        """Set the catalog map for meta_type to include the list
        catalog_names.
        """
        prefix = 'catalog_names_'
        for key in REQUEST.form.keys():
            if key.startswith(prefix):
                k = key[len(prefix):]
                v = REQUEST.form.get(key)
                self.setCatalogsByType(k, v)

        return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                         '/manage_catalogs')

    security.declareProtected(permissions.ManagePortal,
                              'setCatalogsByType')
    def setCatalogsByType(self, portal_type, catalogList):
        """ associate catalogList with meta_type. (unfortunally not portal_type).
        
            catalogList is a list of strings with the ids of the catalogs.
            Each catalog is has to be a tool, means unique in site root.
        """
        self.catalog_map[portal_type] = catalogList


    security.declareProtected(permissions.View, 'getCatalogsByType')
    def getCatalogsByType(self, portal_type):
        """Return the catalog objects assoicated with a given type.
        """
        catalogs = []
        catalog_map = getattr(self, 'catalog_map', None)
        if catalog_map is not None:
            names = self.catalog_map.get(portal_type, ['portal_catalog'])
        else:
            names = ['portal_catalog']
        portal = getToolByName(self, 'portal_url').getPortalObject()
        for name in names:
            try:
                catalogs.append(getToolByName(portal, name))
            except (ConflictError, KeyboardInterrupt):
                raise
            except Exception, E:
                log('No tool', name, E)
                pass
        return catalogs
Exemplo n.º 17
0
class MembershipTool (UniqueObject, SimpleItem, ActionProviderBase):
    # This tool accesses member data through an acl_users object.
    # It can be replaced with something that accesses member data in
    # a different way.
    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'
    _actions = []
    security = ClassSecurityInfo()
    memberareaCreationFlag = 1

    manage_options=( ({ 'label' : 'Configuration'
                     , 'action' : 'manage_mapRoles'
                     },) +
                     ActionProviderBase.manage_options + 
                   ( { 'label' : 'Overview'
                     , 'action' : 'manage_overview'
                     },
                   ) + SimpleItem.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected( CMFCorePermissions.ManagePortal
                             , 'manage_overview' )
    manage_overview = DTMLFile( 'explainMembershipTool', _dtmldir )
 
    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir )
 
    security.declareProtected(CMFCorePermissions.SetOwnPassword, 'setPassword')
    def setPassword(self, password, domains=None):
        '''Allows the authenticated member to set his/her own password.
        '''
        registration = getToolByName(self, 'portal_registration', None)
        if not self.isAnonymousUser():
            member = self.getAuthenticatedMember()
            if registration:
                failMessage = registration.testPasswordValidity(password)
                if failMessage is not None:
                    raise 'Bad Request', failMessage
            member.setSecurityProfile(password=password, domains=domains)
        else:
            raise 'Bad Request', 'Not logged in.'

    security.declarePublic('getAuthenticatedMember')
    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')
    def wrapUser(self, u, wrap_anon=0):
        '''
        Sets up the correct acquisition wrappers for a user
        object and provides an opportunity for a portal_memberdata
        tool to retrieve and store member data independently of
        the user object.
        '''
        b = getattr(u, 'aq_base', None)
        if b is None:
            # u isn't wrapped at all.  Wrap it in self.acl_users.
            b = u
            u = u.__of__(self.acl_users)
        if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'):
            # This user is either not recognized by acl_users or it is
            # already registered with something that implements the 
            # member data tool at least partially.
            return u
        
        parent = self.aq_inner.aq_parent
        base = getattr(parent, 'aq_base', None)
        if hasattr(base, 'portal_memberdata'):
            # Apply any role mapping if we have it
            if hasattr(self, 'role_map'):
                for portal_role in self.role_map.keys():
                    if (self.role_map.get(portal_role) in u.roles and
                            portal_role not in u.roles):
                        u.roles.append(portal_role)

            # Get portal_memberdata to do the wrapping.
            md = getToolByName(parent, 'portal_memberdata')
            try:
                portal_user = md.wrapUser(u)

                # Check for the member area creation flag and
                # take appropriate (non-) action
                if getattr(self, 'memberareaCreationFlag', 0) != 0:
                    if self.getHomeUrl(portal_user.getId()) is None:
                        self.createMemberarea(portal_user.getId())

                return portal_user
            except ConflictError:
                raise
            except:
                from zLOG import LOG, ERROR
                import sys
                type,value,tb = sys.exc_info()
                try:
                    LOG('CMFCore.MembershipTool',
                        ERROR,
                        'Error during wrapUser:'******'getPortalRoles')
    def getPortalRoles(self):
        """
        Return all local roles defined by the portal itself,
        which means roles that are useful and understood 
        by the portal object
        """
        parent = self.aq_inner.aq_parent
        roles = list(parent.__ac_roles__)

        # This is *not* a local role in the portal but used by it
        roles.append('Manager')
        roles.append('Owner')

        return roles

    security.declareProtected(ManagePortal, 'setRoleMapping')
    def setRoleMapping(self, portal_role, userfolder_role):
        """
        set the mapping of roles between roles understood by 
        the portal and roles coming from outside user sources
        """
        if not hasattr(self, 'role_map'): self.role_map = PersistentMapping()

        if len(userfolder_role) < 1:
            del self.role_map[portal_role]
        else:
            self.role_map[portal_role] = userfolder_role

        return MessageDialog(
               title  ='Mapping updated',
               message='The Role mappings have been updated',
               action ='manage_mapRoles')

    security.declareProtected(ManagePortal, 'getMappedRole')
    def getMappedRole(self, portal_role):
        """
        returns a role name if the portal role is mapped to
        something else or an empty string if it is not
        """
        if hasattr(self, 'role_map'):
            return self.role_map.get(portal_role, '')
        else:
            return ''

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')
    def getMemberareaCreationFlag(self):
        """
        Returns the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going 
        through the join process
        """
        return self.memberareaCreationFlag

    security.declareProtected(ManagePortal, 'setMemberareaCreationFlag')
    def setMemberareaCreationFlag(self):
        """
        sets the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        if self.memberareaCreationFlag == 0:
            self.memberareaCreationFlag = 1
        else:
            self.memberareaCreationFlag = 0

        return MessageDialog(
               title  ='Member area creation flag changed',
               message='Member area creation flag has been updated',
               action ='manage_mapRoles')

    security.declareProtected(ManagePortal, 'createMemberarea')
    def createMemberarea(self, member_id):
        """
        create a member area
        """
        parent = self.aq_inner.aq_parent
        members =  getattr(parent, 'Members', None)
        user = self.acl_users.getUser( member_id ).__of__( self.acl_users )
        
        if members is not None and user is not None:
            f_title = "%s's Home" % member_id
            members.manage_addPortalFolder( id=member_id, title=f_title )
            f=getattr(members, member_id)
 
            f.manage_permission(CMFCorePermissions.View,
                                ['Owner','Manager','Reviewer'], 0)
            f.manage_permission(CMFCorePermissions.AccessContentsInformation,
                                ['Owner','Manager','Reviewer'], 0)  

            # Grant ownership to Member
            try: f.changeOwnership(user)
            except AttributeError: pass  # Zope 2.1.x compatibility
            f.manage_setLocalRoles(member_id, ['Owner'])


    security.declarePublic('isAnonymousUser')
    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')
    def checkPermission(self, permissionName, object, subobjectName=None):
        '''
        Checks whether the current user has the given permission on
        the given object or subobject.
        '''
        if subobjectName is not None:
            object = getattr(object, subobjectName)
        return _checkPermission(permissionName, object)

    security.declarePublic('credentialsChanged')
    def credentialsChanged(self, password):
        '''
        Notifies the authentication mechanism that this user has changed
        passwords.  This can be used to update the authentication cookie.
        Note that this call should *not* cause any change at all to user
        databases.
        '''
        if not self.isAnonymousUser():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            id = user.getUserName()
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, id, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, id, password)

    security.declareProtected(ManagePortal, 'getMemberById')
    def getMemberById(self, id):
        '''
        Returns the given member.
        '''
        u = self.acl_users.getUser(id)
        if u is not None:
            u = self.wrapUser(u)
        return u

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManagePortal, 'listMemberIds')
    def listMemberIds(self):
        '''Lists the ids of all members.  This may eventually be
        replaced with a set of methods for querying pieces of the
        list rather than the entire list at once.
        '''
        return self.__getPUS().getUserNames()
    
    security.declareProtected(ManagePortal, 'listMembers')
    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declareProtected( CMFCorePermissions.ListPortalMembers
                             , 'searchMembers')
    def searchMembers( self, search_param, search_term ):
        """ Search the membership """
        md = getToolByName( self, 'portal_memberdata' )

        return md.searchMemberDataContents( search_param, search_term )

        
    security.declareProtected(CMFCorePermissions.View, 'getCandidateLocalRoles')
    def getCandidateLocalRoles( self, obj ):
        """ What local roles can I assign? """
        member = self.getAuthenticatedMember()

        if 'Manager' in member.getRoles():
            return self.getPortalRoles()
        else:
            member_roles = list( member.getRolesInContext( obj ) )
            del member_roles[member_roles.index( 'Member')]

        return tuple( member_roles )

    security.declareProtected(CMFCorePermissions.View, 'setLocalRoles')
    def setLocalRoles( self, obj, member_ids, member_role, reindex=1 ):
        """ Set local roles on an item """
        member = self.getAuthenticatedMember()
        my_roles = member.getRolesInContext( obj )

        if 'Manager' in my_roles or member_role in my_roles:
            for member_id in member_ids:
                roles = list(obj.get_local_roles_for_userid( userid=member_id ))

                if member_role not in roles:
                    roles.append( member_role )
                    obj.manage_setLocalRoles( member_id, roles )

        if reindex:
            # It is assumed that all objects have the method
            # reindexObjectSecurity, which is in CMFCatalogAware and
            # thus PortalContent and PortalFolder.
            obj.reindexObjectSecurity()

    security.declareProtected(CMFCorePermissions.View, 'deleteLocalRoles')
    def deleteLocalRoles( self, obj, member_ids, reindex=1 ):
        """ Delete local roles for members member_ids """
        member = self.getAuthenticatedMember()
        my_roles = member.getRolesInContext( obj )

        if 'Manager' in my_roles or 'Owner' in my_roles:
            obj.manage_delLocalRoles( userids=member_ids )

        if reindex:
            obj.reindexObjectSecurity()

    security.declarePrivate('addMember')
    def addMember(self, id, password, roles, domains, properties=None):
        '''Adds a new member to the user folder.  Security checks will have
        already been performed.  Called by portal_registration.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_addUser'):
            acl_users._addUser(id, password, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            membership = getToolByName(self, 'portal_membership')
            member = membership.getMemberById(id)
            member.setMemberProperties(properties)


    security.declarePrivate('listActions')
    def listActions(self, info=None):
        return None

    security.declarePublic('getHomeFolder')
    def getHomeFolder(self, id=None, verifyPermission=0):
        """Returns a member's home folder object or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
        
    security.declarePublic('getHomeUrl')
    def getHomeUrl(self, id=None, verifyPermission=0):
        """Returns the URL to a member's home folder or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
Exemplo n.º 18
0
class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
    """Stores messages and their translations...
    """

    meta_type = "MessageCatalog"

    security = ClassSecurityInfo()

    def __init__(self, id, title, sourcelang, languages):
        self.id = id

        self.title = title

        # Language Manager data
        self._languages = tuple(languages)
        self._default_language = sourcelang

        # Here the message translations are stored
        self._messages = PersistentMapping()

        # Data for the PO files headers
        self._po_headers = PersistentMapping()
        for lang in self._languages:
            self._po_headers[lang] = empty_po_header

    #######################################################################
    # Private API
    #######################################################################
    def get_message_key(self, message):
        if message in self._messages:
            return message
        # A message may be stored as unicode or byte string
        encoding = HTTPRequest.default_encoding
        if isinstance(message, unicode):
            message = message.encode(encoding)
        else:
            message = unicode(message, encoding)
        if message in self._messages:
            return message

    def get_translations(self, message):
        message = self.get_message_key(message)
        return self._messages[message]

    #######################################################################
    # Public API
    #######################################################################
    security.declarePublic("message_exists")

    def message_exists(self, message):
        """ """
        return self._messages.has_key(message)

    security.declareProtected("Manage messages", "message_edit")

    def message_edit(self, message, language, translation, note):
        """ """
        self._messages[message][language] = translation
        self._messages[message]["note"] = note

    security.declareProtected("Manage messages", "message_del")

    def message_del(self, message):
        """ """
        del self._messages[message]

    security.declarePublic("gettext")

    def gettext(self, message, lang=None, add=1, default=None):
        """Returns the message translation from the database if available.

        If add=1, add any unknown message to the database.
        If a default is provided, use it instead of the message id
        as a translation for unknown messages.
        """
        if not isinstance(message, (str, unicode)):
            raise TypeError, "only strings can be translated."

        message = message.strip()
        # assume empty message is always translated as empty message
        if not message:
            return message

        if default is None:
            default = message

        # Add it if it's not in the dictionary
        if add and not self._messages.has_key(message) and message:
            update_transaction_note()
            self._messages[message] = PersistentMapping()

        if message and not self._messages[message].has_key("en"):
            self._messages[message]["en"] = default

        # Get the string
        if self._messages.has_key(message):
            m = self._messages[message]

            if lang is None:
                # Builds the list of available languages
                # should the empty translations be filtered?
                available_languages = list(self._languages)

                # Imagine that the default language is 'en'. There is no
                # translation from 'en' to 'en' in the message catalog
                # The user has the preferences 'en' and 'nl' in that order
                # The next two lines make certain 'en' is shown, not 'nl'
                if not self._default_language in available_languages:
                    available_languages.append(self._default_language)

                # Get the language!
                lang = lang_negotiator(available_languages)

                # Is it None? use the default
                if lang is None:
                    lang = self._default_language

            if lang is not None:
                return m.get(lang) or default

        return default

    __call__ = gettext

    def translate(self, domain, msgid, *args, **kw):
        """This method is required to get the i18n namespace from ZPT working.
        """

        default = kw.get("default")
        if default is not None and not default.strip():
            default = None
        msgstr = self.gettext(msgid, default=default)
        mapping = kw.get("mapping")
        return interpolate(msgstr, mapping)

    #######################################################################
    # Management screens
    #######################################################################
    def manage_options(self):
        """ """
        options = (
            (
                {"label": u"Messages", "action": "manage_messages", "help": ("Localizer", "MC_messages.stx")},
                {"label": u"Properties", "action": "manage_propertiesForm"},
                {"label": u"Import", "action": "manage_Import_form", "help": ("Localizer", "MC_importExport.stx")},
                {"label": u"Export", "action": "manage_Export_form", "help": ("Localizer", "MC_importExport.stx")},
            )
            + LanguageManager.manage_options
            + SimpleItem.manage_options
        )

        r = []
        for option in options:
            option = option.copy()
            option["label"] = _(option["label"])
            r.append(option)

        return r

    #######################################################################
    # Management screens -- Messages
    #######################################################################
    security.declareProtected("Manage messages", "manage_messages")
    manage_messages = LocalDTMLFile("ui/MC_messages", globals())

    security.declarePublic("get_namespace")

    def get_namespace(self, REQUEST):
        """For the management interface, allows to filter the messages to
        show.
        """
        # Check whether there are languages or not
        languages = self.get_languages_mapping()
        if not languages:
            return {}

        # Input
        batch_start = REQUEST.get("batch_start", 0)
        batch_size = REQUEST.get("batch_size", 15)
        empty = REQUEST.get("empty", 0)
        regex = REQUEST.get("regex", "")
        message = REQUEST.get("msg", None)

        # Build the namespace
        namespace = {}
        namespace["batch_size"] = batch_size
        namespace["empty"] = empty
        namespace["regex"] = regex

        # The language
        lang = REQUEST.get("lang", None) or languages[0]["code"]
        namespace["language"] = lang

        # Filter the messages
        query = regex.strip()
        try:
            query = compile(query)
        except:
            query = compile("")

        messages = []
        for m, t in self._messages.items():
            if query.search(m) and (not empty or not t.get(lang, "").strip()):
                messages.append(m)
        messages.sort(filter_sort)
        # How many messages
        n = len(messages)
        namespace["n_messages"] = n

        # Calculate the start
        while batch_start >= n:
            batch_start = batch_start - batch_size
        if batch_start < 0:
            batch_start = 0
        namespace["batch_start"] = batch_start
        # Select the batch to show
        batch_end = batch_start + batch_size
        messages = messages[batch_start:batch_end]
        # Batch links
        namespace["previous"] = get_url(REQUEST.URL, batch_start - batch_size, batch_size, regex, lang, empty)
        namespace["next"] = get_url(REQUEST.URL, batch_start + batch_size, batch_size, regex, lang, empty)

        # Get the message
        message_encoded = None
        translations = {}
        if message is None:
            if messages:
                message = messages[0]
                translations = self.get_translations(message)
                message = to_unicode(message)
                message_encoded = message_encode(message)
        else:
            message_encoded = message
            message = message_decode(message_encoded)
            translations = self.get_translations(message)
            message = to_unicode(message)
        namespace["message"] = message
        namespace["message_encoded"] = message_encoded
        namespace["translations"] = translations
        namespace["translation"] = translations.get(lang, "")
        namespace["note"] = translations.get("note", "")

        # Calculate the current message
        namespace["messages"] = []
        for x in messages:
            x = to_unicode(x)
            x_encoded = message_encode(x)
            url = get_url(REQUEST.URL, batch_start, batch_size, regex, lang, empty, msg=x_encoded)
            namespace["messages"].append(
                {"message": x, "message_encoded": x_encoded, "current": x == message, "url": url}
            )

        # The languages
        for language in languages:
            code = language["code"]
            language["name"] = _(language["name"], language=code)
            language["url"] = get_url(REQUEST.URL, batch_start, batch_size, regex, code, empty, msg=message_encoded)
        namespace["languages"] = languages

        return namespace

    security.declareProtected("Manage messages", "manage_editMessage")

    def manage_editMessage(self, message, language, translation, note, REQUEST, RESPONSE):
        """Modifies a message.
        """
        message_encoded = message
        message = message_decode(message_encoded)
        message_key = self.get_message_key(message)
        self.message_edit(message_key, language, translation, note)

        url = get_url(
            REQUEST.URL1 + "/manage_messages",
            REQUEST["batch_start"],
            REQUEST["batch_size"],
            REQUEST["regex"],
            REQUEST.get("lang", ""),
            REQUEST.get("empty", 0),
            msg=message_encoded,
            manage_tabs_message=_(u"Saved changes."),
        )
        RESPONSE.redirect(url)

    security.declareProtected("Manage messages", "manage_delMessage")

    def manage_delMessage(self, message, REQUEST, RESPONSE):
        """ """
        message = message_decode(message)
        message_key = self.get_message_key(message)
        self.message_del(message_key)

        url = get_url(
            REQUEST.URL1 + "/manage_messages",
            REQUEST["batch_start"],
            REQUEST["batch_size"],
            REQUEST["regex"],
            REQUEST.get("lang", ""),
            REQUEST.get("empty", 0),
            manage_tabs_message=_(u"Saved changes."),
        )
        RESPONSE.redirect(url)

    #######################################################################
    # Management screens -- Properties
    # Management screens -- Import/Export
    # FTP access
    #######################################################################
    security.declareProtected("View management screens", "manage_propertiesForm")
    manage_propertiesForm = LocalDTMLFile("ui/MC_properties", globals())

    security.declareProtected("View management screens", "manage_properties")

    def manage_properties(self, title, REQUEST=None, RESPONSE=None):
        """Change the Message Catalog properties.
        """
        self.title = title

        if RESPONSE is not None:
            RESPONSE.redirect("manage_propertiesForm")

    # Properties management screen
    security.declareProtected("View management screens", "get_po_header")

    def get_po_header(self, lang):
        """ """
        # For backwards compatibility
        if not hasattr(aq_base(self), "_po_headers"):
            self._po_headers = PersistentMapping()

        return self._po_headers.get(lang, empty_po_header)

    security.declareProtected("View management screens", "update_po_header")

    def update_po_header(
        self,
        lang,
        last_translator_name=None,
        last_translator_email=None,
        language_team=None,
        charset=None,
        REQUEST=None,
        RESPONSE=None,
    ):
        """ """
        header = self.get_po_header(lang)

        if last_translator_name is None:
            last_translator_name = header["last_translator_name"]

        if last_translator_email is None:
            last_translator_email = header["last_translator_email"]

        if language_team is None:
            language_team = header["language_team"]

        if charset is None:
            charset = header["charset"]

        header = {
            "last_translator_name": last_translator_name,
            "last_translator_email": last_translator_email,
            "language_team": language_team,
            "charset": charset,
        }

        self._po_headers[lang] = header

        if RESPONSE is not None:
            RESPONSE.redirect("manage_propertiesForm")

    security.declareProtected("View management screens", "manage_Import_form")
    manage_Import_form = LocalDTMLFile("ui/MC_Import_form", globals())

    security.declarePublic("get_charsets")

    def get_charsets(self):
        """ """
        return charsets[:]

    security.declarePublic("manage_export")

    def manage_export(self, x, REQUEST=None, RESPONSE=None):
        """Exports the content of the message catalog either to a template
        file (locale.pot) or to an language specific PO file (<x>.po).
        """
        # Get the PO header info
        header = self.get_po_header(x)
        last_translator_name = header["last_translator_name"]
        last_translator_email = header["last_translator_email"]
        language_team = header["language_team"]
        charset = header["charset"]

        # PO file header, empty message.
        po_revision_date = strftime("%Y-%m-%d %H:%m+%Z", gmtime(time()))
        pot_creation_date = po_revision_date
        last_translator = "%s <%s>" % (last_translator_name, last_translator_email)

        if x == "locale.pot":
            language_team = "LANGUAGE <*****@*****.**>"
        else:
            language_team = "%s <%s>" % (x, language_team)

        r = [
            'msgid ""',
            'msgstr "Project-Id-Version: %s\\n"' % self.title,
            '"POT-Creation-Date: %s\\n"' % pot_creation_date,
            '"PO-Revision-Date: %s\\n"' % po_revision_date,
            '"Last-Translator: %s\\n"' % last_translator,
            '"Language-Team: %s\\n"' % language_team,
            '"MIME-Version: 1.0\\n"',
            '"Content-Type: text/plain; charset=%s\\n"' % charset,
            '"Content-Transfer-Encoding: 8bit\\n"',
            "",
            "",
        ]

        # Get the messages, and perhaps its translations.
        d = {}
        if x == "locale.pot":
            filename = x
            for k in self._messages.keys():
                d[k] = ""
        else:
            filename = "%s.po" % x
            for k, v in self._messages.items():
                try:
                    d[k] = v[x]
                except KeyError:
                    d[k] = ""

        # Generate the file
        def backslashescape(x):
            quote_esc = compile(r'"')
            x = quote_esc.sub('\\"', x)

            trans = [("\n", "\\n"), ("\r", "\\r"), ("\t", "\\t")]
            for a, b in trans:
                x = x.replace(a, b)

            return x

        # Generate sorted msgids to simplify diffs
        dkeys = d.keys()
        dkeys.sort()
        for k in dkeys:
            r.append('msgid "%s"' % backslashescape(k))
            v = d[k]
            r.append('msgstr "%s"' % backslashescape(v))
            r.append("")

        if RESPONSE is not None:
            RESPONSE.setHeader("Content-type", "application/data")
            RESPONSE.setHeader("Content-Disposition", "inline;filename=%s" % filename)

        r2 = []
        for x in r:
            if isinstance(x, unicode):
                r2.append(x.encode(charset))
            else:
                r2.append(x)

        return "\n".join(r2)

    security.declareProtected("Manage messages", "po_import")

    def po_import(self, lang, data):
        """ """
        messages = self._messages

        # Load the data
        po = POFile(string=data)
        for msgid in po.get_msgids():
            if msgid:
                msgstr = po.get_msgstr(msgid) or ""
                if not messages.has_key(msgid):
                    messages[msgid] = PersistentMapping()
                messages[msgid][lang] = msgstr

        # Set the encoding (the full header should be loaded XXX)
        self.update_po_header(lang, charset=po.get_encoding())

    security.declareProtected("Manage messages", "manage_import")

    def manage_import(self, lang, file, REQUEST=None, RESPONSE=None):
        """ """
        # XXX For backwards compatibility only, use "po_import" instead.
        if isinstance(file, str):
            content = file
        else:
            content = file.read()

        self.po_import(lang, content)

        if RESPONSE is not None:
            RESPONSE.redirect("manage_messages")

    def objectItems(self, spec=None):
        """ """
        for lang in self._languages:
            if not hasattr(aq_base(self), lang):
                self._setObject(lang, POFile(lang))

        r = MessageCatalog.inheritedAttribute("objectItems")(self, spec)
        return r

    #######################################################################
    # TMX support
    security.declareProtected("View management screens", "manage_Export_form")
    manage_Export_form = LocalDTMLFile("ui/MC_Export_form", globals())

    security.declareProtected("Manage messages", "tmx_export")

    def tmx_export(self, REQUEST, RESPONSE=None):
        """Exports the content of the message catalog to a TMX file
        """
        orglang = self._default_language

        # Get the header info
        header = self.get_po_header(orglang)
        charset = header["charset"]

        # build data structure for the xml header
        xml_header = {}
        xml_header["standalone"] = -1
        xml_header["xml_version"] = u"1.0"
        xml_header["document_type"] = (u"tmx", u"http://www.lisa.org/tmx/tmx14.dtd")
        # build data structure for the tmx header
        version = u"1.4"
        tmx_header = {}
        tmx_header["creationtool"] = u"Localizer"
        tmx_header["creationtoolversion"] = u"1.x"
        tmx_header["datatype"] = u"plaintext"
        tmx_header["segtype"] = u"paragraph"
        tmx_header["adminlang"] = u"%s" % orglang
        tmx_header["srclang"] = u"%s" % orglang
        tmx_header["o-encoding"] = u"%s" % charset.lower()

        # handle messages
        d = {}
        filename = "%s.tmx" % self.id
        for msgkey, transunit in self._messages.items():
            sentences = {}
            for lang in transunit.keys():
                if lang != "note":
                    s = Sentence(transunit[lang], {"lang": "%s" % lang})
                    sentences[lang] = s

            if orglang not in transunit.keys():
                s = Sentence(msgkey, {"lang": "%s" % orglang})
                sentences[orglang] = s

            if transunit.has_key("note"):
                d[msgkey] = Message(sentences, {}, [Note(transunit.get("note"))])
            else:
                d[msgkey] = Message(sentences)

        tmx = TMX()
        tmx.build(xml_header, version, tmx_header, d)

        if RESPONSE is not None:
            RESPONSE.setHeader("Content-type", "application/data")
            RESPONSE.setHeader("Content-Disposition", 'attachment; filename="%s"' % filename)

        return tmx.to_str()

    security.declareProtected("Manage messages", "tmx_import")

    def tmx_import(self, howmuch, file, REQUEST=None, RESPONSE=None):
        """Imports a TMX level 1 file.
        """
        try:
            data = file.read()
            tmx = TMX(string=data)
        except:
            return MessageDialog(
                title="Parse error", message=_("impossible to parse the file"), action="manage_Import_form"
            )

        num_notes = 0
        num_trans = 0

        if howmuch == "clear":
            # Clear the message catalogue prior to import
            self._messages = {}
            self._languages = ()
            self._default_language = tmx.get_srclang()

        for (id, msg) in tmx.state.messages.items():
            if not self._messages.has_key(id) and howmuch == "existing":
                pass
            else:
                msg.msgstr.pop(self._default_language)
                if not self._messages.has_key(id):
                    self._messages[id] = {}
                for lang in msg.msgstr.keys():
                    # normalize the languageTag and extract the core
                    (core, local) = LanguageTag.decode(lang)
                    lang = LanguageTag.encode((core, local))
                    if lang not in self._languages:
                        self._languages += (lang,)
                    if msg.msgstr[lang].text:
                        self._messages[id][lang] = msg.msgstr[lang].text
                        if core != lang and core != self._default_language:
                            if core not in self._languages:
                                self._languages += (core,)
                            if not msg.msgstr.has_key(core):
                                self._messages[id][core] = msg.msgstr[lang].text
                if msg.notes:
                    ns = [m.text for m in msg.notes]
                    self._messages[id]["note"] = u" ".join(ns)
                    num_notes += 1
                num_trans += 1

        if REQUEST is not None:
            return MessageDialog(
                title=_(u"Messages imported"),
                message=_(u"Imported %d messages and %d notes") % (num_trans, num_notes),
                action="manage_messages",
            )

    #######################################################################
    # Backwards compatibility (XXX)
    #######################################################################

    hasmsg = message_exists
    hasLS = message_exists  # CMFLocalizer uses it

    security.declareProtected("Manage messages", "xliff_export")

    def xliff_export(self, x, export_all=1, REQUEST=None, RESPONSE=None):
        """Exports the content of the message catalog to an XLIFF file
        """
        orglang = self._default_language
        export_all = int(export_all)
        from DateTime import DateTime

        # Generate the XLIFF file header
        RESPONSE.setHeader("Content-Type", "text/xml; charset=UTF-8")
        RESPONSE.setHeader("Content-Disposition", 'attachment; filename="%s_%s_%s.xlf"' % (self.id, orglang, x))
        # build data structure for the xml header
        xml_header = {}
        xml_header["standalone"] = -1
        xml_header["xml_version"] = u"1.0"
        xml_header["document_type"] = (u"xliff", u"http://www.oasis-open.org/committees/xliff/documents/xliff.dtd")

        version = u"1.0"

        # build the data-stucture for the File tag
        attributes = {}
        attributes["original"] = u"/%s" % self.absolute_url(1)
        attributes["product-name"] = u"Localizer"
        attributes["product-version"] = u"1.1.x"
        attributes["data-type"] = u"plaintext"
        attributes["source-language"] = orglang
        attributes["target-language"] = x
        attributes["date"] = DateTime().HTML4()

        # Get the messages, and perhaps its translations.
        d = {}
        for msgkey, transunit in self._messages.items():
            target = transunit.get(x, "")
            # if export_all=1 export all messages otherwise export
            # only untranslated messages
            if export_all or not target:
                id = md5text(msgkey)
                notes = []
                if transunit.has_key("note") and transunit["note"]:
                    notes = [xliff_Note(transunit["note"])]
                if target:
                    t = Translation(msgkey, target, {"id": id}, notes)
                else:
                    t = Translation(msgkey, msgkey, {"id": id}, notes)
                d[msgkey] = t

        files = [xliff_File(d, attributes)]

        xliff = XLIFF()
        xliff.build(xml_header, version, files)

        return xliff.to_str()

    security.declareProtected("Manage messages", "xliff_import")

    def xliff_import(self, howmuch, file, REQUEST=None):
        """XLIFF is the XML Localization Interchange File Format designed by a
        group of software providers.  It is specified by www.oasis-open.org
        """
        try:
            data = file.read()
            xliff = XLIFF(string=data)
        except:
            return MessageDialog(
                title="Parse error", message=_("impossible to parse the file"), action="manage_Import_form"
            )

        num_notes = 0
        num_trans = 0
        (file_ids, sources, targets) = xliff.get_languages()

        if howmuch == "clear":
            # Clear the message catalogue prior to import
            self._messages = {}
            self._languages = ()
            self._default_language = sources[0]

        # update languages
        if len(sources) > 1 or sources[0] != self._default_language:
            return MessageDialog(
                title="Language error", message=_("incompatible language sources"), action="manage_Import_form"
            )
        for lang in targets:
            if lang != self._default_language and lang not in self._languages:
                self._languages += (lang,)

        # get messages
        for file in xliff.state.files:
            cur_target = file.attributes.get("target-language", "")
            for msg in file.body.keys():
                if not self._messages.has_key(msg) and howmuch == "existing":
                    pass
                else:
                    if not self._messages.has_key(msg):
                        self._messages[msg] = {}

                    if cur_target and file.body[msg].target:
                        self._messages[msg][cur_target] = file.body[msg].target
                        num_trans += 1
                    if file.body[msg].notes:
                        ns = [n.text for n in file.body[msg].notes]
                        comment = " ".join(ns)
                        self._messages[msg]["note"] = comment
                        num_notes += 1

        if REQUEST is not None:
            return MessageDialog(
                title=_(u"Messages imported"),
                message=(_(u"Imported %d messages and %d notes to %s") % (num_trans, num_notes, " ".join(targets))),
                action="manage_messages",
            )
Exemplo n.º 19
0
class DiscussionItemContainer(Persistent, Implicit, Traversable):
    """
        Store DiscussionItem objects. Discussable content that
        has DiscussionItems associated with it will have an
        instance of DiscussionItemContainer injected into it to
        hold the discussion threads.
    """

    __implements__ = Discussable

    # for the security machinery to allow traversal
    #__roles__ = None

    security = ClassSecurityInfo()

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()

    security.declareProtected(View, 'getId')

    def getId(self):
        return self.id

    security.declareProtected(View, 'getReply')

    def getReply(self, reply_id):
        """
            Return a discussion item, given its ID;  raise KeyError
            if not found.
        """
        return self._container.get(reply_id).__of__(self)

    # Is this right?
    security.declareProtected(View, '__bobo_traverse__')

    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target

        else:
            try:
                return self.getReply(name)
            except:
                parent = aq_parent(aq_inner(self))
                if parent.getId() == name:
                    return parent
                else:
                    REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    security.declarePrivate('manage_afterAdd')

    def manage_afterAdd(self, item, container):
        """
            We have juste been added or moved.
            Add the contained items to the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__(self).manage_afterAdd(item, container)

    security.declarePrivate('manage_afterClone')

    def manage_afterClone(self, item):
        """
            We have just been cloned.
            Notify the workflow about the contained items.
        """
        for obj in self.objectValues():
            obj.__of__(self).manage_afterClone(item)

    security.declarePrivate('manage_beforeDelete')

    def manage_beforeDelete(self, item, container):
        """
            Remove the contained items from the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__(self).manage_beforeDelete(item, container)

    #
    #   OFS.ObjectManager query interface.
    #
    security.declareProtected(AccessContentsInformation, 'objectIds')

    def objectIds(self, spec=None):
        """
            Return a list of the ids of our DiscussionItems.
        """
        if spec and spec is not DiscussionItem.meta_type:
            return []
        return self._container.keys()

    security.declareProtected(AccessContentsInformation, 'objectItems')

    def objectItems(self, spec=None):
        """
            Return a list of (id, subobject) tuples for our DiscussionItems.
        """
        r = []
        a = r.append
        g = self._container.get
        for id in self.objectIds(spec):
            a((id, g(id)))
        return r

    security.declareProtected(AccessContentsInformation, 'objectValues')

    def objectValues(self):
        """
            Return a list of our DiscussionItems.
        """
        return self._container.values()

    #
    #   Discussable interface
    #
    security.declareProtected(ReplyToItem, 'createReply')

    def createReply(self, title, text, Creator=None):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while self._container.get(str(id), None) is not None:
            id = id + 1
        id = str(id)

        item = DiscussionItem(id, title=title, description=title)
        item._edit(text_format='structured-text', text=text)

        if Creator:
            item.creator = Creator

        item.__of__(self).indexObject()

        item.setReplyTo(self._getDiscussable())

        self._container[id] = item

        return id

    security.declareProtected(ManagePortal, 'deleteReply')

    def deleteReply(self, reply_id):
        """ Remove a reply from this container """
        if self._container.has_key(reply_id):
            reply = self._container.get(reply_id).__of__(self)
            my_replies = reply.talkback.getReplies()
            for my_reply in my_replies:
                my_reply_id = my_reply.getId()
                if hasattr(my_reply, 'unindexObject'):
                    my_reply.unindexObject()

                del self._container[my_reply_id]

            if hasattr(reply, 'unindexObject'):
                reply.unindexObject()

            del self._container[reply_id]

    security.declareProtected(View, 'hasReplies')

    def hasReplies(self, content_obj):
        """
            Test to see if there are any dicussion items
        """
        outer = self._getDiscussable(outer=1)
        if content_obj == outer:
            return not not len(self._container)
        else:
            return not not len(content_obj.talkback._getReplyResults())

    security.declareProtected(View, 'replyCount')

    def replyCount(self, content_obj):
        """ How many replies do i have? """
        outer = self._getDiscussable(outer=1)
        if content_obj == outer:
            return len(self._container)
        else:
            replies = content_obj.talkback.getReplies()
            return self._repcount(replies)

    security.declarePrivate('_repcount')

    def _repcount(self, replies):
        """  counts the total number of replies by recursing thru the various levels
        """
        count = 0

        for reply in replies:
            count = count + 1

            #if there is at least one reply to this reply
            replies = reply.talkback.getReplies()
            if replies:
                count = count + self._repcount(replies)

        return count

    security.declareProtected(View, 'getReplies')

    def getReplies(self):
        """
            Return a sequence of the DiscussionResponse objects which are
            associated with this Discussable
        """
        objects = []
        a = objects.append
        result_ids = self._getReplyResults()

        for id in result_ids:
            a(self._container.get(id).__of__(self))

        return objects

    security.declareProtected(View, 'quotedContents')

    def quotedContents(self):
        """
            Return this object's contents in a form suitable for inclusion
            as a quote in a response.
        """

        return ""

    #
    #   Utility methods
    #
    security.declarePrivate('_getReplyParent')

    def _getReplyParent(self, in_reply_to):
        """
            Return the object indicated by the 'in_reply_to', where
            'None' represents the "outer" content object.
        """
        outer = self._getDiscussable(outer=1)
        if in_reply_to is None:
            return outer
        parent = self._container[in_reply_to].__of__(aq_inner(self))
        return parent.__of__(outer)

    security.declarePrivate('_getDiscussable')

    def _getDiscussable(self, outer=0):
        """
        """
        tb = outer and aq_inner(self) or self
        return getattr(tb, 'aq_parent', None)

    security.declarePrivate('_getReplyResults')

    def _getReplyResults(self):
        """
           Get a list of ids of DiscussionItems which are replies to
           our Discussable.
        """
        discussable = self._getDiscussable()
        outer = self._getDiscussable(outer=1)

        if discussable == outer:
            in_reply_to = None
        else:
            in_reply_to = discussable.getId()

        result = []
        a = result.append
        for key, value in self._container.items():
            if value.in_reply_to == in_reply_to:
                a(key)

        return result
Exemplo n.º 20
0
class UserFolder(BasicUserFolder):

    """Standard UserFolder object

    A UserFolder holds User objects which contain information
    about users including name, password domain, and roles.
    UserFolders function chiefly to control access by authenticating
    users and binding them to a collection of roles."""

    implements(IStandardUserFolder)

    meta_type='User Folder'
    id       ='acl_users'
    title    ='User Folder'
    icon     ='p_/UserFolder'

    def __init__(self):
        self.data=PersistentMapping()

    def getUserNames(self):
        """Return a list of usernames"""
        names=self.data.keys()
        names.sort()
        return names

    def getUsers(self):
        """Return a list of user objects"""
        data=self.data
        names=data.keys()
        names.sort()
        return [data[n] for n in names]

    def getUser(self, name):
        """Return the named user object or None"""
        return self.data.get(name, None)

    def hasUsers(self):
        """ This is not a formal API method: it is used only to provide
        a way for the quickstart page to determine if the default user
        folder contains any users to provide instructions on how to
        add a user for newbies.  Using getUserNames or getUsers would have
        posed a denial of service risk."""
        return not not len(self.data)

    def _doAddUser(self, name, password, roles, domains, **kw):
        """Create a new user"""
        if password is not None and self.encrypt_passwords \
                                and not self._isPasswordEncrypted(password):
            password = self._encryptPassword(password)
        self.data[name]=User(name,password,roles,domains)

    def _doChangeUser(self, name, password, roles, domains, **kw):
        user=self.data[name]
        if password is not None:
            if (  self.encrypt_passwords
                  and not self._isPasswordEncrypted(password)):
                password = self._encryptPassword(password)
            user.__=password
        user.roles=roles
        user.domains=domains

    def _doDelUsers(self, names):
        for name in names:
            del self.data[name]

    def _createInitialUser(self):
        """
        If there are no users or only one user in this user folder,
        populates from the 'inituser' file in the instance home.
        We have to do this even when there is already a user
        just in case the initial user ignored the setup messages.
        We don't do it for more than one user to avoid
        abuse of this mechanism.
        Called only by OFS.Application.initialize().
        """
        if len(self.data) <= 1:
            info = readUserAccessFile('inituser')
            if info:
                import App.config
                name, password, domains, remote_user_mode = info
                self._doDelUsers(self.getUserNames())
                self._doAddUser(name, password, ('Manager',), domains)
                cfg = App.config.getConfiguration()
                try:
                    os.remove(os.path.join(cfg.instancehome, 'inituser'))
                except:
                    pass
Exemplo n.º 21
0
class AuthenticationTool(
    BasicUserFolder, Role, ObjectManager, session_manager, file_utils, plugins_tool, PropertyManager
):

    meta_type = METATYPE_AUTHENTICATIONTOOL
    icon = "misc_/NaayaCore/AuthenticationTool.gif"

    manage_options = (
        {"label": "Users", "action": "manage_users_html"},
        {"label": "Roles", "action": "manage_roles_html"},
        {"label": "Permissions", "action": "manage_permissions_html"},
        {"label": "Other sources", "action": "manage_sources_html"},
        {"label": "Properties", "action": "manage_propertiesForm", "help": ("OFSP", "Properties.stx")},
    )

    _properties = (
        {"id": "title", "type": "string", "mode": "w", "label": "Title"},
        {"id": "encrypt_passwords", "type": "boolean", "mode": "w", "label": "Encrypt users passwords"},
        {
            "id": "email_expression",
            "type": "string",
            "mode": "w",
            "label": "E-mail should match this regular expression",
        },
        {
            "id": "email_confirmation",
            "type": "boolean",
            "mode": "w",
            "label": "Ask for email confirmation before add user ",
        },
    )

    security = ClassSecurityInfo()
    #
    # Properties
    #
    encrypt_passwords = False
    email_expression = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$"
    email_confirmation = False

    def __init__(self, id, title):
        self.id = id
        self.title = title
        self.data = PersistentMapping()
        Role.__dict__["__init__"](self)
        plugins_tool.__dict__["__init__"](self)

    security.declarePrivate("loadDefaultData")

    def loadDefaultData(self):
        # load default stuff
        pass

    security.declarePrivate("_doAddTempUser")

    def _doAddTempUser(self, **kwargs):
        """Generate a confirmation string, add it to temp users list,
           and return it.
        """
        text = object2string(kwargs)
        if not hasattr(self, "_temp_users"):
            self._temp_users = []
        if text in self._temp_users:
            raise Exception, "User already request access roles."
        self._temp_users.append(text)
        self._p_changed = 1
        return text

    security.declarePrivate("_doAddUser")

    def _doAddUser(self, name, password, roles, domains, firstname, lastname, email, **kw):
        """Create a new user. The 'password' will be the
           original input password, unencrypted. This
           method is responsible for performing any needed encryption."""

        if password is not None and self.encrypt_passwords:
            password = self._encryptPassword(password)
        self.data[name] = User(name, password, roles, domains, firstname, lastname, email)
        self._p_changed = 1
        return name

    security.declarePrivate("_doChangeUser")

    def _doChangeUser(self, name, password, roles, domains, firstname, lastname, email, lastupdated, **kw):
        """Modify an existing user. The 'password' will be the
           original input password, unencrypted. The implementation of this
           method is responsible for performing any needed encryption."""

        user = self.data[name]
        if password is not None:
            if self.encrypt_passwords and not self._isPasswordEncrypted(password):
                password = self._encryptPassword(password)
            user.__ = password
        user.roles = roles
        user.domains = domains
        user.firstname = firstname
        user.lastname = lastname
        user.email = email
        user.lastupdated = lastupdated
        self._p_changed = 1

    security.declarePublic("changeLastLogin")

    def changeLastLogin(self, name):
        user = self.data.get(name, None)
        if user:
            user.lastlogin = time.strftime("%d %b %Y %H:%M:%S")
            self._p_changed = 1

    security.declarePublic("changeLastPost")

    def changeLastPost(self, name):
        user = self.data.get(name, None)
        if user:
            user.lastpost = time.strftime("%d %b %Y %H:%M:%S")
            self._p_changed = 1

    security.declareProtected(manage_users, "getUserPass")

    def getUserPass(self):
        """Return a list of usernames"""
        temp = {}
        names = self.data.keys()
        for name in names:
            temp[name] = self.getUser(name).__
        return temp

    security.declarePrivate("_doChangeUserRoles")

    def _doChangeUserRoles(self, name, roles, **kw):
        """ """
        user = self.data[name]
        user.roles = roles
        self._p_changed = 1

    security.declarePrivate("_doDelUserRoles")

    def _doDelUserRoles(self, name, **kw):
        """ """
        for user in name:
            user_obj = self.data[user]
            user_obj.roles = []
        self._p_changed = 1

    security.declarePrivate("_doDelUsers")

    def _doDelUsers(self, names):
        """Delete one or more users."""

        for name in names:
            del self.data[name]
        self._p_changed = 1

    # zmi actions
    security.declareProtected(manage_users, "manage_confirmUser")

    def manage_confirmUser(self, key="", REQUEST=None):
        """ Add user from key
        """
        if key not in getattr(self, "_temp_users", []):
            raise Exception, "Invalid activation key !"
        try:
            res = string2object(key)
        except InvalidStringError, err:
            raise Exception, "Invalid activation key !"
        else:
Exemplo n.º 22
0
class DiscussionItemContainer(Persistent, Implicit, Traversable):
    """
        Store DiscussionItem objects. Discussable content that
        has DiscussionItems associated with it will have an
        instance of DiscussionItemContainer injected into it to
        hold the discussion threads.
    """

    # for the security machinery to allow traversal
    #__roles__ = None

    security = ClassSecurityInfo()

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()

    security.declareProtected(CMFCorePermissions.View, 'getId')

    def getId(self):
        return self.id

    # Is this right?
    security.declareProtected(CMFCorePermissions.View, '__bobo_traverse__')

    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target
        else:
            try:
                return self._container.get(name).__of__(self)
            except:
                REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    security.declarePrivate('manage_beforeDelete')

    def manage_beforeDelete(self, item, container):
        """
            Remove the contained items from the catalog.
        """
        if aq_base(container) is not aq_base(self):
            for obj in self.objectValues():
                obj.__of__(self).manage_beforeDelete(item, container)

    #
    #   OFS.ObjectManager query interface.
    #
    security.declareProtected(CMFCorePermissions.AccessContentsInformation,
                              'objectIds')

    def objectIds(self, spec=None):
        """
            Return a list of the ids of our DiscussionItems.
        """
        if spec and spec is not DiscussionItem.meta_type:
            return []
        return self._container.keys()

    security.declareProtected(CMFCorePermissions.AccessContentsInformation,
                              'objectItems')

    def objectItems(self, spec=None):
        """
            Return a list of (id, subobject) tuples for our DiscussionItems.
        """
        r = []
        a = r.append
        g = self._container.get
        for id in self.objectIds(spec):
            a((id, g(id)))
        return r

    security.declareProtected(CMFCorePermissions.AccessContentsInformation,
                              'objectValues')

    def objectValues(self):
        """
            Return a list of our DiscussionItems.
        """
        return self._container.values()

    #
    #   Discussable interface
    #
    security.declareProtected(CMFCorePermissions.ReplyToItem, 'createReply')

    def createReply(self, title, text, Creator=None):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while self._container.get(str(id), None) is not None:
            id = id + 1
        id = str(id)

        item = DiscussionItem(id, title=title, description=title)
        item._edit(text_format='structured-text', text=text)

        if Creator:
            item.creator = Creator

        item.__of__(self).indexObject()

        item.setReplyTo(self._getDiscussable())

        self._container[id] = item

        return id

    security.declareProtected(CMFCorePermissions.View, 'hasReplies')

    def hasReplies(self):
        """
            Test to see if there are any dicussion items
        """
        if len(self._container) == 0:
            return 0

        return len(self._getReplyResults())

    security.declareProtected(CMFCorePermissions.View, 'getReplies')

    def getReplies(self):
        """
            Return a sequence of the DiscussionResponse objects which are
            associated with this Discussable
        """
        objects = []
        a = objects.append
        result_ids = self._getReplyResults()

        for id in result_ids:
            a(self._container.get(id).__of__(self))

        return objects

    security.declareProtected(CMFCorePermissions.View, 'quotedContents')

    def quotedContents(self):
        """
            Return this object's contents in a form suitable for inclusion
            as a quote in a response.
        """

        return ""

    #
    #   Utility methods
    #
    security.declarePrivate('_getReplyParent')

    def _getReplyParent(self, in_reply_to):
        """
            Return the object indicated by the 'in_reply_to', where
            'None' represents the "outer" content object.
        """
        outer = self._getDiscussable(outer=1)
        if in_reply_to is None:
            return outer
        parent = self._container[in_reply_to].__of__(aq_inner(self))
        return parent.__of__(outer)

    security.declarePrivate('_getDiscussable')

    def _getDiscussable(self, outer=0):
        """
        """
        tb = outer and aq_inner(self) or self
        return getattr(tb, 'aq_parent', None)

    security.declarePrivate('_getReplyResults')

    def _getReplyResults(self):
        """
           Get a list of ids of DiscussionItems which are replies to
           our Discussable.
        """
        discussable = self._getDiscussable()
        outer = self._getDiscussable(outer=1)

        if discussable == outer:
            in_reply_to = None
        else:
            in_reply_to = discussable.getId()

        result = []
        a = result.append
        for key, value in self._container.items():
            if value.in_reply_to == in_reply_to:
                a(key)

        return result
Exemplo n.º 23
0
class ContentTypeRegistry( SimpleItem ):
    """
        Registry for rules which map PUT args to a CMF Type Object.
    """

    __implements__ = IContentTypeRegistry

    meta_type = 'Content Type Registry'
    id = 'content_type_registry'

    manage_options = ( { 'label'    : 'Predicates'
                       , 'action'   : 'manage_predicates'
                       }
                     , { 'label'    : 'Test'
                       , 'action'   : 'manage_testRegistry'
                       }
                     ) + SimpleItem.manage_options

    security = ClassSecurityInfo()

    def __init__( self ):
        self.predicate_ids  = ()
        self.predicates     = PersistentMapping()

    #
    #   ZMI
    #
    security.declarePublic( 'listPredicateTypes' )
    def listPredicateTypes( self ):
        """
        """
        return map( lambda x: x[0], _predicate_types )

    security.declareProtected( ManagePortal, 'manage_predicates' )
    manage_predicates = DTMLFile( 'registryPredList', _dtmldir )

    security.declareProtected( ManagePortal, 'doAddPredicate' )
    def doAddPredicate( self, predicate_id, predicate_type, REQUEST ):
        """
        """
        self.addPredicate( predicate_id, predicate_type )
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                              + '/manage_predicates'
                              + '?manage_tabs_message=Predicate+added.'
                              )

    security.declareProtected( ManagePortal, 'doUpdatePredicate' )
    def doUpdatePredicate( self
                         , predicate_id
                         , predicate
                         , typeObjectName
                         , REQUEST
                         ):
        """
        """
        self.updatePredicate( predicate_id, predicate, typeObjectName )
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                              + '/manage_predicates'
                              + '?manage_tabs_message=Predicate+updated.'
                              )

    security.declareProtected( ManagePortal, 'doMovePredicateUp' )
    def doMovePredicateUp( self, predicate_id, REQUEST ):
        """
        """
        predicate_ids = list( self.predicate_ids )
        ndx = predicate_ids.index( predicate_id )
        if ndx == 0:
            msg = "Predicate+already+first."
        else:
            self.reorderPredicate( predicate_id, ndx - 1 )
            msg = "Predicate+moved."
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                              + '/manage_predicates'
                              + '?manage_tabs_message=%s' % msg
                              )

    security.declareProtected( ManagePortal, 'doMovePredicateDown' )
    def doMovePredicateDown( self, predicate_id, REQUEST ):
        """
        """
        predicate_ids = list( self.predicate_ids )
        ndx = predicate_ids.index( predicate_id )
        if ndx == len( predicate_ids ) - 1:
            msg = "Predicate+already+last."
        else:
            self.reorderPredicate( predicate_id, ndx + 1 )
            msg = "Predicate+moved."
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                              + '/manage_predicates'
                              + '?manage_tabs_message=%s' % msg
                              )

    security.declareProtected( ManagePortal, 'doRemovePredicate' )
    def doRemovePredicate( self, predicate_id, REQUEST ):
        """
        """
        self.removePredicate( predicate_id )
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                              + '/manage_predicates'
                              + '?manage_tabs_message=Predicate+removed.'
                              )

    security.declareProtected( ManagePortal, 'manage_testRegistry' )
    manage_testRegistry = DTMLFile( 'registryTest', _dtmldir )

    security.declareProtected( ManagePortal, 'doTestRegistry' )
    def doTestRegistry( self, name, content_type, body, REQUEST ):
        """
        """
        typeName = self.findTypeName( name, content_type, body )
        if typeName is None:
            typeName = '<unknown>'
        else:
            types_tool = getToolByName(self, 'portal_types')
            typeName = types_tool.getTypeInfo(typeName).Title()
        REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                               + '/manage_testRegistry'
                               + '?testResults=Type:+%s'
                                       % urllib.quote( typeName )
                               )

    #
    #   Predicate manipulation
    #
    security.declarePublic( 'getPredicate' )
    def getPredicate( self, predicate_id ):
        """
            Find the predicate whose id is 'id';  return the predicate
            object, if found, or else None.
        """
        return self.predicates.get( predicate_id, ( None, None ) )[0]

    security.declarePublic( 'listPredicates' )
    def listPredicates( self ):
        """
            Return a sequence of tuples,
            '( id, ( predicate, typeObjectName ) )'
            for all predicates in the registry
        """
        result = []
        for predicate_id in self.predicate_ids:
            result.append( ( predicate_id, self.predicates[ predicate_id ] ) )
        return tuple( result )

    security.declarePublic( 'getTypeObjectName' )
    def getTypeObjectName( self, predicate_id ):
        """
            Find the predicate whose id is 'id';  return the name of
            the type object, if found, or else None.
        """
        return self.predicates.get( predicate_id, ( None, None ) )[1]

    security.declareProtected( ManagePortal, 'addPredicate' )
    def addPredicate( self, predicate_id, predicate_type ):
        """
            Add a predicate to this element of type 'typ' to the registry.
        """
        if predicate_id in self.predicate_ids:
            raise ValueError, "Existing predicate: %s" % predicate_id

        klass = None
        for key, value in _predicate_types:
            if key == predicate_type:
                klass = value

        if klass is None:
            raise ValueError, "Unknown predicate type: %s" % predicate_type

        self.predicates[ predicate_id ] = ( klass( predicate_id ), None )
        self.predicate_ids = self.predicate_ids + ( predicate_id, )

    security.declareProtected( ManagePortal, 'updatePredicate' )
    def updatePredicate( self, predicate_id, predicate, typeObjectName ):
        """
            Update a predicate in this element.
        """
        if not predicate_id in self.predicate_ids:
            raise ValueError, "Unknown predicate: %s" % predicate_id

        predObj = self.predicates[ predicate_id ][0]
        mapply( predObj.edit, (), predicate.__dict__ )
        self.assignTypeName( predicate_id, typeObjectName )

    security.declareProtected( ManagePortal, 'removePredicate' )
    def removePredicate( self, predicate_id ):
        """
            Remove a predicate from the registry.
        """
        del self.predicates[ predicate_id ]
        idlist = list( self.predicate_ids )
        ndx = idlist.index( predicate_id )
        idlist = idlist[ :ndx ] + idlist[ ndx+1: ]
        self.predicate_ids = tuple( idlist )

    security.declareProtected( ManagePortal, 'reorderPredicate' )
    def reorderPredicate( self, predicate_id, newIndex ):
        """
            Move a given predicate to a new location in the list.
        """
        idlist = list( self.predicate_ids )
        ndx = idlist.index( predicate_id )
        pred = idlist[ ndx ]
        idlist = idlist[ :ndx ] + idlist[ ndx+1: ]
        idlist.insert( newIndex, pred )
        self.predicate_ids = tuple( idlist )

    security.declareProtected( ManagePortal, 'assignTypeName' )
    def assignTypeName( self, predicate_id, typeObjectName ):
        """
            Bind the given predicate to a particular type object.
        """
        pred, oldTypeObjName = self.predicates[ predicate_id ]
        self.predicates[ predicate_id ] = ( pred, typeObjectName )

    #
    #   ContentTypeRegistry interface
    #
    def findTypeName( self, name, typ, body ):
        """
            Perform a lookup over a collection of rules, returning the
            the name of the Type object corresponding to name/typ/body.
            Return None if no match found.
        """
        for predicate_id in self.predicate_ids:
            pred, typeObjectName = self.predicates[ predicate_id ]
            if pred( name, typ, body ):
                return typeObjectName

        return None
Exemplo n.º 24
0
class UserFolder(BasicUserFolder):

    """Standard UserFolder object

    A UserFolder holds User objects which contain information
    about users including name, password domain, and roles.
    UserFolders function chiefly to control access by authenticating
    users and binding them to a collection of roles."""

    implements(IStandardUserFolder)

    meta_type='User Folder'
    id       ='acl_users'
    title    ='User Folder'
    icon     ='p_/UserFolder'

    def __init__(self):
        self.data=PersistentMapping()

    def getUserNames(self):
        """Return a list of usernames"""
        names=self.data.keys()
        names.sort()
        return names

    def getUsers(self):
        """Return a list of user objects"""
        data=self.data
        names=data.keys()
        names.sort()
        return [data[n] for n in names]

    def getUser(self, name):
        """Return the named user object or None"""
        return self.data.get(name, None)

    def hasUsers(self):
        """ This is not a formal API method: it is used only to provide
        a way for the quickstart page to determine if the default user
        folder contains any users to provide instructions on how to
        add a user for newbies.  Using getUserNames or getUsers would have
        posed a denial of service risk."""
        return not not len(self.data)

    def _doAddUser(self, name, password, roles, domains, **kw):
        """Create a new user"""
        if password is not None and self.encrypt_passwords \
                                and not self._isPasswordEncrypted(password):
            password = self._encryptPassword(password)
        self.data[name]=User(name,password,roles,domains)

    def _doChangeUser(self, name, password, roles, domains, **kw):
        user=self.data[name]
        if password is not None:
            if (  self.encrypt_passwords
                  and not self._isPasswordEncrypted(password)):
                password = self._encryptPassword(password)
            user.__=password
        user.roles=roles
        user.domains=domains

    def _doDelUsers(self, names):
        for name in names:
            del self.data[name]

    def _createInitialUser(self):
        """
        If there are no users or only one user in this user folder,
        populates from the 'inituser' file in the instance home.
        We have to do this even when there is already a user
        just in case the initial user ignored the setup messages.
        We don't do it for more than one user to avoid
        abuse of this mechanism.
        Called only by OFS.Application.initialize().
        """
        if len(self.data) <= 1:
            info = readUserAccessFile('inituser')
            if info:
                import App.config
                name, password, domains, remote_user_mode = info
                self._doDelUsers(self.getUserNames())
                self._doAddUser(name, password, ('Manager',), domains)
                cfg = App.config.getConfiguration()
                try:
                    os.remove(os.path.join(cfg.instancehome, 'inituser'))
                except:
                    pass
Exemplo n.º 25
0
class MembershipTool(UniqueObject, SimpleItem):
    # This tool accesses member data through an acl_users object.
    # It can be replaced with something that accesses member data in
    # a different way.
    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'

    security = ClassSecurityInfo()

    manage_options = ({
        'label': 'Overview',
        'action': 'manage_overview'
    }, {
        'label': 'Configuration',
        'action': 'manage_mapRoles'
    }) + SimpleItem.manage_options

    #
    #   ZMI methods
    #
    security.declareProtected(CMFCorePermissions.ManagePortal,
                              'manage_overview')
    manage_overview = DTMLFile('explainMembershipTool', _dtmldir)

    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir)

    security.declarePublic('getAuthenticatedMember')

    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')

    def wrapUser(self, u, wrap_anon=0):
        '''
        Sets up the correct acquisition wrappers for a user
        object and provides an opportunity for a portal_memberdata
        tool to retrieve and store member data independently of
        the user object.
        '''
        b = getattr(u, 'aq_base', None)
        if b is None:
            # u isn't wrapped at all.  Wrap it in self.acl_users.
            b = u
            u = u.__of__(self.acl_users)
        if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'):
            # This user is either not recognized by acl_users or it is
            # already registered with something that implements the
            # member data tool at least partially.
            return u

        parent = self.aq_inner.aq_parent
        base = getattr(parent, 'aq_base', None)
        if hasattr(base, 'portal_memberdata'):
            # Apply any role mapping if we have it
            if hasattr(self, 'role_map'):
                for portal_role in self.role_map.keys():
                    if (self.role_map.get(portal_role) in u.roles
                            and portal_role not in u.roles):
                        u.roles.append(portal_role)

            # Get portal_memberdata to do the wrapping.
            md = getToolByName(parent, 'portal_memberdata')
            try:
                portal_user = md.wrapUser(u)

                # Check for the member area creation flag and
                # take appropriate (non-) action
                if getattr(self, 'memberareaCreationFlag', 0) != 0:
                    if self.getHomeUrl(portal_user.getId()) is None:
                        self.createMemberarea(portal_user.getId())

                return portal_user

            except:
                from zLOG import LOG, ERROR
                import sys
                type, value, tb = sys.exc_info()
                try:
                    LOG('CMFCore.MembershipTool', ERROR,
                        'Error during wrapUser:'******'getPortalRoles')

    def getPortalRoles(self):
        """
        Return all local roles defined by the portal itself,
        which means roles that are useful and understood 
        by the portal object
        """
        parent = self.aq_inner.aq_parent
        roles = list(parent.__ac_roles__)

        # This is *not* a local role in the portal but used by it
        roles.append('Manager')
        roles.append('Owner')

        return roles

    security.declareProtected(ManagePortal, 'setRoleMapping')

    def setRoleMapping(self, portal_role, userfolder_role):
        """
        set the mapping of roles between roles understood by 
        the portal and roles coming from outside user sources
        """
        if not hasattr(self, 'role_map'): self.role_map = PersistentMapping()

        if len(userfolder_role) < 1:
            del self.role_map[portal_role]
        else:
            self.role_map[portal_role] = userfolder_role

        return MessageDialog(title='Mapping updated',
                             message='The Role mappings have been updated',
                             action='manage_mapRoles')

    security.declareProtected(ManagePortal, 'getMappedRole')

    def getMappedRole(self, portal_role):
        """
        returns a role name if the portal role is mapped to
        something else or an empty string if it is not
        """
        if hasattr(self, 'role_map'):
            return self.role_map.get(portal_role, '')
        else:
            return ''

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')

    def getMemberareaCreationFlag(self):
        """
        Returns the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going 
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        return self.memberareaCreationFlag

    security.declareProtected(ManagePortal, 'setMemberareaCreationFlag')

    def setMemberareaCreationFlag(self):
        """
        sets the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        if self.memberareaCreationFlag == 0:
            self.memberareaCreationFlag = 1
        else:
            self.memberareaCreationFlag = 0

        return MessageDialog(
            title='Member area creation flag changed',
            message='Member area creation flag has been updated',
            action='manage_mapRoles')

    security.declareProtected(ManagePortal, 'createMemberarea')

    def createMemberarea(self, member_id):
        """
        create a member area
        """
        parent = self.aq_inner.aq_parent
        members = getattr(parent, 'Members', None)
        user = self.acl_users.getUser(member_id).__of__(self.acl_users)

        if members is not None and user is not None:
            f_title = "%s's Home" % member_id
            members.manage_addPortalFolder(id=member_id, title=f_title)
            f = getattr(members, member_id)

            f.manage_permission(CMFCorePermissions.View,
                                ['Owner', 'Manager', 'Reviewer'], 0)
            f.manage_permission(CMFCorePermissions.AccessContentsInformation,
                                ['Owner', 'Manager', 'Reviewer'], 0)

            # Grant ownership to Member
            try:
                f.changeOwnership(user)
            except AttributeError:
                pass  # Zope 2.1.x compatibility
            f.manage_setLocalRoles(member_id, ['Owner'])

    security.declarePublic('isAnonymousUser')

    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')

    def checkPermission(self, permissionName, object, subobjectName=None):
        '''
        Checks whether the current user has the given permission on
        the given object or subobject.
        '''
        if subobjectName is not None:
            object = getattr(object, subobjectName)
        return _checkPermission(permissionName, object)

    security.declarePublic('credentialsChanged')

    def credentialsChanged(self, password):
        '''
        Notifies the authentication mechanism that this user has changed
        passwords.  This can be used to update the authentication cookie.
        Note that this call should *not* cause any change at all to user
        databases.
        '''
        if not self.isAnonymousUser():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            id = user.getUserName()
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, id, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, id, password)

    security.declareProtected(ManagePortal, 'getMemberById')

    def getMemberById(self, id):
        '''
        Returns the given member.
        '''
        u = self.acl_users.getUser(id)
        if u is not None:
            u = self.wrapUser(u)
        return u

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManagePortal, 'listMemberIds')

    def listMemberIds(self):
        '''Lists the ids of all members.  This may eventually be
        replaced with a set of methods for querying pieces of the
        list rather than the entire list at once.
        '''
        return self.__getPUS().getUserNames()

    security.declareProtected(ManagePortal, 'listMembers')

    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declareProtected(CMFCorePermissions.View, 'searchMembers')

    def searchMembers(self, search_param, search_term):
        """ Search the membership """
        md = getToolByName(self, 'portal_memberdata')

        return md.searchMemberDataContents(search_param, search_term)

    security.declareProtected(CMFCorePermissions.View,
                              'getCandidateLocalRoles')

    def getCandidateLocalRoles(self, obj):
        """ What local roles can I assign? """
        member = self.getAuthenticatedMember()

        if 'Manager' in member.getRoles():
            return self.getPortalRoles()
        else:
            member_roles = list(member.getRolesInContext(obj))
            del member_roles[member_roles.index('Member')]

        return tuple(member_roles)

    security.declareProtected(CMFCorePermissions.View, 'setLocalRoles')

    def setLocalRoles(self, obj, member_ids, member_role):
        """ Set local roles on an item """
        member = self.getAuthenticatedMember()
        my_roles = member.getRolesInContext(obj)

        if 'Manager' in my_roles or member_role in my_roles:
            for member_id in member_ids:
                roles = list(obj.get_local_roles_for_userid(userid=member_id))

                if member_role not in roles:
                    roles.append(member_role)
                    obj.manage_setLocalRoles(member_id, roles)

    security.declareProtected(CMFCorePermissions.View, 'deleteLocalRoles')

    def deleteLocalRoles(self, obj, member_ids):
        """ Delete local roles for members member_ids """
        member = self.getAuthenticatedMember()
        my_roles = member.getRolesInContext(obj)

        if 'Manager' in my_roles or 'Owner' in my_roles:
            obj.manage_delLocalRoles(userids=member_ids)

    security.declarePrivate('addMember')

    def addMember(self, id, password, roles, domains, properties=None):
        '''Adds a new member to the user folder.  Security checks will have
        already been performed.  Called by portal_registration.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_addUser'):
            acl_users._addUser(id, password, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            membership = getToolByName(self, 'portal_membership')
            member = membership.getMemberById(id)
            member.setMemberProperties(properties)

    security.declarePrivate('listActions')

    def listActions(self, info):
        return []

    security.declarePublic('getHomeFolder')

    def getHomeFolder(self, id=None, verifyPermission=0):
        """Returns a member's home folder object or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None

    security.declarePublic('getHomeUrl')

    def getHomeUrl(self, id=None, verifyPermission=0):
        """Returns the URL to a member's home folder or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
Exemplo n.º 26
0
class DiscussionItemContainer(Persistent, Implicit):
    """
    This class stores DiscussionItem objects. Discussable 
    content that has DiscussionItems associated with it 
    will have an instance of DiscussionItemContainer 
    injected into it to hold the discussion threads.
    """

    # for the security machinery to allow traversal
    __roles__ = None
    __allow_access_to_unprotected_subobjects__ = 1  # legacy code

    __ac_permissions__ = (('Access contents information',
                           ('objectIds', 'objectValues', 'objectItems')),
                          ('View', ('hasReplies', 'getReplies',
                                    '__bobo_traverse__')), ('Reply to item',
                                                            ('createReply', )))

    def __init__(self):
        self.id = 'talkback'
        self._container = PersistentMapping()

    def __bobo_traverse__(self, REQUEST, name):
        """
        This will make this container traversable
        """
        target = getattr(self, name, None)
        if target is not None:
            return target
        else:
            try:
                return self._container.get(name).__of__(self)
            except:
                REQUEST.RESPONSE.notFoundError("%s\n%s" % (name, ''))

    def objectIds(self, spec=None):
        """
        return a list of ids of DiscussionItems in
        this DiscussionItemContainer
        """
        return self._container.keys()

    def objectItems(self, spec=None):
        """
        Returns a list of (id, subobject) tuples of the current object.
        If 'spec' is specified, returns only objects whose meta_type
        match 'spec'
        """
        r = []
        a = r.append
        g = self._container.get
        for id in self.objectIds(spec):
            a((id, g(id)))
        return r

    def objectValues(self):
        """
        return the list of objects stored in this
        DiscussionItemContainer
        """
        return self._container.values()

    def createReply(self, title, text, REQUEST, RESPONSE):
        """
            Create a reply in the proper place
        """
        container = self._container

        id = int(DateTime().timeTime())
        while getattr(self._container, ` id `, None) is not None:
            id = id + 1

        item = DiscussionItem( ` id `)
        item.title = title
        item.description = title
        item.text_format = 'structured-text'
        item.text = text
        item.__of__(self).setReplyTo(self.aq_parent)

        item._parse()
        self._container[ ` id `] = item

        RESPONSE.redirect(self.aq_inner.aq_parent.absolute_url() + '/view')
Exemplo n.º 27
0
class MembershipTool(UniqueObject, Folder, ActionProviderBase):
    """ This tool accesses member data through an acl_users object.

    It can be replaced with something that accesses member data in a
    different way.
    """

    __implements__ = (IMembershipTool, ActionProviderBase.__implements__)

    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'
    _actions = ()

    memberareaCreationFlag = 1

    security = ClassSecurityInfo()

    manage_options = (({
        'label': 'Configuration',
        'action': 'manage_mapRoles'
    }, ) + ActionProviderBase.manage_options + ({
        'label': 'Overview',
        'action': 'manage_overview'
    }, ) + Folder.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainMembershipTool', _dtmldir)

    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir)

    security.declareProtected(SetOwnPassword, 'setPassword')

    def setPassword(self, password, domains=None):
        '''Allows the authenticated member to set his/her own password.
        '''
        registration = getToolByName(self, 'portal_registration', None)
        if not self.isAnonymousUser():
            member = self.getAuthenticatedMember()
            if registration:
                failMessage = registration.testPasswordValidity(password)
                if failMessage is not None:
                    raise 'Bad Request', failMessage
            member.setSecurityProfile(password=password, domains=domains)
        else:
            raise 'Bad Request', 'Not logged in.'

    security.declarePublic('getAuthenticatedMember')

    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')

    def wrapUser(self, u, wrap_anon=0):
        '''
        Sets up the correct acquisition wrappers for a user
        object and provides an opportunity for a portal_memberdata
        tool to retrieve and store member data independently of
        the user object.
        '''
        b = getattr(u, 'aq_base', None)
        if b is None:
            # u isn't wrapped at all.  Wrap it in self.acl_users.
            b = u
            u = u.__of__(self.acl_users)
        if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'):
            # This user is either not recognized by acl_users or it is
            # already registered with something that implements the
            # member data tool at least partially.
            return u

        parent = self.aq_inner.aq_parent
        base = getattr(parent, 'aq_base', None)
        if hasattr(base, 'portal_memberdata'):
            # Apply any role mapping if we have it
            if hasattr(self, 'role_map'):
                for portal_role in self.role_map.keys():
                    if (self.role_map.get(portal_role) in u.roles
                            and portal_role not in u.roles):
                        u.roles.append(portal_role)

            # Get portal_memberdata to do the wrapping.
            md = getToolByName(parent, 'portal_memberdata')
            try:
                portal_user = md.wrapUser(u)
                return portal_user

            except:
                from zLOG import LOG, ERROR
                import sys
                LOG(
                    'CMFCore.MembershipTool',
                    ERROR,
                    'Error during wrapUser',
                    error=sys.exc_info(),
                )
        # Failed.
        return u

    security.declareProtected(ManagePortal, 'getPortalRoles')

    def getPortalRoles(self):
        """
        Return all local roles defined by the portal itself,
        which means roles that are useful and understood 
        by the portal object
        """
        parent = self.aq_inner.aq_parent
        roles = list(parent.__ac_roles__)

        # This is *not* a local role in the portal but used by it
        roles.append('Manager')
        roles.append('Owner')

        return roles

    security.declareProtected(ManagePortal, 'setRoleMapping')

    def setRoleMapping(self, portal_role, userfolder_role):
        """
        set the mapping of roles between roles understood by 
        the portal and roles coming from outside user sources
        """
        if not hasattr(self, 'role_map'): self.role_map = PersistentMapping()

        if len(userfolder_role) < 1:
            del self.role_map[portal_role]
        else:
            self.role_map[portal_role] = userfolder_role

        return MessageDialog(title='Mapping updated',
                             message='The Role mappings have been updated',
                             action='manage_mapRoles')

    security.declareProtected(ManagePortal, 'getMappedRole')

    def getMappedRole(self, portal_role):
        """
        returns a role name if the portal role is mapped to
        something else or an empty string if it is not
        """
        if hasattr(self, 'role_map'):
            return self.role_map.get(portal_role, '')
        else:
            return ''

    security.declarePublic('getMembersFolder')

    def getMembersFolder(self):
        """ Get the members folder object.
        """
        parent = aq_parent(aq_inner(self))
        members = getattr(parent, 'Members', None)
        return members

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')

    def getMemberareaCreationFlag(self):
        """
        Returns the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going 
        through the join process
        """
        return self.memberareaCreationFlag

    security.declareProtected(ManagePortal, 'setMemberareaCreationFlag')

    def setMemberareaCreationFlag(self):
        """
        sets the flag indicating whether the membership tool
        will create a member area if an authenticated user from
        an underlying user folder logs in first without going
        through the join process
        """
        if not hasattr(self, 'memberareaCreationFlag'):
            self.memberareaCreationFlag = 0

        if self.memberareaCreationFlag == 0:
            self.memberareaCreationFlag = 1
        else:
            self.memberareaCreationFlag = 0

        return MessageDialog(
            title='Member area creation flag changed',
            message='Member area creation flag has been updated',
            action='manage_mapRoles')

    security.declarePublic('createMemberArea')

    def createMemberArea(self, member_id=''):
        """ Create a member area for 'member_id' or authenticated user.
        """
        if not self.getMemberareaCreationFlag():
            return None
        members = self.getMembersFolder()
        if not members:
            return None
        if self.isAnonymousUser():
            return None
        # Note: We can't use getAuthenticatedMember() and getMemberById()
        # because they might be wrapped by MemberDataTool.
        user = _getAuthenticatedUser(self)
        user_id = user.getId()
        if member_id in ('', user_id):
            member = user
            member_id = user_id
        else:
            if _checkPermission(ManageUsers, self):
                member = self.acl_users.getUserById(member_id, None)
                if member:
                    member = member.__of__(self.acl_users)
                else:
                    raise ValueError, 'Member %s does not exist' % member_id
            else:
                return None
        if hasattr(aq_base(members), member_id):
            return None
        else:
            f_title = "%s's Home" % member_id
            members.manage_addPortalFolder(id=member_id, title=f_title)
            f = getattr(members, member_id)

            f.manage_permission(View, ['Owner', 'Manager', 'Reviewer'], 0)
            f.manage_permission(AccessContentsInformation,
                                ['Owner', 'Manager', 'Reviewer'], 0)

            # Grant Ownership and Owner role to Member
            f.changeOwnership(member)
            f.__ac_local_roles__ = None
            f.manage_setLocalRoles(member_id, ['Owner'])
        return f

    security.declarePublic('createMemberarea')
    createMemberarea = createMemberArea

    security.declareProtected(ManageUsers, 'deleteMemberArea')

    def deleteMemberArea(self, member_id):
        """ Delete member area of member specified by member_id.
        """
        members = self.getMembersFolder()
        if not members:
            return 0
        if hasattr(aq_base(members), member_id):
            members.manage_delObjects(member_id)
            return 1
        else:
            return 0

    security.declarePublic('isAnonymousUser')

    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')

    def checkPermission(self, permissionName, object, subobjectName=None):
        '''
        Checks whether the current user has the given permission on
        the given object or subobject.
        '''
        if subobjectName is not None:
            object = getattr(object, subobjectName)
        return _checkPermission(permissionName, object)

    security.declarePublic('credentialsChanged')

    def credentialsChanged(self, password):
        '''
        Notifies the authentication mechanism that this user has changed
        passwords.  This can be used to update the authentication cookie.
        Note that this call should *not* cause any change at all to user
        databases.
        '''
        if not self.isAnonymousUser():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            name = user.getUserName()
            # this really does need to be the user name, and not the user id,
            # because we're dealing with authentication credentials
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, name, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, name, password)

    security.declareProtected(ManageUsers, 'getMemberById')

    def getMemberById(self, id):
        '''
        Returns the given member.
        '''
        u = self.acl_users.getUserById(id, None)
        if u is not None:
            u = self.wrapUser(u)
        return u

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManageUsers, 'listMemberIds')

    def listMemberIds(self):
        '''Lists the ids of all members.  This may eventually be
        replaced with a set of methods for querying pieces of the
        list rather than the entire list at once.
        '''
        user_folder = self.__getPUS()
        return [x.getId() for x in user_folder.getUsers()]

    security.declareProtected(ManageUsers, 'listMembers')

    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declareProtected(ListPortalMembers, 'searchMembers')

    def searchMembers(self, search_param, search_term):
        """ Search the membership """
        md = getToolByName(self, 'portal_memberdata')

        return md.searchMemberData(search_param, search_term)

    security.declareProtected(View, 'getCandidateLocalRoles')

    def getCandidateLocalRoles(self, obj):
        """ What local roles can I assign?
        """
        member = self.getAuthenticatedMember()
        member_roles = member.getRolesInContext(obj)
        if _checkPermission(ManageUsers, obj):
            local_roles = self.getPortalRoles()
            if 'Manager' not in member_roles:
                local_roles.remove('Manager')
        else:
            local_roles = [
                role for role in member_roles
                if role not in ('Member', 'Authenticated')
            ]
        local_roles.sort()
        return tuple(local_roles)

    security.declareProtected(View, 'setLocalRoles')

    def setLocalRoles(self, obj, member_ids, member_role, reindex=1):
        """ Add local roles on an item.
        """
        if (_checkPermission(ChangeLocalRoles, obj)
                and member_role in self.getCandidateLocalRoles(obj)):
            for member_id in member_ids:
                roles = list(obj.get_local_roles_for_userid(userid=member_id))

                if member_role not in roles:
                    roles.append(member_role)
                    obj.manage_setLocalRoles(member_id, roles)

        if reindex:
            # It is assumed that all objects have the method
            # reindexObjectSecurity, which is in CMFCatalogAware and
            # thus PortalContent and PortalFolder.
            obj.reindexObjectSecurity()

    security.declareProtected(View, 'deleteLocalRoles')

    def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0):
        """ Delete local roles of specified members.
        """
        if _checkPermission(ChangeLocalRoles, obj):
            for member_id in member_ids:
                if obj.get_local_roles_for_userid(userid=member_id):
                    obj.manage_delLocalRoles(userids=member_ids)
                    break

        if recursive and hasattr(aq_base(obj), 'contentValues'):
            for subobj in obj.contentValues():
                self.deleteLocalRoles(subobj, member_ids, 0, 1)

        if reindex:
            # reindexObjectSecurity is always recursive
            obj.reindexObjectSecurity()

    security.declarePrivate('addMember')

    def addMember(self, id, password, roles, domains, properties=None):
        '''Adds a new member to the user folder.  Security checks will have
        already been performed.  Called by portal_registration.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_addUser'):
            acl_users._addUser(id, password, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            member = self.getMemberById(id)
            member.setMemberProperties(properties)

    security.declareProtected(ManageUsers, 'deleteMembers')

    def deleteMembers(self,
                      member_ids,
                      delete_memberareas=1,
                      delete_localroles=1):
        """ Delete members specified by member_ids.
        """

        # Delete members in acl_users.
        acl_users = self.acl_users
        if _checkPermission(ManageUsers, acl_users):
            if type(member_ids) is StringType:
                member_ids = (member_ids, )
            member_ids = list(member_ids)
            for member_id in member_ids[:]:
                if not acl_users.getUserById(member_id, None):
                    member_ids.remove(member_id)
            try:
                acl_users.userFolderDelUsers(member_ids)
            except (NotImplementedError, 'NotImplemented'):
                raise CMFNotImplementedError(
                    'The underlying User Folder '
                    'doesn\'t support deleting members.')
        else:
            raise CMFUnauthorizedError(
                'You need the \'Manage users\' '
                'permission for the underlying User Folder.')

        # Delete member data in portal_memberdata.
        mdtool = getToolByName(self, 'portal_memberdata', None)
        if mdtool:
            for member_id in member_ids:
                mdtool.deleteMemberData(member_id)

        # Delete members' home folders including all content items.
        if delete_memberareas:
            for member_id in member_ids:
                self.deleteMemberArea(member_id)

        # Delete members' local roles.
        if delete_localroles:
            utool = getToolByName(self, 'portal_url', None)
            self.deleteLocalRoles(utool.getPortalObject(),
                                  member_ids,
                                  reindex=1,
                                  recursive=1)

        return tuple(member_ids)

    security.declarePublic('getHomeFolder')

    def getHomeFolder(self, id=None, verifyPermission=0):
        """Returns a member's home folder object or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None

    security.declarePublic('getHomeUrl')

    def getHomeUrl(self, id=None, verifyPermission=0):
        """Returns the URL to a member's home folder or None.
        Set verifyPermission to 1 to return None when the user
        doesn't have the View permission on the folder.
        """
        return None
Exemplo n.º 28
0
class MimeTypesRegistry(UniqueObject, ActionProviderBase, Folder):
    """Mimetype registry that deals with
    a) registering types
    b) wildcarding of rfc-2046 types
    c) classifying data into a given type
    """

    __implements__ = (IMimetypesRegistry, ISourceAdapter)
    implements(IMimetypesRegistryTool)

    id        = 'mimetypes_registry'
    meta_type = 'MimeTypes Registry'
    isPrincipiaFolderish = 1 # Show up in the ZMI

    meta_types = all_meta_types = (
        { 'name'   : 'MimeType',
          'action' : 'manage_addMimeTypeForm'},
        )

    manage_options = (
        ( { 'label'   : 'MimeTypes',
            'action' : 'manage_main'},) +
        Folder.manage_options[2:]
        )

    manage_addMimeTypeForm = PageTemplateFile('addMimeType', _www)
    manage_main = PageTemplateFile('listMimeTypes', _www)
    manage_editMimeTypeForm = PageTemplateFile('editMimeType', _www)

    security = ClassSecurityInfo()

    # FIXME
    __allow_access_to_unprotected_subobjects__ = 1

    def __init__(self,):
        self.encodings_map = encodings_map.copy()
        self.suffix_map = suffix_map.copy()
        # Major key -> minor IMimetype objects
        self._mimetypes  = PersistentMapping()
        # ext -> IMimetype mapping
        self.extensions = PersistentMapping()
        # glob -> (regex, mimetype) mapping
        self.globs = OOBTree()
        self.manage_addProperty('defaultMimetype', 'text/plain', 'string')
        self.manage_addProperty('unicodePolicies', 'strict ignore replace',
                                'tokens')
        self.manage_addProperty('unicodePolicy', 'unicodePolicies', 'selection')
        self.manage_addProperty('fallbackEncoding', 'latin1', 'string')

        # initialize mime types
        initialize(self)
        self._new_style_mtr = 1

    security.declareProtected(ManagePortal, 'register')
    def register(self, mimetype):
        """ Register a new mimetype

        mimetype must implement IMimetype
        """
        mimetype = aq_base(mimetype)
        assert IMimetype.isImplementedBy(mimetype)
        for t in mimetype.mimetypes:
            self.register_mimetype(t, mimetype)
        for extension in mimetype.extensions:
            self.register_extension(extension, mimetype)
        for glob in mimetype.globs:
            self.register_glob(glob, mimetype)

    security.declareProtected(ManagePortal, 'register_mimetype')
    def register_mimetype(self, mt, mimetype):
        major, minor = split(mt)
        if not major or not minor or minor == '*':
            raise MimeTypeException('Can\'t register mime type %s' % mt)
        group = self._mimetypes.setdefault(major, PersistentMapping())
        if group.has_key(minor):
            if group.get(minor) != mimetype:
                log('Warning: redefining mime type %s (%s)' % (
                    mt, mimetype.__class__))
        group[minor] = mimetype

    security.declareProtected(ManagePortal, 'register_extension')
    def register_extension(self, extension, mimetype):
        """ Associate a file's extension to a IMimetype

        extension is a string representing a file extension (not
        prefixed by a dot) mimetype must implement IMimetype
        """
        mimetype = aq_base(mimetype)
        if self.extensions.has_key(extension):
            if self.extensions.get(extension) != mimetype:
                log('Warning: redefining extension %s from %s to %s' % (
                    extension, self.extensions[extension], mimetype))
        # we don't validate fmt yet, but its ["txt", "html"]
        self.extensions[extension] = mimetype

    security.declareProtected(ManagePortal, 'register_glob')
    def register_glob(self, glob, mimetype):
        """ Associate a glob to a IMimetype

        glob is a shell-like glob that will be translated to a regex
        to match against whole filename.
        mimetype must implement IMimetype.
        """
        globs = getattr(self, 'globs', None)
        if globs is None:
            self.globs = globs = OOBTree()
        mimetype = aq_base(mimetype)
        existing = globs.get(glob)
        if existing is not None:
            regex, mt = existing
            if mt != mimetype:
                log('Warning: redefining glob %s from %s to %s' % (
                    glob, mt, mimetype))
        # we don't validate fmt yet, but its ["txt", "html"]
        pattern = re.compile(fnmatch.translate(glob))
        globs[glob] = (pattern, mimetype)

    security.declareProtected(ManagePortal, 'unregister')
    def unregister(self, mimetype):
        """ Unregister a new mimetype

        mimetype must implement IMimetype
        """
        assert IMimetype.isImplementedBy(mimetype)
        for t in mimetype.mimetypes:
            major, minor = split(t)
            group = self._mimetypes.get(major, {})
            if group.get(minor) == mimetype:
                del group[minor]
        for e in mimetype.extensions:
            if self.extensions.get(e) == mimetype:
                del self.extensions[e]
        globs = getattr(self, 'globs', None)
        if globs is not None:
            for glob in mimetype.globs:
                existing = globs.get(glob)
                if existing is None:
                    continue
                regex, mt = existing
                if mt == mimetype:
                    del globs[glob]

    security.declarePublic('mimetypes')
    def mimetypes(self):
        """Return all defined mime types, each one implements at least
        IMimetype
        """
        res = {}
        for g in self._mimetypes.values():
            for mt in g.values():
                res[mt] =1
        return [aq_base(mtitem) for mtitem in res.keys()]


    security.declarePublic('list_mimetypes')
    def list_mimetypes(self):
        """Return all defined mime types, as string"""
        return [str(mt) for mt in self.mimetypes()]

    security.declarePublic('lookup')
    def lookup(self, mimetypestring):
        """Lookup for IMimetypes object matching mimetypestring

        mimetypestring may have an empty minor part or containing a
        wildcard (*) mimetypestring may and IMimetype object (in this
        case it will be returned unchanged

        Return a list of mimetypes objects associated with the
        RFC-2046 name return an empty list if no one is known.
        """
        if IMimetype.isImplementedBy(mimetypestring):
            return (aq_base(mimetypestring), )
        __traceback_info__ = (repr(mimetypestring), str(mimetypestring))
        major, minor = split(str(mimetypestring))
        group = self._mimetypes.get(major, {})
        if not minor or minor == '*':
            res = group.values()
        else:
            res = group.get(minor)
            if res:
                res = (res,)
            else:
                return ()
        return tuple([aq_base(mtitem) for mtitem in res])

    security.declarePublic('lookupExtension')
    def lookupExtension(self, filename):
        """Lookup for IMimetypes object matching filename

        Filename maybe a file name like 'content.txt' or an extension
        like 'rest'

        Return an IMimetype object associated with the file's
        extension or None
        """
        if filename.find('.') != -1:
            base, ext = os.path.splitext(filename)
            ext = ext[1:] # remove the dot
            while self.suffix_map.has_key(ext):
                base, ext = os.path.splitext(base + self.suffix_map[ext])
                ext = ext[1:] # remove the dot
        else:
            ext = filename
            base = None

        # XXX This code below make no sense and may break because base
        # isn't defined.
        if self.encodings_map.has_key(ext) and base:
            encoding = self.encodings_map[ext]
            base, ext = os.path.splitext(base)
            ext = ext[1:] # remove the dot
        else:
            encoding = None
        return aq_base(self.extensions.get(ext))

    security.declarePublic('globFilename')
    def globFilename(self, filename):
        """Lookup for IMimetypes object matching filename

        Filename must be a complete filename with extension.

        Return an IMimetype object associated with the glob's or None
        """
        globs = getattr(self, 'globs', None)
        if globs is None:
            return None
        for key in globs.keys():
            glob, mimetype = globs[key]
            if glob.match(filename):
                return aq_base(mimetype)
        return None

    security.declarePublic('lookupGlob')
    def lookupGlob(self, glob):
        globs = getattr(self, 'globs', None)
        if globs is None:
            return None
        return aq_base(globs.get(glob))

    def _classifiers(self):
        return [mt for mt in self.mimetypes() if IClassifier.isImplementedBy(mt)]

    security.declarePublic('classify')
    def classify(self, data, mimetype=None, filename=None):
        """Classify works as follows:
        1) you tell me the rfc-2046 name and I give you an IMimetype
           object
        2) the filename includes an extension from which we can guess
           the mimetype
        3) we can optionally introspect the data
        4) default to self.defaultMimetype if no data was provided
           else to application/octet-stream of no filename was provided,
           else to text/plain

        Return an IMimetype object or None 
        """
        mt = None
        if mimetype:
            mt = self.lookup(mimetype)
            if mt:
                mt = mt[0]
        elif filename:
            mt = self.lookupExtension(filename)
            if mt is None:
                mt = self.globFilename(filename)
        if data and not mt:
            for c in self._classifiers():
                if c.classify(data):
                    mt = c
                    break
            if not mt:
                mstr = magic.guessMime(data)
                if mstr:
                    mt = self.lookup(mstr)[0]
        if not mt:
            if not data:
                mtlist = self.lookup(self.defaultMimetype)
            elif filename:
                mtlist = self.lookup('application/octet-stream')
            else:
                failed = 'text/x-unknown-content-type'
                filename = filename or ''
                data = data or ''
                ct, enc = guess_content_type(filename, data, None)
                if ct == failed:
                    ct = 'text/plain'
                mtlist = self.lookup(ct)
            if len(mtlist)>0:
                mt = mtlist[0]
            else:
                return None

        # Remove acquisition wrappers
        return aq_base(mt)

    def __call__(self, data, **kwargs):
        """ Return a triple (data, filename, mimetypeobject) given
        some raw data and optional paramters

        method from the isourceAdapter interface
        """
        mimetype = kwargs.get('mimetype', None)
        filename = kwargs.get('filename', None)
        encoding = kwargs.get('encoding', None)
        mt = None
        if hasattr(data, 'filename'):
            filename = os.path.basename(data.filename)
        elif hasattr(data, 'name'):
            filename = os.path.basename(data.name)

        if hasattr(data, 'read'):
            _data = data.read()
            if hasattr(data, 'seek'):
                data.seek(0)
            data = _data

        # We need to figure out if data is binary and skip encoding if
        # it is
        mt = self.classify(data, mimetype=mimetype, filename=filename)

        if not mt.binary and not type(data) is UnicodeType:
            # if no encoding specified, try to guess it from data
            if encoding is None:
                encoding = self.guess_encoding(data)

            # ugly workaround for
            # https://sourceforge.net/tracker/?func=detail&aid=1068001&group_id=75272&atid=543430
            # covered by
            # https://sourceforge.net/tracker/?func=detail&atid=355470&aid=843590&group_id=5470
            # dont remove this code unless python is fixed.
            if encoding is "macintosh":
                encoding = 'mac_roman'

            try:
                try:
                    data = unicode(data, encoding, self.unicodePolicy)
                except (ValueError, LookupError):
                    # wrong unicodePolicy
                    data = unicode(data, encoding)
            except:
                data = unicode(data, self.fallbackEncoding)

        return (data, filename, aq_base(mt))

    security.declarePublic('guess_encoding')
    def guess_encoding(self, data):
        """ Try to guess encoding from a text value if no encoding
        guessed, used the default charset from site properties (Zope)
        with a fallback to UTF-8 (should never happen with correct
        site_properties, but always raise Attribute error without
        Zope)
        """
        if type(data) is type(u''):
            # data maybe unicode but with another encoding specified
            data = data.encode('UTF-8')
        encoding = guess_encoding(data)
        if encoding is None:
            try:
                site_props = self.portal_properties.site_properties
                encoding = site_props.getProperty('default_charset', 'UTF-8')
            except:
                encoding = 'UTF-8'
        return encoding

    security.declareProtected(ManagePortal, 'manage_delObjects')
    def manage_delObjects(self, ids, REQUEST=None):
        """ delete the selected mime types """
        for id in ids:
            self.unregister(self.lookup(id)[0])
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

    security.declareProtected(ManagePortal, 'manage_addMimeType')
    def manage_addMimeType(self, id, mimetypes, extensions, icon_path,
                           binary=0, globs=None, REQUEST=None):
        """add a mime type to the tool"""
        mt = MimeTypeItem(id, mimetypes, extensions=extensions,
                          binary=binary, icon_path=icon_path, globs=globs)
        self.register(mt)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

    security.declareProtected(ManagePortal, 'manage_editMimeType')
    def manage_editMimeType(self, name, new_name, mimetypes, extensions,
                            icon_path, binary=0, globs=None, REQUEST=None):
        """Edit a mime type by name
        """
        mt = self.lookup(name)[0]
        self.unregister(mt)
        mt.edit(new_name, mimetypes, extensions, icon_path=icon_path,
                binary=binary, globs=globs)
        self.register(mt)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')