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 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;

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 # 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']

View file

@ -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">

View file

@ -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

View file

@ -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):

View file

@ -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>

View file

@ -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.

View file

@ -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 = "

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. 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 ...>]

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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):