From dae9610e2efa21b3fe018b78ff73ad32038f1f76 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 27 Nov 2019 13:19:17 +0100 Subject: [PATCH 1/9] allow hiding title, e.g. if shown already in another macro --- browser/concept_macros.pt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/concept_macros.pt b/browser/concept_macros.pt index 47d9905..46e08c0 100644 --- a/browser/concept_macros.pt +++ b/browser/concept_macros.pt @@ -10,7 +10,9 @@
- + + + From 814f10ae515322c1800e94d80628020f91569149 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 27 Nov 2019 13:20:42 +0100 Subject: [PATCH 2/9] unify naming: concept_macros means macros, not template --- organize/browser/member.py | 4 ---- organize/browser/view_macros.pt | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/organize/browser/member.py b/organize/browser/member.py index 7aabe80..46ff45b 100644 --- a/organize/browser/member.py +++ b/organize/browser/member.py @@ -73,10 +73,6 @@ class PersonalInfo(ConceptView): def macro(self): return organize_macros.macros['conceptdata'] - @Lazy - def concept_macros(self): - return concept_macros - @Lazy def view(self): return self diff --git a/organize/browser/view_macros.pt b/organize/browser/view_macros.pt index 93ef80e..1e296bd 100644 --- a/organize/browser/view_macros.pt +++ b/organize/browser/view_macros.pt @@ -61,7 +61,7 @@ -
+
No Person object associated with your user account.
From dc5d913b9908f7cde33249ce14d9712e3b7dd110 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Thu, 28 Nov 2019 08:33:24 +0100 Subject: [PATCH 3/9] user account: add principal title if given --- organize/member.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/organize/member.py b/organize/member.py index ab2aded..c2357bf 100644 --- a/organize/member.py +++ b/organize/member.py @@ -100,6 +100,8 @@ class MemberRegistrationManager(object): if userId in pFolder: principal = pFolder[userId] principal.password = password + if title: + principal.title = title else: pFolder[userId] = principal elif useExisting: From 9c2517a5189b0b8df1a0f9e79a5fb1486156fe38 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 09:42:45 +0100 Subject: [PATCH 4/9] take psu.py from bbmaster2 branch, with some improvements --- psu.py | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 psu.py diff --git a/psu.py b/psu.py new file mode 100644 index 0000000..a65cc5d --- /dev/null +++ b/psu.py @@ -0,0 +1,168 @@ +# psu - paster shell utilities +# use this from (e.g.): +# +# bin/paster shell deploy.ini +# +# then: +# +# from loops import psu +# psu.setup(root) +# obj = psu.byuid('578457950') +# + +from transaction import commit, abort +from zope.app.authentication.principalfolder import Principal +from zope.app.component.hooks import setSite +from zope.app.container.contained import ObjectAddedEvent, ObjectRemovedEvent +from zope.cachedescriptors.property import Lazy +from zope.catalog.interfaces import ICatalog +from zope.copypastemove.interfaces import IContainerItemRenamer +from zope import component +from zope.event import notify +from zope.exceptions.interfaces import DuplicationError +from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent +from zope.publisher.browser import TestRequest as BaseTestRequest +from zope.security.management import getInteraction, newInteraction, endInteraction +from zope.interface import Interface + +from cybertools.util.jeep import Jeep +from loops.common import adapted, baseObject +from loops.util import getObjectForUid, getUidForObject, getCatalog, reindex +#from xxx import config + + +sc = Jeep() # shortcuts +rf = None # root folder + +def setup(root): + global sm, smdefault, catalog, intids, pau, sc + setSite(root) + sm = component.getSiteManager(root) + smdefault = sm['default'] + intids = smdefault['IntIds'] + pau = smdefault['PluggableAuthentication'] + #user = getattr(config, 'shell_user', 'zope.manager') + #password = (getattr(config, 'shell_pw', None) or + # raw_input('Enter manager password: ')) + user = 'zope.manager' + password = raw_input('Enter manager password: ') + login(Principal(user, password, u'Manager')) + + +def byuid(uid): + return getObjectForUid(uid) + +def uid(obj): + return getUidForObject(obj) + +def notifyModification(obj): + obj = baseObject(obj) + notify(ObjectModifiedEvent(obj)) + +def save(obj): + notifyModification(obj) + commit() + +def notifyAdded(obj): + obj = baseObject(obj) + notify(ObjectAddedEvent(obj)) + +def notifyRemoved(obj): + obj = baseObject(obj) + notify(ObjectRemovedEvent(obj)) + +def delete(container, name): + obj = container.get(name) + if obj is None: + print '*** Object', name, 'not found!' + return + notifyRemoved(obj) + del container[name] + commit() + +def rename(container, old, new, docommit=True): + obj = container.get(old) + if obj is None: + print '*** Object', old, 'not found!' + return + renamer = IContainerItemRenamer(container) + if new != old: + try: + renamer.renameItem(old, new) + except DuplicationError: + print '*** Object', new, 'already exists!' + # container[new] = obj + # notifyAdded(obj) + notifyModification(obj) + if docommit: + commit() + +def move(source, target, name): + obj = source.get(name) + if obj is None: + print '*** Object', name, 'not found!' + return + #notifyRemoved(obj) + #del source[name] + target[name] = obj + #notifyAdded(obj) + notifyModification(obj) + commit() + +def get(container, obj): + if isinstance(obj, basestring): + name = obj + obj = container.get(name) + if obj is None: + print '*** Object', name, 'not found!' + return None + return adapted(obj) + +# catalog / indexing + +def getCatalog(context): + context = baseObject(context) + for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=context): + return cat + print '*** No catalog found!' + +def reindex(obj, catalog=None): + obj = baseObject(obj) + if catalog is None: + catalog = getCatalog(obj) + if catalog is not None: + catalog.index_doc(int(getUidForObject(obj)), obj) + + +# helper functions and classes + +def login(principal): + endInteraction() + newInteraction(Participation(principal)) + + +class TestRequest(BaseTestRequest): + + basePrincipal = BaseTestRequest.principal + + @Lazy + def principal(self): + interaction = getInteraction() + if interaction is not None: + parts = interaction.participations + if parts: + prin = parts[0].principal + if prin is not None: + return prin + return self.basePrincipal + + +class Participation(object): + """ Dummy Participation class for testing. + """ + + interaction = None + + def __init__(self, principal): + self.principal = principal + From c5fe2044b5104f03386c30a845f12db404bfa672 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 09:58:24 +0100 Subject: [PATCH 5/9] add common psu utilities, esp generic loop --- psu.py | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 12 deletions(-) diff --git a/psu.py b/psu.py index a65cc5d..7a27d24 100644 --- a/psu.py +++ b/psu.py @@ -10,6 +10,7 @@ # obj = psu.byuid('578457950') # +import os from transaction import commit, abort from zope.app.authentication.principalfolder import Principal from zope.app.component.hooks import setSite @@ -25,11 +26,14 @@ from zope.publisher.browser import TestRequest as BaseTestRequest from zope.security.management import getInteraction, newInteraction, endInteraction from zope.interface import Interface +from cybertools.util.date import date2TimeStamp, strptime from cybertools.util.jeep import Jeep from loops.common import adapted, baseObject from loops.util import getObjectForUid, getUidForObject, getCatalog, reindex #from xxx import config +os.environ['NLS_LANG'] = 'German_Germany.UTF8' + sc = Jeep() # shortcuts rf = None # root folder @@ -118,20 +122,117 @@ def get(container, obj): return None return adapted(obj) -# catalog / indexing +# startup, loop, finish... -def getCatalog(context): - context = baseObject(context) - for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=context): - return cat - print '*** No catalog found!' +def startup(msg, **kw): + print '***', msg + step = kw.pop('step', 10) + return Jeep(count=0, step=step, message=msg, **kw) -def reindex(obj, catalog=None): - obj = baseObject(obj) - if catalog is None: - catalog = getCatalog(obj) - if catalog is not None: - catalog.index_doc(int(getUidForObject(obj)), obj) +def update(fct, obj, info): + info.count += 1 + start = info.get('start') + if start and info.count < start: + return + if info.count % info.step == 0: + try: + objInfo = obj.__name__ + except: + try: + objInfo = obj.context.__name__ + except: + objInfo = obj + print '*** Processing object # %i: %s' % (info.count, objInfo) + if info.get('updated'): + print '*** updated: %i.' % info.updated + if info.get('errors'): + print '*** errors: %i.' % info.error + commit() + return fct(obj, info) + +def finish(info): + print '*** count: %i.' % info.count + if info.get('updated'): + print '*** updated: %i.' % info.updated + if info.get('errors'): + print '*** errors: %i.' % info.error + commit() + +def stop_condition(info): + stop = info.get('stop') + return stop is not None and info.count > stop + +def loop(message, objects, fct, **kw): + def _fct(obj, info): + params = info.get('fctparams', {}) + fct(obj, info, **params) + info = startup(message, **kw) + for obj in objects: + update(_fct, obj, info) + if stop_condition(info): + break + finish(info) + + +# indexing + +def reindex_objects(objs, **kw): + catalog = util.getCatalog(objs[0]) + def do_reindex(obj, info): + util.reindex(obj, catalog) + loop('reindex %s objects' % len(objs), objs, do_reindex, **kw) + +# auxiliary functions + +def get_type_instances(name): + return sc.concepts[name].getChildren([sc.hasType]) + +def notify_modification(c, info): + notifyModification(c) + + +# some common repair tasks + +def update_type_instances(**kw): + info = startup('Notify Type Instances', **kw) + ctype = kw.pop('type') + for c in get_type_instances(ctype): + update(notify_modification, c, info) + if stop_condition(info): + break + finish(info) + +def update_type_instances_title_from_adapted(**kw): + info = startup('Update Type Instances Title', **kw) + ctype = kw.pop('type') + for c in get_type_instances(ctype): + update(update_type_title_from_adapted, c, info) + if stop_condition(info): + break + finish(info) + +def update_type_title_from_adapted(c, info): + c.title = adapted(c).title + notifyModification(c) + + +def removeRecords(container, **kw): + """Remove records from container selected by the criteria given.""" + info = startup('Remove records', container=container, **kw) + date = kw.pop('date', None) + if date: + kw['timeFromTo'] = ( + date2TimeStamp(strptime(date + ' 00:00:00')), + date2TimeStamp(strptime(date + ' 23:59:59'))) + for obj in container.query(**kw): + update(remove, obj, info) + if stop_condition(info): + break + finish(info) + +def remove(obj, info): + notifyRemoved(obj) + del info.container[obj.__name__] # helper functions and classes From b4a8ae1ed1eb19c4dba6f3ff7361eeebf86fa65c Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 10:12:00 +0100 Subject: [PATCH 6/9] some more improvements --- psu.py | 47 ++++++++++++++--------------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/psu.py b/psu.py index 7a27d24..96eafe8 100644 --- a/psu.py +++ b/psu.py @@ -182,7 +182,8 @@ def reindex_objects(objs, **kw): util.reindex(obj, catalog) loop('reindex %s objects' % len(objs), objs, do_reindex, **kw) -# auxiliary functions + +# some common repair tasks def get_type_instances(name): return sc.concepts[name].getChildren([sc.hasType]) @@ -190,49 +191,29 @@ def get_type_instances(name): def notify_modification(c, info): notifyModification(c) - -# some common repair tasks - def update_type_instances(**kw): - info = startup('Notify Type Instances', **kw) - ctype = kw.pop('type') - for c in get_type_instances(ctype): - update(notify_modification, c, info) - if stop_condition(info): - break - finish(info) + objs = get_type_instances(kw.pop('type')) + loop('Notify Type Instances', objs, notify_modification, **kw) def update_type_instances_title_from_adapted(**kw): - info = startup('Update Type Instances Title', **kw) - ctype = kw.pop('type') - for c in get_type_instances(ctype): - update(update_type_title_from_adapted, c, info) - if stop_condition(info): - break - finish(info) - -def update_type_title_from_adapted(c, info): - c.title = adapted(c).title - notifyModification(c) - + def update_type_title_from_adapted(c, info): + c.title = adapted(c).title + notifyModification(c) + objs = get_type_instances(kw.pop('type')) + loop('Update Type Instances Title', objs, update_type_title_from_adapted, **kw) def removeRecords(container, **kw): """Remove records from container selected by the criteria given.""" - info = startup('Remove records', container=container, **kw) + def remove(obj, info): + notifyRemoved(obj) + del container[obj.__name__] + info = startup('Remove records', **kw) date = kw.pop('date', None) if date: kw['timeFromTo'] = ( date2TimeStamp(strptime(date + ' 00:00:00')), date2TimeStamp(strptime(date + ' 23:59:59'))) - for obj in container.query(**kw): - update(remove, obj, info) - if stop_condition(info): - break - finish(info) - -def remove(obj, info): - notifyRemoved(obj) - del info.container[obj.__name__] + loop('Remove records', container.query(**kw), remove, **kw) # helper functions and classes From 1854903d0f1c5c0edad0aa2255df4fc81b872776 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 11:31:52 +0100 Subject: [PATCH 7/9] conditional commit for deletion of objects --- psu.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/psu.py b/psu.py index 96eafe8..a962d29 100644 --- a/psu.py +++ b/psu.py @@ -75,14 +75,15 @@ def notifyRemoved(obj): obj = baseObject(obj) notify(ObjectRemovedEvent(obj)) -def delete(container, name): +def delete(container, name, docommit=True): obj = container.get(name) if obj is None: print '*** Object', name, 'not found!' return notifyRemoved(obj) del container[name] - commit() + if docommit: + commit() def rename(container, old, new, docommit=True): obj = container.get(old) From 9ab3e61f9a54e3ac7d2d0f023773a5fc885c7f06 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 16:05:21 +0100 Subject: [PATCH 8/9] make loopsRoot path and config module configurable in setup() function --- psu.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/psu.py b/psu.py index a962d29..b93e97c 100644 --- a/psu.py +++ b/psu.py @@ -36,21 +36,25 @@ os.environ['NLS_LANG'] = 'German_Germany.UTF8' sc = Jeep() # shortcuts -rf = None # root folder -def setup(root): +def setup(root, loopsRootPath=[], config=None): global sm, smdefault, catalog, intids, pau, sc setSite(root) sm = component.getSiteManager(root) smdefault = sm['default'] intids = smdefault['IntIds'] pau = smdefault['PluggableAuthentication'] - #user = getattr(config, 'shell_user', 'zope.manager') - #password = (getattr(config, 'shell_pw', None) or - # raw_input('Enter manager password: ')) - user = 'zope.manager' - password = raw_input('Enter manager password: ') + user = getattr(config, 'shell_user', 'zope.manager') + password = (getattr(config, 'shell_pw', None) or + raw_input('Enter manager password: ')) login(Principal(user, password, u'Manager')) + loopsRoot = root + for name in loopsRootPath.split('/'): + if name: + loopsRoot = loopsRoot[name] + sc.concepts = loopsRoot['concepts'] + for name in ('standard', 'hasType',): + sc[name] = sc.concepts[name] def byuid(uid): From 082acf3fbc0625dd4fec7e3ff5170d35d2af1436 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Dec 2019 16:22:40 +0100 Subject: [PATCH 9/9] add loopsRoot to module global variables --- psu.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/psu.py b/psu.py index b93e97c..d983010 100644 --- a/psu.py +++ b/psu.py @@ -5,8 +5,9 @@ # # then: # -# from loops import psu -# psu.setup(root) +# from cco.common import psu +# from custom.config import myproject as config +# psu.setup(root, 'path/to/loopsRoot', config) # obj = psu.byuid('578457950') # @@ -38,7 +39,7 @@ os.environ['NLS_LANG'] = 'German_Germany.UTF8' sc = Jeep() # shortcuts def setup(root, loopsRootPath=[], config=None): - global sm, smdefault, catalog, intids, pau, sc + global sm, smdefault, intids, pau, loopsRoot, sc setSite(root) sm = component.getSiteManager(root) smdefault = sm['default']