<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[14456] CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/14456">14456</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-02-19 17:47:23 -0800 (Thu, 19 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Use DAL Record for iMIP tokens.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimipinboundpy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/inbound.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimipoutboundpy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/outbound.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_inboundpy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_mailgatewaypy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_mailgateway.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_outboundpy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommondatastoresqlpy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommonicommondatastorepy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/icommondatastore.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommondatastoresql_imippy">CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql_imip.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimipinboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/inbound.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/inbound.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/inbound.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -260,11 +260,11 @@
</span><span class="cx">             return
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction(label=&quot;MailReceiver.processDSN&quot;)
</span><del>-        result = (yield txn.imipLookupByToken(token))
</del><ins>+        records = (yield txn.imipLookupByToken(token))
</ins><span class="cx">         yield txn.commit()
</span><span class="cx">         try:
</span><span class="cx">             # Note the results are returned as utf-8 encoded strings
</span><del>-            organizer, attendee, _ignore_icaluid = result[0]
</del><ins>+            record = records[0]
</ins><span class="cx">         except:
</span><span class="cx">             # This isn't a token we recognize
</span><span class="cx">             log.error(
</span><span class="lines">@@ -272,7 +272,7 @@
</span><span class="cx">                 % (token, msgId))
</span><span class="cx">             returnValue(self.UNKNOWN_TOKEN)
</span><span class="cx"> 
</span><del>-        calendar.removeAllButOneAttendee(attendee)
</del><ins>+        calendar.removeAllButOneAttendee(record.attendee)
</ins><span class="cx">         calendar.getOrganizerProperty().setValue(organizer)
</span><span class="cx">         for comp in calendar.subcomponents():
</span><span class="cx">             if comp.name() == &quot;VEVENT&quot;:
</span><span class="lines">@@ -288,8 +288,11 @@
</span><span class="cx">         log.warn(&quot;Mail gateway processing DSN %s&quot; % (msgId,))
</span><span class="cx">         txn = self.store.newTransaction(label=&quot;MailReceiver.processDSN&quot;)
</span><span class="cx">         yield txn.enqueue(
</span><del>-            IMIPReplyWork, organizer=organizer, attendee=attendee,
-            icalendarText=str(calendar))
</del><ins>+            IMIPReplyWork,
+            organizer=record.organizer,
+            attendee=record.attendee,
+            icalendarText=str(calendar)
+        )
</ins><span class="cx">         yield txn.commit()
</span><span class="cx">         returnValue(self.INJECTION_SUBMITTED)
</span><span class="cx"> 
</span><span class="lines">@@ -313,11 +316,11 @@
</span><span class="cx">             returnValue(self.MALFORMED_TO_ADDRESS)
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction(label=&quot;MailReceiver.processReply&quot;)
</span><del>-        result = (yield txn.imipLookupByToken(token))
</del><ins>+        records = (yield txn.imipLookupByToken(token))
</ins><span class="cx">         yield txn.commit()
</span><span class="cx">         try:
</span><span class="cx">             # Note the results are returned as utf-8 encoded strings
</span><del>-            organizer, attendee, _ignore_icaluid = result[0]
</del><ins>+            record = records[0]
</ins><span class="cx">         except:
</span><span class="cx">             # This isn't a token we recognize
</span><span class="cx">             log.error(
</span><span class="lines">@@ -337,11 +340,11 @@
</span><span class="cx">                 &quot;in message %s&quot; % (msg['Message-ID'],))
</span><span class="cx"> 
</span><span class="cx">             toAddr = None
</span><del>-            fromAddr = attendee[7:]
-            if organizer.startswith(&quot;mailto:&quot;):
-                toAddr = organizer[7:]
-            elif organizer.startswith(&quot;urn:x-uid:&quot;):
-                uid = organizer[10:]
</del><ins>+            fromAddr = record.attendee[7:]
+            if record.organizer.startswith(&quot;mailto:&quot;):
+                toAddr = record.organizer[7:]
+            elif record.organizer.startswith(&quot;urn:x-uid:&quot;):
+                uid = record.organizer[10:]
</ins><span class="cx">                 record = yield self.directory.recordWithUID(uid)
</span><span class="cx">                 try:
</span><span class="cx">                     if record and record.emailAddresses:
</span><span class="lines">@@ -376,23 +379,23 @@
</span><span class="cx">         calendar = Component.fromString(calBody)
</span><span class="cx">         event = calendar.mainComponent()
</span><span class="cx"> 
</span><del>-        calendar.removeAllButOneAttendee(attendee)
</del><ins>+        calendar.removeAllButOneAttendee(record.attendee)
</ins><span class="cx">         organizerProperty = calendar.getOrganizerProperty()
</span><span class="cx">         if organizerProperty is None:
</span><span class="cx">             # ORGANIZER is required per rfc2446 section 3.2.3
</span><span class="cx">             log.warn(
</span><span class="cx">                 &quot;Mail gateway didn't find an ORGANIZER in REPLY %s&quot;
</span><span class="cx">                 % (msg['Message-ID'],))
</span><del>-            event.addProperty(Property(&quot;ORGANIZER&quot;, organizer))
</del><ins>+            event.addProperty(Property(&quot;ORGANIZER&quot;, record.organizer))
</ins><span class="cx">         else:
</span><del>-            organizerProperty.setValue(organizer)
</del><ins>+            organizerProperty.setValue(record.organizer)
</ins><span class="cx"> 
</span><span class="cx">         if not calendar.getAttendees():
</span><span class="cx">             # The attendee we're expecting isn't there, so add it back
</span><span class="cx">             # with a SCHEDULE-STATUS of SERVICE_UNAVAILABLE.
</span><span class="cx">             # The organizer will then see that the reply was not successful.
</span><span class="cx">             attendeeProp = Property(
</span><del>-                &quot;ATTENDEE&quot;, attendee,
</del><ins>+                &quot;ATTENDEE&quot;, record.attendee,
</ins><span class="cx">                 params={
</span><span class="cx">                     &quot;SCHEDULE-STATUS&quot;: iTIPRequestStatus.SERVICE_UNAVAILABLE,
</span><span class="cx">                 }
</span><span class="lines">@@ -406,8 +409,11 @@
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction(label=&quot;MailReceiver.processReply&quot;)
</span><span class="cx">         yield txn.enqueue(
</span><del>-            IMIPReplyWork, organizer=organizer, attendee=attendee,
-            icalendarText=str(calendar))
</del><ins>+            IMIPReplyWork,
+            organizer=record.organizer,
+            attendee=record.attendee,
+            icalendarText=str(calendar)
+        )
</ins><span class="cx">         yield txn.commit()
</span><span class="cx">         returnValue(self.INJECTION_SUBMITTED)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimipoutboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/outbound.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/outbound.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/outbound.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -364,28 +364,29 @@
</span><span class="cx"> 
</span><span class="cx">             # Reuse or generate a token based on originator, toAddr, and
</span><span class="cx">             # event uid
</span><del>-            token = (yield txn.imipGetToken(originator, toAddr.lower(), icaluid))
-            if token is None:
</del><ins>+            record = (yield txn.imipGetToken(originator, toAddr.lower(), icaluid))
+            if record is None:
</ins><span class="cx"> 
</span><span class="cx">                 # Because in the past the originator was sometimes in mailto:
</span><span class="cx">                 # form, lookup an existing token by mailto: as well
</span><span class="cx">                 organizerProperty = calendar.getOrganizerProperty()
</span><span class="cx">                 organizerEmailAddress = organizerProperty.parameterValue(&quot;EMAIL&quot;, None)
</span><span class="cx">                 if organizerEmailAddress is not None:
</span><del>-                    token = (yield txn.imipGetToken(&quot;mailto:%s&quot; % (organizerEmailAddress.lower(),), toAddr.lower(), icaluid))
</del><ins>+                    record = (yield txn.imipGetToken(&quot;mailto:%s&quot; % (organizerEmailAddress.lower(),), toAddr.lower(), icaluid))
</ins><span class="cx"> 
</span><del>-            if token is None:
-                token = (yield txn.imipCreateToken(originator, toAddr.lower(), icaluid))
</del><ins>+            if record is None:
+                record = (yield txn.imipCreateToken(originator, toAddr.lower(), icaluid))
</ins><span class="cx">                 self.log.debug(&quot;Mail gateway created token %s for %s &quot;
</span><span class="cx">                                &quot;(originator), %s (recipient) and %s (icaluid)&quot;
</span><del>-                               % (token, originator, toAddr, icaluid))
</del><ins>+                               % (record.token, originator, toAddr, icaluid))
</ins><span class="cx">                 inviteState = &quot;new&quot;
</span><span class="cx"> 
</span><span class="cx">             else:
</span><span class="cx">                 self.log.debug(&quot;Mail gateway reusing token %s for %s &quot;
</span><span class="cx">                                &quot;(originator), %s (recipient) and %s (icaluid)&quot;
</span><del>-                               % (token, originator, toAddr, icaluid))
</del><ins>+                               % (record.token, originator, toAddr, icaluid))
</ins><span class="cx">                 inviteState = &quot;update&quot;
</span><ins>+            token = record.token
</ins><span class="cx"> 
</span><span class="cx">             fullServerAddress = self.address
</span><span class="cx">             _ignore_name, serverAddress = email.utils.parseaddr(fullServerAddress)
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_inboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -175,13 +175,13 @@
</span><span class="cx"> 
</span><span class="cx">         # Make sure a known token *is* processed
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token = (yield txn.imipCreateToken(
</del><ins>+        record = (yield txn.imipCreateToken(
</ins><span class="cx">             &quot;urn:x-uid:5A985493-EE2C-4665-94CF-4DFEA3A89500&quot;,
</span><span class="cx">             &quot;mailto:user02@example.com&quot;,
</span><span class="cx">             &quot;1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C&quot;
</span><span class="cx">         ))
</span><span class="cx">         yield txn.commit()
</span><del>-        calBody = template % token
</del><ins>+        calBody = template % record.token
</ins><span class="cx">         result = (yield self.receiver.processDSN(calBody, &quot;xyzzy&quot;))
</span><span class="cx">         self.assertEquals(result, MailReceiver.INJECTION_SUBMITTED)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_mailgatewaypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_mailgateway.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_mailgateway.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_mailgateway.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -44,9 +44,8 @@
</span><span class="cx">             &quot;icaluid1&quot;, token=&quot;token1&quot;)
</span><span class="cx">         yield migrateTokensToStore(self.path, self.store)
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        results = yield (txn.imipLookupByToken(&quot;token1&quot;))
-        organizer, attendee, icaluid = results[0]
</del><ins>+        records = yield (txn.imipLookupByToken(&quot;token1&quot;))
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(organizer, &quot;urn:uuid:user01&quot;)
-        self.assertEquals(attendee, &quot;mailto:attendee@example.com&quot;)
-        self.assertEquals(icaluid, &quot;icaluid1&quot;)
</del><ins>+        self.assertEquals(records[0].organizer, &quot;urn:uuid:user01&quot;)
+        self.assertEquals(records[0].attendee, &quot;mailto:attendee@example.com&quot;)
+        self.assertEquals(records[0].icaluid, &quot;icaluid1&quot;)
</ins></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcaldavdatastoreschedulingimiptesttest_outboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -316,17 +316,17 @@
</span><span class="cx">         yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token = (yield txn.imipGetToken(
</del><ins>+        record = (yield txn.imipGetToken(
</ins><span class="cx">             ORGANIZER,
</span><span class="cx">             ATTENDEE,
</span><span class="cx">             ICALUID
</span><span class="cx">         ))
</span><del>-        self.assertTrue(token)
-        organizer, attendee, icaluid = (yield txn.imipLookupByToken(token))[0]
</del><ins>+        self.assertTrue(record is not None)
+        record = (yield txn.imipLookupByToken(record.token))[0]
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(organizer, ORGANIZER)
-        self.assertEquals(attendee, ATTENDEE)
-        self.assertEquals(icaluid, ICALUID)
</del><ins>+        self.assertEquals(record.organizer, ORGANIZER)
+        self.assertEquals(record.attendee, ATTENDEE)
+        self.assertEquals(record.icaluid, ICALUID)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -492,12 +492,12 @@
</span><span class="cx">             if UID: # The organizer is local, and server is sending to remote
</span><span class="cx">                     # attendee
</span><span class="cx">                 txn = self.store.newTransaction()
</span><del>-                token = (yield txn.imipGetToken(inputOriginator, inputRecipient, UID))
</del><ins>+                record = (yield txn.imipGetToken(inputOriginator, inputRecipient, UID))
</ins><span class="cx">                 yield txn.commit()
</span><del>-                self.assertNotEquals(token, None)
</del><ins>+                self.assertNotEquals(record, None)
</ins><span class="cx">                 self.assertEquals(
</span><span class="cx">                     msg[&quot;Reply-To&quot;],
</span><del>-                    &quot;server+%s@example.com&quot; % (token,))
</del><ins>+                    &quot;server+%s@example.com&quot; % (record.token,))
</ins><span class="cx"> 
</span><span class="cx">                 # Make sure attendee property for organizer exists and matches
</span><span class="cx">                 # the CUA of the organizer property
</span><span class="lines">@@ -529,31 +529,31 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_tokens(self):
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token = (yield txn.imipLookupByToken(&quot;xyzzy&quot;))
</del><ins>+        self.assertEquals((yield txn.imipLookupByToken(&quot;xyzzy&quot;)), [])
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(token, [])
</del><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token1 = (yield txn.imipCreateToken(&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;))
</del><ins>+        record1 = (yield txn.imipCreateToken(&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;))
</ins><span class="cx">         yield txn.commit()
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token2 = (yield txn.imipGetToken(&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;))
</del><ins>+        record2 = (yield txn.imipGetToken(&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;))
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(token1, token2)
</del><ins>+        self.assertEquals(record1.token, record2.token)
</ins><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><ins>+        record = (yield txn.imipLookupByToken(record1.token))[0]
</ins><span class="cx">         self.assertEquals(
</span><del>-            (yield txn.imipLookupByToken(token1)),
-            [[&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;]])
</del><ins>+            [record.organizer, record.attendee, record.icaluid],
+            [&quot;organizer&quot;, &quot;attendee&quot;, &quot;icaluid&quot;])
</ins><span class="cx">         yield txn.commit()
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        yield txn.imipRemoveToken(token1)
</del><ins>+        yield txn.imipRemoveToken(record1.token)
</ins><span class="cx">         yield txn.commit()
</span><span class="cx"> 
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        self.assertEquals((yield txn.imipLookupByToken(token1)), [])
</del><ins>+        self.assertEquals((yield txn.imipLookupByToken(record1.token)), [])
</ins><span class="cx">         yield txn.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -568,7 +568,7 @@
</span><span class="cx">         # Explictly store a token with mailto: CUA for organizer
</span><span class="cx">         # (something that doesn't happen any more, but did in the past)
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        origToken = (yield txn.imipCreateToken(
</del><ins>+        origRecord = (yield txn.imipCreateToken(
</ins><span class="cx">             organizerEmail,
</span><span class="cx">             &quot;mailto:attendee@example.com&quot;,
</span><span class="cx">             &quot;CFDD5E46-4F74-478A-9311-B3FF905449C3&quot;
</span><span class="lines">@@ -588,15 +588,15 @@
</span><span class="cx"> 
</span><span class="cx">         # Verify we didn't create a new token...
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token = (yield txn.imipGetToken(inputOriginator, inputRecipient, UID))
</del><ins>+        record = (yield txn.imipGetToken(inputOriginator, inputRecipient, UID))
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(token, None)
</del><ins>+        self.assertEquals(record, None)
</ins><span class="cx"> 
</span><span class="cx">         # But instead kept the old one...
</span><span class="cx">         txn = self.store.newTransaction()
</span><del>-        token = (yield txn.imipGetToken(organizerEmail, inputRecipient, UID))
</del><ins>+        record = (yield txn.imipGetToken(organizerEmail, inputRecipient, UID))
</ins><span class="cx">         yield txn.commit()
</span><del>-        self.assertEquals(token, origToken)
</del><ins>+        self.assertEquals(record.token, origRecord.token)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def generateSampleEmail(self, caltext=initialInviteText):
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -14,6 +14,7 @@
</span><span class="cx"> # See the License for the specific language governing permissions and
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><ins>+from txdav.common.datastore.sql_imip import imipAPIMixin
</ins><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> SQL data store.
</span><span class="lines">@@ -75,8 +76,7 @@
</span><span class="cx">     HomeChildNameAlreadyExistsError, NoSuchHomeChildError, \
</span><span class="cx">     ObjectResourceNameNotAllowedError, ObjectResourceNameAlreadyExistsError, \
</span><span class="cx">     NoSuchObjectResourceError, AllRetriesFailed, InvalidSubscriptionValues, \
</span><del>-    InvalidIMIPTokenValues, TooManyObjectResourcesError, \
-    SyncTokenValidException
</del><ins>+    TooManyObjectResourcesError, SyncTokenValidException
</ins><span class="cx"> from txdav.common.idirectoryservice import IStoreDirectoryService, \
</span><span class="cx">     DirectoryRecordNotFoundError
</span><span class="cx"> from txdav.common.inotifications import INotificationCollection, \
</span><span class="lines">@@ -565,7 +565,10 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class CommonStoreTransaction(GroupsAPIMixin, GroupCacherAPIMixin, DelegatesAPIMixin):
</del><ins>+class CommonStoreTransaction(
+    GroupsAPIMixin, GroupCacherAPIMixin, DelegatesAPIMixin,
+    imipAPIMixin,
+):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Transaction implementation for SQL database.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -921,121 +924,6 @@
</span><span class="cx">         return self._apnSubscriptionsBySubscriberQuery.on(self, subscriberGUID=guid)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    # Create IMIP token
-
-    @classproperty
-    def _insertIMIPTokenQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Insert({
-            imip.TOKEN: Parameter(&quot;token&quot;),
-            imip.ORGANIZER: Parameter(&quot;organizer&quot;),
-            imip.ATTENDEE: Parameter(&quot;attendee&quot;),
-            imip.ICALUID: Parameter(&quot;icaluid&quot;),
-        })
-
-
-    @inlineCallbacks
-    def imipCreateToken(self, organizer, attendee, icaluid, token=None):
-        if not (organizer and attendee and icaluid):
-            raise InvalidIMIPTokenValues()
-
-        if token is None:
-            token = str(uuid4())
-
-        try:
-            yield self._insertIMIPTokenQuery.on(
-                self,
-                token=token, organizer=organizer, attendee=attendee,
-                icaluid=icaluid)
-        except Exception:
-            # TODO: is it okay if someone else created the same row just now?
-            pass
-        returnValue(token)
-
-    # Lookup IMIP organizer+attendee+icaluid for token
-
-
-    @classproperty
-    def _selectIMIPTokenByTokenQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Select([imip.ORGANIZER, imip.ATTENDEE, imip.ICALUID], From=imip,
-                      Where=(imip.TOKEN == Parameter(&quot;token&quot;)))
-
-
-    def imipLookupByToken(self, token):
-        return self._selectIMIPTokenByTokenQuery.on(self, token=token)
-
-    # Lookup IMIP token for organizer+attendee+icaluid
-
-
-    @classproperty
-    def _selectIMIPTokenQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Select(
-            [imip.TOKEN],
-            From=imip,
-            Where=(imip.ORGANIZER == Parameter(&quot;organizer&quot;)).And(
-                imip.ATTENDEE == Parameter(&quot;attendee&quot;)).And(
-                imip.ICALUID == Parameter(&quot;icaluid&quot;))
-        )
-
-
-    @classproperty
-    def _updateIMIPTokenQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Update(
-            {imip.ACCESSED: utcNowSQL, },
-            Where=(imip.ORGANIZER == Parameter(&quot;organizer&quot;)).And(
-                imip.ATTENDEE == Parameter(&quot;attendee&quot;)).And(
-                    imip.ICALUID == Parameter(&quot;icaluid&quot;))
-        )
-
-
-    @inlineCallbacks
-    def imipGetToken(self, organizer, attendee, icaluid):
-        row = (yield self._selectIMIPTokenQuery.on(
-            self, organizer=organizer,
-            attendee=attendee, icaluid=icaluid))
-        if row:
-            token = row[0][0]
-            # update the timestamp
-            yield self._updateIMIPTokenQuery.on(
-                self, organizer=organizer,
-                attendee=attendee, icaluid=icaluid)
-        else:
-            token = None
-        returnValue(token)
-
-
-    # Remove IMIP token
-    @classproperty
-    def _removeIMIPTokenQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Delete(From=imip,
-                      Where=(imip.TOKEN == Parameter(&quot;token&quot;)))
-
-
-    def imipRemoveToken(self, token):
-        return self._removeIMIPTokenQuery.on(self, token=token)
-
-
-    # Purge old IMIP tokens
-    @classproperty
-    def _purgeOldIMIPTokensQuery(cls):
-        imip = schema.IMIP_TOKENS
-        return Delete(From=imip,
-                      Where=(imip.ACCESSED &lt; Parameter(&quot;olderThan&quot;)))
-
-
-    def purgeOldIMIPTokens(self, olderThan):
-        &quot;&quot;&quot;
-        @type olderThan: datetime
-        &quot;&quot;&quot;
-        return self._purgeOldIMIPTokensQuery.on(self, olderThan=olderThan)
-
-    # End of IMIP
-
-
</del><span class="cx">     def preCommit(self, operation):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Run things before C{commit}.  (Note: only provided by SQL
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommondatastoresql_imippy"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql_imip.py (0 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql_imip.py                                (rev 0)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/sql_imip.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+# -*- test-case-name: twext.enterprise.dal.test.test_record -*-
+##
+# Copyright (c) 2015 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twext.enterprise.dal.record import SerializableRecord, fromTable
+from twext.enterprise.dal.syntax import utcNowSQL
+from twext.python.log import Logger
+from twisted.internet.defer import inlineCallbacks, returnValue
+from txdav.common.datastore.sql_tables import schema
+from txdav.common.icommondatastore import InvalidIMIPTokenValues
+from uuid import uuid4
+
+log = Logger()
+
+&quot;&quot;&quot;
+Classes and methods that relate to iMIP objects in the SQL store.
+&quot;&quot;&quot;
+
+class iMIPTokensRecord(SerializableRecord, fromTable(schema.IMIP_TOKENS)):
+    &quot;&quot;&quot;
+    @DynamicAttrs
+    L{Record} for L{schema.IMIP_TOKENS}.
+    &quot;&quot;&quot;
+    pass
+
+
+
+class imipAPIMixin(object):
+    &quot;&quot;&quot;
+    A mixin for L{CommonStoreTransaction} that covers the iMIP API.
+    &quot;&quot;&quot;
+
+    # Create IMIP token
+    @inlineCallbacks
+    def imipCreateToken(self, organizer, attendee, icaluid, token=None):
+        if not (organizer and attendee and icaluid):
+            raise InvalidIMIPTokenValues()
+
+        if token is None:
+            token = str(uuid4())
+
+        try:
+            record = yield iMIPTokensRecord.create(
+                self,
+                token=token,
+                organizer=organizer,
+                attendee=attendee,
+                icaluid=icaluid
+            )
+        except Exception:
+            # TODO: is it okay if someone else created the same row just now?
+            record = yield self.imipGetToken(organizer, attendee, icaluid)
+        returnValue(record)
+
+
+    # Lookup IMIP organizer+attendee+icaluid for token
+    def imipLookupByToken(self, token):
+        return iMIPTokensRecord.querysimple(self, token=token)
+
+
+    # Lookup IMIP token for organizer+attendee+icaluid
+    @inlineCallbacks
+    def imipGetToken(self, organizer, attendee, icaluid):
+        records = yield iMIPTokensRecord.querysimple(
+            self,
+            organizer=organizer,
+            attendee=attendee,
+            icaluid=icaluid,
+        )
+        if records:
+            # update the timestamp
+            record = records[0]
+            yield record.update(accessed=utcNowSQL)
+        else:
+            record = None
+        returnValue(record)
+
+
+    # Remove IMIP token
+    def imipRemoveToken(self, token):
+        return iMIPTokensRecord.deletesimple(self, token=token)
+
+
+    # Purge old IMIP tokens
+    def purgeOldIMIPTokens(self, olderThan):
+        &quot;&quot;&quot;
+        @type olderThan: datetime
+        &quot;&quot;&quot;
+        return iMIPTokensRecord.delete(self, iMIPTokensRecord.accessed &lt; olderThan)
</ins></span></pre></div>
<a id="CalendarServerbranchesuserscdaboopod2podmigrationtxdavcommonicommondatastorepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/icommondatastore.py (14455 => 14456)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/icommondatastore.py        2015-02-20 00:00:46 UTC (rev 14455)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/icommondatastore.py        2015-02-20 01:47:23 UTC (rev 14456)
</span><span class="lines">@@ -389,8 +389,8 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns the organizer, attendee, and icaluid corresponding to the token
</span><span class="cx"> 
</span><del>-        @param token: the token to look up
-        @type token: C{str}
</del><ins>+        @param token: the token record
+        @type token: L{Record}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def imipGetToken(organizer, attendee, icaluid): #@NoSelf
</span></span></pre>
</div>
</div>

</body>
</html>