provide a comments overview listing, e.g. for moderation of comments
This commit is contained in:
parent
f34dc4a59c
commit
2d2240244e
8 changed files with 175 additions and 38 deletions
|
@ -16,6 +16,7 @@
|
||||||
<div metal:use-macro="item/report_macros/params" />
|
<div metal:use-macro="item/report_macros/params" />
|
||||||
<div metal:define-macro="buttons">
|
<div metal:define-macro="buttons">
|
||||||
<input type="submit" name="report_execute" value="Execute Report"
|
<input type="submit" name="report_execute" value="Execute Report"
|
||||||
|
tal:condition="item/queryFields"
|
||||||
i18n:attributes="value" />
|
i18n:attributes="value" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2014 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -29,6 +29,7 @@ from cybertools.composer.report.field import Field as BaseField
|
||||||
from cybertools.composer.report.result import ResultSet
|
from cybertools.composer.report.result import ResultSet
|
||||||
from cybertools.stateful.interfaces import IStateful, IStatesDefinition
|
from cybertools.stateful.interfaces import IStateful, IStatesDefinition
|
||||||
from cybertools.util.date import timeStamp2Date
|
from cybertools.util.date import timeStamp2Date
|
||||||
|
from cybertools.util.format import formatDate
|
||||||
from loops.common import baseObject
|
from loops.common import baseObject
|
||||||
from loops.expert.report import ReportInstance
|
from loops.expert.report import ReportInstance
|
||||||
from loops import util
|
from loops import util
|
||||||
|
@ -209,6 +210,41 @@ class TargetField(RelationField):
|
||||||
return util.getObjectForUid(value)
|
return util.getObjectForUid(value)
|
||||||
|
|
||||||
|
|
||||||
|
# track fields
|
||||||
|
|
||||||
|
class TrackDateField(Field):
|
||||||
|
|
||||||
|
fieldType = 'date'
|
||||||
|
part = 'date'
|
||||||
|
format = 'short'
|
||||||
|
cssClass = 'right'
|
||||||
|
|
||||||
|
def getValue(self, row):
|
||||||
|
value = self.getRawValue(row)
|
||||||
|
if not value:
|
||||||
|
return None
|
||||||
|
return timeStamp2Date(value)
|
||||||
|
|
||||||
|
def getDisplayValue(self, row):
|
||||||
|
value = self.getValue(row)
|
||||||
|
if value:
|
||||||
|
view = row.parent.context.view
|
||||||
|
return formatDate(value, self.part, self.format,
|
||||||
|
view.languageInfo.language)
|
||||||
|
return u''
|
||||||
|
|
||||||
|
def getSelectValue(self, row):
|
||||||
|
value = self.getRawValue(row)
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return timeStamp2ISO(value)[:10]
|
||||||
|
|
||||||
|
|
||||||
|
class TrackTimeField(TrackDateField):
|
||||||
|
|
||||||
|
part = 'time'
|
||||||
|
|
||||||
|
|
||||||
# sub-report stuff
|
# sub-report stuff
|
||||||
|
|
||||||
class SubReport(ReportInstance):
|
class SubReport(ReportInstance):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2014 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,9 +25,11 @@ from zope.component import adapts
|
||||||
from zope.interface import Interface, Attribute, implements
|
from zope.interface import Interface, Attribute, implements
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
from zope.traversing.api import getName
|
||||||
|
|
||||||
from cybertools.composer.report.base import Report as BaseReport
|
from cybertools.composer.report.base import Report as BaseReport
|
||||||
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
|
from cybertools.composer.report.base import LeafQueryCriteria
|
||||||
|
from cybertools.composer.report.base import CompoundQueryCriteria
|
||||||
from cybertools.composer.report.interfaces import IReport as IBaseReport
|
from cybertools.composer.report.interfaces import IReport as IBaseReport
|
||||||
from cybertools.composer.report.interfaces import IReportParams
|
from cybertools.composer.report.interfaces import IReportParams
|
||||||
from cybertools.composer.report.result import ResultSet, Row
|
from cybertools.composer.report.result import ResultSet, Row
|
||||||
|
@ -53,6 +55,8 @@ class IReport(ILoopsAdapter, IReportParams):
|
||||||
source='loops.expert.reportTypeSource',
|
source='loops.expert.reportTypeSource',
|
||||||
required=True)
|
required=True)
|
||||||
|
|
||||||
|
name = Attribute('The name of the report.')
|
||||||
|
|
||||||
|
|
||||||
class IReportInstance(IBaseReport):
|
class IReportInstance(IBaseReport):
|
||||||
""" The report-type-specific object (an adapter on the report) that
|
""" The report-type-specific object (an adapter on the report) that
|
||||||
|
@ -68,6 +72,10 @@ class Report(AdapterBase):
|
||||||
|
|
||||||
_contextAttributes = list(IReport)
|
_contextAttributes = list(IReport)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def name(self):
|
||||||
|
return getName(self.context)
|
||||||
|
|
||||||
TypeInterfaceSourceList.typeInterfaces += (IReport,)
|
TypeInterfaceSourceList.typeInterfaces += (IReport,)
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,9 +87,11 @@ class ReportInstance(BaseReport):
|
||||||
rowFactory = Row
|
rowFactory = Row
|
||||||
|
|
||||||
view = None # set upon creation
|
view = None # set upon creation
|
||||||
|
#headerRowFactory = Row
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.name = self.type
|
||||||
|
|
||||||
def getResultsRenderer(self, name, macros):
|
def getResultsRenderer(self, name, macros):
|
||||||
return macros[name]
|
return macros[name]
|
||||||
|
@ -105,6 +115,8 @@ class ReportInstance(BaseReport):
|
||||||
if k in crit.parts.keys():
|
if k in crit.parts.keys():
|
||||||
crit.parts[k].comparisonValue = v
|
crit.parts[k].comparisonValue = v
|
||||||
parts = Jeep(crit.parts)
|
parts = Jeep(crit.parts)
|
||||||
|
if getattr(self, 'limitsCount', ''):
|
||||||
|
limits = None
|
||||||
result = list(self.selectObjects(parts)) # may modify parts
|
result = list(self.selectObjects(parts)) # may modify parts
|
||||||
qc = CompoundQueryCriteria(parts)
|
qc = CompoundQueryCriteria(parts)
|
||||||
return ResultSet(self, result, rowFactory=self.rowFactory,
|
return ResultSet(self, result, rowFactory=self.rowFactory,
|
||||||
|
@ -161,3 +173,15 @@ class DefaultConceptReportInstance(ReportInstance):
|
||||||
|
|
||||||
label = u'Default Concept Report'
|
label = u'Default Concept Report'
|
||||||
|
|
||||||
|
|
||||||
|
# specialized rows
|
||||||
|
|
||||||
|
class TrackRow(Row):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getContextAttr(obj, attr):
|
||||||
|
if attr in obj.context.metadata_attributes:
|
||||||
|
return getattr(obj.context, attr)
|
||||||
|
return obj.context.data.get(attr)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,12 @@ Viewing comments
|
||||||
('My comment', u'... ...', u'john')
|
('My comment', u'... ...', u'john')
|
||||||
|
|
||||||
|
|
||||||
|
Reporting
|
||||||
|
=========
|
||||||
|
|
||||||
|
>>> from loops.organize.comment.report import CommentsOverview
|
||||||
|
|
||||||
|
|
||||||
Fin de partie
|
Fin de partie
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -37,4 +37,26 @@
|
||||||
factory="loops.organize.comment.browser.CreateComment"
|
factory="loops.organize.comment.browser.CreateComment"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<!-- reporting -->
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="list_comments.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.organize.comment.report.CommentsOverview"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="comments_overview"
|
||||||
|
factory="loops.organize.comment.report.CommentsReportInstance"
|
||||||
|
provides="loops.expert.report.IReportInstance"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="loops.organize.comment.report.CommentsReportInstance">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.expert.report.IReportInstance" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.expert.report.IReportInstance" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
6
organize/comment/loops_comment_de.dmp
Normal file
6
organize/comment/loops_comment_de.dmp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
type(u'report', u'Report', options=u'',
|
||||||
|
typeInterface='loops.expert.report.IReport', viewName=u'')
|
||||||
|
concept(u'comments_overview', u'\xdcbersicht Kommentare', u'report',
|
||||||
|
reportType=u'comments_overview')
|
||||||
|
concept(u'comments', u'Kommentare', u'query', options=u'',
|
||||||
|
viewName=u'list_comments.html')
|
75
organize/comment/report.py
Normal file
75
organize/comment/report.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Report views and definitions for comments listings and similar stuff.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cybertools.util.jeep import Jeep
|
||||||
|
from loops.expert.browser.report import ReportConceptView
|
||||||
|
from loops.expert.field import Field, StateField, TargetField
|
||||||
|
from loops.expert.field import TrackDateField
|
||||||
|
from loops.expert.report import ReportInstance, TrackRow
|
||||||
|
|
||||||
|
|
||||||
|
class CommentsOverview(ReportConceptView):
|
||||||
|
|
||||||
|
reportName = 'comments_overview'
|
||||||
|
|
||||||
|
|
||||||
|
timeStamp = TrackDateField('timeStamp', u'Timestamp',
|
||||||
|
description=u'The date and time the comment was posted.',
|
||||||
|
part='dateTime',
|
||||||
|
executionSteps=['sort', 'output'])
|
||||||
|
target = TargetField('taskId', u'Target',
|
||||||
|
description=u'The resource or concept the comment was posted at.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
name = Field('name', u'Name',
|
||||||
|
description=u'The name addres of the poster.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
email = Field('email', u'E-Mail Address',
|
||||||
|
description=u'The email addres of the poster.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
subject = Field('subject', u'Subject',
|
||||||
|
description=u'The subject of the comment.',
|
||||||
|
executionSteps=['output'])
|
||||||
|
state = StateField('state', u'State',
|
||||||
|
description=u'The state of the comment.',
|
||||||
|
cssClass='center',
|
||||||
|
statesDefinition='organize.commentStates',
|
||||||
|
executionSteps=['query', 'sort', 'output'])
|
||||||
|
|
||||||
|
|
||||||
|
class CommentsRow(TrackRow):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CommentsReportInstance(ReportInstance):
|
||||||
|
|
||||||
|
type = "comments_overview"
|
||||||
|
label = u'Comments Overview'
|
||||||
|
|
||||||
|
rowFactory = CommentsRow
|
||||||
|
|
||||||
|
fields = Jeep((timeStamp, target, name, email, subject, state))
|
||||||
|
defaultOutputFields = fields
|
||||||
|
defaultSortCriteria = (state, timeStamp)
|
||||||
|
|
||||||
|
def selectObjects(self, parts):
|
||||||
|
return self.recordManager['comments'].values()
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2014 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,13 +30,13 @@ from cybertools.composer.report.field import CalculatedField
|
||||||
from cybertools.composer.report.result import ResultSet, Row as BaseRow
|
from cybertools.composer.report.result import ResultSet, Row as BaseRow
|
||||||
from cybertools.organize.interfaces import IWorkItems
|
from cybertools.organize.interfaces import IWorkItems
|
||||||
from cybertools.util.date import timeStamp2Date, timeStamp2ISO
|
from cybertools.util.date import timeStamp2Date, timeStamp2ISO
|
||||||
from cybertools.util.format import formatDate
|
|
||||||
from cybertools.util.jeep import Jeep
|
from cybertools.util.jeep import Jeep
|
||||||
from loops.common import adapted, baseObject
|
from loops.common import adapted, baseObject
|
||||||
from loops.expert.browser.report import ReportConceptView
|
from loops.expert.browser.report import ReportConceptView
|
||||||
from loops.expert.field import Field, TargetField, DateField, StateField, \
|
from loops.expert.field import Field, TargetField, DateField, StateField, \
|
||||||
TextField, HtmlTextField, UrlField
|
TextField, HtmlTextField, UrlField
|
||||||
from loops.expert.field import SubReport, SubReportField
|
from loops.expert.field import SubReport, SubReportField
|
||||||
|
from loops.expert.field import TrackDateField, TrackTimeField
|
||||||
from loops.expert.report import ReportInstance
|
from loops.expert.report import ReportInstance
|
||||||
from loops import util
|
from loops import util
|
||||||
|
|
||||||
|
@ -50,39 +50,6 @@ class WorkStatementView(ReportConceptView):
|
||||||
|
|
||||||
# fields
|
# fields
|
||||||
|
|
||||||
class TrackDateField(Field):
|
|
||||||
|
|
||||||
fieldType = 'date'
|
|
||||||
part = 'date'
|
|
||||||
format = 'short'
|
|
||||||
cssClass = 'right'
|
|
||||||
|
|
||||||
def getValue(self, row):
|
|
||||||
value = self.getRawValue(row)
|
|
||||||
if not value:
|
|
||||||
return None
|
|
||||||
return timeStamp2Date(value)
|
|
||||||
|
|
||||||
def getDisplayValue(self, row):
|
|
||||||
value = self.getValue(row)
|
|
||||||
if value:
|
|
||||||
view = row.parent.context.view
|
|
||||||
return formatDate(value, self.part, self.format,
|
|
||||||
view.languageInfo.language)
|
|
||||||
return u''
|
|
||||||
|
|
||||||
def getSelectValue(self, row):
|
|
||||||
value = self.getRawValue(row)
|
|
||||||
if not value:
|
|
||||||
return ''
|
|
||||||
return timeStamp2ISO(value)[:10]
|
|
||||||
|
|
||||||
|
|
||||||
class TrackTimeField(TrackDateField):
|
|
||||||
|
|
||||||
part = 'time'
|
|
||||||
|
|
||||||
|
|
||||||
class DurationField(Field):
|
class DurationField(Field):
|
||||||
|
|
||||||
cssClass = 'right'
|
cssClass = 'right'
|
||||||
|
|
Loading…
Add table
Reference in a new issue