Projects
Kolab:Winterfell
pykolab
Log In
Username
Password
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], - subject, - folder - ) + _("Would have deleted ACL %s for subject %s on folder %s") % ( + acls[subject], + subject, + folder ) + ) else: log.info( - _("Deleting ACL %s for subject %s on folder %s") % ( - acls[subject], - subject, - folder - ) + _("Deleting ACL %s for subject %s on folder %s") % ( + acls[subject], + subject, + folder ) + ) try: - imap.set_acl(folder, aci_subject, '') + imap.set_acl(folder, subject, '') + # pylint: disable=bare-except except: log.error( - _("Error removing ACL %s for subject %s from folder %s") % ( - acls[subject], - subject, - folder - ) + _("Error removing ACL %s for subject %s from folder %s") % ( + acls[subject], + subject, + folder ) - + )
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
.