member registration basically usable
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1221 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									a70fe7d830
								
							
						
					
					
						commit
						00e27595ca
					
				
					 11 changed files with 353 additions and 57 deletions
				
			
		| 
						 | 
					@ -44,7 +44,7 @@ from loops import util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EditForm(BaseEditForm):
 | 
					class EditForm(BaseEditForm):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template = NamedTemplate('pageform')
 | 
					    template = NamedTemplate('loops.pageform')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def deleteObjectAction(self):
 | 
					    def deleteObjectAction(self):
 | 
				
			||||||
        return None  # better not to show the edit button at the moment
 | 
					        return None  # better not to show the edit button at the moment
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@ from zope.cachedescriptors.property import Lazy
 | 
				
			||||||
from zope.dottedname.resolve import resolve
 | 
					from zope.dottedname.resolve import resolve
 | 
				
			||||||
from zope.event import notify
 | 
					from zope.event import notify
 | 
				
			||||||
from zope.formlib.form import EditForm, FormFields
 | 
					from zope.formlib.form import EditForm, FormFields
 | 
				
			||||||
 | 
					from zope.formlib.namedtemplate import NamedTemplate
 | 
				
			||||||
from zope.interface import implements
 | 
					from zope.interface import implements
 | 
				
			||||||
from zope.publisher.interfaces import BadRequest
 | 
					from zope.publisher.interfaces import BadRequest
 | 
				
			||||||
from zope.publisher.interfaces.browser import IBrowserRequest
 | 
					from zope.publisher.interfaces.browser import IBrowserRequest
 | 
				
			||||||
| 
						 | 
					@ -63,8 +64,11 @@ class ConceptEditForm(EditForm):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConceptView(BaseView):
 | 
					class ConceptView(BaseView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template = ViewPageTemplateFile('concept_macros.pt')
 | 
					    template = NamedTemplate('loops.concept_macros')
 | 
				
			||||||
    macro = template.macros['conceptlisting']
 | 
					    
 | 
				
			||||||
 | 
					    @Lazy
 | 
				
			||||||
 | 
					    def macro(self):
 | 
				
			||||||
 | 
					        return self.template.macros['conceptlisting']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def children(self):
 | 
					    def children(self):
 | 
				
			||||||
        for r in self.context.getChildRelations():
 | 
					        for r in self.context.getChildRelations():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,12 +61,27 @@
 | 
				
			||||||
      permission="zope.View"
 | 
					      permission="zope.View"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <!-- named template(s) -->
 | 
					  <!-- named templates - forms and macro templates -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <zope:adapter
 | 
					  <zope:adapter
 | 
				
			||||||
      factory="loops.browser.util.pageform"
 | 
					      factory="loops.browser.util.pageform"
 | 
				
			||||||
      for="zope.interface.Interface"
 | 
					      for="zope.interface.Interface"
 | 
				
			||||||
      name="pageform" />
 | 
					      name="loops.pageform" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:adapter
 | 
				
			||||||
 | 
					      factory="loops.browser.util.dataform"
 | 
				
			||||||
 | 
					      for="zope.interface.Interface"
 | 
				
			||||||
 | 
					      name="loops.dataform" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:adapter
 | 
				
			||||||
 | 
					      factory="loops.browser.util.concept_macros"
 | 
				
			||||||
 | 
					      for="loops.browser.common.BaseView"
 | 
				
			||||||
 | 
					      name="loops.concept_macros" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:adapter
 | 
				
			||||||
 | 
					      factory="loops.browser.util.node_macros"
 | 
				
			||||||
 | 
					      for="loops.browser.common.BaseView"
 | 
				
			||||||
 | 
					      name="loops.node_macros" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <!-- loops top-level container -->
 | 
					  <!-- loops top-level container -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										169
									
								
								browser/dataform.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								browser/dataform.pt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,169 @@
 | 
				
			||||||
 | 
					<html metal:extend-macro="context/@@standard_macros/view"
 | 
				
			||||||
 | 
					      metal:define-macro="main">
 | 
				
			||||||
 | 
					<head></head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<metal:settings fill-slot="settings"
 | 
				
			||||||
 | 
					    tal:define="dummy python:
 | 
				
			||||||
 | 
					        controller.macros.register('css', resourceName='node.css', media='all');" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					<div class="box" metal:fill-slot="navigators">
 | 
				
			||||||
 | 
					    <h4>Navigation</h4>
 | 
				
			||||||
 | 
					    <tal:menu define="item view/menu;
 | 
				
			||||||
 | 
					                      level level|python: 1"
 | 
				
			||||||
 | 
					              condition="item">
 | 
				
			||||||
 | 
					      <div class="body">
 | 
				
			||||||
 | 
					        <metal:menu use-macro="views/node_macros/menu" />
 | 
				
			||||||
 | 
					      </div>      
 | 
				
			||||||
 | 
					    </tal:menu>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div metal:fill-slot="body">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div metal:define-macro="form">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<form action="." metal:define-macro="master"
 | 
				
			||||||
 | 
					      tal:attributes="action request/URL" method="post"
 | 
				
			||||||
 | 
					      class="edit-form" enctype="multipart/form-data"
 | 
				
			||||||
 | 
					      id="zc.page.browser_form">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script type="text/javascript"><!--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function toggleFormFieldHelp(ob,state) {
 | 
				
			||||||
 | 
					  // ob is the label element
 | 
				
			||||||
 | 
					  var field = ob.form[ob.htmlFor];
 | 
				
			||||||
 | 
					  if (field) {
 | 
				
			||||||
 | 
					    var viz = state && 'hidden' || 'visible';
 | 
				
			||||||
 | 
					    if (field.length == null) {
 | 
				
			||||||
 | 
					      field.style.visibility = viz;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      for (var i = 0; i < field.length; ++i) {
 | 
				
			||||||
 | 
					        var e = field.item(i);
 | 
				
			||||||
 | 
					        e.style.visibility = viz;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var help = document.getElementById("field-help-for-" + field.name);
 | 
				
			||||||
 | 
					    if (help) {
 | 
				
			||||||
 | 
					      help.style.visibility = state && 'visible' || 'hidden';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-->
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div id="viewspace" metal:define-slot="viewspace">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <h1 tal:content="view/label">Edit ...</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <metal:block define-macro="header">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="form-status"
 | 
				
			||||||
 | 
					       tal:define="status view/status"
 | 
				
			||||||
 | 
					       tal:condition="status">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="summary"
 | 
				
			||||||
 | 
					           i18n:translate=""
 | 
				
			||||||
 | 
					           tal:content="view/status">
 | 
				
			||||||
 | 
					        Form status summary
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <ul class="errors" tal:condition="view/errors">
 | 
				
			||||||
 | 
					         <li tal:repeat="error view/error_views">
 | 
				
			||||||
 | 
					            <span tal:replace="structure error">Error Type</span>
 | 
				
			||||||
 | 
					         </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <br />
 | 
				
			||||||
 | 
					  </metal:block>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div metal:define-slot="extra_info" tal:replace="nothing">
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <table class="form-fields">
 | 
				
			||||||
 | 
					    <tr class="row" metal:define-slot="extra_top" tal:replace="nothing">
 | 
				
			||||||
 | 
					        <td class="label">Extra top</td>
 | 
				
			||||||
 | 
					        <td class="label"><input type="text" /></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tbody metal:define-slot="formbody" tal:omit-tag="">
 | 
				
			||||||
 | 
					      <tr tal:repeat="widget view/widgets">
 | 
				
			||||||
 | 
					        <td class="label" tal:define="hint widget/hint"
 | 
				
			||||||
 | 
					          metal:define-macro="labelcell">
 | 
				
			||||||
 | 
					          <label tal:condition="python:hint"
 | 
				
			||||||
 | 
					                 tal:attributes="for widget/name"
 | 
				
			||||||
 | 
					                 onmousedown="toggleFormFieldHelp(this,1)"
 | 
				
			||||||
 | 
					                 onmouseup="toggleFormFieldHelp(this,0)"
 | 
				
			||||||
 | 
					                 onmouseout="toggleFormFieldHelp(this,0)"
 | 
				
			||||||
 | 
					                 style="cursor: help">
 | 
				
			||||||
 | 
					            <span class="required" tal:condition="widget/required"
 | 
				
			||||||
 | 
					            >*</span><span i18n:translate=""
 | 
				
			||||||
 | 
					                           tal:content="widget/label">label</span>
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					          <label tal:condition="python:not hint"
 | 
				
			||||||
 | 
					                 tal:attributes="for widget/name">
 | 
				
			||||||
 | 
					            <span class="required" tal:condition="widget/required"
 | 
				
			||||||
 | 
					            >*</span><span i18n:translate=""
 | 
				
			||||||
 | 
					                           tal:content="widget/label">label</span>
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td class="field" tal:define="hint widget/hint"
 | 
				
			||||||
 | 
					            metal:define-macro="widgetcell">
 | 
				
			||||||
 | 
					          <div class="form-fields-help"
 | 
				
			||||||
 | 
					               i18n:translate=""
 | 
				
			||||||
 | 
					               tal:content="hint"
 | 
				
			||||||
 | 
					               tal:condition="hint"
 | 
				
			||||||
 | 
					               tal:attributes="id string:field-help-for-${widget/name}"
 | 
				
			||||||
 | 
					               onclick="this.style.visibility='hidden';"
 | 
				
			||||||
 | 
					               style="visibility: hidden; position: absolute;"
 | 
				
			||||||
 | 
					               >Title of this content object.</div>
 | 
				
			||||||
 | 
					          <div class="widget" tal:content="structure widget">
 | 
				
			||||||
 | 
					          <input type="text" /></div>
 | 
				
			||||||
 | 
					          <div class="error"
 | 
				
			||||||
 | 
					               tal:condition="widget/error"
 | 
				
			||||||
 | 
					               >
 | 
				
			||||||
 | 
					            <!-- TODO Put this back, the Zope3 way.
 | 
				
			||||||
 | 
					            <img src="alert.gif" alt="Error"
 | 
				
			||||||
 | 
					            tal:replace="structure context/alert.gif" />
 | 
				
			||||||
 | 
					            -->
 | 
				
			||||||
 | 
					            <span tal:replace="structure widget/error">error</span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </tbody>
 | 
				
			||||||
 | 
					    <tr class="row" metal:define-slot="extra_bottom" tal:replace="nothing">
 | 
				
			||||||
 | 
					      <td class="label">Extra bottom</td>
 | 
				
			||||||
 | 
					      <td class="label"><input type="text" /></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					  <metal:block define-slot="above_buttons" />
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div id="actionsView">
 | 
				
			||||||
 | 
					  <br />
 | 
				
			||||||
 | 
					  <span class="actionButtons"
 | 
				
			||||||
 | 
					        tal:condition="view/availableActions"
 | 
				
			||||||
 | 
					        metal:define-slot="bottom_buttons">
 | 
				
			||||||
 | 
					    <input tal:repeat="action view/actions"
 | 
				
			||||||
 | 
					           tal:replace="structure action/render"
 | 
				
			||||||
 | 
					           />
 | 
				
			||||||
 | 
					  </span>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<form metal:use-macro="views/resource_macros/delete_object" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script type="text/javascript" metal:define-slot="trackChanges">
 | 
				
			||||||
 | 
					  zc_trackChanges(document.getElementById('zc.page.browser_form'));
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script type="text/javascript"
 | 
				
			||||||
 | 
					    tal:define="extra_script view/extra_script | nothing"
 | 
				
			||||||
 | 
					    tal:condition="extra_script"
 | 
				
			||||||
 | 
					    tal:content="structure extra_script" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></div></body></html>
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
 | 
				
			||||||
from zope.app.intid.interfaces import IIntIds
 | 
					from zope.app.intid.interfaces import IIntIds
 | 
				
			||||||
from zope.dottedname.resolve import resolve
 | 
					from zope.dottedname.resolve import resolve
 | 
				
			||||||
from zope.event import notify
 | 
					from zope.event import notify
 | 
				
			||||||
 | 
					from zope.formlib.namedtemplate import NamedTemplate
 | 
				
			||||||
from zope.proxy import removeAllProxies
 | 
					from zope.proxy import removeAllProxies
 | 
				
			||||||
from zope.security import canAccess, canWrite
 | 
					from zope.security import canAccess, canWrite
 | 
				
			||||||
from zope.security.proxy import removeSecurityProxy
 | 
					from zope.security.proxy import removeSecurityProxy
 | 
				
			||||||
| 
						 | 
					@ -50,7 +51,7 @@ from loops.browser.concept import ConceptView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NodeView(BaseView):
 | 
					class NodeView(BaseView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template = ViewPageTemplateFile('node_macros.pt')
 | 
					    template = NamedTemplate('loops.node_macros')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Lazy
 | 
					    @Lazy
 | 
				
			||||||
    def macro(self):
 | 
					    def macro(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,10 @@ from zope.formlib.namedtemplate import NamedTemplateImplementation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pageform = NamedTemplateImplementation(ViewPageTemplateFile('pageform.pt'))
 | 
					pageform = NamedTemplateImplementation(ViewPageTemplateFile('pageform.pt'))
 | 
				
			||||||
 | 
					dataform = NamedTemplateImplementation(ViewPageTemplateFile('dataform.pt'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					concept_macros = NamedTemplateImplementation(ViewPageTemplateFile('concept_macros.pt'))
 | 
				
			||||||
 | 
					node_macros = NamedTemplateImplementation(ViewPageTemplateFile('node_macros.pt'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LoopsMenu(BrowserMenu):
 | 
					class LoopsMenu(BrowserMenu):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,19 +208,19 @@ sure that a principal object can be served by a corresponding factory):
 | 
				
			||||||
  >>> from zope.app.authentication.principalfolder import FoundPrincipalFactory
 | 
					  >>> from zope.app.authentication.principalfolder import FoundPrincipalFactory
 | 
				
			||||||
  >>> component.provideAdapter(FoundPrincipalFactory)
 | 
					  >>> component.provideAdapter(FoundPrincipalFactory)
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  >>> form = {'field.userId': u'newuser',
 | 
					  >>> data = {'loginName': u'newuser',
 | 
				
			||||||
  ...         'field.passwd': u'quack',
 | 
					  ...         'password': u'quack',
 | 
				
			||||||
  ...         'field.passwdConfirm': u'quack',
 | 
					  ...         'passwordConfirm': u'quack',
 | 
				
			||||||
  ...         'field.lastName': u'Sawyer',
 | 
					  ...         'lastName': u'Sawyer',
 | 
				
			||||||
  ...         'field.firstName': u'Tom'}
 | 
					  ...         'firstName': u'Tom'}
 | 
				
			||||||
  >>> from zope.publisher.browser import TestRequest
 | 
					 | 
				
			||||||
  >>> request = TestRequest(form=form)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
and register it
 | 
					and register it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  >>> from zope.publisher.browser import TestRequest
 | 
				
			||||||
 | 
					  >>> request = TestRequest()
 | 
				
			||||||
  >>> from loops.organize.browser import MemberRegistration
 | 
					  >>> from loops.organize.browser import MemberRegistration
 | 
				
			||||||
  >>> regView = MemberRegistration(menu, request)
 | 
					  >>> regView = MemberRegistration(menu, request)
 | 
				
			||||||
  >>> personAdapter = regView.register()
 | 
					  >>> 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'newuser', u'Sawyer', u'loops.newuser')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,23 +25,31 @@ $Id$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zope import interface, component
 | 
					from zope import interface, component
 | 
				
			||||||
from zope.app import zapi
 | 
					from zope.app import zapi
 | 
				
			||||||
 | 
					from zope.app.form.browser.textwidgets import PasswordWidget as BasePasswordWidget
 | 
				
			||||||
 | 
					from zope.app.form.interfaces import WidgetInputError
 | 
				
			||||||
from zope.app.pagetemplate import ViewPageTemplateFile
 | 
					from zope.app.pagetemplate import ViewPageTemplateFile
 | 
				
			||||||
from zope.app.principalannotation import annotations
 | 
					from zope.app.principalannotation import annotations
 | 
				
			||||||
from zope.cachedescriptors.property import Lazy
 | 
					from zope.cachedescriptors.property import Lazy
 | 
				
			||||||
 | 
					from zope.formlib.form import Form, FormFields, action
 | 
				
			||||||
 | 
					from zope.formlib.namedtemplate import NamedTemplate
 | 
				
			||||||
from zope.i18nmessageid import MessageFactory
 | 
					from zope.i18nmessageid import MessageFactory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from loops.browser.common import BaseView
 | 
					from loops.browser.common import BaseView
 | 
				
			||||||
 | 
					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 raiseValidationError
 | 
					from loops.organize.interfaces import IMemberRegistration, raiseValidationError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_ = MessageFactory('zope')
 | 
					_ = MessageFactory('zope')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MyConcepts(BaseView):
 | 
					class MyConcepts(BaseView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template = ViewPageTemplateFile('../browser/concept_macros.pt')
 | 
					    template = NamedTemplate('loops.concept_macros')
 | 
				
			||||||
    macro = template.macros['conceptlisting']
 | 
					
 | 
				
			||||||
 | 
					    @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
 | 
				
			||||||
| 
						 | 
					@ -70,21 +78,42 @@ class MyConcepts(BaseView):
 | 
				
			||||||
            yield ConceptRelationView(r, self.request, contextIsSecond=True)
 | 
					            yield ConceptRelationView(r, self.request, contextIsSecond=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MemberRegistration(object):
 | 
					class PasswordWidget(BasePasswordWidget):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getInputValue(self):
 | 
				
			||||||
 | 
					        value = super(PasswordWidget, self).getInputValue()
 | 
				
			||||||
 | 
					        confirm = self.request.get('form.passwordConfirm')
 | 
				
			||||||
 | 
					        if confirm != value:
 | 
				
			||||||
 | 
					            v = _(u'Password and password confirmation do not match.')
 | 
				
			||||||
 | 
					            self._error = WidgetInputError(
 | 
				
			||||||
 | 
					                self.context.__name__, self.label, v)
 | 
				
			||||||
 | 
					            raise self._error
 | 
				
			||||||
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MemberRegistration(Form, NodeView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    form_fields = FormFields(IMemberRegistration)
 | 
				
			||||||
 | 
					    template = NamedTemplate('loops.dataform')
 | 
				
			||||||
 | 
					    label = _(u'Member Registration')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, context, request):
 | 
					    def __init__(self, context, request):
 | 
				
			||||||
        self.context = context
 | 
					        NodeView.__init__(self, context, request)
 | 
				
			||||||
        self.request = request
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def register(self):
 | 
					    @action(_(u'Register'))
 | 
				
			||||||
        form = self.request.form
 | 
					    def handle_register_action(self, action, data):
 | 
				
			||||||
        pw = form.get('field.passwd')
 | 
					        self.register(data)
 | 
				
			||||||
        if form.get('field.passwdConfirm') != pw:
 | 
					
 | 
				
			||||||
            raiseValidationError(_(u'Password and password confirmation '
 | 
					    def register(self, data=None):
 | 
				
			||||||
                                    'do not match.'))
 | 
					        form = data or self.request.form
 | 
				
			||||||
 | 
					        pw = form.get('password')
 | 
				
			||||||
 | 
					        if form.get('passwordConfirm') != pw:
 | 
				
			||||||
 | 
					            raise ValueError(u'Password and password confirmation do not match.')
 | 
				
			||||||
        regMan = IMemberRegistrationManager(self.context.getLoopsRoot())
 | 
					        regMan = IMemberRegistrationManager(self.context.getLoopsRoot())
 | 
				
			||||||
        person = regMan.register(form.get('field.userId'), pw,
 | 
					        person = regMan.register(form.get('loginName'), pw,
 | 
				
			||||||
                                 form.get('field.lastName'),
 | 
					                                 form.get('lastName'),
 | 
				
			||||||
                                 form.get('field.firstName'))
 | 
					                                 form.get('firstName'))
 | 
				
			||||||
 | 
					        message = _(u'You have been registered and can now login.')
 | 
				
			||||||
 | 
					        self.request.response.redirect('%s?message=%s' % (self.url, message))
 | 
				
			||||||
        return person
 | 
					        return person
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@
 | 
				
			||||||
   i18n_domain="zope"
 | 
					   i18n_domain="zope"
 | 
				
			||||||
   >
 | 
					   >
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <!-- adapters -->
 | 
					  <!-- party: person, ... -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <zope:adapter factory="loops.organize.party.Person"
 | 
					  <zope:adapter factory="loops.organize.party.Person"
 | 
				
			||||||
                provides="loops.organize.interfaces.IPerson"
 | 
					                provides="loops.organize.interfaces.IPerson"
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,14 @@
 | 
				
			||||||
             set_schema="loops.organize.interfaces.IPerson" />
 | 
					             set_schema="loops.organize.interfaces.IPerson" />
 | 
				
			||||||
  </zope:class>
 | 
					  </zope:class>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:subscriber
 | 
				
			||||||
 | 
					        for="loops.interfaces.IConcept
 | 
				
			||||||
 | 
					             zope.app.container.interfaces.IObjectRemovedEvent"
 | 
				
			||||||
 | 
					        handler="loops.organize.party.removePersonReferenceFromPrincipal"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <!-- my stuff and other views -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <zope:adapter
 | 
					  <zope:adapter
 | 
				
			||||||
        name="myconcepts"
 | 
					        name="myconcepts"
 | 
				
			||||||
        for="loops.interfaces.IConcept
 | 
					        for="loops.interfaces.IConcept
 | 
				
			||||||
| 
						 | 
					@ -28,10 +36,27 @@
 | 
				
			||||||
        permission="zope.View"
 | 
					        permission="zope.View"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <zope:subscriber
 | 
					  <!-- member registration -->
 | 
				
			||||||
        for="loops.interfaces.IConcept
 | 
					
 | 
				
			||||||
             zope.app.container.interfaces.IObjectRemovedEvent"
 | 
					  <zope:adapter factory="loops.organize.member.MemberRegistrationManager"
 | 
				
			||||||
        handler="loops.organize.party.removePersonReferenceFromPrincipal"
 | 
					                trusted="True" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:class class="loops.organize.member.MemberRegistrationManager">
 | 
				
			||||||
 | 
					    <require permission ="zope.Public"
 | 
				
			||||||
 | 
					             interface="loops.organize.interfaces.IMemberRegistrationManager" />
 | 
				
			||||||
 | 
					  </zope:class>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <browser:page name="registration.html"
 | 
				
			||||||
 | 
					        for="loops.interfaces.IView"
 | 
				
			||||||
 | 
					        class="loops.organize.browser.MemberRegistration"
 | 
				
			||||||
 | 
					        permission="zope.Public" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <zope:view
 | 
				
			||||||
 | 
					      type="zope.publisher.interfaces.browser.IBrowserRequest"
 | 
				
			||||||
 | 
					      for="loops.organize.interfaces.Password"
 | 
				
			||||||
 | 
					      provides="zope.app.form.interfaces.IInputWidget"
 | 
				
			||||||
 | 
					      factory="loops.organize.browser.PasswordWidget"
 | 
				
			||||||
 | 
					      permission="zope.Public"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</configure>
 | 
					</configure>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ $Id$
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zope.interface import Interface, Attribute
 | 
					from zope.interface import Interface, Attribute
 | 
				
			||||||
from zope import component, schema
 | 
					from zope import interface, component, schema
 | 
				
			||||||
from zope.app import zapi
 | 
					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
 | 
				
			||||||
| 
						 | 
					@ -65,22 +65,68 @@ class UserId(schema.TextLine):
 | 
				
			||||||
                               userId=userId)))
 | 
					                               userId=userId)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LoginName(schema.TextLine):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate(self, userId):
 | 
				
			||||||
 | 
					        super(LoginName, self)._validate(userId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Password(schema.Password):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate(self, pw):
 | 
				
			||||||
 | 
					        super(Password, self)._validate(pw)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IPerson(IBasePerson):
 | 
					class IPerson(IBasePerson):
 | 
				
			||||||
    """ Resembles a human being with a name (first and last name),
 | 
					    """ Resembles a human being with a name (first and last name),
 | 
				
			||||||
        a birth date, and a set of addresses. This interface only
 | 
					        a birth date, and a set of addresses. This interface only
 | 
				
			||||||
        lists fields used in addidtion to those provided by the
 | 
					        lists fields used in addition to those provided by the
 | 
				
			||||||
        basic cybertools.organize package.
 | 
					        basic cybertools.organize package.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    userId = UserId(
 | 
					    userId = UserId(title=_(u'User ID'),
 | 
				
			||||||
                    title=_(u'User ID'),
 | 
					                    description=_(u'The principal id (including prinicipal '
 | 
				
			||||||
                    description=_(u'The principal id of a user that should '
 | 
					                                   'folder prefix) of a user that should '
 | 
				
			||||||
                                   'be associated with this person.'),
 | 
					                                   'be associated with this person.'),
 | 
				
			||||||
                    required=False,)
 | 
					                    required=False,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IPasswordEntry(Interface):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    password = Password(title=_(u'Password'),
 | 
				
			||||||
 | 
					                    description=_(u'Enter password.'),
 | 
				
			||||||
 | 
					                    required=True,)
 | 
				
			||||||
 | 
					    passwordConfirm = schema.Password(title=_(u'Confirm password'),
 | 
				
			||||||
 | 
					                    description=_(u'Please repeat the password.'),
 | 
				
			||||||
 | 
					                    required=True,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #@interface.invariant
 | 
				
			||||||
 | 
					    #def passwordMatchConfirm(data):
 | 
				
			||||||
 | 
					    #    if data.password != data.passwordConfirm:
 | 
				
			||||||
 | 
					    #        raise interface.Invalid(_(u'Password and password confirmation '
 | 
				
			||||||
 | 
					    #                                   'do not match.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IPasswordChange(IPasswordEntry):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    oldPassword = schema.Password(title=_(u'Old password'),
 | 
				
			||||||
 | 
					                    description=_(u'Enter old password.'),
 | 
				
			||||||
 | 
					                    required=True,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IMemberRegistration(IBasePerson, IPasswordEntry):
 | 
				
			||||||
 | 
					    """ Schema for registering a new member (user + person).
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loginName = LoginName(
 | 
				
			||||||
 | 
					                    title=_(u'User ID'),
 | 
				
			||||||
 | 
					                    description=_(u'Enter a user id.'),
 | 
				
			||||||
 | 
					                    required=True,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IMemberRegistrationManager(Interface):
 | 
					class IMemberRegistrationManager(Interface):
 | 
				
			||||||
    """ Knows what to do for registrating a new member (portal user).
 | 
					    """ Knows what to do for registrating a new member (portal user),
 | 
				
			||||||
 | 
					        change password, etc.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    authPluginId = Attribute(u'The id of an authentication plugin to be '
 | 
					    authPluginId = Attribute(u'The id of an authentication plugin to be '
 | 
				
			||||||
| 
						 | 
					@ -89,11 +135,11 @@ class IMemberRegistrationManager(Interface):
 | 
				
			||||||
    def register(userId, password, lastName, firstName=u'', **kw):
 | 
					    def register(userId, password, lastName, firstName=u'', **kw):
 | 
				
			||||||
        """ Register a new member for this loops site.
 | 
					        """ Register a new member for this loops site.
 | 
				
			||||||
            Return the person adapter for the concept created.
 | 
					            Return the person adapter for the concept created.
 | 
				
			||||||
            Raise ValidationError if the user could not be created.
 | 
					            Raise Validation Error (?) if the user could not be created.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def changePassword(oldPw, newPw):
 | 
					    def changePassword(newPw):
 | 
				
			||||||
        """ Change the password of the user currently logged-in.
 | 
					        """ Change the password of the user currently logged-in.
 | 
				
			||||||
            Raise a ValidationError if the oldPw does not match the
 | 
					            Raise a Validation Error (?) if the oldPw does not match the
 | 
				
			||||||
            current password.
 | 
					            current password.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,13 +23,15 @@ $Id$
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zope.app import zapi
 | 
					from zope.app import zapi
 | 
				
			||||||
from zope import interface, component
 | 
					from zope import interface, component, schema
 | 
				
			||||||
from zope.component import adapts
 | 
					from zope.component import adapts
 | 
				
			||||||
from zope.interface import implements
 | 
					from zope.interface import implements
 | 
				
			||||||
from zope.app.authentication.interfaces import IPluggableAuthentication
 | 
					from zope.app.authentication.interfaces import IPluggableAuthentication
 | 
				
			||||||
from zope.app.authentication.interfaces import IAuthenticatorPlugin
 | 
					from zope.app.authentication.interfaces import IAuthenticatorPlugin
 | 
				
			||||||
from zope.app.authentication.principalfolder import InternalPrincipal
 | 
					from zope.app.authentication.principalfolder import InternalPrincipal
 | 
				
			||||||
 | 
					from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent
 | 
				
			||||||
from zope.app.security.interfaces import IAuthentication
 | 
					from zope.app.security.interfaces import IAuthentication
 | 
				
			||||||
 | 
					from zope.event import notify
 | 
				
			||||||
from zope.i18nmessageid import MessageFactory
 | 
					from zope.i18nmessageid import MessageFactory
 | 
				
			||||||
from zope.cachedescriptors.property import Lazy
 | 
					from zope.cachedescriptors.property import Lazy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +39,6 @@ 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.interfaces import raiseValidationError
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
_ = MessageFactory('zope')
 | 
					_ = MessageFactory('zope')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,24 +57,24 @@ class MemberRegistrationManager(object):
 | 
				
			||||||
        # 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)
 | 
					        pau = zapi.getUtility(IAuthentication, context=self.context)
 | 
				
			||||||
        if not IPluggableAuthentication.providedBy(pau):
 | 
					        if not IPluggableAuthentication.providedBy(pau):
 | 
				
			||||||
            raiseValidationError(_(u'There is no pluggable authentication '
 | 
					            raise ValueError(u'There is no pluggable authentication '
 | 
				
			||||||
                                    'utility available.'))
 | 
					                                    'utility available.')
 | 
				
			||||||
        if not self.authPluginId in pau.authenticatorPlugins:
 | 
					        if not self.authPluginId in pau.authenticatorPlugins:
 | 
				
			||||||
            raiseValidationError(_(u'There is no loops authenticator '
 | 
					            raise ValueError(u'There is no loops authenticator '
 | 
				
			||||||
                                    'plugin available.'))
 | 
					                                    'plugin available.')
 | 
				
			||||||
        pFolder = component.queryUtility(IAuthenticatorPlugin, self.authPluginId,
 | 
					        pFolder = component.queryUtility(IAuthenticatorPlugin, self.authPluginId,
 | 
				
			||||||
                                         context=pau)
 | 
					                                         context=pau)
 | 
				
			||||||
        title = firstName and ' '.join((firstName, lastName)) or lastName
 | 
					        title = firstName and ' '.join((firstName, lastName)) or lastName
 | 
				
			||||||
        # TODO: encrypt password:
 | 
					        # TODO: care for password encryption:
 | 
				
			||||||
        principal = InternalPrincipal(userId, password, title)
 | 
					        principal = InternalPrincipal(userId, password, title)
 | 
				
			||||||
        pFolder[userId] = principal
 | 
					        pFolder[userId] = principal
 | 
				
			||||||
        # step 1: create a corresponding person concept:
 | 
					        # step 2: create a corresponding person concept:
 | 
				
			||||||
        cm = self.context.getConceptManager()
 | 
					        cm = self.context.getConceptManager()
 | 
				
			||||||
        id = userId
 | 
					        id = userId
 | 
				
			||||||
        num = 0
 | 
					        num = 0
 | 
				
			||||||
        while id in cm:
 | 
					        while id in cm:
 | 
				
			||||||
            num +=1
 | 
					            num +=1
 | 
				
			||||||
            id = userid + str(num)
 | 
					            id = userId + 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!
 | 
				
			||||||
        person.conceptType = cm['person']
 | 
					        person.conceptType = cm['person']
 | 
				
			||||||
| 
						 | 
					@ -81,6 +82,8 @@ class MemberRegistrationManager(object):
 | 
				
			||||||
        personAdapter.firstName = firstName
 | 
					        personAdapter.firstName = firstName
 | 
				
			||||||
        personAdapter.lastName = lastName
 | 
					        personAdapter.lastName = lastName
 | 
				
			||||||
        personAdapter.userId = '.'.join((self.authPluginId, userId))
 | 
					        personAdapter.userId = '.'.join((self.authPluginId, userId))
 | 
				
			||||||
 | 
					        notify(ObjectCreatedEvent(person))
 | 
				
			||||||
 | 
					        notify(ObjectModifiedEvent(person))
 | 
				
			||||||
        return personAdapter
 | 
					        return personAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def changePassword(self, oldPw, newPw):
 | 
					    def changePassword(self, oldPw, newPw):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue