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):
 | 
			
		||||
 | 
			
		||||
    template = NamedTemplate('pageform')
 | 
			
		||||
    template = NamedTemplate('loops.pageform')
 | 
			
		||||
 | 
			
		||||
    def deleteObjectAction(self):
 | 
			
		||||
        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.event import notify
 | 
			
		||||
from zope.formlib.form import EditForm, FormFields
 | 
			
		||||
from zope.formlib.namedtemplate import NamedTemplate
 | 
			
		||||
from zope.interface import implements
 | 
			
		||||
from zope.publisher.interfaces import BadRequest
 | 
			
		||||
from zope.publisher.interfaces.browser import IBrowserRequest
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +64,11 @@ class ConceptEditForm(EditForm):
 | 
			
		|||
 | 
			
		||||
class ConceptView(BaseView):
 | 
			
		||||
 | 
			
		||||
    template = ViewPageTemplateFile('concept_macros.pt')
 | 
			
		||||
    macro = template.macros['conceptlisting']
 | 
			
		||||
    template = NamedTemplate('loops.concept_macros')
 | 
			
		||||
    
 | 
			
		||||
    @Lazy
 | 
			
		||||
    def macro(self):
 | 
			
		||||
        return self.template.macros['conceptlisting']
 | 
			
		||||
 | 
			
		||||
    def children(self):
 | 
			
		||||
        for r in self.context.getChildRelations():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,12 +61,27 @@
 | 
			
		|||
      permission="zope.View"
 | 
			
		||||
      />
 | 
			
		||||
 | 
			
		||||
  <!-- named template(s) -->
 | 
			
		||||
  <!-- named templates - forms and macro templates -->
 | 
			
		||||
 | 
			
		||||
  <zope:adapter
 | 
			
		||||
      factory="loops.browser.util.pageform"
 | 
			
		||||
      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 -->
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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.dottedname.resolve import resolve
 | 
			
		||||
from zope.event import notify
 | 
			
		||||
from zope.formlib.namedtemplate import NamedTemplate
 | 
			
		||||
from zope.proxy import removeAllProxies
 | 
			
		||||
from zope.security import canAccess, canWrite
 | 
			
		||||
from zope.security.proxy import removeSecurityProxy
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +51,7 @@ from loops.browser.concept import ConceptView
 | 
			
		|||
 | 
			
		||||
class NodeView(BaseView):
 | 
			
		||||
 | 
			
		||||
    template = ViewPageTemplateFile('node_macros.pt')
 | 
			
		||||
    template = NamedTemplate('loops.node_macros')
 | 
			
		||||
 | 
			
		||||
    @Lazy
 | 
			
		||||
    def macro(self):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,10 @@ from zope.formlib.namedtemplate import NamedTemplateImplementation
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,19 +208,19 @@ sure that a principal object can be served by a corresponding factory):
 | 
			
		|||
  >>> from zope.app.authentication.principalfolder import FoundPrincipalFactory
 | 
			
		||||
  >>> component.provideAdapter(FoundPrincipalFactory)
 | 
			
		||||
  
 | 
			
		||||
  >>> form = {'field.userId': u'newuser',
 | 
			
		||||
  ...         'field.passwd': u'quack',
 | 
			
		||||
  ...         'field.passwdConfirm': u'quack',
 | 
			
		||||
  ...         'field.lastName': u'Sawyer',
 | 
			
		||||
  ...         'field.firstName': u'Tom'}
 | 
			
		||||
  >>> from zope.publisher.browser import TestRequest
 | 
			
		||||
  >>> request = TestRequest(form=form)
 | 
			
		||||
  >>> data = {'loginName': u'newuser',
 | 
			
		||||
  ...         'password': u'quack',
 | 
			
		||||
  ...         'passwordConfirm': u'quack',
 | 
			
		||||
  ...         'lastName': u'Sawyer',
 | 
			
		||||
  ...         'firstName': u'Tom'}
 | 
			
		||||
 | 
			
		||||
and register it
 | 
			
		||||
 | 
			
		||||
  >>> from zope.publisher.browser import TestRequest
 | 
			
		||||
  >>> request = TestRequest()
 | 
			
		||||
  >>> from loops.organize.browser import MemberRegistration
 | 
			
		||||
  >>> regView = MemberRegistration(menu, request)
 | 
			
		||||
  >>> personAdapter = regView.register()
 | 
			
		||||
  >>> personAdapter = regView.register(data)
 | 
			
		||||
 | 
			
		||||
  >>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId
 | 
			
		||||
  (u'newuser', u'Sawyer', u'loops.newuser')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,23 +25,31 @@ $Id$
 | 
			
		|||
 | 
			
		||||
