Ejemplo n.º 1
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
Ejemplo n.º 2
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:
Ejemplo n.º 3
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:
Ejemplo n.º 4
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())
Ejemplo 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."""

    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
Ejemplo n.º 6
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')
Ejemplo n.º 7
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
Ejemplo n.º 8
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',)
Ejemplo n.º 9
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
Ejemplo n.º 10
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",
            )
Ejemplo 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' )
Ejemplo 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
Ejemplo n.º 13
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
Ejemplo 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.
    """

    __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 ]
Ejemplo n.º 15
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
Ejemplo n.º 16
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
Ejemplo n.º 17
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.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: