merge branch master

This commit is contained in:
Helmut Merz 2015-10-10 11:48:52 +02:00
commit 1800fe7c9e
11 changed files with 87 additions and 28 deletions

View file

@ -737,7 +737,9 @@ on data provided in this form:
>>> component.provideAdapter(NameChooser)
>>> request = TestRequest(form={'title': u'Test Note',
... 'form.type': u'.loops/concepts/note'})
... 'form.type': u'.loops/concepts/note',
... 'contentType': u'text/restructured',
... 'linkUrl': u'http://'})
>>> view = NodeView(m112, request)
>>> cont = CreateObject(view, request)
>>> cont.update()
@ -802,7 +804,7 @@ The new technique uses the ``fields`` and ``data`` attributes...
linkText textline False None
>>> view.data
{'linkUrl': u'http://', 'contentType': 'text/restructured', 'data': u'',
{'linkUrl': u'http://', 'contentType': u'text/restructured', 'data': u'',
'linkText': u'', 'title': u'Test Note'}
The object is changed via a FormController adapter created for

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
# Copyright (c) 2015 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 @@
"""
Adapters and others classes for analyzing resources.
$Id$
"""
from itertools import tee
@ -41,6 +39,7 @@ from loops.resource import Resource
from loops.setup import addAndConfigureObject
from loops.type import TypeInterfaceSourceList
logger = getLogger('Classifier')
TypeInterfaceSourceList.typeInterfaces += (IClassifier,)
@ -102,6 +101,7 @@ class Classifier(AdapterBase):
if resource not in resources:
concept.assignResource(resource, predicate)
message = u'Assigning: %s %s %s'
self.log(message % (resource.title, predicate.title, concept.title), 5)
else:
message = u'Already assigned: %s %s %s'
self.log(message % (resource.title, predicate.title, concept.title), 4)
@ -109,8 +109,7 @@ class Classifier(AdapterBase):
def log(self, message, level=5):
if level >= self.logLevel:
#print 'Classifier %s:' % getName(self.context), message
getLogger('Classifier').info(
u'%s: %s' % (getName(self.context), message))
logger.info(u'%s: %s' % (getName(self.context), message))
class Extractor(object):

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
# Copyright (c) 2015 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,17 +18,20 @@
"""
View class(es) for resource classifiers.
$Id$
"""
from logging import getLogger
import transaction
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from zope.traversing.api import getName
from loops.browser.concept import ConceptView
from loops.common import adapted
logger = getLogger('ClassifierView')
class ClassifierView(ConceptView):
@ -42,12 +45,18 @@ class ClassifierView(ConceptView):
if 'update' in self.request.form:
cta = adapted(self.context)
if cta is not None:
for r in collectResources(self.context):
for idx, r in enumerate(collectResources(self.context)):
if idx % 1000 == 0:
logger.info('Committing, resource # %s' % idx)
transaction.commit()
cta.process(r)
logger.info('Finished processing')
transaction.commit()
return True
def collectResources(concept, checkedConcepts=None, result=None):
logger.info('Start collecting resources for %s' % getName(concept))
if result is None:
result = []
if checkedConcepts is None:
@ -59,4 +68,5 @@ def collectResources(concept, checkedConcepts=None, result=None):
if c not in checkedConcepts:
checkedConcepts.append(c)
collectResources(c, checkedConcepts, result)
logger.info('Collected %s resources' % len(result))
return result

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: 0.13.1\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2015-06-06 12:00 CET\n"
"PO-Revision-Date: 2015-09-22 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n"
@ -597,9 +597,6 @@ msgstr "Informationen über dieses Objekt"
msgid "Information about this object."
msgstr "Informationen über dieses Objekt."
msgid "Send a link to this object by email."
msgstr "Einen Link zu diesem Objekt per E-Mail versenden."
msgid "Edit with external editor."
msgstr "Mit 'External Editor' bearbeiten."
@ -1416,3 +1413,27 @@ msgstr "Zeitraum"
msgid "Technology"
msgstr "Technik"
# send mail
msgid "Send a link to this object by email."
msgstr "Einen Link zu diesem Objekt per E-Mail versenden."
msgid "Send Link by Email"
msgstr "Link per E-Mail versenden"
msgid "Mail Subject"
msgstr "Betreff"
msgid "Mail Body"
msgstr "Text"
msgid "Recipients"
msgstr "Empfänger"
msgid "Additional Recipients"
msgstr "Weitere Empfänger"
msgid "Send email"
msgstr "E-Mail senden"

View file

@ -175,6 +175,10 @@ class SendEmailForm(NodeView):
@Lazy
def subject(self):
optionKey = 'organize.sendmail_subject'
option = self.globalOptions(optionKey) or self.typeOptions(optionKey)
if option:
return option[0]
menu = self.context.getMenu()
zdc = IZopeDublinCore(menu)
zdc.languageInfo = self.languageInfo
@ -185,6 +189,8 @@ class SendEmailForm(NodeView):
class SendEmail(FormController):
bccToSender = False
def checkPermissions(self):
return (not self.isAnonymous and
super(SendEmail, self).checkPermissions())
@ -201,7 +207,10 @@ class SendEmail(FormController):
msg = MIMEText(message.encode('utf-8'), 'plain', 'utf-8')
msg['Subject'] = subject.encode('utf-8')
msg['From'] = sender
msg['To'] = ', '.join(r.strip() for r in recipients if r.strip())
recipients = [r.strip() for r in recipients if r.strip()]
msg['To'] = ', '.join(recipients)
if self.bccToSender:
recipients.append(sender)
mailhost = component.getUtility(IMailDelivery, 'Mail')
mailhost.send(sender, recipients, msg.as_string())
return True

View file

@ -125,14 +125,15 @@
<span tal:content="view/target/title"></span></div>
<metal:content define-macro="mail_content">
<div>
<label i18n:translate="" for="subject">Subject</label>
<label i18n:translate="" for="subject">Mail Subject</label>
<div>
<input name="subject" id="subject" style="width: 60em"
dojoType="dijit.form.ValidationTextBox" required
tal:attributes="value view/subject" /></div>
</div>
<div>
<label i18n:translate="" for="mailbody">Mail Body</label>
<label i18n:translate=""
for="mailbody">Mail Body</label>
<div>
<textarea name="mailbody" cols="80" rows="4" id="mailbody"
dojoType="dijit.form.SimpleTextarea" style="width: 60em"
@ -155,7 +156,8 @@
<span i18n:translate="">Toggle all</span></div>
</div>
<div>
<label i18n:translate="" for="addrecipients">Additional recipients</label>
<label i18n:translate=""
for="addrecipients">Additional Recipients</label>
<div>
<textarea name="addrecipients" cols="80" rows="4" id="addrecipients"
dojoType="dijit.form.SimpleTextarea"

View file

@ -177,11 +177,15 @@ Recent changes
>>> data[0].timeStamp
u'... ...:...'
>>> data[0].objectData
{'version': '', 'canAccess': True, 'title': 'Change Doc 001', 'url': '',
'object': <loops.resource.Resource object at ...>, 'type': u'Text'}
{'version': '', 'description': u'', 'title': 'Change Doc 001', 'url': '',
'object': <loops.resource.Resource object at ...>, 'type': u'Text',
'canAccess': True}
>>> data[0].user
{'url': '', 'object': <loops.concept.Concept ...>, 'title': u'john'}
>>> data[0].action
'modify'

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2014 Helmut Merz helmutm@cy55.de
# Copyright (c) 2015 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
@ -265,20 +265,23 @@ class TrackDetails(BaseView):
def objectData(self):
obj = self.object
if obj is None:
return dict(object=None, title='-', type='-', url='',
return dict(object=None, title='-', description='',
type='-', url='',
version=None, canAccess=False)
node = self.view.nodeView
url = node is not None and node.getUrlForTarget(obj) or ''
view = self.view.getViewForObject(obj)
if view is None:
title = obj.title
desc = obj.description
else:
title = view.listingTitle
desc = view.description
versionable = IVersionable(self.object, None)
version = ((versionable is not None and
not (versionable.notVersioned) and
versionable.versionId) or '')
return dict(object=obj, title=title,
return dict(object=obj, title=title, description=desc,
type=self.longTypeTitle, url=url, version=version,
canAccess=canAccessObject(obj))

View file

@ -27,7 +27,7 @@
<tr tal:define="wiType row/workItemType"
tal:attributes="class wiType/indicator|nothing">
<td class="nowrap center"
tal:define="today python: row.isToday and ' today' or ''"
tal:define="today python:row.isToday and ' today' or ''"
tal:attributes="title row/weekDay;
class string:nowrap center$today"
i18n:attributes="title"
@ -35,9 +35,10 @@
<td class="nowrap center" tal:content="row/start">17:30</td>
<td class="nowrap center" tal:content="row/end">20:00</td>
<td class="nowrap center" tal:content="row/duration">2:30</td>
<td tal:condition="python: 'Task' in work.columns">
<td tal:condition="python:'Task' in work.columns">
<a tal:define="data row/objectData"
tal:attributes="href data/url"
tal:attributes="href data/url;
title data/description"
tal:content="data/title">Task</a></td>
<td tal:condition="python: 'User' in work.columns">
<a tal:attributes="href row/user/url"

View file

@ -88,6 +88,13 @@ class DataTable(AdapterBase):
if data is None:
data = OOBTree()
self.context._data = data
reclen = len(self.columns) - 1
for k, v in data.items():
v = v[:reclen]
missing = reclen - len(v)
if missing > 0:
v += (missing * [u''])
data[k] = v
return data
def setData(self, data):
self.context._data = OOBTree(data)
@ -102,6 +109,7 @@ class DataTable(AdapterBase):
item[c] = k
else:
item[c] = v[idx-1]
#item[c] = len(v) > idx and v[idx-1] or u''
result.append(item)
return result