from zope import interface, component
 | 
			
		||||
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.principalannotation import annotations
 | 
			
		||||
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 loops.browser.common import BaseView
 | 
			
		||||
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 raiseValidationError
 | 
			
		||||
from loops.organize.interfaces import IMemberRegistration, raiseValidationError
 | 
			
		||||
 | 
			
		||||
_ = MessageFactory('zope')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyConcepts(BaseView):
 | 
			
		||||
 | 
			
		||||
    template = ViewPageTemplateFile('../browser/concept_macros.pt')
 | 
			
		||||
    macro = template.macros['conceptlisting']
 | 
			
		||||
    template = NamedTemplate('loops.concept_macros')
 | 
			
		||||
 | 
			
		||||
    @Lazy
 | 
			
		||||
    def macro(self):
 | 
			
		||||
        return self.template.macros['conceptlisting']
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, request):
 | 
			
		||||
        self.context = context
 | 
			
		||||
| 
						 | 
				
			
			@ -70,21 +78,42 @@ class MyConcepts(BaseView):
 | 
			
		|||
            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):
 | 
			
		||||
        self.context = context
 | 
			
		||||
        self.request = request
 | 
			
		||||
        NodeView.__init__(self, context, request)
 | 
			
		||||
 | 
			
		||||
    def register(self):
 | 
			
		||||
        form = self.request.form
 | 
			
		||||
        pw = form.get('field.passwd')
 | 
			
		||||
        if form.get('field.passwdConfirm') != pw:
 | 
			
		||||
            raiseValidationError(_(u'Password and password confirmation '
 | 
			
		||||
                                    'do not match.'))
 | 
			
		||||
    @action(_(u'Register'))
 | 
			
		||||
    def handle_register_action(self, action, data):
 | 
			
		||||
        self.register(data)
 | 
			
		||||
 | 
			
		||||
    def register(self, data=None):
 | 
			
		||||
        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())
 | 
			
		||||
        person = regMan.register(form.get('field.userId'), pw,
 | 
			
		||||
                                 form.get('field.lastName'),
 | 
			
		||||
                                 form.get('field.firstName'))
 | 
			
		||||
        person = regMan.register(form.get('loginName'), 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))
 | 
			
		||||
        return person
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
   i18n_domain="zope"
 | 
			
		||||
   >
 | 
			
		||||
 | 
			
		||||
  <!-- adapters -->
 | 
			
		||||
  <!-- party: person, ... -->
 | 
			
		||||
 | 
			
		||||
  <zope:adapter factory="loops.organize.party.Person"
 | 
			
		||||
                provides="loops.organize.interfaces.IPerson"
 | 
			
		||||
| 
						 | 
				
			
			@ -19,19 +19,44 @@
 | 
			
		|||
             set_schema="loops.organize.interfaces.IPerson" />
 | 
			
		||||
  </zope:class>
 | 
			
		||||
 | 
			
		||||
  <zope:adapter
 | 
			
		||||
      name="myconcepts"
 | 
			
		||||
      for="loops.interfaces.IConcept
 | 
			
		||||
           zope.publisher.interfaces.browser.IBrowserRequest"
 | 
			
		||||
      provides="zope.interface.Interface"
 | 
			
		||||
      factory="loops.organize.browser.MyConcepts"
 | 
			
		||||
      permission="zope.View"
 | 
			
		||||
      />
 | 
			
		||||
  
 | 
			
		||||
  <zope:subscriber
 | 
			
		||||
        for="loops.interfaces.IConcept
 | 
			
		||||
             zope.app.container.interfaces.IObjectRemovedEvent"
 | 
			
		||||
        handler="loops.organize.party.removePersonReferenceFromPrincipal"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
  <!-- my stuff and other views -->
 | 
			
		||||
 | 
			
		||||
  <zope:adapter
 | 
			
		||||
        name="myconcepts"
 | 
			
		||||
        for="loops.interfaces.IConcept
 | 
			
		||||
            zope.publisher.interfaces.browser.IBrowserRequest"
 | 
			
		||||
        provides="zope.interface.Interface"
 | 
			
		||||
        factory="loops.organize.browser.MyConcepts"
 | 
			
		||||
        permission="zope.View"
 | 
			
		||||
        />
 | 
			
		||||
  
 | 
			
		||||
  <!-- member registration -->
 | 
			
		||||
 | 
			
		||||
  <zope:adapter factory="loops.organize.member.MemberRegistrationManager"
 | 
			
		||||
                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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ $Id$
 | 
			
		|||
