more on registration; extend concept view to show the attributes of the typeInterface
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1222 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									00e27595ca
								
							
						
					
					
						commit
						6ab11a50e9
					
				
					 8 changed files with 110 additions and 52 deletions
				
			
		|  | @ -68,7 +68,18 @@ class ConceptView(BaseView): | |||
|      | ||||
|     @Lazy | ||||
|     def macro(self): | ||||
|         return self.template.macros['conceptlisting'] | ||||
|         return self.template.macros['conceptdata'] | ||||
| 
 | ||||
|     def fieldData(self): | ||||
|         ti = IType(self.context).typeInterface | ||||
|         if not ti: return  | ||||
|         adapter = ti(self.context) | ||||
|         for f in ti: | ||||
|             title = getattr(ti[f], 'title', '') | ||||
|             value = getattr(adapter, f, '') | ||||
|             if not (value and title): | ||||
|                 continue | ||||
|             yield {'title': title, 'value': value, 'id': f} | ||||
| 
 | ||||
|     def children(self): | ||||
|         for r in self.context.getChildRelations(): | ||||
|  |  | |||
|  | @ -1,4 +1,23 @@ | |||
| <metal:body define-macro="conceptlisting"> | ||||
| <metal:data define-macro="conceptdata"> | ||||
|   <div tal:attributes="class string:content-$level; | ||||
|                        ondblclick item/openEditWindow"> | ||||
|     <h3> | ||||
|       <span i18n:translate="">Concept</span>: | ||||
|       <span tal:content="item/title">Title</span> | ||||
|     </h3> | ||||
|     <table> | ||||
|       <tr tal:repeat="field item/fieldData"> | ||||
|         <td><span tal:content="field/title" | ||||
|                   i18n:translate="" />:</td> | ||||
|         <td tal:content="nocall:field/value"></td> | ||||
|       </tr> | ||||
|     </table> | ||||
|     <metal:listing use-macro="item/template/macros/conceptlisting2" /> | ||||
|   </div> | ||||
| </metal:data> | ||||
| 
 | ||||
| 
 | ||||
| <metal:listing define-macro="conceptlisting"> | ||||
|   <div> | ||||
|     <h3 tal:attributes="class string:content-$level; | ||||
|                         ondblclick item/openEditWindow"> | ||||
|  | @ -12,7 +31,7 @@ | |||
|         <div tal:repeat="related item/parents"> | ||||
|           <a href="#" | ||||
|              tal:attributes="href string:${view/url}/.target${related/uniqueId}" | ||||
|              tal:content="related/title">Resource Title</a> | ||||
|              tal:content="related/title">Concept Title</a> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div tal:attributes="class string:content-$level; | ||||
|  | @ -21,7 +40,7 @@ | |||
|         <div tal:repeat="related item/children"> | ||||
|           <a href="#" | ||||
|              tal:attributes="href string:${view/url}/.target${related/uniqueId}" | ||||
|              tal:content="related/title">Resource Title</a> | ||||
|              tal:content="related/title">Concept Title</a> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div tal:attributes="class string:content-$level; | ||||
|  | @ -35,4 +54,4 @@ | |||
|       </div> | ||||
|     </metal:listing> | ||||
|   </div> | ||||
| </metal:body> | ||||
| </metal:listing> | ||||
|  |  | |||
|  | @ -223,7 +223,7 @@ and register it | |||
|   >>> personAdapter = regView.register(data) | ||||
| 
 | ||||
|   >>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId | ||||
|   (u'newuser', u'Sawyer', u'loops.newuser') | ||||
|   (u'person.newuser', u'Sawyer', u'loops.newuser') | ||||
| 
 | ||||
| Now we can also retrieve it from the authentication utility: | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,22 +34,17 @@ from zope.formlib.form import Form, FormFields, action | |||
| from zope.formlib.namedtemplate import NamedTemplate | ||||
| from zope.i18nmessageid import MessageFactory | ||||
| 
 | ||||
| from loops.browser.common import BaseView | ||||
| from cybertools.typology.interfaces import IType | ||||
| from loops.browser.concept import ConceptView | ||||
| from loops.browser.node import NodeView | ||||
| from loops.browser.concept import ConceptRelationView | ||||
| from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager | ||||
| from loops.organize.interfaces import IMemberRegistration, raiseValidationError | ||||
| from loops.organize.interfaces import IMemberRegistration | ||||
| 
 | ||||
| _ = MessageFactory('zope') | ||||
| 
 | ||||
| 
 | ||||
| class MyConcepts(BaseView): | ||||
| 
 | ||||
|     template = NamedTemplate('loops.concept_macros') | ||||
| 
 | ||||
|     @Lazy | ||||
|     def macro(self): | ||||
|         return self.template.macros['conceptlisting'] | ||||
| class MyStuff(ConceptView): | ||||
| 
 | ||||
|     def __init__(self, context, request): | ||||
|         self.context = context | ||||
|  | @ -59,23 +54,9 @@ class MyConcepts(BaseView): | |||
|         if self.person is not None: | ||||
|             self.context = self.person | ||||
| 
 | ||||
|     def children(self): | ||||
|         if self.person is None: | ||||
|             return | ||||
|         for r in self.person.getChildRelations(): | ||||
|             yield ConceptRelationView(r, self.request, contextIsSecond=True) | ||||
| 
 | ||||
|     def parents(self): | ||||
|         if self.person is None: | ||||
|             return | ||||
|         for r in self.person.getParentRelations(): | ||||
|             yield ConceptRelationView(r, self.request) | ||||
| 
 | ||||
|     def resources(self): | ||||
|         if self.person is None: | ||||
|             return | ||||
|         for r in self.person.getResourceRelations(): | ||||
|             yield ConceptRelationView(r, self.request, contextIsSecond=True) | ||||
|     @Lazy | ||||
|     def view(self): | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
| class PasswordWidget(BasePasswordWidget): | ||||
|  | @ -109,11 +90,13 @@ class MemberRegistration(Form, NodeView): | |||
|         pw = form.get('password') | ||||
|         if form.get('passwordConfirm') != pw: | ||||
|             raise ValueError(u'Password and password confirmation do not match.') | ||||
|         login = form.get('loginName') | ||||
|         regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) | ||||
|         person = regMan.register(form.get('loginName'), pw, | ||||
|         person = regMan.register(login, pw, | ||||
|                                  form.get('lastName'), | ||||
|                                  form.get('firstName')) | ||||
|         message = _(u'You have been registered and can now login.') | ||||
|         self.request.response.redirect('%s?message=%s' % (self.url, message)) | ||||
|         self.request.response.redirect('%s/login.html?login=%s&message=%s' | ||||
|                             % (self.url, login, message)) | ||||
|         return person | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,11 +28,11 @@ | |||
|   <!-- my stuff and other views --> | ||||
| 
 | ||||
|   <zope:adapter | ||||
|         name="myconcepts" | ||||
|         name="mystuff" | ||||
|         for="loops.interfaces.IConcept | ||||
|             zope.publisher.interfaces.browser.IBrowserRequest" | ||||
|         provides="zope.interface.Interface" | ||||
|         factory="loops.organize.browser.MyConcepts" | ||||
|         factory="loops.organize.browser.MyStuff" | ||||
|         permission="zope.View" | ||||
|         /> | ||||
|    | ||||
|  |  | |||
|  | @ -28,7 +28,10 @@ from zope.app import zapi | |||
| from zope.app.principalannotation import annotations | ||||
| from zope.app.security.interfaces import IAuthentication, PrincipalLookupError | ||||
| from zope.i18nmessageid import MessageFactory | ||||
| from zope.security.proxy import removeSecurityProxy | ||||
| 
 | ||||
| from cybertools.organize.interfaces import IPerson as IBasePerson | ||||
| from loops.organize.util import getPrincipalFolder, authPluginId | ||||
| 
 | ||||
| _ = MessageFactory('zope') | ||||
| 
 | ||||
|  | @ -50,7 +53,8 @@ class UserId(schema.TextLine): | |||
|     def _validate(self, userId): | ||||
|         if not userId: | ||||
|             return | ||||
|         auth = component.getUtility(IAuthentication, context=self.context) | ||||
|         context = removeSecurityProxy(self.context).context | ||||
|         auth = component.getUtility(IAuthentication, context=context) | ||||
|         try: | ||||
|             principal = auth.getPrincipal(userId) | ||||
|         except PrincipalLookupError: | ||||
|  | @ -58,7 +62,7 @@ class UserId(schema.TextLine): | |||
|                                    mapping={'userId': userId})) | ||||
|         pa = annotations(principal) | ||||
|         person = pa.get(ANNOTATION_KEY, None) | ||||
|         if person is not None and person != self.context: | ||||
|         if person is not None and person != context: | ||||
|             raiseValidationError( | ||||
|                 _(u'There is alread a person ($person) assigned to user $userId.', | ||||
|                   mapping=dict(person=zapi.getName(person), | ||||
|  | @ -69,6 +73,10 @@ class LoginName(schema.TextLine): | |||
| 
 | ||||
|     def _validate(self, userId): | ||||
|         super(LoginName, self)._validate(userId) | ||||
|         if userId in getPrincipalFolder(self.context): | ||||
|             raiseValidationError( | ||||
|                 _(u'There is alread a user with ID $userId.', | ||||
|                   mapping=dict(userId=userId))) | ||||
| 
 | ||||
| 
 | ||||
| class Password(schema.Password): | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ from cybertools.typology.interfaces import IType | |||
| from loops.interfaces import ILoops | ||||
| from loops.concept import Concept | ||||
| from loops.organize.interfaces import IMemberRegistrationManager | ||||
| from loops.organize.util import getPrincipalFolder, authPluginId | ||||
| 
 | ||||
| _ = MessageFactory('zope') | ||||
| 
 | ||||
|  | @ -48,40 +49,32 @@ class MemberRegistrationManager(object): | |||
|     implements(IMemberRegistrationManager) | ||||
|     adapts(ILoops) | ||||
| 
 | ||||
|     authPluginId = 'loops' | ||||
| 
 | ||||
|     def __init__(self, context): | ||||
|         self.context = context | ||||
| 
 | ||||
|     def register(self, userId, password, lastName, firstName=u'', **kw): | ||||
|         # step 1: create an internal principal in the loops principal folder: | ||||
|         pau = zapi.getUtility(IAuthentication, context=self.context) | ||||
|         if not IPluggableAuthentication.providedBy(pau): | ||||
|             raise ValueError(u'There is no pluggable authentication ' | ||||
|                                     'utility available.') | ||||
|         if not self.authPluginId in pau.authenticatorPlugins: | ||||
|             raise ValueError(u'There is no loops authenticator ' | ||||
|                                     'plugin available.') | ||||
|         pFolder = component.queryUtility(IAuthenticatorPlugin, self.authPluginId, | ||||
|                                          context=pau) | ||||
|         pFolder = getPrincipalFolder(self.context) | ||||
|         title = firstName and ' '.join((firstName, lastName)) or lastName | ||||
|         # TODO: care for password encryption: | ||||
|         principal = InternalPrincipal(userId, password, title) | ||||
|         pFolder[userId] = principal | ||||
|         # step 2: create a corresponding person concept: | ||||
|         cm = self.context.getConceptManager() | ||||
|         id = userId | ||||
|         id = baseId = 'person.' + userId | ||||
|         num = 0 | ||||
|         while id in cm: | ||||
|             num +=1 | ||||
|             id = userId + str(num) | ||||
|             id = baseId + str(num) | ||||
|         person = cm[id] = Concept(title) | ||||
|         # TODO: the name of the person type object must be kept flexible! | ||||
|         # So we have to search for a type concept that has IPerson as | ||||
|         # its typeInterface... | ||||
|         person.conceptType = cm['person'] | ||||
|         personAdapter = IType(person).typeInterface(person) | ||||
|         personAdapter.firstName = firstName | ||||
|         personAdapter.lastName = lastName | ||||
|         personAdapter.userId = '.'.join((self.authPluginId, userId)) | ||||
|         personAdapter.userId = '.'.join((authPluginId, userId)) | ||||
|         notify(ObjectCreatedEvent(person)) | ||||
|         notify(ObjectModifiedEvent(person)) | ||||
|         return personAdapter | ||||
|  |  | |||
							
								
								
									
										44
									
								
								organize/util.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								organize/util.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| # | ||||
| #  Copyright (c) 2006 Helmut Merz helmutm@cy55.de | ||||
| # | ||||
| #  This program is free software; you can redistribute it and/or modify | ||||
| #  it under the terms of the GNU General Public License as published by | ||||
| #  the Free Software Foundation; either version 2 of the License, or | ||||
| #  (at your option) any later version. | ||||
| # | ||||
| #  This program is distributed in the hope that it will be useful, | ||||
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| #  GNU General Public License for more details. | ||||
| # | ||||
| #  You should have received a copy of the GNU General Public License | ||||
| #  along with this program; if not, write to the Free Software | ||||
| #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| Utilities for the loops.organize package. | ||||
| 
 | ||||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| from zope.app import zapi | ||||
| from zope import interface, component, schema | ||||
| from zope.app.authentication.interfaces import IPluggableAuthentication | ||||
| from zope.app.authentication.interfaces import IAuthenticatorPlugin | ||||
| from zope.app.security.interfaces import IAuthentication | ||||
| 
 | ||||
| authPluginId = 'loops' | ||||
| 
 | ||||
| 
 | ||||
| def getPrincipalFolder(context=None): | ||||
|         pau = zapi.getUtility(IAuthentication, context=context) | ||||
|         if not IPluggableAuthentication.providedBy(pau): | ||||
|             raise ValueError(u'There is no pluggable authentication ' | ||||
|                               'utility available.') | ||||
|         if not authPluginId in pau.authenticatorPlugins: | ||||
|             raise ValueError(u'There is no loops authenticator ' | ||||
|                               'plugin available.') | ||||
|         return component.queryUtility(IAuthenticatorPlugin, authPluginId, | ||||
|                                          context=pau) | ||||
| 
 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm