From d21c4a28eae99f58c6b95c26d060cf72cacd7510 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 30 Apr 2011 14:00:59 +0200 Subject: [PATCH] Yellow Pages: view task_candidates for listing persons with knowledge required for task. --- CHANGES.txt | 2 ++ knowledge/browser.py | 16 ++++++--- knowledge/configure.zcml | 11 ++++-- knowledge/interfaces.py | 8 +++-- knowledge/knowledge.py | 25 ++++++++++++++ knowledge/knowledge_macros.pt | 59 +++++++++++++++++++++++--------- locales/de/LC_MESSAGES/loops.mo | Bin 14539 -> 14729 bytes locales/de/LC_MESSAGES/loops.po | 21 ++++++++++-- 8 files changed, 114 insertions(+), 28 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1485bf1..d4269a0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,8 @@ $Id$ 1.1 --- +- yellow pages: view task_candidates for selecting persons with required + knowledge for task - improve 'move' and 'delegate' actions: create new run, store source and target work items, keep state when moving - keep access trail (history) in session diff --git a/knowledge/browser.py b/knowledge/browser.py index 5da1369..2b79bf7 100644 --- a/knowledge/browser.py +++ b/knowledge/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2011 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 @@ -58,14 +58,13 @@ actions.register('editTopic', 'portlet', DialogAction, ) -class MyKnowledge(BaseView): +class MyKnowledge(ConceptView): - #template = NamedTemplate('loops.knowledge_macros') template = ViewPageTemplateFile('knowledge_macros.pt') @Lazy def macro(self): - return self.template.macros['requirements'] + return self.template.macros['requirement_providers'] @Lazy def person(self): @@ -91,3 +90,12 @@ class MyKnowledge(BaseView): 'providers': (BaseView(p.context, request) for p in prov)} for req, prov in providers) + +class Candidates(ConceptView): + + template = ViewPageTemplateFile('knowledge_macros.pt') + + @Lazy + def macro(self): + return self.template.macros['requirement_candidates'] + diff --git a/knowledge/configure.zcml b/knowledge/configure.zcml index 1821b38..5b3a3c4 100644 --- a/knowledge/configure.zcml +++ b/knowledge/configure.zcml @@ -74,8 +74,15 @@ zope.publisher.interfaces.browser.IBrowserRequest" provides="zope.interface.Interface" factory="loops.knowledge.browser.MyKnowledge" - permission="zope.View" - /> + permission="zope.View" /> + + diff --git a/knowledge/interfaces.py b/knowledge/interfaces.py index 964ffc0..5d747ad 100644 --- a/knowledge/interfaces.py +++ b/knowledge/interfaces.py @@ -36,8 +36,6 @@ from loops.schema.base import Relation, RelationSet _ = MessageFactory('loops') -# TODO: separate interfaces for viewing and changing methods! - class IPerson(IBasePerson, IKnowing, ILoopsAdapter): """ A person, including knowledge/learning management features. @@ -54,6 +52,12 @@ class ITask(IBaseTask, IRequirementProfile, ILoopsAdapter): """ A task, also acting as a knowledge requirement profile. """ + requirements = RelationSet( + title=_(u'Requirements'), + description=_(u'The knowledge required for this task.'), + #target_types=('topic',), # set via global option knowledge.element + required=False) + class ITopic(IConceptSchema, IKnowledgeElement, ILoopsAdapter): """ Just a topic, some general classification concept. diff --git a/knowledge/knowledge.py b/knowledge/knowledge.py index 68a18c9..38db3fd 100644 --- a/knowledge/knowledge.py +++ b/knowledge/knowledge.py @@ -150,6 +150,11 @@ class Task(BaseTask, KnowledgeAdapterMixin): implements(ITask) + _adapterAttributes = BasePerson._adapterAttributes + ('requirements',) + _noexportAttributes = ('requirements',) + + requirements = ParentRelationSetProperty('requires') + def getRequirements(self): return (IKnowledgeElement(c) for c in self.context.getParents((self.requiresPred,))) @@ -160,6 +165,26 @@ class Task(BaseTask, KnowledgeAdapterMixin): def removeRequirement(self, obj): self.context.deassignParent(obj.context, (self.requiresPred,)) + def getCandidates(self): + result = [] + candidates = [] + reqs = list(self.requirements) + for req in reqs: + for p in req.getKnowers(): + if p not in candidates: + candidates.append(p) + item = dict(person=p, required=[], other=[], fit=0.0) + for k in p.knowledge: + if k in reqs: + item['required'].append(k) + item['fit'] += 1.0 + else: + item['other'].append(k) + result.append(item) + for item in result: + item['fit'] /= len(reqs) + return sorted(result, key=lambda x: (-x['fit'], x['person'].title)) + class ConceptKnowledgeProvider(AdapterBase, KnowledgeAdapterMixin): diff --git a/knowledge/knowledge_macros.pt b/knowledge/knowledge_macros.pt index 5abc24d..1a8f660 100644 --- a/knowledge/knowledge_macros.pt +++ b/knowledge/knowledge_macros.pt @@ -1,14 +1,11 @@ - + + + + +
-

- Concept: - Title -

-
-

Requirements

+

Requirements

@@ -16,20 +13,48 @@
Requirement
- Concept Title + Concept Title - Provider Title + Provider Title
-
-
+ + + + + +

Candidates for Task

+ + + + + + + + + + +
CandidateFitKnowledge
+ + + + + , +
+
+ + + diff --git a/locales/de/LC_MESSAGES/loops.mo b/locales/de/LC_MESSAGES/loops.mo index 91529e9fdb91d6ab5843621b4a6cc479d18bc5d7..8cda197bed722ba9db83a6749d7394c9037be436 100644 GIT binary patch delta 6058 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 RPqD|>x5tWrvWlMj{tMR%Lht|p diff --git a/locales/de/LC_MESSAGES/loops.po b/locales/de/LC_MESSAGES/loops.po index ccdf831..028544c 100644 --- a/locales/de/LC_MESSAGES/loops.po +++ b/locales/de/LC_MESSAGES/loops.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: $Id$\n" "POT-Creation-Date: 2007-05-22 12:00 CET\n" -"PO-Revision-Date: 2011-03-07 12:00 CET\n" +"PO-Revision-Date: 2011-04-30 12:00 CET\n" "Last-Translator: Helmut Merz \n" "Language-Team: loops developers \n" "MIME-Version: 1.0\n" @@ -498,10 +498,25 @@ msgid "End date" msgstr "Ende" msgid "Knowledge" -msgstr "Wissen" +msgstr "Kompetenzen" + +msgid "Requirements" +msgstr "Anforderungen" msgid "The knowledge elements for this person." -msgstr "Die Wissenselemente für diese Person." +msgstr "Die Kompetenzen dieser Person." + +msgid "Candidates for Task" +msgstr "Kandidaten für Aufgabe" + +msgid "Candidate" +msgstr "Kandidat" + +msgid "Fit" +msgstr "DG" + +msgid "description_fit" +msgstr "Deckungsgrad" msgid "Create loops Note" msgstr "loops-Notiz anlegen"