"""
 | 
			
		||||
 | 
			
		||||
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.principalannotation import annotations
 | 
			
		||||
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
 | 
			
		||||
| 
						 | 
				
			
			@ -65,22 +65,68 @@ class UserId(schema.TextLine):
 | 
			
		|||
                               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):
 | 
			
		||||
    """ Resembles a human being with a name (first and last name),
 | 
			
		||||
        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.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    userId = UserId(
 | 
			
		||||
                    title=_(u'User ID'),
 | 
			
		||||
                    description=_(u'The principal id of a user that should '
 | 
			
		||||
    userId = UserId(title=_(u'User ID'),
 | 
			
		||||
                    description=_(u'The principal id (including prinicipal '
 | 
			
		||||
                                   'folder prefix) of a user that should '
 | 
			
		||||
                                   'be associated with this person.'),
 | 
			
		||||
                    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):
 | 
			
		||||
    """ 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 '
 | 
			
		||||
| 
						 | 
				
			
			@ -89,11 +135,11 @@ class IMemberRegistrationManager(Interface):
 | 
			
		|||
    def register(userId, password, lastName, firstName=u'', **kw):
 | 
			
		||||
        """ Register a new member for this loops site.
 | 
			
		||||
            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.
 | 
			
		||||
            Raise a ValidationError if the oldPw does not match the
 | 
			
		||||
            Raise a Validation Error (?) if the oldPw does not match the
 | 
			
		||||
            current password.
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,13 +23,15 @@ $Id$
 | 
			
		|||
"""
 | 
			
		||||
 | 
			
		||||
from zope.app import zapi
 | 
			
		||||
from zope import interface, component
 | 
			
		||||
from zope import interface, component, schema
 | 
			
		||||
from zope.component import adapts
 | 
			
		||||
from zope.interface import implements
 | 
			
		||||
from zope.app.authentication.interfaces import IPluggableAuthentication
 | 
			
		||||
from zope.app.authentication.interfaces import IAuthenticatorPlugin
 | 
			
		||||
from zope.app.authentication.principalfolder import InternalPrincipal
 | 
			
		||||
from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent
 | 
			
		||||
from zope.app.security.interfaces import IAuthentication
 | 
			
		||||
from zope.event import notify
 | 
			
		||||
from zope.i18nmessageid import MessageFactory
 | 
			
		||||
from zope.cachedescriptors.property import Lazy
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +39,6 @@ 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.interfaces import raiseValidationError
 | 
			
		||||
 | 
			
		||||
_ = MessageFactory('zope')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,24 +57,24 @@ class MemberRegistrationManager(object):
 | 
			
		|||
        # step 1: create an internal principal in the loops principal folder:
 | 
			
		||||
        pau = zapi.getUtility(IAuthentication, context=self.context)
 | 
			
		||||
        if not IPluggableAuthentication.providedBy(pau):
 | 
			
		||||
            raiseValidationError(_(u'There is no pluggable authentication '
 | 
			
		||||
                                    'utility available.'))
 | 
			
		||||
            raise ValueError(u'There is no pluggable authentication '
 | 
			
		||||
                                    'utility available.')
 | 
			
		||||
        if not self.authPluginId in pau.authenticatorPlugins:
 | 
			
		||||
            raiseValidationError(_(u'There is no loops authenticator '
 | 
			
		||||
                                    'plugin available.'))
 | 
			
		||||
            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
 | 
			
		||||
        # TODO: encrypt password:
 | 
			
		||||
        # TODO: care for password encryption:
 | 
			
		||||
        principal = InternalPrincipal(userId, password, title)
 | 
			
		||||
        pFolder[userId] = principal
 | 
			
		||||
        # step 1: create a corresponding person concept:
 | 
			
		||||
        # step 2: create a corresponding person concept:
 | 
			
		||||
        cm = self.context.getConceptManager()
 | 
			
		||||
        id = userId
 | 
			
		||||
        num = 0
 | 
			
		||||
        while id in cm:
 | 
			
		||||
            num +=1
 | 
			
		||||
            id = userid + str(num)
 | 
			
		||||
            id = userId + str(num)
 | 
			
		||||
        person = cm[id] = Concept(title)
 | 
			
		||||
        # TODO: the name of the person type object must be kept flexible!
 | 
			
		||||
        person.conceptType = cm['person']
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +82,8 @@ class MemberRegistrationManager(object):
 | 
			
		|||
        personAdapter.firstName = firstName
 | 
			
		||||
        personAdapter.lastName = lastName
 | 
			
		||||
        personAdapter.userId = '.'.join((self.authPluginId, userId))
 | 
			
		||||
        notify(ObjectCreatedEvent(person))
 | 
			
		||||
        notify(ObjectModifiedEvent(person))
 | 
			
		||||
        return personAdapter
 | 
			
		||||
 | 
			
		||||
    def changePassword(self, oldPw, newPw):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue