From 142e1cb20b0f543c512ff2047f1617d914139a0f Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Tue, 17 Jul 2012 08:42:36 +0200 Subject: [PATCH] provide separate interfaces and type concepts for events and agenda items, e.g. for improving meeting minutes --- locales/de/LC_MESSAGES/loops.mo | Bin 17811 -> 17851 bytes locales/de/LC_MESSAGES/loops.po | 5 ++++- organize/browser/event.py | 1 - organize/configure.zcml | 20 ++++++++++++++++++++ organize/interfaces.py | 22 ++++++++++++++++++---- organize/task.py | 32 +++++++++++++++++++++++++------- organize/tests.py | 5 ++++- organize/work/README.txt | 24 +++++++++++++++--------- organize/work/report.py | 1 + 9 files changed, 87 insertions(+), 23 deletions(-) diff --git a/locales/de/LC_MESSAGES/loops.mo b/locales/de/LC_MESSAGES/loops.mo index c90233031aa981a76556703f28f70f418b92d917..2a03d4ac049211996b729548cdc73bc3faba5bce 100644 GIT binary patch delta 6260 zcmZA5dz?>Y9>DQ4m~kDKF=J*7X3St{+^;ia(NL=*TSM#}BBe~V5=ECON!S#r&{9g5{e0#;f9-koo%i!R=Q+>)oEatOrEHp)lGv9~ zYjMO?mJ&rR@YA|cw2Jf-O)ZV0(&kY#0?V)j=VBUe3~t8Sy*{GaQBKcq7`tAJGBK!8$lU(N8{JX-(7f}u+L7)3uf`m)F27TaZbjFqFN>rgs_Z9kJ3L9>N8R$~B zL1$Km-Y-YnxfE^p>QH_YI)K@sd?D5&pI9CW9!2+XBRaBO=t>+wm+UaQ5?`VnokHuS z6~%8&Gjs)8paW`;*6)t4OutY*5Nnb@A89`k4JY9YM`BN$7~hBpR-&SV{O&Z5o8 zVnlno+qk?1T3&(;=szka;e#X4Lv|%P!s+OMW}-_w z8*AYLw0<(=A4bp2Bj}1ehwk;u$bZpJemIen=>61ovFVtwVit*1EJT;8J$A)zn1&P3 z!#EME4-NA5jOL>CA3;}S9ooT5A^$qsZWW$~AEPVNwm5#SXEE#VO!`w`2N$3N8Xqd$ zi04RoNNq4kfU^}a1;{m&wi+CE;wuIPJR zj%-^r7Tv4a$m&H)(E)5hXZ9-E@pg1&szUie>_Gl-$Y+qLK|Ti^KpuJ~3KJx3us7OJ zKeXZV&<2O0hwpNh z{(ncp2i#aYs*N_(2peD~`e18x25F2VxxE72v}iZ-wZ{Xl&a${X~E2VR8UFU5Qufwngl zGjKNg++uX1>q2>=G9;?dk$-_M>1lM2>h_F(-R7esAB1gi4EiV9EcCTh@(r8_7c%l5{`Tx_Qh4$6!)Q9@C~|@XV96Y^^V_$cIXy#LZwdKb=wD2S&;iyii&vr*Cj20@BcUb8s~L4g56xBR5>G=rz72gl z7NSeJ3|+BR=xg;D`n#Y4eQqQAI&Vh5q&v{(>a)*oQPaMxzcXt=K_Ql4TO1xL+=4cA z2RgvJgMUH?vH;!lrRV@2L>qoIxB(sD^Ju*-=!#XM6WrUE^>>8FC~ygXL6c+TAUpZs3<|g(^-sm&=cLe zbJ3BHLicVgx^&ie0QX`EEKhHm9n?1mpDd_TMxufPuYBs$Y7w4sCO0FI(FI)ScG(K&H>ceH*fdbY~Z`y;Ui zUV{l6x{ide$5hP2ThOzx2;Hj{XuY+eyaJu+R`k2D9bKvYX#KCl{nJ>3d{iDkUlT7P z+W@&0jVWjSoxwvCII`8~d;SzU^5@XgTp8}~!rtWfqlYbfaNKY&wEnNqGcXh#$jFc% zhqf~b9q0^n0CNVj{?23@1van?9r0eYfltr}kA(Z*qV-dT#MZ@{3~&{%Y@#-oRD8rr~Z=!3IEegQhbC1^)0(00~i3cg5uM_8u~ z1$UuW7U?Ik2wM@Yuc$7Le{`k5>mK6U>J;yO@<`LX{<++_oszqWVZ@EZcH#^%o|sQ~ z9gL~|xsaa&iKfXxnb|3wlcO_x4BbQi6ybG}_>gEv+wHLv@eOgB@M=Q&bJ&q+N%|^W zNgO8HC*RBL((-*$bBG$;U4#1x|FB(z?<8Ai6}S9=R0m4@mTw}wx|6>N|DC)xtElBG zq}ma6DD~=ri{oUpE4ezWsQa7bJe*#Qx!argI?hH<1fRy@(83E*@`tR#{vFBoB>W$% zzEryje!E0J5`2216NE31=Xna@l|kKE*eyA_S$2n_XP@ zBT`kw*5uIayeT_K`HQ0q;kAu;hG@j|t8p5!fJg~_?j-H?Eb$ZZl^L$T#8iKRJ5l#e z@{fkH>#>0NBDpI&Kjp3DiR`BR`-JvJQGSeQYfv@=y}l%#Ct8Gh$4UQ&@On8pD5q)P z`rK(i)S{$<$S3_UUP}B-6p;5iMDTs6{;e_5f|TTfoWk6fNYxBgEbU5^5;@6jIe9}q zwutKj;t$m+zOT5KXi2lL{H+ZWQW|mM3>OVr<6QEcr~Q#LfluK z;{cJ*Cen!&l;z>Q;ocbhEwPq3N+gLRgxA|K)jxmWXD_0JXZ?iqsV?Q@T}h%J@h;Jv zo2&43!fOkWMwwTyC~-H#lJe0G^*Hr I_RDqt2jEnEMgRZ+ delta 6238 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 diff --git a/locales/de/LC_MESSAGES/loops.po b/locales/de/LC_MESSAGES/loops.po index 76f2957..cae5306 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: 2012-06-10 12:00 CET\n" +"PO-Revision-Date: 2012-07-17 12:00 CET\n" "Last-Translator: Helmut Merz \n" "Language-Team: loops developers \n" "MIME-Version: 1.0\n" @@ -296,6 +296,9 @@ msgstr "Besprechungsprotokoll für dieses Objekt anzeigen." msgid "Download Meeting Minutes" msgstr "Besprechungsprotokoll generieren" +msgid "Participants" +msgstr "Teilnehmer" + msgid "Task/Action" msgstr "Aufgabe" diff --git a/organize/browser/event.py b/organize/browser/event.py index 560abad..d42abfb 100644 --- a/organize/browser/event.py +++ b/organize/browser/event.py @@ -316,7 +316,6 @@ class CreateFollowUpEvent(CreateConcept, BaseFollowUpController): result = super(CreateFollowUpEvent, self).update() form = self.request.form toBeAssigned = form.get('cb_select_tasks') or [] - print '***', toBeAssigned for uid in toBeAssigned: task = util.getObjectForUid(uid) self.createFollowUpTask(adapted(task)) diff --git a/organize/configure.zcml b/organize/configure.zcml index e760a03..3f03420 100644 --- a/organize/configure.zcml +++ b/organize/configure.zcml @@ -39,6 +39,26 @@ set_schema="loops.organize.interfaces.ITask" /> + + + + + + + + + + + + diff --git a/organize/interfaces.py b/organize/interfaces.py index c60fdc8..20413a8 100644 --- a/organize/interfaces.py +++ b/organize/interfaces.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 @@ -18,8 +18,6 @@ """ Interfaces for organizational stuff like persons and addresses. - -$Id$ """ from zope.interface import Interface, Attribute @@ -156,13 +154,29 @@ class IMemberRegistrationManager(Interface): current password. """ -# task +# task management, meeting minutes: task, event, agenda item class ITask(IConceptSchema, ITask, ILoopsAdapter): pass +class IEvent(ITask): + + participants = schema.Text( + title=_(u'Participants'), + description=_(u'The names of the persons taking part in the event.'), + default=u'', + missing_value=u'', + required=False) + + + +class IAgendaItem(ILoopsAdapter): + + pass + + # 'hasrole' predicate class IHasRole(IRelationAdapter): diff --git a/organize/task.py b/organize/task.py index b069497..cdbd172 100644 --- a/organize/task.py +++ b/organize/task.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009 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 @@ -17,23 +17,22 @@ # """ -Adapters for IConcept providing interfaces from the cybertools.organize package. - -$Id$ +Adapters for IConcept providing interfaces from the +cybertools.organize package. """ from time import mktime from zope.component import adapts from zope.interface import implements -from loops.organize.interfaces import ITask +from loops.organize.interfaces import ITask, IEvent, IAgendaItem from loops.interfaces import IConcept from loops.interfaces import IIndexAttributes from loops.common import AdapterBase from loops.type import TypeInterfaceSourceList -TypeInterfaceSourceList.typeInterfaces += (ITask,) +TypeInterfaceSourceList.typeInterfaces += (ITask, IEvent, IAgendaItem) class Task(AdapterBase): @@ -42,10 +41,29 @@ class Task(AdapterBase): implements(ITask) - _adapterAttributes = ('context', '__parent__',) + _adapterAttributes = AdapterBase._adapterAttributes _contextAttributes = list(ITask) +class Event(Task): + """ A scheduled event or appointment. + """ + + implements(IEvent) + + _contextAttributes = list(IEvent) + + +class AgendaItem(AdapterBase): + """ Some topic (a sort of task) that is discussed during an event. + """ + + implements(IAgendaItem) + + _adapterAttributes = AdapterBase._adapterAttributes + _contextAttributes = list(IAgendaItem) + + class IndexAttributes(object): implements(IIndexAttributes) diff --git a/organize/tests.py b/organize/tests.py index 7222b18..21f4a65 100755 --- a/organize/tests.py +++ b/organize/tests.py @@ -24,8 +24,9 @@ from cybertools.util.jeep import Jeep from loops.common import adapted from loops.concept import Concept from loops.organize.interfaces import IPerson, IHasRole +from loops.organize.interfaces import IEvent, IAgendaItem from loops.organize.party import Person, HasRole -from loops.organize.task import Task +from loops.organize.task import Task, Event, AgendaItem from loops.setup import addAndConfigureObject from loops.tests.auth import login @@ -37,6 +38,8 @@ def setupUtilitiesAndAdapters(loopsRoot): component.provideUtility(principalAnnotations, IPrincipalAnnotationUtility) component.provideAdapter(Person, provides=IPerson) component.provideAdapter(Task) + component.provideAdapter(Event, provides=IEvent) + component.provideAdapter(AgendaItem, provides=IAgendaItem) component.provideAdapter(FoundPrincipalFactory) component.provideAdapter(HasRole, provides=IHasRole) return Jeep(( diff --git a/organize/work/README.txt b/organize/work/README.txt index 1e3f88f..1cce6d4 100644 --- a/organize/work/README.txt +++ b/organize/work/README.txt @@ -242,14 +242,19 @@ and recording information about the tasks. Let's start with creating an a event and assigning it a task. - >>> from loops.organize.interfaces import ITask + >>> from loops.organize.interfaces import IEvent, IAgendaItem >>> tEvent = addAndConfigureObject(concepts, Concept, 'event', - ... title=u'Event', conceptType=concepts.getTypeConcept(), - ... typeInterface=ITask) + ... title=u'Event', conceptType=concepts.getTypeConcept(), + ... typeInterface=IEvent) + >>> tAgendaItem = addAndConfigureObject(concepts, Concept, 'agendaitem', + ... title=u'AgendaItem', conceptType=concepts.getTypeConcept(), + ... typeInterface=IEvent) >>> ev01 = addAndConfigureObject(concepts, Concept, 'ev01', - ... title=u'loops Meeting', conceptType=tEvent) - >>> ev01.assignChild(task01) + ... title=u'loops Meeting', conceptType=tEvent) + >>> aitem01 = addAndConfigureObject(concepts, Concept, 'aitem01', + ... title=u'Documentation of Features', conceptType=tAgendaItem) + >>> ev01.assignChild(aitem01) Now we create the meeting minutes report. We assign the event type as a child in order to provide the information for which types of objects the @@ -259,9 +264,9 @@ report is available. >>> component.provideAdapter(MeetingMinutes, provides=IReportInstance, ... name='meeting_minutes') - >>> meetingMinutes = addAndConfigureObject(concepts, Concept, 'meeting_minutes', - ... title=u'Meeting Minutes', conceptType=tReport, - ... reportType='meeting_minutes') + >>> meetingMinutes = addAndConfigureObject(concepts, Concept, + ... 'meeting_minutes', title=u'Meeting Minutes', conceptType=tReport, + ... reportType='meeting_minutes') >>> meetingMinutes.assignChild(tEvent, hasReport) We can now access the report using a corresponding report-based view. @@ -277,7 +282,8 @@ We can now access the report using a corresponding report-based view. ... for col in reportView.displayedColumns: ... print col.getDisplayValue(row), ... print - {'url': 'http://127.0.0.1/loops/views/home/.36', 'title': u'loops Development'} + {'url': 'http://127.0.0.1/loops/views/home/.58', + 'title': u'Documentation of Features'} diff --git a/organize/work/report.py b/organize/work/report.py index 86dc356..2cd9628 100644 --- a/organize/work/report.py +++ b/organize/work/report.py @@ -371,6 +371,7 @@ class MeetingMinutes(WorkReportInstance): tasks, taskTitle, taskDescription, workItems)) defaultOutputFields = fields states = ('planned', 'accepted', 'done', 'done_x', 'finished') + taskTypeNames = ('agendaitem',) def selectObjects(self, parts): return [adapted(t) for t in self.getTasks(parts)[1:]]