new view list_children.html; action options for queries; send mail feature basically working; presence with link to person
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3575 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
21036dae20
commit
a6dbafcce8
14 changed files with 104 additions and 15 deletions
|
@ -8,6 +8,9 @@ $Id$
|
||||||
|
|
||||||
New features
|
New features
|
||||||
|
|
||||||
|
- new view: ``list_children.html``
|
||||||
|
- evaluate action settings also on queries
|
||||||
|
- "send email" feature, controlled by global option ``organize.allowSendEmail``
|
||||||
- presence: portlet showing other users logged-in and working within the
|
- presence: portlet showing other users logged-in and working within the
|
||||||
same loops site, controlled by global option ``organize.showPresence`,
|
same loops site, controlled by global option ``organize.showPresence`,
|
||||||
using new LoopsSessionCredentialsPlugin;
|
using new LoopsSessionCredentialsPlugin;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2009 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
|
||||||
|
@ -352,9 +352,8 @@ class ConceptView(BaseView):
|
||||||
|
|
||||||
def getActions(self, category='object', page=None, target=None):
|
def getActions(self, category='object', page=None, target=None):
|
||||||
acts = []
|
acts = []
|
||||||
t = IType(self.context)
|
optKey = 'action.' + category
|
||||||
actInfo = t.optionsDict.get('action.' + category, '')
|
actNames = (self.options(optKey) or []) + (self.typeOptions(optKey) or [])
|
||||||
actNames = [n.strip() for n in actInfo.split(',')]
|
|
||||||
if actNames:
|
if actNames:
|
||||||
acts = list(actions.get(category, actNames,
|
acts = list(actions.get(category, actNames,
|
||||||
view=self, page=page, target=target))
|
view=self, page=page, target=target))
|
||||||
|
@ -508,3 +507,11 @@ class ConceptConfigureView(ConceptView):
|
||||||
yield terms.getTerm(pred)
|
yield terms.getTerm(pred)
|
||||||
|
|
||||||
|
|
||||||
|
# query views
|
||||||
|
|
||||||
|
class ListChildren(ConceptView):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return concept_macros.macros['list_children']
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,8 @@
|
||||||
ondblclick python: item.openEditWindow('configure.html')"
|
ondblclick python: item.openEditWindow('configure.html')"
|
||||||
tal:define="children python: list(item.children())"
|
tal:define="children python: list(item.children())"
|
||||||
tal:condition="children">
|
tal:condition="children">
|
||||||
<h2 i18n:translate="">Children</h2>
|
<h2 i18n:translate=""
|
||||||
|
tal:condition="show_headline|python:True">Children</h2>
|
||||||
<table class="listing">
|
<table class="listing">
|
||||||
<tr>
|
<tr>
|
||||||
<th i18n:translate="">Title</th>
|
<th i18n:translate="">Title</th>
|
||||||
|
@ -218,6 +219,14 @@
|
||||||
</metal:listing>
|
</metal:listing>
|
||||||
|
|
||||||
|
|
||||||
|
<metal:listing define-macro="list_children">
|
||||||
|
<div tal:define="show_headline nothing">
|
||||||
|
<metal:fields use-macro="item/template/macros/concepttitle" /><br />
|
||||||
|
<metal:fields use-macro="item/template/macros/conceptchildren" />
|
||||||
|
</div>
|
||||||
|
</metal:listing>
|
||||||
|
|
||||||
|
|
||||||
<!-- portlets -->
|
<!-- portlets -->
|
||||||
|
|
||||||
<metal:actions define-macro="parents">
|
<metal:actions define-macro="parents">
|
||||||
|
|
|
@ -531,6 +531,16 @@
|
||||||
|
|
||||||
</pages>
|
</pages>
|
||||||
|
|
||||||
|
<!-- query views -->
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="list_children.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.browser.concept.ListChildren"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
<!-- dialogs/forms (end-user views) -->
|
<!-- dialogs/forms (end-user views) -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
|
|
@ -150,8 +150,13 @@ class NodeView(BaseView):
|
||||||
def usersPresent(self):
|
def usersPresent(self):
|
||||||
presence = component.getUtility(IPresence)
|
presence = component.getUtility(IPresence)
|
||||||
presence.update(self.request.principal.id)
|
presence.update(self.request.principal.id)
|
||||||
data = presence.getPresentUsers()
|
data = presence.getPresentUsers(self.context)
|
||||||
return data
|
for u in data:
|
||||||
|
if IConcept.providedBy(u):
|
||||||
|
url = self.getUrlForTarget(u)
|
||||||
|
else:
|
||||||
|
url = None
|
||||||
|
yield dict(title=u.title, url=url)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def view(self):
|
def view(self):
|
||||||
|
|
|
@ -238,7 +238,10 @@
|
||||||
|
|
||||||
<metal:actions define-macro="presence">
|
<metal:actions define-macro="presence">
|
||||||
<tal:user repeat="user view/usersPresent">
|
<tal:user repeat="user view/usersPresent">
|
||||||
<div tal:content="user" />
|
<div>
|
||||||
|
<a tal:omit-tag="not:user/url"
|
||||||
|
tal:attributes="href user/url"
|
||||||
|
tal:content="user/title" /></div>
|
||||||
</tal:user>
|
</tal:user>
|
||||||
</metal:actions>
|
</metal:actions>
|
||||||
|
|
||||||
|
|
|
@ -600,7 +600,8 @@ class IConceptRelation(IDyadicRelation):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
predicate = Attribute("A concept of type 'predicate' that defines the "
|
predicate = Attribute("A concept of type 'predicate' that defines the "
|
||||||
"type of the relation-")
|
"type of the relation.")
|
||||||
|
relevance = Attribute("A float between 0 and 1.")
|
||||||
|
|
||||||
|
|
||||||
# interfaces for catalog indexes
|
# interfaces for catalog indexes
|
||||||
|
|
Binary file not shown.
|
@ -3,7 +3,7 @@ msgstr ""
|
||||||
|
|
||||||
"Project-Id-Version: $Id$\n"
|
"Project-Id-Version: $Id$\n"
|
||||||
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
|
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
|
||||||
"PO-Revision-Date: 2009-09-17 12:00 CET\n"
|
"PO-Revision-Date: 2009-10-11 12:00 CET\n"
|
||||||
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
|
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
|
||||||
"Language-Team: loops developers <helmutm@cy55.de>\n"
|
"Language-Team: loops developers <helmutm@cy55.de>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
|
@ -98,6 +98,18 @@ msgstr "Glossareintrag anlegen..."
|
||||||
msgid "Create Glossary Item"
|
msgid "Create Glossary Item"
|
||||||
msgstr "Glossareintrag anlegen"
|
msgstr "Glossareintrag anlegen"
|
||||||
|
|
||||||
|
msgid "Create Person..."
|
||||||
|
msgstr "Person anlegen..."
|
||||||
|
|
||||||
|
msgid "Create a new person."
|
||||||
|
msgstr "Eine neue Person anlegen"
|
||||||
|
|
||||||
|
msgid "Edit Person..."
|
||||||
|
msgstr "Person bearbeiten..."
|
||||||
|
|
||||||
|
msgid "Modify person."
|
||||||
|
msgstr "Person bearbeiten"
|
||||||
|
|
||||||
msgid "Create Resource, Type = "
|
msgid "Create Resource, Type = "
|
||||||
msgstr "Ressource anlegen, Typ = "
|
msgstr "Ressource anlegen, Typ = "
|
||||||
|
|
||||||
|
|
|
@ -364,6 +364,7 @@ OK, the action is not provided automatically any more by the TaskView
|
||||||
but has to be entered as a type option.
|
but has to be entered as a type option.
|
||||||
|
|
||||||
>>> adapted(task).options = ['action.portlet:editTask']
|
>>> adapted(task).options = ['action.portlet:editTask']
|
||||||
|
>>> view = TaskView(task01, TestRequest())
|
||||||
>>> list(view.getActions('portlet'))
|
>>> list(view.getActions('portlet'))
|
||||||
[<loops.browser.action.DialogAction ...>]
|
[<loops.browser.action.DialogAction ...>]
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,13 @@
|
||||||
class="loops.organize.browser.party.SendEmailForm"
|
class="loops.organize.browser.party.SendEmailForm"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="send_email"
|
||||||
|
for="loops.browser.node.NodeView
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
factory="loops.organize.browser.party.SendEmail"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
<!-- authentication -->
|
<!-- authentication -->
|
||||||
|
|
||||||
<browser:addform
|
<browser:addform
|
||||||
|
|
|
@ -23,16 +23,20 @@ loops.organize.party.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from email.MIMEText import MIMEText
|
||||||
from zope import interface, component
|
from zope import interface, component
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.dublincore.interfaces import IZopeDublinCore
|
from zope.dublincore.interfaces import IZopeDublinCore
|
||||||
|
from zope.sendmail.interfaces import IMailDelivery
|
||||||
|
|
||||||
from cybertools.ajax import innerHtml
|
from cybertools.ajax import innerHtml
|
||||||
from cybertools.browser.action import actions
|
from cybertools.browser.action import actions
|
||||||
|
from cybertools.browser.form import FormController
|
||||||
from loops.browser.action import DialogAction
|
from loops.browser.action import DialogAction
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
from loops.common import adapted
|
from loops.common import adapted
|
||||||
|
from loops.organize.party import getPersonForUser
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
|
||||||
organize_macros = ViewPageTemplateFile('view_macros.pt')
|
organize_macros = ViewPageTemplateFile('view_macros.pt')
|
||||||
|
@ -123,3 +127,22 @@ class SendEmailForm(NodeView):
|
||||||
site = zdc.title or menu.title
|
site = zdc.title or menu.title
|
||||||
return _(u"loops Notification from '$site'",
|
return _(u"loops Notification from '$site'",
|
||||||
mapping=dict(site=site))
|
mapping=dict(site=site))
|
||||||
|
|
||||||
|
|
||||||
|
class SendEmail(FormController):
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
form = self.request.form
|
||||||
|
subject = form.get('subject') or u''
|
||||||
|
message = form.get('mailbody') or u''
|
||||||
|
recipients = form.get('recipients') or []
|
||||||
|
recipients += (form.get('addrRecipients') or u'').split('\n')
|
||||||
|
person = getPersonForUser(self.context, self.request)
|
||||||
|
sender = person and adapted(person).email or 'loops@unknown.com'
|
||||||
|
msg = MIMEText(message, 'plain', 'utf-8')
|
||||||
|
msg['Subject'] = subject
|
||||||
|
msg['From'] = sender
|
||||||
|
msg['To'] = ', '.join(r.strip() for r in recipients if r.strip())
|
||||||
|
mailhost = component.getUtility(IMailDelivery, 'Mail')
|
||||||
|
mailhost.send(sender, recipients, msg.as_string())
|
||||||
|
return True
|
||||||
|
|
|
@ -55,9 +55,9 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:block define-macro="send_email">
|
<metal:block define-macro="send_email">
|
||||||
<form method="post" id="sendEmail_form" class="dialog"
|
<form method="post" id="sendEmail_form" name="sendEmail" class="dialog"
|
||||||
dojoType="dijit.form.Form">
|
dojoType="dijit.form.Form">
|
||||||
<input type="hidden" name="form.action" value="create_workitem" />
|
<input type="hidden" name="form.action" value="send_email" />
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<span i18n:translate="">Send Link by Email</span> -
|
<span i18n:translate="">Send Link by Email</span> -
|
||||||
<span tal:content="view/target/title"></span></div>
|
<span tal:content="view/target/title"></span></div>
|
||||||
|
@ -78,11 +78,16 @@
|
||||||
<div>
|
<div>
|
||||||
<label i18n:translate="">Recipients</label>
|
<label i18n:translate="">Recipients</label>
|
||||||
<div tal:repeat="member view/members">
|
<div tal:repeat="member view/members">
|
||||||
<input type="checkbox" checked name="recipients:list"
|
<input type="checkbox" name="recipients:list"
|
||||||
tal:attributes="value member/email" />
|
tal:attributes="value member/email" />
|
||||||
<span tal:content="member/title">Johnny</span>
|
<span tal:content="member/title">Johnny</span>
|
||||||
(<span tal:content="member/email">Johnny</span>)
|
(<span tal:content="member/email">Johnny</span>)
|
||||||
</div>
|
</div>
|
||||||
|
<div style="color: grey">
|
||||||
|
<input type="checkbox"
|
||||||
|
onClick="p = document.forms.sendEmail['recipients:list'];
|
||||||
|
for (i in p) p[i].checked=this.checked;" />
|
||||||
|
<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>
|
<div>
|
||||||
|
|
|
@ -30,6 +30,7 @@ from zope.cachedescriptors.property import Lazy
|
||||||
from cybertools.meta.interfaces import IOptions
|
from cybertools.meta.interfaces import IOptions
|
||||||
from cybertools.util.date import getTimeStamp
|
from cybertools.util.date import getTimeStamp
|
||||||
from loops.organize.interfaces import IPresence
|
from loops.organize.interfaces import IPresence
|
||||||
|
from loops.organize.party import getPersonForUser
|
||||||
from loops.organize import util
|
from loops.organize import util
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,10 +58,12 @@ class Presence(object):
|
||||||
if id in self.presentUsers:
|
if id in self.presentUsers:
|
||||||
del self.presentUsers[id]
|
del self.presentUsers[id]
|
||||||
|
|
||||||
def getPresentUsers(self):
|
def getPresentUsers(self, context=None):
|
||||||
ret = []
|
ret = []
|
||||||
for id, timeStamp in self.presentUsers.iteritems():
|
for id, timeStamp in self.presentUsers.iteritems():
|
||||||
ret.append(util.getPrincipalForUserId(id).title)
|
principal = util.getPrincipalForUserId(id)
|
||||||
|
person = getPersonForUser(context, principal=principal)
|
||||||
|
ret.append(person or principal)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def removePresentUser(self, principalId):
|
def removePresentUser(self, principalId):
|
||||||
|
|
Loading…
Add table
Reference in a new issue