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 |     @Lazy | ||||||
|     def macro(self): |     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): |     def children(self): | ||||||
|         for r in self.context.getChildRelations(): |         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> |   <div> | ||||||
|     <h3 tal:attributes="class string:content-$level; |     <h3 tal:attributes="class string:content-$level; | ||||||
|                         ondblclick item/openEditWindow"> |                         ondblclick item/openEditWindow"> | ||||||
|  | @ -12,7 +31,7 @@ | ||||||
|         <div tal:repeat="related item/parents"> |         <div tal:repeat="related item/parents"> | ||||||
|           <a href="#" |           <a href="#" | ||||||
|              tal:attributes="href string:${view/url}/.target${related/uniqueId}" |              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> |       </div> | ||||||
|       <div tal:attributes="class string:content-$level; |       <div tal:attributes="class string:content-$level; | ||||||
|  | @ -21,7 +40,7 @@ | ||||||
|         <div tal:repeat="related item/children"> |         <div tal:repeat="related item/children"> | ||||||
|           <a href="#" |           <a href="#" | ||||||
|              tal:attributes="href string:${view/url}/.target${related/uniqueId}" |              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> |       </div> | ||||||
|       <div tal:attributes="class string:content-$level; |       <div tal:attributes="class string:content-$level; | ||||||
|  | @ -35,4 +54,4 @@ | ||||||
|       </div> |       </div> | ||||||
|     </metal:listing> |     </metal:listing> | ||||||
|   </div> |   </div> | ||||||
| </metal:body> | </metal:listing> | ||||||
|  |  | ||||||
|  | @ -223,7 +223,7 @@ and register it | ||||||
|   >>> personAdapter = regView.register(data) |   >>> personAdapter = regView.register(data) | ||||||
| 
 | 
 | ||||||
|   >>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId |   >>> 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: | 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.formlib.namedtemplate import NamedTemplate | ||||||
| from zope.i18nmessageid import MessageFactory | 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.node import NodeView | ||||||
| from loops.browser.concept import ConceptRelationView | from loops.browser.concept import ConceptRelationView | ||||||
| from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager | from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager | ||||||
| from loops.organize.interfaces import IMemberRegistration, raiseValidationError | from loops.organize.interfaces import IMemberRegistration | ||||||
| 
 | 
 | ||||||
| _ = MessageFactory('zope') | _ = MessageFactory('zope') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MyConcepts(BaseView): | class MyStuff(ConceptView): | ||||||
| 
 |  | ||||||
|     template = NamedTemplate('loops.concept_macros') |  | ||||||
| 
 |  | ||||||
|     @Lazy |  | ||||||
|     def macro(self): |  | ||||||
|         return self.template.macros['conceptlisting'] |  | ||||||
| 
 | 
 | ||||||
|     def __init__(self, context, request): |     def __init__(self, context, request): | ||||||
|         self.context = context |         self.context = context | ||||||
|  | @ -59,23 +54,9 @@ class MyConcepts(BaseView): | ||||||
|         if self.person is not None: |         if self.person is not None: | ||||||
|             self.context = self.person |             self.context = self.person | ||||||
| 
 | 
 | ||||||
|     def children(self): |     @Lazy | ||||||
|         if self.person is None: |     def view(self): | ||||||
|             return |         return self | ||||||
|         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) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PasswordWidget(BasePasswordWidget): | class PasswordWidget(BasePasswordWidget): | ||||||
|  | @ -109,11 +90,13 @@ class MemberRegistration(Form, NodeView): | ||||||
|         pw = form.get('password') |         pw = form.get('password') | ||||||
|         if form.get('passwordConfirm') != pw: |         if form.get('passwordConfirm') != pw: | ||||||
|             raise ValueError(u'Password and password confirmation do not match.') |             raise ValueError(u'Password and password confirmation do not match.') | ||||||
|  |         login = form.get('loginName') | ||||||
|         regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) |         regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) | ||||||
|         person = regMan.register(form.get('loginName'), pw, |         person = regMan.register(login, pw, | ||||||
|                                  form.get('lastName'), |                                  form.get('lastName'), | ||||||
|                                  form.get('firstName')) |                                  form.get('firstName')) | ||||||
|         message = _(u'You have been registered and can now login.') |         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 |         return person | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,11 +28,11 @@ | ||||||
|   <!-- my stuff and other views --> |   <!-- my stuff and other views --> | ||||||
| 
 | 
 | ||||||
|   <zope:adapter |   <zope:adapter | ||||||
|         name="myconcepts" |         name="mystuff" | ||||||
|         for="loops.interfaces.IConcept |         for="loops.interfaces.IConcept | ||||||
|             zope.publisher.interfaces.browser.IBrowserRequest" |             zope.publisher.interfaces.browser.IBrowserRequest" | ||||||
|         provides="zope.interface.Interface" |         provides="zope.interface.Interface" | ||||||
|         factory="loops.organize.browser.MyConcepts" |         factory="loops.organize.browser.MyStuff" | ||||||
|         permission="zope.View" |         permission="zope.View" | ||||||
|         /> |         /> | ||||||
|    |    | ||||||
|  |  | ||||||
|  | @ -28,7 +28,10 @@ from zope.app import zapi | ||||||
| from zope.app.principalannotation import annotations | from zope.app.principalannotation import annotations | ||||||
| from zope.app.security.interfaces import IAuthentication, PrincipalLookupError | from zope.app.security.interfaces import IAuthentication, PrincipalLookupError | ||||||
| from zope.i18nmessageid import MessageFactory | from zope.i18nmessageid import MessageFactory | ||||||
|  | from zope.security.proxy import removeSecurityProxy | ||||||
|  | 
 | ||||||
| from cybertools.organize.interfaces import IPerson as IBasePerson | from cybertools.organize.interfaces import IPerson as IBasePerson | ||||||
|  | from loops.organize.util import getPrincipalFolder, authPluginId | ||||||
| 
 | 
 | ||||||
| _ = MessageFactory('zope') | _ = MessageFactory('zope') | ||||||
| 
 | 
 | ||||||
|  | @ -50,7 +53,8 @@ class UserId(schema.TextLine): | ||||||
|     def _validate(self, userId): |     def _validate(self, userId): | ||||||
|         if not userId: |         if not userId: | ||||||
|             return |             return | ||||||
|         auth = component.getUtility(IAuthentication, context=self.context) |         context = removeSecurityProxy(self.context).context | ||||||
|  |         auth = component.getUtility(IAuthentication, context=context) | ||||||
|         try: |         try: | ||||||
|             principal = auth.getPrincipal(userId) |             principal = auth.getPrincipal(userId) | ||||||
|         except PrincipalLookupError: |         except PrincipalLookupError: | ||||||
|  | @ -58,7 +62,7 @@ class UserId(schema.TextLine): | ||||||
|                                    mapping={'userId': userId})) |                                    mapping={'userId': userId})) | ||||||
|         pa = annotations(principal) |         pa = annotations(principal) | ||||||
|         person = pa.get(ANNOTATION_KEY, None) |         person = pa.get(ANNOTATION_KEY, None) | ||||||
|         if person is not None and person != self.context: |         if person is not None and person != context: | ||||||
|             raiseValidationError( |             raiseValidationError( | ||||||
|                 _(u'There is alread a person ($person) assigned to user $userId.', |                 _(u'There is alread a person ($person) assigned to user $userId.', | ||||||
|                   mapping=dict(person=zapi.getName(person), |                   mapping=dict(person=zapi.getName(person), | ||||||
|  | @ -69,6 +73,10 @@ class LoginName(schema.TextLine): | ||||||
| 
 | 
 | ||||||
|     def _validate(self, userId): |     def _validate(self, userId): | ||||||
|         super(LoginName, self)._validate(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): | class Password(schema.Password): | ||||||
|  |  | ||||||
|  | @ -39,6 +39,7 @@ from cybertools.typology.interfaces import IType | ||||||
| from loops.interfaces import ILoops | from loops.interfaces import ILoops | ||||||
| from loops.concept import Concept | from loops.concept import Concept | ||||||
| from loops.organize.interfaces import IMemberRegistrationManager | from loops.organize.interfaces import IMemberRegistrationManager | ||||||
|  | from loops.organize.util import getPrincipalFolder, authPluginId | ||||||
| 
 | 
 | ||||||
| _ = MessageFactory('zope') | _ = MessageFactory('zope') | ||||||
| 
 | 
 | ||||||
|  | @ -48,40 +49,32 @@ class MemberRegistrationManager(object): | ||||||
|     implements(IMemberRegistrationManager) |     implements(IMemberRegistrationManager) | ||||||
|     adapts(ILoops) |     adapts(ILoops) | ||||||
| 
 | 
 | ||||||
|     authPluginId = 'loops' |  | ||||||
| 
 |  | ||||||
|     def __init__(self, context): |     def __init__(self, context): | ||||||
|         self.context = context |         self.context = context | ||||||
| 
 | 
 | ||||||
|     def register(self, userId, password, lastName, firstName=u'', **kw): |     def register(self, userId, password, lastName, firstName=u'', **kw): | ||||||
|         # step 1: create an internal principal in the loops principal folder: |         # step 1: create an internal principal in the loops principal folder: | ||||||
|         pau = zapi.getUtility(IAuthentication, context=self.context) |         pFolder = getPrincipalFolder(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) |  | ||||||
|         title = firstName and ' '.join((firstName, lastName)) or lastName |         title = firstName and ' '.join((firstName, lastName)) or lastName | ||||||
|         # TODO: care for password encryption: |         # TODO: care for password encryption: | ||||||
|         principal = InternalPrincipal(userId, password, title) |         principal = InternalPrincipal(userId, password, title) | ||||||
|         pFolder[userId] = principal |         pFolder[userId] = principal | ||||||
|         # step 2: create a corresponding person concept: |         # step 2: create a corresponding person concept: | ||||||
|         cm = self.context.getConceptManager() |         cm = self.context.getConceptManager() | ||||||
|         id = userId |         id = baseId = 'person.' + userId | ||||||
|         num = 0 |         num = 0 | ||||||
|         while id in cm: |         while id in cm: | ||||||
|             num +=1 |             num +=1 | ||||||
|             id = userId + str(num) |             id = baseId + str(num) | ||||||
|         person = cm[id] = Concept(title) |         person = cm[id] = Concept(title) | ||||||
|         # TODO: the name of the person type object must be kept flexible! |         # 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'] |         person.conceptType = cm['person'] | ||||||
|         personAdapter = IType(person).typeInterface(person) |         personAdapter = IType(person).typeInterface(person) | ||||||
|         personAdapter.firstName = firstName |         personAdapter.firstName = firstName | ||||||
|         personAdapter.lastName = lastName |         personAdapter.lastName = lastName | ||||||
|         personAdapter.userId = '.'.join((self.authPluginId, userId)) |         personAdapter.userId = '.'.join((authPluginId, userId)) | ||||||
|         notify(ObjectCreatedEvent(person)) |         notify(ObjectCreatedEvent(person)) | ||||||
|         notify(ObjectModifiedEvent(person)) |         notify(ObjectModifiedEvent(person)) | ||||||
|         return personAdapter |         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