From ef504afc0b2c6fd0676988274bf1ed1696802620 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 18 May 2012 10:05:17 +0200 Subject: [PATCH 1/6] replace setup manager (for package loops.knowledge) by import file --- knowledge/README.txt | 30 +++++++------ knowledge/configure.zcml | 3 -- knowledge/data/loops_knowledge_de.dmp | 32 ++++++++++++++ knowledge/setup.py | 61 --------------------------- knowledge/tests.py | 2 +- 5 files changed, 51 insertions(+), 77 deletions(-) create mode 100644 knowledge/data/loops_knowledge_de.dmp delete mode 100644 knowledge/setup.py diff --git a/knowledge/README.txt b/knowledge/README.txt index ed77023..9d6d649 100644 --- a/knowledge/README.txt +++ b/knowledge/README.txt @@ -2,33 +2,34 @@ loops - Linked Objects for Organization and Processing Services =============================================================== - ($Id$) - -Note: This package depends on cybertools.knowledge and cybertools.organize. +Note: This package depends on cybertools.knowledge and loops.organize. Let's do some basic set up + >>> from zope import component, interface + >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown >>> site = placefulSetUp(True) - >>> from zope import component, interface - 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 ZCML setup): - >>> from loops.interfaces import ILoops, IConcept - >>> from loops.setup import ISetupManager - >>> from loops.knowledge.setup import SetupManager - >>> component.provideAdapter(SetupManager, (ILoops,), ISetupManager, - ... name='knowledge') - >>> from loops.tests.setup import TestSite >>> t = TestSite(site) >>> concepts, resources, views = t.setup() + >>> loopsRoot = site['loops'] + +We then import a loops .dmp file containing all necessary types and +predicates. + + >>> import os + >>> from loops.setup import importData + >>> importPath = os.path.join(os.path.dirname(__file__), 'data') + >>> importData(loopsRoot, importPath, 'loops_knowledge_de.dmp') We need some type concepts for controlling the meaning of the concepts objects, -these have already been created during setup: +these have already been created during setup and .dmp import: >>> topic = concepts['topic'] >>> person = concepts['person'] @@ -40,6 +41,7 @@ Manage knowledge and knowledge requirements The classes used in this package are just adapters to IConcept. + >>> from loops.interfaces import IConcept >>> from loops.knowledge.knowledge import Person, Topic, Task >>> from loops.knowledge.interfaces import IPerson >>> from cybertools.knowledge.interfaces import IKnowledgeElement @@ -166,6 +168,10 @@ For testing, we first have to provide the needed utilities and settings >>> view = MyKnowledge(task01C, request) >>> prov = view.myKnowledgeProvidersForTask() + +Competence and Certification Management +======================================= + Glossaries ========== diff --git a/knowledge/configure.zcml b/knowledge/configure.zcml index 5b3a3c4..eb323e8 100644 --- a/knowledge/configure.zcml +++ b/knowledge/configure.zcml @@ -88,9 +88,6 @@ - - diff --git a/knowledge/data/loops_knowledge_de.dmp b/knowledge/data/loops_knowledge_de.dmp new file mode 100644 index 0000000..8fc9f58 --- /dev/null +++ b/knowledge/data/loops_knowledge_de.dmp @@ -0,0 +1,32 @@ +type(u'person', u'Person', viewName=u'', + typeInterface=u'loops.knowledge.interfaces.IPerson', + options=u'action.portlet:editPerson') +type(u'task', u'Aufgabe', viewName=u'', + typeInterface=u'loops.knowledge.interfaces.ITask', + options=u'action.portlet:createTopic,editTopic') +type(u'topic', u'Thema', viewName=u'', + typeInterface=u'loops.knowledge.interfaces.ITopic', + options=u'action.portlet:createTopic,editTopic') + +concept(u'general', u'Allgemein', u'domain') +concept(u'system', u'System', u'domain') + +# predicates +concept(u'depends', u'depends', u'predicate') +concept(u'knows', u'knows', u'predicate') +concept(u'provides', u'provides', u'predicate') +concept(u'requires', u'requires', u'predicate') + +concept(u'issubtype', u'is Subtype', u'predicate', options=u'hide_children', + predicateInterface='loops.interfaces.IIsSubtype') + +# structure +child(u'depends', u'general', u'standard') +child(u'knows', u'general', u'standard') +child(u'person', u'general', u'standard') +child(u'provides', u'general', u'standard') +child(u'requires', u'general', u'standard') +child(u'task', u'general', u'standard') +child(u'topic', u'general', u'standard') + +child(u'issubtype', u'system', u'standard') diff --git a/knowledge/setup.py b/knowledge/setup.py deleted file mode 100644 index 3bbd5e0..0000000 --- a/knowledge/setup.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright (c) 2006 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -""" -Automatic setup of a loops site for the organize package. - -$Id$ -""" - -from zope.component import adapts -from zope.interface import implements, Interface - -from cybertools.knowledge.interfaces import IKnowledgeElement -from loops.concept import Concept -from loops.interfaces import ITypeConcept -from loops.knowledge.interfaces import IPerson, ITask, ITopic -from loops.setup import SetupManager as BaseSetupManager - - -class SetupManager(BaseSetupManager): - - def setup(self): - concepts = self.context.getConceptManager() - type = concepts.getTypeConcept() - predicate = concepts['predicate'] - # type concepts: - person = self.addObject(concepts, Concept, 'person', title=u'Person', - conceptType=type) - ITypeConcept(person).typeInterface = IPerson # this may override other packages! - topic = self.addObject(concepts, Concept, 'topic', title=u'Topic', - conceptType=type) - ITypeConcept(topic).typeInterface = ITopic - task = self.addObject(concepts, Concept, 'task', title=u'Task', - conceptType=type) - ITypeConcept(task).typeInterface = ITask - # predicates: - depends = self.addObject(concepts, Concept, 'depends', title=u'depends', - conceptType=predicate) - knows = self.addObject(concepts, Concept, 'knows', title=u'knows', - conceptType=predicate) - requires = self.addObject(concepts, Concept, 'requires', title=u'requires', - conceptType=predicate) - provides = self.addObject(concepts, Concept, 'provides', title=u'provides', - conceptType=predicate) - - diff --git a/knowledge/tests.py b/knowledge/tests.py index 888ff78..a671bb3 100755 --- a/knowledge/tests.py +++ b/knowledge/tests.py @@ -1,4 +1,4 @@ -# $Id$ +# tests.py - loops.knowledge package import unittest, doctest from zope.testing.doctestunit import DocFileSuite From ad2e17295c68aafa5d083e8c9e76ee93dc7069d5 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 18 May 2012 11:52:16 +0200 Subject: [PATCH 2/6] provide new import element 'records' that allows creation of record manager objects --- external/element.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/external/element.py b/external/element.py index 1490dd2..672aaa2 100644 --- a/external/element.py +++ b/external/element.py @@ -30,10 +30,11 @@ from zope.traversing.api import getName, traverse from cybertools.composer.interfaces import IInstance from cybertools.composer.schema.interfaces import ISchemaFactory +from cybertools.tracking.btree import TrackingStorage from cybertools.typology.interfaces import IType from loops.common import adapted -from loops.interfaces import IConceptSchema from loops.external.interfaces import IElement +from loops.interfaces import IConceptSchema from loops.i18n.common import I18NValue from loops.layout.base import LayoutNode from loops.predicate import adaptedRelation @@ -132,6 +133,33 @@ class TypeElement(ConceptElement): adapted(self.object).typeInterface = kw['typeInterface'] +class RecordManagerElement(Element): + + elementType = 'records' + posArgs = ('name', 'trackFactory') + + def __init__(self, name, trackFactory, **kw): + self['name'] = name + tf = self['trackFactory'] = trackFactory + if not isinstance(tf, basestring): + self['trackFactory'] = '.'.join((tf.__module__, tf.__name__)) + for k, v in kw.items(): + self[k] = v + + def execute(self, loader): + name = self['name'] + tf = resolve(self['trackFactory']) + records = loader.context.getRecordManager() + obj = records.get(name) + if obj is None: + obj = records[name] = TrackingStorage(trackFactory=tf) + else: + obj.trackFactory = tf + obj.indexAttributes = tf.index_attributes + obj.setupIndexes() + self.object = obj + + class ChildElement(Element): elementType = 'child' @@ -261,6 +289,7 @@ class LayoutNodeElement(NodeElement): elementTypes = dict( type=TypeElement, concept=ConceptElement, + records=RecordManagerElement, child=ChildElement, resource=ResourceElement, resourceRelation=ResourceRelationElement, @@ -270,5 +299,5 @@ elementTypes = dict( I18NValue=I18NValue, ) -toplevelElements = ('type', 'concept', 'resource', +toplevelElements = ('type', 'concept', 'resource', 'records', 'child', 'resourceRelation', 'node', 'deassign') From 53a33964d02e58be6ebe44e1d597dfdb8ae7b134 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 18 May 2012 11:53:02 +0200 Subject: [PATCH 3/6] work in progress: CCM Competence and Certification Management: starting with concepts types and records --- knowledge/data/loops_knowledge_de.dmp | 3 +++ knowledge/knowledge.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/knowledge/data/loops_knowledge_de.dmp b/knowledge/data/loops_knowledge_de.dmp index 8fc9f58..351e42e 100644 --- a/knowledge/data/loops_knowledge_de.dmp +++ b/knowledge/data/loops_knowledge_de.dmp @@ -30,3 +30,6 @@ child(u'task', u'general', u'standard') child(u'topic', u'general', u'standard') child(u'issubtype', u'system', u'standard') + +# records +records(u'qualification', u'loops.knowledge.qualification.QualificationRecord') diff --git a/knowledge/knowledge.py b/knowledge/knowledge.py index a623a90..5f623d0 100644 --- a/knowledge/knowledge.py +++ b/knowledge/knowledge.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2007 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,8 +19,6 @@ """ Adapters for IConcept providing interfaces from the cybertools.knowledge package. - -$Id$ """ from zope import interface, component From a4968e76d6b2ef808bae5fe4c2c13ad7dab8c5a9 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 19 May 2012 10:17:41 +0200 Subject: [PATCH 4/6] work in progress: CCM Competence and Certification Management: starting with concepts types and records --- knowledge/README.txt | 10 +++++ knowledge/configure.zcml | 16 +++++++ knowledge/data/loops_knowledge_de.dmp | 15 +++++++ knowledge/interfaces.py | 15 +++++-- knowledge/qualification.py | 60 +++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 knowledge/qualification.py diff --git a/knowledge/README.txt b/knowledge/README.txt index 9d6d649..10a7953 100644 --- a/knowledge/README.txt +++ b/knowledge/README.txt @@ -172,6 +172,16 @@ For testing, we first have to provide the needed utilities and settings Competence and Certification Management ======================================= + >>> from cybertools.stateful.interfaces import IStatesDefinition + >>> from loops.knowledge.qualification import qualificationStates + >>> from loops.knowledge.interfaces import IQualificationRecords + >>> from loops.knowledge.qualification import QualificationRecords + >>> component.provideUtility(qualificationStates, + ... provides=IStatesDefinition) + >>> component.provideAdapter(QualificationRecords, + ... provides=IQualificationRecords) + + Glossaries ========== diff --git a/knowledge/configure.zcml b/knowledge/configure.zcml index eb323e8..2552184 100644 --- a/knowledge/configure.zcml +++ b/knowledge/configure.zcml @@ -66,6 +66,22 @@ interface="cybertools.knowledge.interfaces.IKnowledgeProvider" /> + + + + + + + + + + + Date: Sat, 19 May 2012 17:21:25 +0200 Subject: [PATCH 5/6] fix doctests after removal of knowledge.setup.SetupManager --- classifier/README.txt | 2 +- classifier/testsetup.py | 4 +-- expert/README.txt | 10 +++---- expert/search.txt | 16 +++++----- expert/testsetup.py | 6 ++-- external/README.txt | 8 +++-- i18n/README.txt | 6 ++-- integrator/README.txt | 2 +- integrator/testsetup.py | 4 +-- knowledge/data/loops_knowledge_de.dmp | 14 +++------ knowledge/qualification.py | 42 +++++++++++++++++++++++++-- knowledge/tests.py | 8 +++++ organize/README.txt | 6 ++-- system/sync/README.txt | 2 +- versioning/README.txt | 8 ++--- versioning/testsetup.py | 4 +-- xmlrpc/README.txt | 26 +++++++++-------- 17 files changed, 105 insertions(+), 63 deletions(-) diff --git a/classifier/README.txt b/classifier/README.txt index f35014d..e5b7a1b 100644 --- a/classifier/README.txt +++ b/classifier/README.txt @@ -27,7 +27,7 @@ configuration): >>> concepts, resources, views = t.setup() >>> len(concepts), len(resources) - (20, 0) + (15, 0) Let's now add an external collection that reads in a set of resources from external files so we have something to work with. diff --git a/classifier/testsetup.py b/classifier/testsetup.py index a529bce..b3414e7 100644 --- a/classifier/testsetup.py +++ b/classifier/testsetup.py @@ -24,7 +24,7 @@ from loops.integrator.collection import DirectoryCollectionProvider from loops.integrator.collection import ExternalCollectionAdapter from loops.integrator.interfaces import IExternalCollection, IExternalCollectionProvider from loops.organize.setup import SetupManager as OrganizeSetupManager -from loops.knowledge.setup import SetupManager as KnowledgeSetupManager +#from loops.knowledge.setup import SetupManager as KnowledgeSetupManager from loops.knowledge.knowledge import Person from loops.knowledge.interfaces import IPerson from loops.setup import SetupManager, addAndConfigureObject @@ -39,7 +39,7 @@ class TestSite(BaseTestSite): self.site = site def setup(self): - component.provideAdapter(KnowledgeSetupManager, name='knowledge') + #component.provideAdapter(KnowledgeSetupManager, name='knowledge') component.provideAdapter(OrganizeSetupManager, name='organize') concepts, resources, views = self.baseSetup() diff --git a/expert/README.txt b/expert/README.txt index 0404b89..9f9d949 100644 --- a/expert/README.txt +++ b/expert/README.txt @@ -27,7 +27,7 @@ configuration): >>> concepts, resources, views = t.setup() >>> len(concepts) + len(resources) - 33 + 37 >>> loopsRoot = site['loops'] @@ -47,19 +47,19 @@ Type- and text-based queries >>> from loops.expert import query >>> qu = query.Title('ty*') >>> list(qu.apply()) - [0, 1, 47] + [0, 1, 68] >>> qu = query.Type('loops:*') >>> len(list(qu.apply())) - 33 + 37 >>> qu = query.Type('loops:concept:predicate') >>> len(list(qu.apply())) - 7 + 8 >>> qu = query.Type('loops:concept:predicate') & query.Title('t*') >>> list(qu.apply()) - [1, 43] + [1, 29] State-based queries ------------------- diff --git a/expert/search.txt b/expert/search.txt index fa33f30..d752ac1 100755 --- a/expert/search.txt +++ b/expert/search.txt @@ -66,13 +66,13 @@ zcml in real life: >>> t = searchView.typesForSearch() >>> len(t) - 14 + 16 >>> t.getTermByToken('loops:resource:*').title 'Any Resource' >>> t = searchView.conceptTypesForSearch() >>> len(t) - 11 + 13 >>> t.getTermByToken('loops:concept:*').title 'Any Concept' @@ -91,7 +91,7 @@ a controller attribute for the search view. >>> searchView.submitReplacing('1.results', '1.search.form', pageView) 'submitReplacing("1.results", "1.search.form", - "http://127.0.0.1/loops/views/page/.target80/@@searchresults.html");...' + "http://127.0.0.1/loops/views/page/.target99/@@searchresults.html");...' Basic (text/title) search ------------------------- @@ -177,7 +177,7 @@ of the concepts' titles: >>> request = TestRequest(form=form) >>> view = Search(page, request) >>> view.listConcepts() - u"{identifier: 'id', items: [{label: 'Zope (Topic)', name: 'Zope', id: '85'}, {label: 'Zope 2 (Topic)', name: 'Zope 2', id: '87'}, {label: 'Zope 3 (Topic)', name: 'Zope 3', id: '89'}]}" + u"{identifier: 'id', items: [{label: 'Zope (Thema)', name: 'Zope', id: '104'}, {label: 'Zope 2 (Thema)', name: 'Zope 2', id: '106'}, {label: 'Zope 3 (Thema)', name: 'Zope 3', id: '108'}]}" Preset Concept Types on Search Forms ------------------------------------ @@ -219,13 +219,13 @@ and thus include the customer type in the preset search types. >>> searchView.conceptsForType('loops:concept:customer') [{'token': 'none', 'title': u'not selected'}, - {'token': '58', 'title': u'Customer 1'}, - {'token': '60', 'title': u'Customer 2'}, - {'token': '62', 'title': u'Customer 3'}] + {'token': '77', 'title': u'Customer 1'}, + {'token': '79', 'title': u'Customer 2'}, + {'token': '81', 'title': u'Customer 3'}] Let's use this new search option for querying: - >>> form = {'search.4.text_selected': u'58'} + >>> form = {'search.4.text_selected': u'77'} >>> resultsView = SearchResults(page, TestRequest(form=form)) >>> results = list(resultsView.results) >>> results[0].title diff --git a/expert/testsetup.py b/expert/testsetup.py index 90b5075..05d8b5e 100644 --- a/expert/testsetup.py +++ b/expert/testsetup.py @@ -14,7 +14,8 @@ from loops.expert.setup import SetupManager as ExpertSetupManager from loops.resource import Resource from loops.knowledge.interfaces import IPerson from loops.knowledge.knowledge import Person -from loops.knowledge.setup import SetupManager as KnowledgeSetupManager +#from loops.knowledge.setup import SetupManager as KnowledgeSetupManager +from loops.knowledge.tests import importData from loops.setup import SetupManager, addObject from loops.tests.setup import TestSite as BaseTestSite from loops.type import ConceptType, ResourceType, TypeConcept @@ -32,10 +33,11 @@ class TestSite(BaseTestSite): component.provideAdapter(Person, provides=IPerson) - component.provideAdapter(KnowledgeSetupManager, name='knowledge') + #component.provideAdapter(KnowledgeSetupManager, name='knowledge') component.provideAdapter(ExpertSetupManager, name='expert') setup = SetupManager(loopsRoot) concepts, resources, views = setup.setup() + importData(loopsRoot) tType = concepts.getTypeConcept() tDomain = concepts['domain'] diff --git a/external/README.txt b/external/README.txt index 357d44c..f88f3aa 100644 --- a/external/README.txt +++ b/external/README.txt @@ -17,7 +17,7 @@ Let's set up a loops site with basic and example concepts and resources. >>> concepts, resources, views = t.setup() >>> loopsRoot = site['loops'] >>> len(concepts), len(resources), len(views) - (30, 3, 1) + (34, 3, 1) Importing loops Objects @@ -44,7 +44,7 @@ Creating the corresponding objects >>> loader = Loader(loopsRoot) >>> loader.load(elements) >>> len(concepts), len(resources), len(views) - (31, 3, 1) + (35, 3, 1) >>> from loops.common import adapted >>> adMyquery = adapted(concepts['myquery']) @@ -118,7 +118,7 @@ Extracting elements >>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export')) >>> elements = list(extractor.extract()) >>> len(elements) - 52 + 67 Writing object information to the external storage -------------------------------------------------- @@ -130,6 +130,7 @@ Writing object information to the external storage >>> writer = PyWriter() >>> writer.write(elements, output) >>> print output.getvalue() + type(u'task', ...)... type(u'country', u'Country', viewName=u'', typeInterface=u''..., options=u''...)... type(u'query', u'Query', viewName=u'', typeInterface='loops.expert.concept.IQueryConcept'..., options=u''...)... concept(u'myquery', u'My Query', u'query', options=u'option1\noption2', @@ -171,6 +172,7 @@ corresponding extractor adapter. >>> PyWriter().write(extractor.extract(), output) >>> print output.getvalue() + type(u'task', ...)... type(u'country', u'Country', viewName=u'', typeInterface=u''..., options=u''...)... concept(u'myquery', u'My Query', u'query', options=u'option1\noption2', viewName=u'mystuff.html')[ diff --git a/i18n/README.txt b/i18n/README.txt index 534ec0b..7aedcd3 100644 --- a/i18n/README.txt +++ b/i18n/README.txt @@ -18,15 +18,15 @@ ZCML setup): >>> from loops.interfaces import ILoops, IConcept >>> from loops.concept import Concept >>> from loops.setup import ISetupManager - >>> from loops.knowledge.setup import SetupManager - >>> component.provideAdapter(SetupManager, (ILoops,), ISetupManager, - ... name='knowledge') >>> from loops.tests.setup import TestSite >>> t = TestSite(site) >>> concepts, resources, views = t.setup() >>> loopsRoot = site['loops'] + >>> from loops.knowledge.tests import importData + >>> importData(loopsRoot) + >>> from loops.knowledge.knowledge import Topic >>> component.provideAdapter(Topic) diff --git a/integrator/README.txt b/integrator/README.txt index 4d84425..cba0381 100644 --- a/integrator/README.txt +++ b/integrator/README.txt @@ -27,7 +27,7 @@ configuration): >>> concepts, resources, views = t.setup() >>> len(concepts) + len(resources) - 18 + 11 >>> loopsRoot = site['loops'] >>> #loopsRoot.options = ['useVersioning:rev'] diff --git a/integrator/testsetup.py b/integrator/testsetup.py index cd4108c..f672a0e 100644 --- a/integrator/testsetup.py +++ b/integrator/testsetup.py @@ -18,7 +18,7 @@ from loops.resource import Resource, FileAdapter, ExternalFileAdapter from loops.integrator.interfaces import IExternalSourceInfo, IExternalCollection from loops.integrator.interfaces import IOfficeFile from loops.integrator.office.base import OfficeFile -from loops.knowledge.setup import SetupManager as KnowledgeSetupManager +#from loops.knowledge.setup import SetupManager as KnowledgeSetupManager from loops.setup import SetupManager, addAndConfigureObject from loops.tests.setup import TestSite as BaseTestSite from loops.versioning.versionable import VersionableResource @@ -32,7 +32,7 @@ class TestSite(BaseTestSite): self.site = site def setup(self): - component.provideAdapter(KnowledgeSetupManager, name='knowledge') + #component.provideAdapter(KnowledgeSetupManager, name='knowledge') concepts, resources, views = self.baseSetup() component.provideAdapter(FileAdapter, provides=IFile) diff --git a/knowledge/data/loops_knowledge_de.dmp b/knowledge/data/loops_knowledge_de.dmp index 36d1462..2ca69b4 100644 --- a/knowledge/data/loops_knowledge_de.dmp +++ b/knowledge/data/loops_knowledge_de.dmp @@ -9,11 +9,9 @@ type(u'task', u'Aufgabe', viewName=u'', type(u'topic', u'Thema', viewName=u'', typeInterface=u'loops.knowledge.interfaces.ITopic', options=u'action.portlet:createTopic,editTopic') -type(u'training_event', u'Schulung', viewName=u'', +type(u'training', u'Schulung', viewName=u'', typeInterface=u'loops.organize.interfaces.ITask', - options=u'action.portlet:edit_concept') -type(u'training_offer', u'Schulungsangebot', viewName=u'', - typeInterface=u'', options=u'action.portlet:create_subtype,edit_concept') + options=u'action.portlet:create_subtype,edit_concept') concept(u'general', u'Allgemein', u'domain') concept(u'system', u'System', u'domain') @@ -36,15 +34,11 @@ child(u'provides', u'general', u'standard') child(u'requires', u'general', u'standard') child(u'task', u'general', u'standard') child(u'topic', u'general', u'standard') -child(u'training_event', u'general', u'standard') -child(u'training_offer', u'general', u'standard') +child(u'training', u'general', u'standard') child(u'issubtype', u'system', u'standard') -child(u'training_event', u'competence', u'issubtype', - usePredicate=u'provides') -child(u'training_offer', u'competence', u'issubtype', - usePredicate=u'provides') +child(u'training', u'competence', u'issubtype', usePredicate=u'provides') # records records(u'qualification', u'loops.knowledge.qualification.QualificationRecord') diff --git a/knowledge/qualification.py b/knowledge/qualification.py index 8f2a5f0..62b115e 100644 --- a/knowledge/qualification.py +++ b/knowledge/qualification.py @@ -38,9 +38,37 @@ from loops.organize.work.base import WorkItem, WorkItems @implementer(IStatesDefinition) def qualificationStates(): return StatesDefinition('qualification', - State('new', 'new', - ('plan', 'accept', 'start', 'work', 'finish', 'delegate', 'cancel'), - color='red'),) + State('open', 'open', + ('register', 'pass', 'fail', 'cancel', 'modify'), + color='red'), + State('registered', 'registered', + ('register', 'pass', 'fail', 'unregister', 'cancel', 'modify'), + color='yellow'), + State('passed', 'passed', + ('cancel', 'close', 'modify', 'open', 'expire'), + color='green'), + State('failed', 'failed', + ('register', 'cancel', 'modify', 'open'), + color='green'), + State('expired', 'expired', + ('register', 'cancel', 'modify', 'open'), + color='red'), + State('cancelled', 'cancelled', ('modify', 'open'), + color='grey'), + State('closed', 'closed', ('modify', 'open'), + color='lightblue'), + # not directly reachable states: + State('open_x', 'open', ('modify',), color='red'), + State('registered_x', 'registered', ('modify',), color='yellow'), + # transitions: + Transition('register', 'register', 'registered'), + Transition('pass', 'pass', 'passed'), + Transition('fail', 'fail', 'failed'), + Transition('unregister', 'unregister', 'open'), + Transition('cancel', 'cancel', 'cancelled'), + Transition('close', 'close', 'closed'), + Transition('open', 'open', 'open'), + initialState='open') class QualificationRecord(WorkItem): @@ -48,8 +76,16 @@ class QualificationRecord(WorkItem): implements(IQualificationRecord) typeName = 'QualificationRecord' + typeInterface = IQualificationRecord statesDefinition = 'knowledge.qualification' + def doAction(self, action, userName, **kw): + new = self.createNew(action, userName, **kw) + new.userName = self.userName + new.doTransition(action) + new.reindex() + return new + class QualificationRecords(WorkItems): """ A tracking storage adapter managing qualification records. diff --git a/knowledge/tests.py b/knowledge/tests.py index a671bb3..baa95b0 100755 --- a/knowledge/tests.py +++ b/knowledge/tests.py @@ -1,10 +1,18 @@ # tests.py - loops.knowledge package +import os import unittest, doctest from zope.testing.doctestunit import DocFileSuite from zope.app.testing import ztapi from zope.interface.verify import verifyClass from loops.organize.party import Person +from loops.setup import importData as baseImportData + + +def importData(loopsRoot): + importPath = os.path.join(os.path.dirname(__file__), 'data') + baseImportData(loopsRoot, importPath, 'loops_knowledge_de.dmp') + class Test(unittest.TestCase): "Basic tests for the knowledge sub-package." diff --git a/organize/README.txt b/organize/README.txt index cbd7bd7..7857c1a 100644 --- a/organize/README.txt +++ b/organize/README.txt @@ -260,7 +260,7 @@ Automatic security settings on persons >>> from zope.traversing.api import getName >>> list(sorted(getName(c) for c in concepts['person'].getChildren())) - [u'jim', u'john', u'martha', u'person.newuser'] + [u'general', u'jim', u'john', u'martha', u'person.newuser'] Person objects that have a user assigned to them receive this user (principal) as their owner. @@ -358,7 +358,7 @@ Task view with edit action >>> from loops.organize.browser.task import TaskView >>> view = TaskView(task01, TestRequest()) >>> list(view.getActions('portlet')) - [] + [...] OK, the action is not provided automatically any more by the TaskView but has to be entered as a type option. @@ -404,7 +404,7 @@ Send Email to Members >>> form.subject u"loops Notification from '$site'" >>> form.mailBody - u'\n\nEvent #1\nhttp://127.0.0.1/loops/views/menu/.97\n\n' + u'\n\nEvent #1\nhttp://127.0.0.1/loops/views/menu/.116\n\n' Show Presence of Other Users diff --git a/system/sync/README.txt b/system/sync/README.txt index 640eef9..c18c601 100644 --- a/system/sync/README.txt +++ b/system/sync/README.txt @@ -18,7 +18,7 @@ Let's set up a loops site with basic and example concepts and resources. >>> concepts, resources, views = t.setup() >>> loopsRoot = site['loops'] >>> len(concepts), len(resources), len(views) - (30, 3, 1) + (34, 3, 1) >>> from cybertools.tracking.btree import TrackingStorage >>> from loops.system.job import JobRecord diff --git a/versioning/README.txt b/versioning/README.txt index 244210f..a50d7fb 100644 --- a/versioning/README.txt +++ b/versioning/README.txt @@ -26,14 +26,12 @@ configuration): >>> t = TestSite(site) >>> concepts, resources, views = t.setup() - >>> #sorted(concepts) - >>> #sorted(resources) - >>> len(concepts) + len(resources) - 23 - >>> loopsRoot = site['loops'] >>> loopsRoot.options = ['useVersioning'] + >>> len(concepts) + len(resources) + 16 + Version Information =================== diff --git a/versioning/testsetup.py b/versioning/testsetup.py index be4463b..3c07a18 100644 --- a/versioning/testsetup.py +++ b/versioning/testsetup.py @@ -33,7 +33,7 @@ from loops.config.base import LoopsOptions from loops.interfaces import ILoopsObject, IConcept from loops.resource import Resource from loops.resource import IndexAttributes as ResourceIndexAttributes -from loops.knowledge.setup import SetupManager as KnowledgeSetupManager +#from loops.knowledge.setup import SetupManager as KnowledgeSetupManager from loops.setup import SetupManager, addObject from loops.type import ConceptType, ResourceType, TypeConcept from loops.versioning.versionable import cleanupVersions @@ -74,7 +74,7 @@ class TestSite(object): loopsRoot = site['loops'] = Loops() - component.provideAdapter(KnowledgeSetupManager, name='knowledge') + #component.provideAdapter(KnowledgeSetupManager, name='knowledge') setup = SetupManager(loopsRoot) concepts, resources, views = setup.setup() diff --git a/xmlrpc/README.txt b/xmlrpc/README.txt index ccd907d..005e192 100755 --- a/xmlrpc/README.txt +++ b/xmlrpc/README.txt @@ -21,8 +21,6 @@ ZCML setup): >>> from loops.setup import addObject >>> from loops.organize.setup import SetupManager as OrganizeSetupManager >>> component.provideAdapter(OrganizeSetupManager, name='organize') - >>> from loops.knowledge.setup import SetupManager as KnowledgeSetupManager - >>> component.provideAdapter(KnowledgeSetupManager, name='knowledge') >>> from loops.tests.setup import TestSite >>> t = TestSite(site) >>> concepts, resources, views = t.setup() @@ -31,10 +29,13 @@ ZCML setup): >>> loopsRoot = site['loops'] >>> loopsId = util.getUidForObject(loopsRoot) + >>> from loops.knowledge.tests import importData + >>> importData(loopsRoot) + Let's look what setup has provided us with: >>> len(concepts) - 18 + 23 Now let's add a few more concepts: @@ -71,10 +72,11 @@ note that the 'hasType' predicate is not shown as it should not be applied in an explicit assignment. >>> sorted(t['name'] for t in xrf.getConceptTypes()) - [u'customer', u'domain', u'file', u'note', u'person', u'predicate', - u'task', u'textdocument', u'topic', u'type'] + [u'competence', u'customer', u'domain', u'file', u'note', u'person', + u'predicate', u'task', u'textdocument', u'topic', u'training', u'type'] >>> sorted(t['name'] for t in xrf.getPredicates()) - [u'depends', u'knows', u'ownedby', u'provides', u'requires', u'standard'] + [u'depends', u'issubtype', u'knows', u'ownedby', u'provides', u'requires', + u'standard'] We can also retrieve a certain object by its id or its name: @@ -93,8 +95,8 @@ All methods that retrieve one object also returns its children and parents: >>> ch[0]['name'] u'hasType' >>> sorted(c['name'] for c in ch[0]['objects']) - [u'customer', u'domain', u'file', u'note', u'person', u'predicate', - u'task', u'textdocument', u'topic', u'type'] + [u'competence', u'customer', u'domain', u'file', u'note', u'person', + u'predicate', u'task', u'textdocument', u'topic', u'training', u'type'] >>> pa = defaultPred['parents'] >>> len(pa) @@ -112,8 +114,8 @@ We can also retrieve children and parents explicitely: >>> ch[0]['name'] u'hasType' >>> sorted(c['name'] for c in ch[0]['objects']) - [u'customer', u'domain', u'file', u'note', u'person', u'predicate', - u'task', u'textdocument', u'topic', u'type'] + [u'competence', u'customer', u'domain', u'file', u'note', u'person', + u'predicate', u'task', u'textdocument', u'topic', u'training', u'type'] >>> pa = xrf.getParents('6') >>> len(pa) @@ -172,14 +174,14 @@ Updating the concept map >>> topicId = xrf.getObjectByName('topic')['id'] >>> xrf.createConcept(topicId, u'zope2', u'Zope 2') - {'description': u'', 'title': u'Zope 2', 'type': '22', 'id': '54', + {'description': u'', 'title': u'Zope 2', 'type': '36', 'id': '75', 'name': u'zope2'} The name of the concept is checked by a name chooser; if the corresponding parameter is empty, the name will be generated from the title. >>> xrf.createConcept(topicId, u'', u'Python') - {'description': u'', 'title': u'Python', 'type': '22', 'id': '56', + {'description': u'', 'title': u'Python', 'type': '36', 'id': '77', 'name': u'python'} If we try to deassign a ``hasType`` relation nothing will happen; a From a2f8410496e887fe6db38ef901e4084359d8d382 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 20 May 2012 12:03:36 +0200 Subject: [PATCH 6/6] work in progress: CCM competence and certification management: starting with forms and other views --- knowledge/README.txt | 22 ++++++++++++++---- knowledge/browser.py | 44 +++++++++++++++++++++++++++++++---- knowledge/knowledge_macros.pt | 15 ++++++++++++ 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/knowledge/README.txt b/knowledge/README.txt index 10a7953..994b7ae 100644 --- a/knowledge/README.txt +++ b/knowledge/README.txt @@ -23,10 +23,8 @@ ZCML setup): We then import a loops .dmp file containing all necessary types and predicates. - >>> import os - >>> from loops.setup import importData - >>> importPath = os.path.join(os.path.dirname(__file__), 'data') - >>> importData(loopsRoot, importPath, 'loops_knowledge_de.dmp') + >>> from loops.knowledge.tests import importData + >>> importData(loopsRoot) We need some type concepts for controlling the meaning of the concepts objects, these have already been created during setup and .dmp import: @@ -177,10 +175,24 @@ Competence and Certification Management >>> from loops.knowledge.interfaces import IQualificationRecords >>> from loops.knowledge.qualification import QualificationRecords >>> component.provideUtility(qualificationStates, - ... provides=IStatesDefinition) + ... provides=IStatesDefinition, + ... name='knowledge.qualification') >>> component.provideAdapter(QualificationRecords, ... provides=IQualificationRecords) + >>> qurecs = loopsRoot.getRecordManager()['qualification'] + +We first create a training that provides knowledge in Python specials. + + >>> trainingPySpecC = concepts['trpyspec'] = Concept( + ... u'Python Specials Training') + >>> trainingPySpecC.assignParent(pySpecialsC) + +Then we record the need for John to acquire this knowledge. + + >>> from loops.knowledge.browser import CreateQualificationRecordForm + >>> from loops.knowledge.browser import CreateQualificationRecord + Glossaries ========== diff --git a/knowledge/browser.py b/knowledge/browser.py index 53b7634..ff9781e 100644 --- a/knowledge/browser.py +++ b/knowledge/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,8 +19,6 @@ """ Definition of view classes and other browser related stuff for the loops.knowledge package. - -$Id$ """ from zope import interface, component @@ -32,11 +30,17 @@ from cybertools.typology.interfaces import IType from loops.browser.action import DialogAction from loops.browser.common import BaseView from loops.browser.concept import ConceptView +from loops.expert.browser.report import ResultsConceptView from loops.knowledge.interfaces import IPerson, ITask +from loops.organize.work.browser import CreateWorkItemForm, CreateWorkItem from loops.organize.party import getPersonForUser from loops.util import _ +template = ViewPageTemplateFile('knowledge_macros.pt') +knowledge_macros = template.macros + + actions.register('createTopic', 'portlet', DialogAction, title=_(u'Create Topic...'), description=_(u'Create a new topic.'), @@ -54,10 +58,19 @@ actions.register('editTopic', 'portlet', DialogAction, dialogName='editTopic', ) +actions.register('createQualification', 'portlet', DialogAction, + title=_(u'Create Qualification Record...'), + description=_(u'Create a work item for this person.'), + viewName='create_qualification.html', + dialogName='createQualification', + prerequisites=['registerDojoDateWidget', 'registerDojoNumberWidget', + 'registerDojoTextarea'], +) + class MyKnowledge(ConceptView): - template = ViewPageTemplateFile('knowledge_macros.pt') + template = template @Lazy def macro(self): @@ -90,9 +103,30 @@ class MyKnowledge(ConceptView): class Candidates(ConceptView): - template = ViewPageTemplateFile('knowledge_macros.pt') + template = template @Lazy def macro(self): return self.template.macros['requirement_candidates'] + +# qualification stuff + +class PersonQualificationView(ResultsConceptView): + + pass + + +class CreateQualificationRecordForm(CreateWorkItemForm): + + macros = knowledge_macros + + @Lazy + def macro(self): + return self.macros['create_qualification'] + + +class CreateQualificationRecord(CreateWorkItem): + + pass + diff --git a/knowledge/knowledge_macros.pt b/knowledge/knowledge_macros.pt index 1a8f660..5d12f77 100644 --- a/knowledge/knowledge_macros.pt +++ b/knowledge/knowledge_macros.pt @@ -57,4 +57,19 @@ + + + +
+
+ +
+
+
+ +