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
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:
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:
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())
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
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')
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
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 + '?' + '&'.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',)
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
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", )
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' )
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
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
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 ]
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
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
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: