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:
helmutm 2009-10-12 06:05:14 +00:00
parent 21036dae20
commit a6dbafcce8
14 changed files with 104 additions and 15 deletions

View file

@ -8,6 +8,9 @@ $Id$
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
same loops site, controlled by global option ``organize.showPresence`,
using new LoopsSessionCredentialsPlugin;

View file

@ -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
# 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):
acts = []
t = IType(self.context)
actInfo = t.optionsDict.get('action.' + category, '')
actNames = [n.strip() for n in actInfo.split(',')]
optKey = 'action.' + category
actNames = (self.options(optKey) or []) + (self.typeOptions(optKey) or [])
if actNames:
acts = list(actions.get(category, actNames,
view=self, page=page, target=target))
@ -508,3 +507,11 @@ class ConceptConfigureView(ConceptView):
yield terms.getTerm(pred)
# query views
class ListChildren(ConceptView):
@Lazy
def macro(self):
return concept_macros.macros['list_children']

View file

@ -93,7 +93,8 @@
ondblclick python: item.openEditWindow('configure.html')"
tal:define="children python: list(item.children())"
tal:condition="children">
<h2 i18n:translate="">Children</h2>
<h2 i18n:translate=""
tal:condition="show_headline|python:True">Children</h2>
<table class="listing">
<tr>
<th i18n:translate="">Title</th>
@ -218,6 +219,14 @@
</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 -->
<metal:actions define-macro="parents">

View file

@ -531,6 +531,16 @@
</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) -->
<page

View file

@ -150,8 +150,13 @@ class NodeView(BaseView):
def usersPresent(self):
presence = component.getUtility(IPresence)
presence.update(self.request.principal.id)
data = presence.getPresentUsers()
return data
data = presence.getPresentUsers(self.context)
for u in data:
if IConcept.providedBy(u):
url = self.getUrlForTarget(u)
else:
url = None
yield dict(title=u.title, url=url)
@Lazy
def view(self):

View file

@ -238,7 +238,10 @@
<metal:actions define-macro="presence">
<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>
</metal:actions>

View file

@ -600,7 +600,8 @@ class IConceptRelation(IDyadicRelation):
"""
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

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\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"
"Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n"
@ -98,6 +98,18 @@ msgstr "Glossareintrag anlegen..."
msgid "Create Glossary Item"
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 = "
msgstr "Ressource anlegen, Typ = "

View file

@ -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.
>>> adapted(task).options = ['action.portlet:editTask']
>>> view = TaskView(task01, TestRequest())
>>> list(view.getActions('portlet'))
[<loops.browser.action.DialogAction ...>]

View file

@ -62,6 +62,13 @@
class="loops.organize.browser.party.SendEmailForm"
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 -->
<browser:addform

View file

@ -23,16 +23,20 @@ loops.organize.party.
$Id$
"""
from email.MIMEText import MIMEText
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from zope.dublincore.interfaces import IZopeDublinCore
from zope.sendmail.interfaces import IMailDelivery
from cybertools.ajax import innerHtml
from cybertools.browser.action import actions
from cybertools.browser.form import FormController
from loops.browser.action import DialogAction
from loops.browser.node import NodeView
from loops.common import adapted
from loops.organize.party import getPersonForUser
from loops.util import _
organize_macros = ViewPageTemplateFile('view_macros.pt')
@ -123,3 +127,22 @@ class SendEmailForm(NodeView):
site = zdc.title or menu.title
return _(u"loops Notification from '$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

View file

@ -55,9 +55,9 @@
<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">
<input type="hidden" name="form.action" value="create_workitem" />
<input type="hidden" name="form.action" value="send_email" />
<div class="heading">
<span i18n:translate="">Send Link by Email</span> -
<span tal:content="view/target/title"></span></div>
@ -78,11 +78,16 @@
<div>
<label i18n:translate="">Recipients</label>
<div tal:repeat="member view/members">
<input type="checkbox" checked name="recipients:list"
<input type="checkbox" name="recipients:list"
tal:attributes="value member/email" />
<span tal:content="member/title">Johnny</span>
(<span tal:content="member/email">Johnny</span>)
</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>
<label i18n:translate="" for="addrecipients">Additional recipients</label>
<div>

View file

@ -30,6 +30,7 @@ from zope.cachedescriptors.property import Lazy
from cybertools.meta.interfaces import IOptions
from cybertools.util.date import getTimeStamp
from loops.organize.interfaces import IPresence
from loops.organize.party import getPersonForUser
from loops.organize import util
@ -57,10 +58,12 @@ class Presence(object):
if id in self.presentUsers:
del self.presentUsers[id]
def getPresentUsers(self):
def getPresentUsers(self, context=None):
ret = []
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
def removePresentUser(self, principalId):