diff --git a/knowledge/README.txt b/knowledge/README.txt index 714f137..febd92c 100644 --- a/knowledge/README.txt +++ b/knowledge/README.txt @@ -12,7 +12,6 @@ Let's do some basic set up >>> site = placefulSetUp(True) >>> from zope import component, interface - >>> from zope.app import zapi and setup a simple loops site with a concept manager and some concepts (with all the type machinery, what in real life is done via standard diff --git a/organize/README.txt b/organize/README.txt index afae88b..b508254 100644 --- a/organize/README.txt +++ b/organize/README.txt @@ -6,42 +6,25 @@ loops - Linked Objects for Organization and Processing Services Note: This packages depends on cybertools.organize. -Let's do some basic set up +Let's do some basic setup >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown >>> site = placefulSetUp(True) - >>> from zope import component, interface - >>> from zope.app import zapi -and setup a simple loops site with a concept manager and some concepts +and set up a simple loops site with a concept manager and some concepts (with all the type machinery, what in real life is done via standard ZCML setup): - >>> from cybertools.relation.interfaces import IRelationRegistry - >>> from cybertools.relation.registry import DummyRelationRegistry - >>> relations = DummyRelationRegistry() - >>> component.provideUtility(relations) - - >>> from cybertools.typology.interfaces import IType - >>> from loops.interfaces import IConcept, ITypeConcept - >>> from loops.type import ConceptType, TypeConcept - >>> component.provideAdapter(ConceptType, (IConcept,), IType) - >>> component.provideAdapter(TypeConcept, (IConcept,), ITypeConcept) - - >>> from loops.interfaces import ILoops - >>> from loops.setup import ISetupManager >>> from loops.organize.setup import SetupManager - >>> component.provideAdapter(SetupManager, (ILoops,), ISetupManager, - ... name='organize') + >>> component.provideAdapter(SetupManager, name='organize') + >>> from loops.tests.setup import TestSite + >>> t = TestSite(site) + >>> concepts, resources, views = t.setup() - >>> from loops.base import Loops - >>> loopsRoot = site['loops'] = Loops() - >>> loopsId = relations.getUniqueIdForObject(loopsRoot) - - >>> from loops.setup import SetupManager - >>> setup = SetupManager(loopsRoot) - >>> concepts, resources, views = setup.setup() + >>> from loops import util + >>> loopsRoot = site['loops'] + >>> loopsId = util.getUidForObject(loopsRoot) >>> type = concepts['type'] >>> person = concepts['person'] @@ -56,6 +39,7 @@ Organizations: Persons (and Users), Institutions, Addresses... The classes used in this package are just adapters to IConcept. + >>> from loops.interfaces import IConcept >>> from loops.organize.interfaces import IPerson >>> from loops.organize.party import Person >>> component.provideAdapter(Person, (IConcept,), IPerson) @@ -192,7 +176,6 @@ and register an IMemberRegistrationManager adapter for the loops root object: >>> menu.nodeType = 'menu' >>> from loops.organize.member import MemberRegistrationManager - >>> from loops.organize.interfaces import IMemberRegistrationManager >>> component.provideAdapter(MemberRegistrationManager) Now we can enter the registration info for a new member (after having made @@ -205,18 +188,24 @@ sure that a principal object can be served by a corresponding factory): ... 'password': u'quack', ... 'passwordConfirm': u'quack', ... 'lastName': u'Sawyer', - ... 'firstName': u'Tom'} + ... 'firstName': u'Tom', + ... 'email': u'tommy@sawyer.com', + ... 'action': 'update',} -and register it +and register it. >>> from zope.publisher.browser import TestRequest - >>> request = TestRequest() + >>> request = TestRequest(form=data) >>> from loops.organize.browser import MemberRegistration - >>> regView = MemberRegistration(menu, request, testing=True) - >>> personAdapter = regView.register(data) + >>> regView = MemberRegistration(menu, request) + >>> regView.update() + False - >>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId - (u'person.newuser', u'Sawyer', u'loops.newuser') + >>> from loops.common import adapted + >>> person = concepts['person.newuser'] + >>> pa = adapted(person) + >>> pa.lastName, pa.userId + (u'Sawyer', u'loops.newuser') Now we can also retrieve it from the authentication utility: diff --git a/organize/browser.py b/organize/browser.py index 47bbbea..d6ebf63 100644 --- a/organize/browser.py +++ b/organize/browser.py @@ -33,16 +33,18 @@ from zope.formlib.form import Form as FormlibForm, FormFields, action from zope.formlib.namedtemplate import NamedTemplate from zope.i18nmessageid import MessageFactory +from cybertools.composer.interfaces import IInstance from cybertools.composer.schema.browser.common import schema_macros -from cybertools.composer.schema.browser.form import Form +from cybertools.composer.schema.browser.form import Form, CreateForm from cybertools.composer.schema.schema import FormState, FormError from cybertools.typology.interfaces import IType from loops.browser.concept import ConceptView from loops.browser.node import NodeView from loops.browser.concept import ConceptRelationView +from loops.concept import Concept from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager from loops.organize.interfaces import IMemberRegistration, IPasswordChange -from loops.organize.party import getPersonForUser +from loops.organize.party import getPersonForUser, Person from loops.organize.util import getInternalPrincipal import loops.browser.util from loops.util import _ @@ -75,64 +77,75 @@ class PasswordWidget(BasePasswordWidget): return value -class MemberRegistration(NodeView, FormlibForm): +class MemberRegistration(NodeView, CreateForm): + + interface = IMemberRegistration + message = _(u'You have been registered.') + + formErrors = dict( + confirm_nomatch=FormError(_(u'Password and password confirmation do not match.')), + ) - form_fields = FormFields(IMemberRegistration).omit('age') - form_fields['password'].custom_widget = PasswordWidget - template = loops.browser.util.dataform label = _(u'Member Registration') - - def __init__(self, context, request, testing=False): - super(MemberRegistration, self).__init__(context, request) - if not testing: - self.setUpWidgets() + label_submit = _(u'Register') @Lazy def macro(self): - return self.template.macros['content'] + return schema_macros.macros['form'] @Lazy def item(self): return self + @Lazy + def schema(self): + schema = super(MemberRegistration, self).schema + if 'birthDate' in schema.fields: + del schema.fields['birthDate'] + return schema + + @Lazy + def object(self): + return Person(Concept()) + def update(self): - # see cybertools.browser.view.GenericView.update() - NodeView.update(self) - Form.update(self) - return True - - @action(_(u'Register')) - def handle_register_action(self, action, data): - print 'register' - self.register(data) - - def register(self, data=None): - form = data or self.request.form + form = self.request.form + if not form.get('action'): + return True + instance = component.getAdapter(self.object, IInstance, name='editor') + instance.template = self.schema + self.formState = formState = instance.applyTemplate(data=form, + fieldHandlers=self.fieldHandlers) + if formState.severity > 0: + # show form again + return True pw = form.get('password') if form.get('passwordConfirm') != pw: - raise ValueError(u'Password and password confirmation do not match.') + fi = formState.fieldInstances['password'] + fi.setError('confirm_nomatch', self.formErrors) + formState.severity = max(formState.severity, fi.severity) + return True login = form.get('loginName') regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) - person = regMan.register(login, pw, - form.get('lastName'), - form.get('firstName')) - message = _(u'You have been registered and can now login.') + self.object = regMan.register(login, pw, + form.get('lastName'), form.get('firstName')) + msg = self.message self.request.response.redirect('%s/login.html?login=%s&message=%s' - % (self.url, login, message)) - return person + % (self.url, login, msg)) + return False class PasswordChange(NodeView, Form): interface = IPasswordChange - message = u'Your password has been changed.' + message = _(u'Your password has been changed.') formErrors = dict( - confirm_nomatch=FormError(u'Password and password confirmation do not match.'), - wrong_oldpw=FormError(u'Your old password was not entered correctly.'), + confirm_nomatch=FormError(_(u'Password and password confirmation do not match.')), + wrong_oldpw=FormError(_(u'Your old password was not entered correctly.')), ) - label = label_submit = u'Change Password' + label = label_submit = _(u'Change Password') @Lazy def macro(self): diff --git a/organize/interfaces.py b/organize/interfaces.py index 891b000..821adb2 100644 --- a/organize/interfaces.py +++ b/organize/interfaces.py @@ -99,12 +99,8 @@ class IPasswordEntry(Interface): 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.')) + password.nostore = True + passwordConfirm.nostore = True class IPasswordChange(IPasswordEntry): @@ -118,10 +114,11 @@ class IMemberRegistration(IBasePerson, IPasswordEntry): """ Schema for registering a new member (user + person). """ - loginName = LoginName( + loginName = schema.TextLine( title=_(u'User ID'), description=_(u'Enter a user id.'), required=True,) + loginName.nostore = True class IMemberRegistrationManager(Interface): diff --git a/organize/party.py b/organize/party.py index 9349c29..1849279 100644 --- a/organize/party.py +++ b/organize/party.py @@ -43,6 +43,7 @@ from loops.interfaces import IConcept from loops.organize.interfaces import IPerson, ANNOTATION_KEY from loops.common import AdapterBase from loops.type import TypeInterfaceSourceList +from loops import util # register type interfaces - (TODO: use a function for this) @@ -62,8 +63,7 @@ def getPersonForUser(context, request=None, principal=None): return pa else: return None - return pa.get(component.getUtility( - IRelationRegistry, context=context).getUniqueIdForObject(loops)) + return pa.get(util.getUidForObject(loops)) class Person(AdapterBase, BasePerson): @@ -88,8 +88,8 @@ class Person(AdapterBase, BasePerson): % (zapi.getName(person), userId)) pa = annotations(principal) #pa[ANNOTATION_KEY] = self.context - intIds = component.getUtility(IRelationRegistry, context=self.context) - loopsId = intIds.getUniqueIdForObject(self.context.getLoopsRoot()) + #intIds = component.getUtility(IRelationRegistry, context=self.context) + loopsId = util.getUidForObject(self.context.getLoopsRoot()) ann = pa.get(ANNOTATION_KEY) if ann is None: ann = pa[ANNOTATION_KEY] = PersistentMapping() @@ -109,8 +109,7 @@ class Person(AdapterBase, BasePerson): pa[ANNOTATION_KEY] = None else: if ann is not None: - intIds = component.getUtility(IRelationRegistry, context=self.context) - loopsId = intIds.getUniqueIdForObject(self.context.getLoopsRoot()) + loopsId = util.getUidForObject(self.context.getLoopsRoot()) ann[loopsId] = None def getPhoneNumbers(self):