Page MenuHomePhorge

D3050.1775435443.diff
No OneTemporary

Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None

D3050.1775435443.diff

diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -285,6 +285,9 @@
else:
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
return imap_utf7.encode(folder)
diff --git a/tests/unit/test-011-wallace_resources.py b/tests/unit/test-011-wallace_resources.py
--- a/tests/unit/test-011-wallace_resources.py
+++ b/tests/unit/test-011-wallace_resources.py
@@ -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,51 @@
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_tentative_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_TENTATIVE_AND_NOTIFY]
+ }
+
+ conf.command_set('wallace', 'webmail_url', 'https://%(domain)s/roundcube')
+ module_resources.imap = IMAP()
+
+ module_resources.accept_reservation_request(itip_event, resource)
+
+ self.assertEqual(len(self.smtplog), 2)
+ self.assertEqual(len(self.imap_append_log), 1)
+
+ # Assert the reply message sent to the organizer
+ 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("doe@example.org", self.smtplog[0][1])
+ self.assertEqual("doe@example.org", mail['to'])
+ self.assertTrue(mail.is_multipart())
+ self.assertIn("Reservation Request for test was Tentatively Accepted", mail['subject'])
+ self.assertIn("PARTSTAT=TENTATIVE", self.smtplog[0][2])
+
+ # Assert the notification sent to the resource owner
+ mail = message_from_string(self.smtplog[1][2])
+
+ self.assertEqual("resource-collection-car@example.org", self.smtplog[1][0])
+ self.assertEqual("resource-collection-car@example.org", mail['from'])
+ self.assertEqual("foo@example.org", self.smtplog[1][1])
+ self.assertEqual("foo@example.org", mail['to'])
+ self.assertFalse(mail.is_multipart())
+ self.assertIn("Booking for Cars has been Tentatively Accepted", mail['subject'])
+ body = mail.get_payload(decode=True)
+ self.assertIn("The resource booking 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>TENTATIVE</text>", self.imap_append_log[0][1])
diff --git a/wallace/module_resources.py b/wallace/module_resources.py
--- a/wallace/module_resources.py
+++ b/wallace/module_resources.py
@@ -58,14 +58,17 @@
ACT_MANUAL = 1
ACT_ACCEPT = 2
ACT_REJECT = 8
+ACT_TENTATIVE = 16
ACT_ACCEPT_AND_NOTIFY = ACT_ACCEPT + COND_NOTIFY
+ACT_TENTATIVE_AND_NOTIFY = ACT_TENTATIVE + 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_TENTATIVE_AND_NOTIFY': ACT_TENTATIVE_AND_NOTIFY
}
# pylint: disable=invalid-name
@@ -1032,10 +1035,11 @@
"""
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.
+ ACCEPTED/TENTATIVE and sends an iTip reply message to the organizer.
"""
owner = get_resource_owner(resource)
confirmation_required = False
+ partstat = 'ACCEPTED'
if not confirmed and owner:
if invitationpolicy is None:
@@ -1046,9 +1050,10 @@
for policy in invitationpolicy:
if policy & ACT_MANUAL and owner['mail']:
confirmation_required = True
+ partstat = 'TENTATIVE'
break
-
- partstat = 'TENTATIVE' if confirmation_required else 'ACCEPTED'
+ if policy & ACT_TENTATIVE:
+ partstat = 'TENTATIVE'
itip_event['xml'].set_transparency(False)
itip_event['xml'].set_attendee_participant_status(
@@ -1063,7 +1068,8 @@
level=8
)
- if saved:
+ # Only send a response back to the organizer if this is a confirmation from the resource owner.
+ if saved and confirmed:
send_response(delegator['mail'] if delegator else resource['mail'], itip_event, owner)
if owner and confirmation_required:
@@ -1110,7 +1116,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 +1137,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
@@ -1666,6 +1670,8 @@
def owner_notification_text(resource, owner, event, success):
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 = _(
@@ -1676,6 +1682,12 @@
*** 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 +1707,8 @@
'date': event.get_date_text(),
'status': participant_status_label(status),
'orgname': organizer.name(),
- 'orgemail': organizer.email()
+ 'orgemail': organizer.email(),
+ 'domain': domain
}

File Metadata

Mime Type
text/plain
Expires
Mon, Apr 6, 12:30 AM (5 h, 23 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18835044
Default Alt Text
D3050.1775435443.diff (9 KB)

Event Timeline