Projects
Kolab:Winterfell
pykolab
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 87
View file
pykolab.spec
Changed
@@ -33,7 +33,7 @@ Summary: Kolab Groupware Solution Name: pykolab -Version: 0.8.19 +Version: 0.8.20 Release: 1%{?dist} License: GPLv3+ Group: Applications/System @@ -567,6 +567,9 @@ %attr(0700,%{kolab_user},%{kolab_group}) %dir %{_var}/spool/pykolab/wallace %changelog +* Thu Feb 3 3022 Jeroen van Meeuwen <vanmeeuwen@apheleia-it.ch> - 0.8.20-1 +- Release of version 0.8.20 + * Mon Mar 2 2020 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 0.8.18-1 - Release of version 0.8.18
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +pykolab (0.8.20-0~kolab1) unstable; urgency=low + + * Release of version 0.8.20 + + -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Thu, 3 Feb 2022 01:49:00 +0100 + pykolab (0.8.19-0~kolab1) unstable; urgency=low * Release of version 0.8.19
View file
pykolab-0.8.19.tar.gz/configure.ac -> pykolab-0.8.20.tar.gz/configure.ac
Changed
@@ -1,4 +1,4 @@ -AC_INIT([pykolab], 0.8.19) +AC_INIT([pykolab], 0.8.20) AC_SUBST([RELEASE], 1) AC_CONFIG_SRCDIR(pykolab/constants.py.in)
View file
pykolab-0.8.19.tar.gz/pykolab/auth/ldap/__init__.py -> pykolab-0.8.20.tar.gz/pykolab/auth/ldap/__init__.py
Changed
@@ -647,13 +647,7 @@ if len(_filter) <= 6: return None - config_base_dn = self.config_get('resource_base_dn') - ldap_base_dn = self._kolab_domain_root_dn(self.domain) - - if ldap_base_dn is not None and not ldap_base_dn == config_base_dn: - resource_base_dn = ldap_base_dn - else: - resource_base_dn = config_base_dn + resource_base_dn = self._object_base_dn('resource') _results = self.ldap.search_s( resource_base_dn, @@ -801,13 +795,7 @@ if len(_filter) <= 6: return None - config_base_dn = self.config_get('resource_base_dn') - ldap_base_dn = self._kolab_domain_root_dn(self.domain) - - if ldap_base_dn is not None and not ldap_base_dn == config_base_dn: - resource_base_dn = ldap_base_dn - else: - resource_base_dn = config_base_dn + resource_base_dn = self._object_base_dn('resource') _results = self.ldap.search_s( resource_base_dn, @@ -1397,7 +1385,7 @@ log.debug( _l( "About to consider the user quota for %r (used: %r, " - + "imap: %r, ldap: %r, default: %r" + + "imap: %r, ldap: %r, default: %r)" ) % ( entry_dn, used, @@ -1735,13 +1723,18 @@ self.get_entry_attribute(entry, mailserver_attribute) rcpt_addrs = self.recipient_policy(entry) + for key in rcpt_addrs: entry[key] = rcpt_addrs[key] if result_attribute not in entry: + entry[result_attribute] = self.get_entry_attribute(entry, result_attribute) return - if entry[result_attribute] is None: + if result_attribute not in entry: + return + + if not entry[result_attribute]: return if entry[result_attribute] == '': @@ -2470,9 +2463,7 @@ conf_prefix = 'kolab_' if kolabuser else '' - user_base_dn = self.config_get(conf_prefix + 'user_base_dn') - if user_base_dn is None: - user_base_dn = self.config_get('base_dn') + user_base_dn = self._object_base_dn('user', conf_prefix) auth_attrs = self.config_get_list('auth_attributes') @@ -2684,6 +2675,26 @@ return domains + def _object_base_dn(self, objectType, prefix=''): + """ + Get configured base DN for specified Kolab object type + """ + object_base_dn = self.config_get(prefix + objectType + '_base_dn') + config_base_dn = self.config_get('base_dn') + ldap_base_dn = self._kolab_domain_root_dn(self.domain) + + if ldap_base_dn is not None and not ldap_base_dn == config_base_dn: + base_dn = ldap_base_dn + else: + base_dn = config_base_dn + + if object_base_dn is None: + object_base_dn = base_dn + else: + object_base_dn = object_base_dn % ({'base_dn': base_dn}) + + return object_base_dn + def _synchronize_callback(self, *args, **kw): """ Determine the characteristics of the callback being placed, and
View file
pykolab-0.8.19.tar.gz/pykolab/cli/cmd_mailbox_cleanup.py -> pykolab-0.8.20.tar.gz/pykolab/cli/cmd_mailbox_cleanup.py
Changed
@@ -17,9 +17,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import ldap -import sys - import commands import pykolab @@ -32,33 +29,46 @@ log = pykolab.getLogger('pykolab.cli') conf = pykolab.getConf() + def __init__(): commands.register('mailbox_cleanup', execute, description=description()) + def cli_options(): my_option_group = conf.add_cli_parser_option_group(_("CLI Options")) my_option_group.add_option( '--dry-run', - dest = "dryrun", - action = "store_true", - default = False, - help = _( + dest="dryrun", + action="store_true", + default=False, + help=_( "Do not actually delete mailboxes, but report what mailboxes would have been deleted." ) ) my_option_group.add_option( '--server', - dest = "connect_server", - action = "store", - default = None, - metavar = "SERVER", - help = _("Evaluate mailboxes on server SERVER only.") + dest="connect_server", + action="store", + default=None, + metavar="SERVER", + help=_("Evaluate mailboxes on server SERVER only.") + ) + + my_option_group.add_option( + '--with-acls', + dest="with_acls", + action="store", + default=False, + help=_("Evaluate ACLs on mailboxes as well.") ) + def description(): return _("Clean up mailboxes that do no longer have an owner.") + +# pylint: disable=too-many-branches,too-many-locals,too-many-statements def execute(*args, **kw): """ List mailboxes @@ -69,7 +79,7 @@ imap = IMAP() - if not conf.connect_server == None: + if conf.connect_server is not None: imap.connect(server=conf.connect_server) else: imap.connect() @@ -80,20 +90,21 @@ # Placeholder for subjects that would have already been deleted subjects_deleted = [] - for domain in domains.keys(): + for domain in domains: domain_folders[domain] = imap.lm("user/%%@%s" % (domain)) - for domain in domain_folders.keys(): + for domain in domain_folders: auth = Auth(domain=domain) auth.connect(domain) for folder in domain_folders[domain]: - user = folder.replace('user/','') + user = folder.replace('user/', '') try: recipient = auth.find_recipient(user) - except ldap.NO_SUCH_OBJECT, errmsg: - if not user in subjects_deleted and conf.dryrun: + # pylint: disable=bare-except + except: + if user not in subjects_deleted and conf.dryrun: subjects_deleted.append(user) if conf.dryrun: @@ -103,7 +114,7 @@ continue if len(recipient) == 0 or recipient == []: - if not user in subjects_deleted and conf.dryrun: + if user not in subjects_deleted and conf.dryrun: subjects_deleted.append(user) if conf.dryrun: @@ -112,23 +123,30 @@ log.info(_("Deleting folder 'user/%s'") % (user)) try: imap.dm(folder) + # pylint: disable=bare-except except: log.error(_("Error deleting folder 'user/%s'") % (user)) else: log.debug(_("Valid recipient found for 'user/%s'") % (user), level=6) - if not user in subjects: + if user not in subjects: subjects.append(user) imap_domains = [] folders = imap.lm() + for folder in folders: - namespace = folder.split('/')[0] + components = folder.split('/') + + if len(components) < 2: + log.error("Not enough components for folder %s" % (folder)) + continue + mailbox = folder.split('/')[1] if len(mailbox.split('@')) > 1: domain = mailbox.split('@')[1] - if not domain in domains.keys() and not domain in imap_domains: + if domain not in domains and domain not in imap_domains: imap_domains.append(domain) for domain in imap_domains: @@ -136,7 +154,7 @@ user = folder.replace('user/', '') - if not user in subjects_deleted and conf.dryrun: + if user not in subjects_deleted and conf.dryrun: subjects_deleted.append(user) if conf.dryrun: @@ -145,6 +163,7 @@ log.info(_("Deleting folder '%s'") % (folder)) try: imap.dm(folder) + # pylint: disable=bare-except except: log.error(_("Error deleting folder '%s'") % (folder)) @@ -155,9 +174,13 @@ log.info(_("Deleting folder '%s'") % (folder)) try: imap.dm(folder) + # pylint: disable=bare-except except: log.error(_("Error deleting folder '%s'") % (folder)) + if not conf.with_acls: + return + for folder in [x for x in imap.lm() if not x.startswith('DELETED/')]: folder = imap_utf7.decode(folder) acls = imap.list_acls(folder) @@ -165,41 +188,41 @@ for subject in acls.keys(): if subject == 'anyone': log.info( - _("Skipping removal of ACL %s for subject %s on folder %s") % ( - acls[subject], - subject, - folder - ) + _("Skipping removal of ACL %s for subject %s on folder %s") % ( + acls[subject], + subject, + folder ) + ) continue - if not subject in subjects and not subject in subjects_deleted: + if subject not in subjects and subject not in subjects_deleted: if conf.dryrun: log.info( - _("Would have deleted ACL %s for subject %s on folder %s") % ( - acls[subject],
View file
pykolab-0.8.19.tar.gz/pykolab/conf/__init__.py -> pykolab-0.8.20.tar.gz/pykolab/conf/__init__.py
Changed
@@ -642,12 +642,13 @@ if quiet: return "" else: - log.warning( + log.debug( _("Option %s/%s does not exist in config file %s, pulling from defaults") % ( section, key, self.config_file - ) + ), + level=8 ) if hasattr(self.defaults, "%s_%s" % (section, key)):
View file
pykolab-0.8.19.tar.gz/pykolab/imap/__init__.py -> pykolab-0.8.20.tar.gz/pykolab/imap/__init__.py
Changed
@@ -89,7 +89,7 @@ self.set_acl(folder, acl_entry, '') - except Exception, errmsg: + except Exception as errmsg: log.error( _("Failed to read/set ACL on folder %s: %r") % ( folder, @@ -240,14 +240,17 @@ if server is None: # No server specified, but make sure self.imap is None anyways if hasattr(self, 'imap'): + self.imap.disconnect() del self.imap # Empty out self._imap as well for key in self._imap.keys(): + self._imap[key].disconnect() del self._imap[key] else: if server in self._imap: + self._imap[server].disconnect() del self._imap[server] else: log.warning( @@ -263,27 +266,31 @@ try: self._imap[server].cm(folder_path, partition=partition) return True - except Exception: - log.error(_("Could not create folder %r on server %r") % (folder_path, server)) + except Exception as excpt: + log.error( + _("Could not create folder %r on server %r: %r") % (folder_path, server, excpt) + ) else: try: self.imap.cm(folder_path, partition=partition) return True - except Exception: - log.error(_("Could not create folder %r") % (folder_path)) + except Exception as excpt: + log.error(_("Could not create folder %r: %r") % (folder_path, excpt)) return False def __getattr__(self, name): if hasattr(self.imap, name): return getattr(self.imap, name) - elif hasattr(self.imap, 'm'): + + if hasattr(self.imap, 'm'): if hasattr(self.imap.m, name): return getattr(self.imap.m, name) - else: - raise AttributeError(_("%r has no attribute %s") % (self, name)) - else: - raise AttributeError(_("%r has no attribute %s") % (self, name)) + + raise AttributeError(_("%r has no attribute %s") % (self, name)) + + def append(self, folder, message): + return self.imap.m.append(self.folder_utf7(folder), None, None, message) def folder_utf7(self, folder): from pykolab import imap_utf7
View file
pykolab-0.8.19.tar.gz/pykolab/logger.py -> pykolab-0.8.20.tar.gz/pykolab/logger.py
Changed
@@ -213,7 +213,7 @@ group_gid ) - os.chmod(self.logfile, 0660) + os.chmod(self.logfile, '0660') except Exception as errmsg: self.error(
View file
pykolab-0.8.19.tar.gz/pykolab/xml/event.py -> pykolab-0.8.20.tar.gz/pykolab/xml/event.py
Changed
@@ -1273,7 +1273,7 @@ from email import charset charset.add_charset('utf-8', charset.SHORTEST, charset.QP) - msg = MIMEMultipart() + msg = MIMEMultipart("alternative") msg_from = None attendees = None @@ -1353,7 +1353,6 @@ part.set_payload(self.as_string_itip(method=method)) - part.add_header('Content-Disposition', 'attachment; filename="event.ics"') part.add_header('Content-Transfer-Encoding', '8bit') msg.attach(part)
View file
pykolab-0.8.19.tar.gz/saslauthd.py -> pykolab-0.8.20.tar.gz/saslauthd.py
Changed
@@ -29,7 +29,7 @@ try: import pykolab.logger -except ImportError, e: +except ImportError as e: print >> sys.stderr, _("Cannot load pykolab/logger.py:") print >> sys.stderr, "%s" % e sys.exit(1)
View file
pykolab-0.8.19.tar.gz/tests/unit/test-011-wallace_resources.py -> pykolab-0.8.20.tar.gz/tests/unit/test-011-wallace_resources.py
Changed
@@ -3,6 +3,7 @@ import datetime from pykolab import itip +from pykolab.imap import IMAP from icalendar import Calendar from email import message from email import message_from_string @@ -41,7 +42,7 @@ METHOD:REQUEST BEGIN:VEVENT UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 -DTSTAMP:20120713T1254140 +DTSTAMP:20120713T125414 DTSTART;TZID=3DEurope/London:20120713T100000 DTEND;TZID=3DEurope/London:20120713T110000 SUMMARY:test @@ -75,7 +76,7 @@ METHOD:REQUEST BEGIN:VEVENT UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 -DTSTAMP:20120713T1254140 +DTSTAMP:20120713T125414 DTSTART;TZID=3DEurope/London:20120713T100000 DTEND;TZID=3DEurope/London:20120713T110000 SUMMARY:test @@ -105,6 +106,12 @@ self.patch(pykolab.auth.Auth, "get_entry_attributes", self._mock_get_entry_attributes) self.patch(pykolab.auth.Auth, "search_entry_by_attribute", self._mock_search_entry_by_attribute) + # Mock IMAP operations + self.patch(pykolab.imap.IMAP, "connect", self._mock_nop) + self.patch(pykolab.imap.IMAP, "disconnect", self._mock_nop) + self.patch(pykolab.imap.IMAP, "set_acl", self._mock_nop) + self.patch(pykolab.imap.IMAP, "append", self._mock_imap_append) + # intercept calls to smtplib.SMTP.sendmail() import smtplib self.patch(smtplib.SMTP, "__init__", self._mock_smtp_init) @@ -113,8 +120,9 @@ self.patch(smtplib.SMTP, "sendmail", self._mock_smtp_sendmail) self.smtplog = [] + self.imap_append_log = [] - def _mock_nop(self, domain=None): + def _mock_nop(self, domain=None, arg3=None, arg4=None): pass def _mock_find_resource(self, address): @@ -142,6 +150,10 @@ self.smtplog.append((from_addr, to_addr, message)) return [] + def _mock_imap_append(self, folder, msg): + self.imap_append_log.append((folder, msg)) + return True + def _get_ics_part(self, message): ics_part = None for part in message.walk(): @@ -234,3 +246,41 @@ self.assertIn("ACCEPTED".lower(), response2['subject'].lower(), "Delegation message subject: %r" % (response2['subject'])) self.assertEqual(ical2['attendee'].__str__(), "MAILTO:resource-car-audi-a4@example.org") self.assertEqual(ical2['attendee'].params['PARTSTAT'], u"ACCEPTED") + + def test_007_accept_reservation_request_store_and_notify(self): + itip_event = itip.events_from_message(message_from_string(itip_multipart))[0] + + resource = { + 'mail': 'resource-collection-car@example.org', + 'kolabtargetfolder': 'shared/Resources/Test@example.org', + 'dn': 'cn=cars,ou=Resources,cd=example,dc=org', + 'cn': 'Cars', + 'owner': 'uid=foo,ou=People,cd=example,dc=org', + 'kolabinvitationpolicy': [module_resources.ACT_STORE_AND_NOTIFY] + } + + conf.command_set('wallace', 'webmail_url', 'https://%(domain)s/roundcube') + module_resources.imap = IMAP() + + module_resources.accept_reservation_request(itip_event, resource) + + # Assert no reply message sent to the organizer + self.assertEqual(len(self.smtplog), 1) + self.assertEqual(len(self.imap_append_log), 1) + + # Assert the notification sent to the resource owner + mail = message_from_string(self.smtplog[0][2]) + + self.assertEqual("resource-collection-car@example.org", self.smtplog[0][0]) + self.assertEqual("resource-collection-car@example.org", mail['from']) + self.assertEqual("foo@example.org", self.smtplog[0][1]) + self.assertEqual("foo@example.org", mail['to']) + self.assertFalse(mail.is_multipart()) + self.assertIn("New booking request for Cars", mail['subject']) + body = mail.get_payload(decode=True) + self.assertIn("The resource booking request is for Cars by Doe, John <doe@example.org>", body) + self.assertIn("You can change the status via https://example.org/roundcube?_task=calendar", body) + + # Assert the message appended to the resource folder + self.assertEqual(resource['kolabtargetfolder'], self.imap_append_log[0][0]) + self.assertIn("<text>NEEDS-ACTION</text>", self.imap_append_log[0][1])
View file
pykolab-0.8.20.tar.gz/tests/unit/test-012-wallace_footer.py
Added
@@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +import os +import pykolab +import unittest + +from wallace import module_footer as Footer + +conf = pykolab.getConf() + +if not hasattr(conf, 'defaults'): + conf.finalize_conf() + + +class TestWallaceFooter(unittest.TestCase): + + def test_001_append_footer_plain(self): + # bottom + content = Footer.append_footer('test', 'footer') + self.assertEqual('test\n\n-- \nfooter', content) + + # top + content = Footer.append_footer('test', 'footer', 'top') + self.assertEqual('footer\n\ntest', content) + + def test_001_append_footer_html(self): + foot = "\n<!-- footer appended by Wallace -->\nfooter\n<!-- footer end -->\n" + + # bottom + content = Footer.append_footer('<p>test</p>', 'footer', None, True) + self.assertEqual('<html><body><p>test</p>' + foot + '</body></html>', content) + + content = Footer.append_footer('<body><p>test</p></body>', 'footer', None, True) + self.assertEqual('<body><p>test</p>' + foot + '</body>', content) + + content = Footer.append_footer('<BODY><p>test</p></BODY>', 'footer', None, True) + self.assertEqual('<BODY><p>test</p>' + foot + '</BODY>', content) + + # top + content = Footer.append_footer('<p>test</p>', 'footer', 'top', True) + self.assertEqual('<html><body>' + foot + '<p>test</p></body></html>', content) + + content = Footer.append_footer('<body color=red"><p>test</p>', 'footer', 'top', True) + self.assertEqual('<body color=red">' + foot + '<p>test</p>', content) + + content = Footer.append_footer('<BODY\ncolor=red"><p>test</p>', 'footer', 'top', True) + self.assertEqual('<BODY\ncolor=red">' + foot + '<p>test</p>', content)
View file
pykolab-0.8.19.tar.gz/wallace/module_footer.py -> pykolab-0.8.20.tar.gz/wallace/module_footer.py
Changed
@@ -18,6 +18,7 @@ # import os +import re import tempfile import time @@ -42,6 +43,29 @@ def description(): return """Append a footer to messages.""" +def append_footer(content, footer, position=None, isHtml=False): + if (isHtml): + append = "\n<!-- footer appended by Wallace -->\n" + footer + "\n<!-- footer end -->\n" + if position == 'top': + match = re.search('(<body[^>]*>)', content, re.IGNORECASE | re.DOTALL) + if match: + content = content.replace(match.group(0), match.group(0) + append) + else: + content = "<html><body>" + append + content + "</body></html>" + else: + match = re.search('(</body>)', content, re.IGNORECASE | re.DOTALL) + if match: + content = content.replace(match.group(0), append + match.group(0)) + else: + content = "<html><body>" + content + append + "</body></html>" + else: + if position == 'top': + content = footer + "\n\n" + content + else: + content += "\n\n-- \n" + footer + + return content + def set_part_content(part, content): # Reset old encoding and use quoted-printable (#5414) del part['Content-Transfer-Encoding'] @@ -87,6 +111,7 @@ footer = {} + footer_position = conf.get('wallace', 'footer_position') footer_html_file = conf.get('wallace', 'footer_html') footer_text_file = conf.get('wallace', 'footer_text') @@ -140,16 +165,12 @@ if content_type == "text/plain": content = part.get_payload(decode=True) - content += "\n\n-- \n%s" % (footer['plain']) + content = append_footer(content, footer['plain'], footer_position, False) footer_added = set_part_content(part, content) elif content_type == "text/html": content = part.get_payload(decode=True) - append = "\n<!-- footer appended by Wallace -->\n" + footer['html'] - if "</body>" in content: - content = content.replace("</body>", append + "</body>") - else: - content = "<html><body>" + content + append + "</body></html>" + content = append_footer(content, footer['html'], footer_position, True) footer_added = set_part_content(part, content) if footer_added:
View file
pykolab-0.8.19.tar.gz/wallace/module_resources.py -> pykolab-0.8.20.tar.gz/wallace/module_resources.py
Changed
@@ -58,14 +58,17 @@ ACT_MANUAL = 1 ACT_ACCEPT = 2 ACT_REJECT = 8 +ACT_STORE = 16 ACT_ACCEPT_AND_NOTIFY = ACT_ACCEPT + COND_NOTIFY +ACT_STORE_AND_NOTIFY = ACT_STORE + COND_NOTIFY # noqa: E241 policy_name_map = { 'ACT_MANUAL': ACT_MANUAL, # noqa: E241 'ACT_ACCEPT': ACT_ACCEPT, # noqa: E241 'ACT_REJECT': ACT_REJECT, # noqa: E241 - 'ACT_ACCEPT_AND_NOTIFY': ACT_ACCEPT_AND_NOTIFY + 'ACT_ACCEPT_AND_NOTIFY': ACT_ACCEPT_AND_NOTIFY, + 'ACT_STORE_AND_NOTIFY': ACT_STORE_AND_NOTIFY } # pylint: disable=invalid-name @@ -1031,11 +1034,14 @@ ): """ Accepts the given iTip event by booking it into the resource's - calendar. Then set the attendee status of the given resource to - ACCEPTED and sends an iTip reply message to the organizer. + calendar. Then, depending on the policy, set the attendee status of the given resource to + ACCEPTED/TENTATIVE and send an iTip reply message to the organizer, or set the status to + NEEDS-ACTION and don't send a reply to the organizer. """ owner = get_resource_owner(resource) confirmation_required = False + do_send_response = True + partstat = 'ACCEPTED' if not confirmed and owner: if invitationpolicy is None: @@ -1046,9 +1052,13 @@ for policy in invitationpolicy: if policy & ACT_MANUAL and owner['mail']: confirmation_required = True + partstat = 'TENTATIVE' + break + if policy & ACT_STORE: + partstat = 'NEEDS-ACTION' + # Do not send an immediate response to the organizer + do_send_response = False break - - partstat = 'TENTATIVE' if confirmation_required else 'ACCEPTED' itip_event['xml'].set_transparency(False) itip_event['xml'].set_attendee_participant_status( @@ -1063,7 +1073,7 @@ level=8 ) - if saved: + if saved and do_send_response: send_response(delegator['mail'] if delegator else resource['mail'], itip_event, owner) if owner and confirmation_required: @@ -1110,7 +1120,6 @@ """ try: save_event = itip_event['xml'] - targetfolder = imap.folder_quote(resource['kolabtargetfolder']) # add exception to existing recurring main event if resource.get('existing_master') is not None: @@ -1132,18 +1141,17 @@ else: imap.set_acl( - targetfolder, + resource['kolabtargetfolder'], conf.get(conf.get('kolab', 'imap_backend'), 'admin_login'), "lrswipkxtecda" ) # append new version - result = imap.imap.m.append( - targetfolder, - None, - None, + result = imap.append( + resource['kolabtargetfolder'], save_event.to_message(creator="Kolab Server <wallace@localhost>").as_string() ) + return result # pylint: disable=broad-except @@ -1642,16 +1650,21 @@ if 'preferredlanguage' in owner: pykolab.translate.setUserLanguage(owner['preferredlanguage']) - message_text = owner_notification_text(resource, owner, itip_event['xml'], success) + message_text = owner_notification_text(resource, owner, itip_event['xml'], success, status) msg = MIMEText(utils.stripped_message(message_text), _charset='utf-8') msg['To'] = owner['mail'] msg['From'] = resource['mail'] msg['Date'] = formatdate(localtime=True) - msg['Subject'] = utils.str2unicode(_('Booking for %s has been %s') % ( - resource['cn'], participant_status_label(status) if success else _('failed') - )) + if status == 'NEEDS-ACTION': + msg['Subject'] = utils.str2unicode(_('New booking request for %s') % ( + resource['cn'] + )) + else: + msg['Subject'] = utils.str2unicode(_('Booking for %s has been %s') % ( + resource['cn'], participant_status_label(status) if success else _('failed') + )) seed = random.randint(0, 6) alarm_after = (seed * 10) + 60 @@ -1663,19 +1676,37 @@ signal.alarm(0) -def owner_notification_text(resource, owner, event, success): +def owner_notification_text(resource, owner, event, success, status): organizer = event.get_organizer() status = event.get_attendee_by_email(resource['mail']).get_participant_status(True) + domain = resource['mail'].split('@')[1] + url = conf.get('wallace', 'webmail_url') if success: - message_text = _( - """ - The resource booking for %(resource)s by %(orgname)s <%(orgemail)s> has been - %(status)s for %(date)s. + if status == 'NEEDS-ACTION': + message_text = _( + """ + The resource booking request is for %(resource)s by %(orgname)s <%(orgemail)s> for %(date)s. - *** This is an automated message, sent to you as the resource owner. *** - """ - ) + *** This is an automated message, sent to you as the resource owner. *** + """ + ) + else: + message_text = _( + """ + The resource booking for %(resource)s by %(orgname)s <%(orgemail)s> has been + %(status)s for %(date)s. + + *** This is an automated message, sent to you as the resource owner. *** + """ + ) + + + if url: + message_text += ( + "\n " + + _("You can change the status via %(url)s") % { 'url': url } + '?_task=calendar' + ) else: message_text = _( """ @@ -1695,7 +1726,8 @@ 'date': event.get_date_text(), 'status': participant_status_label(status), 'orgname': organizer.name(), - 'orgemail': organizer.email() + 'orgemail': organizer.email(), + 'domain': domain }
View file
pykolab.dsc
Changed
@@ -2,7 +2,7 @@ Source: pykolab Binary: pykolab, kolab-cli, kolab-conf, kolab-saslauthd, kolab-server, kolab-telemetry, kolab-xml, wallace Architecture: all -Version: 0.8.19-0~kolab1 +Version: 0.8.20-0~kolab1 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org @@ -41,5 +41,5 @@ pykolab deb python optional wallace deb python optional Files: - 00000000000000000000000000000000 0 pykolab-0.8.19.tar.gz + 00000000000000000000000000000000 0 pykolab-0.8.20.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.