<!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>[12273] CalendarServer/branches/release/CalendarServer-5.2-dev</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/12273">12273</a></dd>
<dt>Author</dt> <dd>wsanchez@apple.com</dd>
<dt>Date</dt> <dd>2014-01-08 14:20:19 -0800 (Wed, 08 Jan 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Pulled up <a href="http://trac.calendarserver.org//changeset/11934">r11934</a> from trunk.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushamppushpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/amppush.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushapplepushpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/applepush.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushnotifierpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/notifier.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_amppushpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_amppush.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_applepushpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_applepush.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_notifierpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_notifier.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushutilpy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/util.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolsampnotificationspy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/ampnotifications.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolsgatewaypy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/gateway.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolstesttest_gatewaypy">CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/test/test_gateway.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcaldavdatastoresqlpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcaldavdatastoretestcommonpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/test/common.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcarddavdatastoretestcommonpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/carddav/datastore/test/common.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresqlpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresql_schemacurrentoracledialectsql">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current-oracle-dialect.sql</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresql_schemacurrentsql">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current.sql</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoretestutilpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/test/util.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52devtxdavidavpy">CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/idav.py</a></li>
</ul>
<h3>Property Changed</h3>
<ul>
<li><a href="#CalendarServerbranchesreleaseCalendarServer52dev">CalendarServer/branches/release/CalendarServer-5.2-dev/</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesreleaseCalendarServer52dev"></a>
<div class="propset"><h4>Property changes: CalendarServer/branches/release/CalendarServer-5.2-dev</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:11898,11991,12021,12028,12030-12031,12036,12241,12262-12263
</span><span class="cx"> + /CalDAVTester/trunk:11193-11198
</span><span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:11898,11934,11991,12021,12028,12030-12031,12036,12241,12262-12263
</span><a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushamppushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/amppush.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/amppush.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/amppush.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -23,7 +23,9 @@
</span><span class="cx"> import time
</span><span class="cx"> import uuid
</span><span class="cx">
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -49,7 +51,8 @@
</span><span class="cx">
</span><span class="cx"> class NotificationForID(amp.Command):
</span><span class="cx"> arguments = [('id', amp.String()),
</span><del>- ('dataChangedTimestamp', amp.Integer(optional=True))]
</del><ins>+ ('dataChangedTimestamp', amp.Integer(optional=True)),
+ ('priority', amp.Integer(optional=True))]
</ins><span class="cx"> response = [('status', amp.String())]
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -82,12 +85,14 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def enqueue(self, transaction, id, dataChangedTimestamp=None):
</del><ins>+ def enqueue(self, transaction, id, dataChangedTimestamp=None,
+ priority=PushPriority.high):
</ins><span class="cx"> if dataChangedTimestamp is None:
</span><span class="cx"> dataChangedTimestamp = int(time.time())
</span><span class="cx"> for protocol in self.protocols:
</span><span class="cx"> yield protocol.callRemote(NotificationForID, id=id,
</span><del>- dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ dataChangedTimestamp=dataChangedTimestamp,
+ priority=priority.value)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -103,10 +108,12 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @NotificationForID.responder
</span><del>- def enqueueFromWorker(self, id, dataChangedTimestamp=None):
</del><ins>+ def enqueueFromWorker(self, id, dataChangedTimestamp=None,
+ priority=PushPriority.high.value):
</ins><span class="cx"> if dataChangedTimestamp is None:
</span><span class="cx"> dataChangedTimestamp = int(time.time())
</span><del>- self.master.enqueue(None, id, dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ self.master.enqueue(None, id, dataChangedTimestamp=dataChangedTimestamp,
+ priority=PushPriority.lookupByValue(priority))
</ins><span class="cx"> return {"status" : "OK"}
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -167,7 +174,8 @@
</span><span class="cx"> self.subscribers.remove(p)
</span><span class="cx">
</span><span class="cx">
</span><del>- def enqueue(self, transaction, pushKey, dataChangedTimestamp=None):
</del><ins>+ def enqueue(self, transaction, pushKey, dataChangedTimestamp=None,
+ priority=PushPriority.high):
</ins><span class="cx"> """
</span><span class="cx"> Sends an AMP push notification to any clients subscribing to this pushKey.
</span><span class="cx">
</span><span class="lines">@@ -192,23 +200,26 @@
</span><span class="cx"> if token is not None:
</span><span class="cx"> tokens.append(token)
</span><span class="cx"> if tokens:
</span><del>- return self.scheduleNotifications(tokens, pushKey, dataChangedTimestamp)
</del><ins>+ return self.scheduleNotifications(tokens, pushKey,
+ dataChangedTimestamp, priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def sendNotification(self, token, id, dataChangedTimestamp):
</del><ins>+ def sendNotification(self, token, id, dataChangedTimestamp, priority):
</ins><span class="cx"> for subscriber in self.subscribers:
</span><span class="cx"> if subscriber.subscribedToID(id):
</span><del>- yield subscriber.notify(token, id, dataChangedTimestamp)
</del><ins>+ yield subscriber.notify(token, id, dataChangedTimestamp,
+ priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def scheduleNotifications(self, tokens, id, dataChangedTimestamp):
</del><ins>+ def scheduleNotifications(self, tokens, id, dataChangedTimestamp, priority):
</ins><span class="cx"> if self.scheduler is not None:
</span><del>- self.scheduler.schedule(tokens, id, dataChangedTimestamp)
</del><ins>+ self.scheduler.schedule(tokens, id, dataChangedTimestamp, priority)
</ins><span class="cx"> else:
</span><span class="cx"> for token in tokens:
</span><del>- yield self.sendNotification(token, id, dataChangedTimestamp)
</del><ins>+ yield self.sendNotification(token, id, dataChangedTimestamp,
+ priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -238,11 +249,12 @@
</span><span class="cx"> return {"status" : "OK"}
</span><span class="cx"> UnsubscribeFromID.responder(unsubscribe)
</span><span class="cx">
</span><del>- def notify(self, token, id, dataChangedTimestamp):
</del><ins>+ def notify(self, token, id, dataChangedTimestamp, priority):
</ins><span class="cx"> if self.subscribedToID(id) == token:
</span><span class="cx"> self.log.debug("Sending notification for %s to %s" % (id, token))
</span><span class="cx"> return self.callRemote(NotificationForID, id=id,
</span><del>- dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ dataChangedTimestamp=dataChangedTimestamp,
+ priority=priority.value)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def subscribedToID(self, id):
</span><span class="lines">@@ -288,8 +300,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def notificationForID(self, id, dataChangedTimestamp):
- yield self.callback(id, dataChangedTimestamp)
</del><ins>+ def notificationForID(self, id, dataChangedTimestamp, priority):
+ yield self.callback(id, dataChangedTimestamp, PushPriority.lookupByValue(priority))
</ins><span class="cx"> returnValue({"status" : "OK"})
</span><span class="cx">
</span><span class="cx"> NotificationForID.responder(notificationForID)
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushapplepushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/applepush.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/applepush.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/applepush.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -36,16 +36,27 @@
</span><span class="cx"> import struct
</span><span class="cx"> import time
</span><span class="cx"> from txdav.common.icommondatastore import InvalidSubscriptionValues
</span><del>-
-from calendarserver.push.util import validToken, TokenHistory, PushScheduler
-
</del><ins>+from calendarserver.push.util import (
+ validToken, TokenHistory, PushScheduler, PushPriority
+)
</ins><span class="cx"> from twext.internet.adaptendpoint import connect
</span><span class="cx"> from twext.internet.gaiendpoint import GAIEndpoint
</span><ins>+from twisted.python.constants import Values, ValueConstant
</ins><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+class ApplePushPriority(Values):
+ """
+ Maps calendarserver.push.util.PushPriority values to APNS-specific values
+ """
+ low = ValueConstant(PushPriority.low.value)
+ medium = ValueConstant(PushPriority.medium.value)
+ high = ValueConstant(PushPriority.high.value)
+
+
+
</ins><span class="cx"> class ApplePushNotifierService(service.MultiService):
</span><span class="cx"> """
</span><span class="cx"> ApplePushNotifierService is a MultiService responsible for
</span><span class="lines">@@ -55,7 +66,7 @@
</span><span class="cx">
</span><span class="cx"> The Apple Push Notification protocol is described here:
</span><span class="cx">
</span><del>- http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html
</del><ins>+ https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html
</ins><span class="cx"> """
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="lines">@@ -177,7 +188,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def enqueue(self, transaction, pushKey, dataChangedTimestamp=None):
</del><ins>+ def enqueue(self, transaction, pushKey, dataChangedTimestamp=None,
+ priority=PushPriority.high):
</ins><span class="cx"> """
</span><span class="cx"> Sends an Apple Push Notification to any device token subscribed to
</span><span class="cx"> this pushKey.
</span><span class="lines">@@ -191,6 +203,8 @@
</span><span class="cx"> @param dataChangedTimestamp: Timestamp (epoch seconds) for the data change
</span><span class="cx"> which triggered this notification (Only used for unit tests)
</span><span class="cx"> @type key: C{int}
</span><ins>+ @param priority: the priority level
+ @type priority: L{PushPriority}
</ins><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> try:
</span><span class="lines">@@ -219,7 +233,8 @@
</span><span class="cx"> if token and uid:
</span><span class="cx"> tokens.append(token)
</span><span class="cx"> if tokens:
</span><del>- provider.scheduleNotifications(tokens, pushKey, dataChangedTimestamp)
</del><ins>+ provider.scheduleNotifications(tokens, pushKey,
+ dataChangedTimestamp, priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -230,8 +245,7 @@
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="cx"> # Sent by provider
</span><del>- COMMAND_SIMPLE = 0
- COMMAND_ENHANCED = 1
</del><ins>+ COMMAND_PROVIDER = 2
</ins><span class="cx">
</span><span class="cx"> # Received by provider
</span><span class="cx"> COMMAND_ERROR = 8
</span><span class="lines">@@ -333,7 +347,7 @@
</span><span class="cx"> yield txn.commit()
</span><span class="cx">
</span><span class="cx">
</span><del>- def sendNotification(self, token, key, dataChangedTimestamp):
</del><ins>+ def sendNotification(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> Sends a push notification message for the key to the device associated
</span><span class="cx"> with the token.
</span><span class="lines">@@ -357,6 +371,7 @@
</span><span class="cx"> return
</span><span class="cx">
</span><span class="cx"> identifier = self.history.add(token)
</span><ins>+ apnsPriority = ApplePushPriority.lookupByValue(priority.value).value
</ins><span class="cx"> payload = json.dumps(
</span><span class="cx"> {
</span><span class="cx"> "key" : key,
</span><span class="lines">@@ -365,23 +380,79 @@
</span><span class="cx"> }
</span><span class="cx"> )
</span><span class="cx"> payloadLength = len(payload)
</span><del>- self.log.debug("Sending APNS notification to {token}: id={id} payload={payload}",
- token=token, id=identifier, payload=payload)
</del><ins>+ self.log.debug("Sending APNS notification to {token}: id={id} payload={payload} priority={priority}",
+ token=token, id=identifier, payload=payload, priority=apnsPriority)
</ins><span class="cx">
</span><ins>+ """
+ Notification format
+
+ Top level: Command (1 byte), Frame length (4 bytes), Frame data (variable)
+ Within Frame data: Item ...
+ Item: Item number (1 byte), Item data length (2 bytes), Item data (variable)
+ Item 1: Device token (32 bytes)
+ Item 2: Payload (variable length) in JSON format, not null-terminated
+ Item 3: Notification ID (4 bytes) an opaque value used for reporting errors
+ Item 4: Expiration date (4 bytes) UNIX epoch in secondcs UTC
+ Item 5: Priority (1 byte): 10 (push sent immediately) or 5 (push sent
+ at a time that conservces power on the device receiving it)
+ """
+
+ # Frame struct.pack format
+ # ! Network byte order
+ command = self.COMMAND_PROVIDER # B
+ frameLength = ( # I
+ # Item 1 (Device token)
+ 1 + # Item number # B
+ 2 + # Item length # H
+ 32 + # device token # 32s
+ # Item 2 (Payload)
+ 1 + # Item number # B
+ 2 + # Item length # H
+ payloadLength + # the JSON payload # %d s
+ # Item 3 (Notification ID)
+ 1 + # Item number # B
+ 2 + # Item length # H
+ 4 + # Notification ID # I
+ # Item 4 (Expiration)
+ 1 + # Item number # B
+ 2 + # Item length # H
+ 4 + # Expiration seconds since epoch # I
+ # Item 5 (Priority)
+ 1 + # Item number # B
+ 2 + # Item length # H
+ 1 # Priority # B
+ )
+
</ins><span class="cx"> self.transport.write(
</span><del>- struct.pack("!BIIH32sH%ds" % (payloadLength,),
- self.COMMAND_ENHANCED, # Command
- identifier, # Identifier
- int(time.time()) + 72 * 60 * 60, # Expires in 72 hours
</del><ins>+ struct.pack("!BIBH32sBH%dsBHIBHIBHB" % (payloadLength,),
+
+ command, # Command
+ frameLength, # Frame length
+
+ 1, # Item 1 (Device token)
</ins><span class="cx"> 32, # Token Length
</span><span class="cx"> binaryToken, # Token
</span><del>- payloadLength, # Payload Length
- payload, # Payload in JSON format
</del><ins>+
+ 2, # Item 2 (Payload)
+ payloadLength, # Payload length
+ payload, # Payload
+
+ 3, # Item 3 (Notification ID)
+ 4, # Notification ID Length
+ identifier, # Notification ID
+
+ 4, # Item 4 (Expiration)
+ 4, # Expiration length
+ int(time.time()) + 72 * 60 * 60, # Expires in 72 hours
+
+ 5, # Item 5 (Priority)
+ 1, # Priority length
+ apnsPriority, # Priority
+
</ins><span class="cx"> )
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> class APNProviderFactory(ReconnectingClientFactory):
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="lines">@@ -509,12 +580,13 @@
</span><span class="cx"> # sent will be put back into the queue.
</span><span class="cx"> queued = list(self.queue)
</span><span class="cx"> self.queue = []
</span><del>- for (token, key), dataChangedTimestamp in queued:
- if token and key and dataChangedTimestamp:
- self.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+ for (token, key), dataChangedTimestamp, priority in queued:
+ if token and key and dataChangedTimestamp and priority:
+ self.sendNotification(token, key, dataChangedTimestamp,
+ priority)
</ins><span class="cx">
</span><span class="cx">
</span><del>- def scheduleNotifications(self, tokens, key, dataChangedTimestamp):
</del><ins>+ def scheduleNotifications(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> The starting point for getting notifications to the APNS server. If there is
</span><span class="cx"> a connection to the APNS server, these notifications are scheduled (or directly
</span><span class="lines">@@ -533,15 +605,15 @@
</span><span class="cx"> connection = getattr(self.factory, "connection", None)
</span><span class="cx"> if connection is not None:
</span><span class="cx"> if self.scheduler is not None:
</span><del>- self.scheduler.schedule(tokens, key, dataChangedTimestamp)
</del><ins>+ self.scheduler.schedule(tokens, key, dataChangedTimestamp, priority)
</ins><span class="cx"> else:
</span><span class="cx"> for token in tokens:
</span><del>- self.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+ self.sendNotification(token, key, dataChangedTimestamp, priority)
</ins><span class="cx"> else:
</span><del>- self._saveForWhenConnected(tokens, key, dataChangedTimestamp)
</del><ins>+ self._saveForWhenConnected(tokens, key, dataChangedTimestamp, priority)
</ins><span class="cx">
</span><span class="cx">
</span><del>- def _saveForWhenConnected(self, tokens, key, dataChangedTimestamp):
</del><ins>+ def _saveForWhenConnected(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> Called in order to save notifications that can't be sent now because there
</span><span class="cx"> is no connection to the APNS server. (token, key) tuples are appended to
</span><span class="lines">@@ -557,16 +629,16 @@
</span><span class="cx"> """
</span><span class="cx"> for token in tokens:
</span><span class="cx"> tokenKeyPair = (token, key)
</span><del>- for existingPair, ignored in self.queue:
</del><ins>+ for existingPair, timstamp, priority in self.queue:
</ins><span class="cx"> if tokenKeyPair == existingPair:
</span><span class="cx"> self.log.debug("APNProviderService has no connection; skipping duplicate: %s %s" % (token, key))
</span><span class="cx"> break # Already scheduled
</span><span class="cx"> else:
</span><span class="cx"> self.log.debug("APNProviderService has no connection; queuing: %s %s" % (token, key))
</span><del>- self.queue.append(((token, key), dataChangedTimestamp))
</del><ins>+ self.queue.append(((token, key), dataChangedTimestamp, priority))
</ins><span class="cx">
</span><span class="cx">
</span><del>- def sendNotification(self, token, key, dataChangedTimestamp):
</del><ins>+ def sendNotification(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> If there is a connection the notification is sent right away, otherwise
</span><span class="cx"> the notification is saved for later.
</span><span class="lines">@@ -579,15 +651,15 @@
</span><span class="cx"> which triggered this notification
</span><span class="cx"> @type key: C{int}
</span><span class="cx"> """
</span><del>- if not (token and key and dataChangedTimestamp):
</del><ins>+ if not (token and key and dataChangedTimestamp, priority):
</ins><span class="cx"> return
</span><span class="cx">
</span><span class="cx"> # Service has reference to factory has reference to protocol instance
</span><span class="cx"> connection = getattr(self.factory, "connection", None)
</span><span class="cx"> if connection is None:
</span><del>- self._saveForWhenConnected([token], key, dataChangedTimestamp)
</del><ins>+ self._saveForWhenConnected([token], key, dataChangedTimestamp, priority)
</ins><span class="cx"> else:
</span><del>- connection.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+ connection.sendNotification(token, key, dataChangedTimestamp, priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushnotifierpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/notifier.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/notifier.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/notifier.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> from twext.enterprise.dal.record import fromTable
</span><del>-from twext.enterprise.dal.syntax import Delete
</del><ins>+from twext.enterprise.dal.syntax import Delete, Select, Parameter
</ins><span class="cx"> from twext.enterprise.queue import WorkItem
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx">
</span><span class="lines">@@ -32,10 +32,13 @@
</span><span class="cx">
</span><span class="cx"> import datetime
</span><span class="cx">
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="cx">
</span><ins>+
+
</ins><span class="cx"> class PushNotificationWork(WorkItem, fromTable(schema.PUSH_NOTIFICATION_WORK)):
</span><span class="cx">
</span><span class="cx"> group = property(lambda self: self.pushID)
</span><span class="lines">@@ -43,14 +46,36 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def doWork(self):
</span><span class="cx">
</span><del>- # Delete all other work items with the same pushID
- yield Delete(From=self.table,
- Where=self.table.PUSH_ID == self.pushID
- ).on(self.transaction)
</del><ins>+ # Find all work items with the same push ID and find the highest
+ # priority. Delete matching work items.
+ results = (yield Select([self.table.WORK_ID, self.table.PRIORITY,
+ self.table.PUSH_ID],
+ From=self.table, Where=self.table.PUSH_ID == self.pushID).on(
+ self.transaction))
</ins><span class="cx">
</span><ins>+ maxPriority = self.priority
+
+ # If there are other enqueued work items for this push ID, find the
+ # highest priority one and use that value
+ if results:
+ workIDs = []
+ for workID, priority, pushID in results:
+ if priority > maxPriority:
+ maxPriority = priority
+ workIDs.append(workID)
+
+ # Delete the work items we selected
+ yield Delete(From=self.table,
+ Where=self.table.WORK_ID.In(
+ Parameter("workIDs", len(workIDs)))
+ ).on(self.transaction, workIDs=workIDs)
+
</ins><span class="cx"> pushDistributor = self.transaction._pushDistributor
</span><span class="cx"> if pushDistributor is not None:
</span><del>- yield pushDistributor.enqueue(self.transaction, self.pushID)
</del><ins>+ # Convert the integer priority value back into a constant
+ priority = PushPriority.lookupByValue(maxPriority)
+ yield pushDistributor.enqueue(self.transaction, self.pushID,
+ priority=priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -84,13 +109,15 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def notify(self, txn):
</del><ins>+ def notify(self, txn, priority=PushPriority.high):
</ins><span class="cx"> """
</span><span class="cx"> Send the notification. For a home object we just push using the home id. For a home
</span><span class="cx"> child we push both the owner home id and the owned home child id.
</span><span class="cx">
</span><span class="cx"> @param txn: The transaction to create the work item with
</span><span class="cx"> @type txn: L{CommonStoreTransaction}
</span><ins>+ @param priority: the priority level
+ @type priority: L{PushPriority}
</ins><span class="cx"> """
</span><span class="cx"> # Push ids from the store objects are a tuple of (prefix, name,) and we need to compose that
</span><span class="cx"> # into a single token.
</span><span class="lines">@@ -102,10 +129,13 @@
</span><span class="cx">
</span><span class="cx"> for prefix, id in ids:
</span><span class="cx"> if self._notify:
</span><del>- self.log.debug("Notifications are enabled: %s %s/%s" % (self._storeObject, prefix, id,))
- yield self._notifierFactory.send(prefix, id, txn)
</del><ins>+ self.log.debug("Notifications are enabled: %s %s/%s priority=%d" %
+ (self._storeObject, prefix, id, priority.value))
+ yield self._notifierFactory.send(prefix, id, txn,
+ priority=priority)
</ins><span class="cx"> else:
</span><del>- self.log.debug("Skipping notification for: %s %s/%s" % (self._storeObject, prefix, id,))
</del><ins>+ self.log.debug("Skipping notification for: %s %s/%s" %
+ (self._storeObject, prefix, id,))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def clone(self, storeObject):
</span><span class="lines">@@ -150,12 +180,14 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def send(self, prefix, id, txn):
</del><ins>+ def send(self, prefix, id, txn, priority=PushPriority.high):
</ins><span class="cx"> """
</span><span class="cx"> Enqueue a push notification work item on the provided transaction.
</span><span class="cx"> """
</span><span class="cx"> notBefore = datetime.datetime.utcnow() + datetime.timedelta(seconds=self.coalesceSeconds)
</span><del>- yield txn.enqueue(PushNotificationWork, pushID=self.pushKeyForId(prefix, id), notBefore=notBefore)
</del><ins>+ yield txn.enqueue(PushNotificationWork,
+ pushID=self.pushKeyForId(prefix, id), notBefore=notBefore,
+ priority=priority.value)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def newNotifier(self, storeObject):
</span><span class="lines">@@ -212,7 +244,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def enqueue(self, transaction, pushKey):
</del><ins>+ def enqueue(self, transaction, pushKey, priority=PushPriority.high):
</ins><span class="cx"> """
</span><span class="cx"> Pass along enqueued pushKey to any observers
</span><span class="cx">
</span><span class="lines">@@ -221,6 +253,10 @@
</span><span class="cx">
</span><span class="cx"> @param pushKey: the push key to distribute to the observers
</span><span class="cx"> @type pushKey: C{str}
</span><ins>+
+ @param priority: the priority level
+ @type priority: L{PushPriority}
</ins><span class="cx"> """
</span><span class="cx"> for observer in self.observers:
</span><del>- yield observer.enqueue(transaction, pushKey)
</del><ins>+ yield observer.enqueue(transaction, pushKey,
+ dataChangedTimestamp=None, priority=priority)
</ins></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_amppushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_amppush.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_amppush.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_amppush.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -18,6 +18,7 @@
</span><span class="cx"> from calendarserver.push.amppush import NotificationForID
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><span class="cx"> from twisted.internet.task import Clock
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx">
</span><span class="cx"> class AMPPushMasterTests(StoreTestCase):
</span><span class="cx">
</span><span class="lines">@@ -57,27 +58,81 @@
</span><span class="cx"> self.assertTrue(client3.subscribedToID("/CalDAV/localhost/user03/"))
</span><span class="cx">
</span><span class="cx"> dataChangedTimestamp = 1354815999
</span><del>- service.enqueue(None, "/CalDAV/localhost/user01/", dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ service.enqueue(None, "/CalDAV/localhost/user01/",
+ dataChangedTimestamp=dataChangedTimestamp,
+ priority=PushPriority.high)
</ins><span class="cx"> self.assertEquals(len(client1.history), 0)
</span><span class="cx"> self.assertEquals(len(client2.history), 0)
</span><span class="cx"> self.assertEquals(len(client3.history), 0)
</span><span class="cx"> clock.advance(1)
</span><del>- self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+ self.assertEquals(
+ client1.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.high.value,
+ }
+ )
+ ]
+ )
</ins><span class="cx"> self.assertEquals(len(client2.history), 0)
</span><span class="cx"> self.assertEquals(len(client3.history), 0)
</span><span class="cx"> clock.advance(3)
</span><del>- self.assertEquals(client2.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+ self.assertEquals(
+ client2.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.high.value,
+ }
+ )
+ ]
+ )
+
</ins><span class="cx"> self.assertEquals(len(client3.history), 0)
</span><span class="cx"> clock.advance(3)
</span><del>- self.assertEquals(client3.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+ self.assertEquals(
+ client3.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.high.value,
+ }
+ )
+ ]
+ )
</ins><span class="cx">
</span><span class="cx"> client1.reset()
</span><span class="cx"> client2.reset()
</span><span class="cx"> client2.unsubscribe("token2", "/CalDAV/localhost/user01/")
</span><del>- service.enqueue(None, "/CalDAV/localhost/user01/", dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ service.enqueue(None, "/CalDAV/localhost/user01/",
+ dataChangedTimestamp=dataChangedTimestamp,
+ priority=PushPriority.low)
</ins><span class="cx"> self.assertEquals(len(client1.history), 0)
</span><span class="cx"> clock.advance(1)
</span><del>- self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
</del><ins>+ self.assertEquals(
+ client1.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.low.value,
+ }
+ )
+ ]
+ )
+
</ins><span class="cx"> self.assertEquals(len(client2.history), 0)
</span><span class="cx"> clock.advance(3)
</span><span class="cx"> self.assertEquals(len(client2.history), 0)
</span><span class="lines">@@ -87,9 +142,35 @@
</span><span class="cx"> client1.reset()
</span><span class="cx"> client2.reset()
</span><span class="cx"> client2.subscribe("token2", "/CalDAV/localhost/user01/")
</span><del>- service.enqueue(None, "/CalDAV/localhost/user01/", dataChangedTimestamp=dataChangedTimestamp)
- self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
- self.assertEquals(client2.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
</del><ins>+ service.enqueue(None, "/CalDAV/localhost/user01/",
+ dataChangedTimestamp=dataChangedTimestamp,
+ priority=PushPriority.medium)
+ self.assertEquals(
+ client1.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.medium.value,
+ }
+ )
+ ]
+ )
+ self.assertEquals(
+ client2.history,
+ [
+ (
+ NotificationForID,
+ {
+ 'id' : '/CalDAV/localhost/user01/',
+ 'dataChangedTimestamp' : 1354815999,
+ 'priority' : PushPriority.medium.value,
+ }
+ )
+ ]
+ )
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_applepushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_applepush.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_applepush.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_applepush.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -18,14 +18,15 @@
</span><span class="cx"> import struct
</span><span class="cx"> import time
</span><span class="cx"> from calendarserver.push.applepush import (
</span><del>- ApplePushNotifierService, APNProviderProtocol
</del><ins>+ ApplePushNotifierService, APNProviderProtocol, ApplePushPriority
</ins><span class="cx"> )
</span><del>-from calendarserver.push.util import validToken, TokenHistory
</del><ins>+from calendarserver.push.util import validToken, TokenHistory, PushPriority
</ins><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, succeed
</span><span class="cx"> from twisted.internet.task import Clock
</span><span class="cx"> from txdav.common.icommondatastore import InvalidSubscriptionValues
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> class ApplePushNotifierServiceTests(StoreTestCase):
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="lines">@@ -120,12 +121,14 @@
</span><span class="cx"> dataChangedTimestamp = 1354815999
</span><span class="cx"> txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx"> yield service.enqueue(txn, "/CalDAV/calendars.example.com/user01/calendar/",
</span><del>- dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+ dataChangedTimestamp=dataChangedTimestamp, priority=PushPriority.high)
</ins><span class="cx"> yield txn.commit()
</span><span class="cx">
</span><span class="cx"> # The notifications should be in the queue
</span><del>- self.assertTrue(((token, key1), dataChangedTimestamp) in service.providers["CalDAV"].queue)
- self.assertTrue(((token2, key1), dataChangedTimestamp) in service.providers["CalDAV"].queue)
</del><ins>+ self.assertTrue(((token, key1), dataChangedTimestamp, PushPriority.high)
+ in service.providers["CalDAV"].queue)
+ self.assertTrue(((token2, key1), dataChangedTimestamp, PushPriority.high)
+ in service.providers["CalDAV"].queue)
</ins><span class="cx">
</span><span class="cx"> # Start the service, making the connection which should service the
</span><span class="cx"> # queue
</span><span class="lines">@@ -137,17 +140,40 @@
</span><span class="cx"> # Verify data sent to APN
</span><span class="cx"> providerConnector = service.providers["CalDAV"].testConnector
</span><span class="cx"> rawData = providerConnector.transport.data
</span><del>- self.assertEquals(len(rawData), 183)
- data = struct.unpack("!BIIH32sH", rawData[:45])
- self.assertEquals(data[0], 1) # command
- self.assertEquals(data[4].encode("hex"), token.replace(" ", "")) # token
- payloadLength = data[5]
- payload = struct.unpack("%ds" % (payloadLength,),
- rawData[45:])
</del><ins>+ self.assertEquals(len(rawData), 199)
+ data = struct.unpack("!BI", rawData[:5])
+ self.assertEquals(data[0], 2) # command
+ self.assertEquals(data[1], 194) # frame length
+ # Item 1 (device token)
+ data = struct.unpack("!BH32s", rawData[5:40])
+ self.assertEquals(data[0], 1)
+ self.assertEquals(data[1], 32)
+ self.assertEquals(data[2].encode("hex"), token.replace(" ", "")) # token
+ # Item 2 (payload)
+ data = struct.unpack("!BH", rawData[40:43])
+ self.assertEquals(data[0], 2)
+ payloadLength = data[1]
+ self.assertEquals(payloadLength, 138)
+ payload = struct.unpack("!%ds" % (payloadLength,), rawData[43:181])
</ins><span class="cx"> payload = json.loads(payload[0])
</span><span class="cx"> self.assertEquals(payload["key"], u"/CalDAV/calendars.example.com/user01/calendar/")
</span><span class="cx"> self.assertEquals(payload["dataChangedTimestamp"], dataChangedTimestamp)
</span><span class="cx"> self.assertTrue("pushRequestSubmittedTimestamp" in payload)
</span><ins>+ # Item 3 (notification id)
+ data = struct.unpack("!BHI", rawData[181:188])
+ self.assertEquals(data[0], 3)
+ self.assertEquals(data[1], 4)
+ self.assertEquals(data[2], 2)
+ # Item 4 (expiration)
+ data = struct.unpack("!BHI", rawData[188:195])
+ self.assertEquals(data[0], 4)
+ self.assertEquals(data[1], 4)
+ # Item 5 (priority)
+ data = struct.unpack("!BHB", rawData[195:199])
+ self.assertEquals(data[0], 5)
+ self.assertEquals(data[1], 1)
+ self.assertEquals(data[2], ApplePushPriority.high.value)
+
</ins><span class="cx"> # Verify token history is updated
</span><span class="cx"> self.assertTrue(token in [t for (_ignore_i, t) in providerConnector.service.protocol.history.history])
</span><span class="cx"> self.assertTrue(token2 in [t for (_ignore_i, t) in providerConnector.service.protocol.history.history])
</span><span class="lines">@@ -160,14 +186,21 @@
</span><span class="cx"> providerConnector.transport.data = None
</span><span class="cx"> # Send notification while service is connected
</span><span class="cx"> txn = self._sqlCalendarStore.newTransaction()
</span><del>- yield service.enqueue(txn, "/CalDAV/calendars.example.com/user01/calendar/")
</del><ins>+ yield service.enqueue(txn, "/CalDAV/calendars.example.com/user01/calendar/",
+ priority=PushPriority.low)
</ins><span class="cx"> yield txn.commit()
</span><span class="cx"> clock.advance(1) # so that first push is sent
</span><del>- self.assertEquals(len(providerConnector.transport.data), 183)
</del><ins>+ self.assertEquals(len(providerConnector.transport.data), 199)
+ # Ensure that the priority is "low"
+ data = struct.unpack("!BHB", providerConnector.transport.data[195:199])
+ self.assertEquals(data[0], 5)
+ self.assertEquals(data[1], 1)
+ self.assertEquals(data[2], ApplePushPriority.low.value)
+
</ins><span class="cx"> # Reset sent data
</span><span class="cx"> providerConnector.transport.data = None
</span><span class="cx"> clock.advance(3) # so that second push is sent
</span><del>- self.assertEquals(len(providerConnector.transport.data), 183)
</del><ins>+ self.assertEquals(len(providerConnector.transport.data), 199)
</ins><span class="cx">
</span><span class="cx"> history = []
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushtesttest_notifierpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_notifier.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_notifier.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/test/test_notifier.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -22,6 +22,8 @@
</span><span class="cx"> from twistedcaldav.config import ConfigDict
</span><span class="cx"> from txdav.common.datastore.test.util import populateCalendarsFrom
</span><span class="cx"> from txdav.common.datastore.sql_tables import _BIND_MODE_WRITE
</span><ins>+from calendarserver.push.util import PushPriority
+from txdav.idav import ChangeCategory
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> class StubService(object):
</span><span class="lines">@@ -33,8 +35,9 @@
</span><span class="cx"> self.history = []
</span><span class="cx">
</span><span class="cx">
</span><del>- def enqueue(self, transaction, id):
- self.history.append(id)
</del><ins>+ def enqueue(self, transaction, id, dataChangedTimestamp=None,
+ priority=None):
+ self.history.append((id, priority))
</ins><span class="cx"> return(succeed(None))
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -45,8 +48,8 @@
</span><span class="cx"> def test_enqueue(self):
</span><span class="cx"> stub = StubService()
</span><span class="cx"> dist = PushDistributor([stub])
</span><del>- yield dist.enqueue(None, "testing")
- self.assertEquals(stub.history, ["testing"])
</del><ins>+ yield dist.enqueue(None, "testing", PushPriority.high)
+ self.assertEquals(stub.history, [("testing", PushPriority.high)])
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def test_getPubSubAPSConfiguration(self):
</span><span class="lines">@@ -91,8 +94,9 @@
</span><span class="cx"> self.history = []
</span><span class="cx">
</span><span class="cx">
</span><del>- def enqueue(self, transaction, pushID):
- self.history.append(pushID)
</del><ins>+ def enqueue(self, transaction, pushID, dataChangedTimestamp=None,
+ priority=None):
+ self.history.append((pushID, priority))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -111,35 +115,62 @@
</span><span class="cx"> txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx"> wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx"> pushID="/CalDAV/localhost/foo/",
</span><ins>+ priority=PushPriority.high.value
</ins><span class="cx"> ))
</span><span class="cx"> yield txn.commit()
</span><span class="cx"> yield wp.whenExecuted()
</span><del>- self.assertEquals(pushDistributor.history, ["/CalDAV/localhost/foo/"])
</del><ins>+ self.assertEquals(pushDistributor.history,
+ [("/CalDAV/localhost/foo/", PushPriority.high)])
</ins><span class="cx">
</span><span class="cx"> pushDistributor.reset()
</span><span class="cx"> txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx"> wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx"> pushID="/CalDAV/localhost/bar/",
</span><ins>+ priority=PushPriority.high.value
</ins><span class="cx"> ))
</span><span class="cx"> wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx"> pushID="/CalDAV/localhost/bar/",
</span><ins>+ priority=PushPriority.high.value
</ins><span class="cx"> ))
</span><span class="cx"> wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx"> pushID="/CalDAV/localhost/bar/",
</span><ins>+ priority=PushPriority.high.value
</ins><span class="cx"> ))
</span><span class="cx"> # Enqueue a different pushID to ensure those are not grouped with
</span><span class="cx"> # the others:
</span><span class="cx"> wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx"> pushID="/CalDAV/localhost/baz/",
</span><ins>+ priority=PushPriority.high.value
</ins><span class="cx"> ))
</span><span class="cx">
</span><span class="cx"> yield txn.commit()
</span><span class="cx"> yield wp.whenExecuted()
</span><ins>+ self.assertEquals(set(pushDistributor.history),
+ set([("/CalDAV/localhost/bar/", PushPriority.high),
+ ("/CalDAV/localhost/baz/", PushPriority.high)]))
+
+ # Ensure only the high-water-mark priority push goes out, by
+ # enqueuing low, medium, and high notifications
+ pushDistributor.reset()
+ txn = self._sqlCalendarStore.newTransaction()
+ wp = (yield txn.enqueue(PushNotificationWork,
+ pushID="/CalDAV/localhost/bar/",
+ priority=PushPriority.low.value
+ ))
+ wp = (yield txn.enqueue(PushNotificationWork,
+ pushID="/CalDAV/localhost/bar/",
+ priority=PushPriority.high.value
+ ))
+ wp = (yield txn.enqueue(PushNotificationWork,
+ pushID="/CalDAV/localhost/bar/",
+ priority=PushPriority.medium.value
+ ))
+ yield txn.commit()
+ yield wp.whenExecuted()
</ins><span class="cx"> self.assertEquals(pushDistributor.history,
</span><del>- ["/CalDAV/localhost/bar/", "/CalDAV/localhost/baz/"])
</del><ins>+ [("/CalDAV/localhost/bar/", PushPriority.high)])
</ins><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> class NotifierFactory(StoreTestCase):
</span><span class="cx">
</span><span class="cx"> requirements = {
</span><span class="lines">@@ -168,8 +199,9 @@
</span><span class="cx"> def test_homeNotifier(self):
</span><span class="cx">
</span><span class="cx"> home = yield self.homeUnderTest()
</span><del>- yield home.notifyChanged()
- self.assertEquals(self.notifierFactory.history, ["/CalDAV/example.com/home1/"])
</del><ins>+ yield home.notifyChanged(category=ChangeCategory.default)
+ self.assertEquals(self.notifierFactory.history,
+ [("/CalDAV/example.com/home1/", PushPriority.high)])
</ins><span class="cx"> yield self.commit()
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -177,10 +209,12 @@
</span><span class="cx"> def test_calendarNotifier(self):
</span><span class="cx">
</span><span class="cx"> calendar = yield self.calendarUnderTest()
</span><del>- yield calendar.notifyChanged()
</del><ins>+ yield calendar.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><del>- set(["/CalDAV/example.com/home1/", "/CalDAV/example.com/home1/calendar_1/"])
</del><ins>+ set([
+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high)])
</ins><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="cx">
</span><span class="lines">@@ -194,9 +228,9 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
- "/CalDAV/example.com/home2/"
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
+ ("/CalDAV/example.com/home2/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -207,9 +241,9 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
- "/CalDAV/example.com/home2/"
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
+ ("/CalDAV/example.com/home2/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -225,10 +259,12 @@
</span><span class="cx"> self.notifierFactory.reset()
</span><span class="cx">
</span><span class="cx"> shared = yield self.calendarUnderTest(home="home2", name=shareName)
</span><del>- yield shared.notifyChanged()
</del><ins>+ yield shared.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><del>- set(["/CalDAV/example.com/home1/", "/CalDAV/example.com/home1/calendar_1/"])
</del><ins>+ set([
+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high)])
</ins><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="cx">
</span><span class="lines">@@ -237,9 +273,11 @@
</span><span class="cx"> def test_notificationNotifier(self):
</span><span class="cx">
</span><span class="cx"> notifications = yield self.transactionUnderTest().notificationsWithUID("home1")
</span><del>- yield notifications.notifyChanged()
</del><ins>+ yield notifications.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><del>- set(["/CalDAV/example.com/home1/", "/CalDAV/example.com/home1/notification/"])
</del><ins>+ set([
+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/notification/", PushPriority.high)])
</ins><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarserverpushutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/util.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/util.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/push/util.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -16,7 +16,20 @@
</span><span class="cx">
</span><span class="cx"> from OpenSSL import crypto
</span><span class="cx"> from twext.python.log import Logger
</span><ins>+from twisted.python.constants import Values, ValueConstant
</ins><span class="cx">
</span><ins>+
+
+class PushPriority(Values):
+ """
+ Constants to use for push priorities
+ """
+ low = ValueConstant(1)
+ medium = ValueConstant(5)
+ high = ValueConstant(10)
+
+
+
</ins><span class="cx"> def getAPNTopicFromCertificate(certPath):
</span><span class="cx"> """
</span><span class="cx"> Given the path to a certificate, extract the UID value portion of the
</span><span class="lines">@@ -128,7 +141,7 @@
</span><span class="cx"> self.staggerSeconds = staggerSeconds
</span><span class="cx">
</span><span class="cx">
</span><del>- def schedule(self, tokens, key, dataChangedTimestamp):
</del><ins>+ def schedule(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> Schedules a batch of notifications for the given tokens, staggered
</span><span class="cx"> with self.staggerSeconds between each one. Duplicates are ignored,
</span><span class="lines">@@ -151,13 +164,14 @@
</span><span class="cx"> (internalKey,))
</span><span class="cx"> else:
</span><span class="cx"> self.outstanding[internalKey] = self.reactor.callLater(
</span><del>- scheduleTime, self.send, token, key, dataChangedTimestamp)
</del><ins>+ scheduleTime, self.send, token, key, dataChangedTimestamp,
+ priority)
</ins><span class="cx"> self.log.debug("PushScheduler scheduled: %s in %.0f sec" %
</span><span class="cx"> (internalKey, scheduleTime))
</span><span class="cx"> scheduleTime += self.staggerSeconds
</span><span class="cx">
</span><span class="cx">
</span><del>- def send(self, token, key, dataChangedTimestamp):
</del><ins>+ def send(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx"> """
</span><span class="cx"> This method is what actually gets scheduled. Its job is to remove
</span><span class="cx"> its corresponding entry from the outstanding dict and call the
</span><span class="lines">@@ -173,7 +187,7 @@
</span><span class="cx"> """
</span><span class="cx"> self.log.debug("PushScheduler fired for %s %s %d" % (token, key, dataChangedTimestamp))
</span><span class="cx"> del self.outstanding[(token, key)]
</span><del>- return self.callback(token, key, dataChangedTimestamp)
</del><ins>+ return self.callback(token, key, dataChangedTimestamp, priority)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def stop(self):
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolsampnotificationspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/ampnotifications.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/ampnotifications.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/ampnotifications.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -141,8 +141,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def notificationCallback(id, dataChangedTimestamp):
- print("Received notification for:", id)
</del><ins>+def notificationCallback(id, dataChangedTimestamp, priority):
+ print("Received notification for:", id, "Priority", priority)
</ins><span class="cx"> return succeed(True)
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolsgatewaypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/gateway.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/gateway.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/gateway.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -142,7 +142,6 @@
</span><span class="cx"> utilityMain(configFileName, RunnerService, verbose=debug)
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> class Runner(object):
</span><span class="cx">
</span><span class="cx"> def __init__(self, root, directory, store, commands, output=None):
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devcalendarservertoolstesttest_gatewaypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/test/test_gateway.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/test/test_gateway.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/calendarserver/tools/test/test_gateway.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -219,6 +219,7 @@
</span><span class="cx"> self.assertEquals(record.extras["comment"], "Test Comment")
</span><span class="cx"> self.assertEquals(record.extras["floor"], "First")
</span><span class="cx"> self.assertEquals(record.extras["capacity"], "40")
</span><ins>+ self.assertEquals(record.extras["geo"], "geo:37.331,-122.030")
</ins><span class="cx">
</span><span class="cx"> results = yield self.runCommand(command_getLocationAttributes)
</span><span class="cx"> self.assertEquals(set(results["result"]["ReadProxies"]), set(['user03', 'user04']))
</span><span class="lines">@@ -457,6 +458,8 @@
</span><span class="cx"> <string>40</string>
</span><span class="cx"> <key>AssociatedAddress</key>
</span><span class="cx"> <string>C701069D-9CA1-4925-A1A9-5CD94767B74B</string>
</span><ins>+ <key>Geo</key>
+ <string>geo:37.331,-122.030</string>
</ins><span class="cx"> <key>ReadProxies</key>
</span><span class="cx"> <array>
</span><span class="cx"> <string>users:user03</string>
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcaldavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/sql.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/sql.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/sql.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx"> from pycalendar.duration import PyCalendarDuration
</span><span class="cx"> from pycalendar.timezone import PyCalendarTimezone
</span><span class="cx"> from pycalendar.value import PyCalendarValue
</span><ins>+from txdav.idav import ChangeCategory
</ins><span class="cx">
</span><span class="cx"> from zope.interface.declarations import implements
</span><span class="cx">
</span><span class="lines">@@ -2284,8 +2285,18 @@
</span><span class="cx"> else:
</span><span class="cx"> yield self._calendar._updateRevision(self._name)
</span><span class="cx">
</span><del>- yield self._calendar.notifyChanged()
</del><ins>+ # Determine change category
+ category = ChangeCategory.default
+ if internal_state == ComponentUpdateState.INBOX:
+ category = ChangeCategory.inbox
+ elif internal_state == ComponentUpdateState.ORGANIZER_ITIP_UPDATE:
+ category = ChangeCategory.organizerITIPUpdate
+ elif (internal_state == ComponentUpdateState.ATTENDEE_ITIP_UPDATE and
+ hasattr(self._txn, "doing_attende_refresh")):
+ category = ChangeCategory.attendeeITIPUpdate
</ins><span class="cx">
</span><ins>+ yield self._calendar.notifyChanged(category=category)
+
</ins><span class="cx"> # Finally check if a split is needed
</span><span class="cx"> if internal_state not in (ComponentUpdateState.SPLIT_OWNER, ComponentUpdateState.SPLIT_ATTENDEE,) and schedule_state == "organizer":
</span><span class="cx"> yield self.checkSplit()
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcaldavdatastoretestcommonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/test/common.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/test/common.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/caldav/datastore/test/common.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -53,7 +53,9 @@
</span><span class="cx"> from txdav.common.icommondatastore import ConcurrentModification
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from twistedcaldav.config import config
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> storePath = FilePath(__file__).parent().child("calendar_store")
</span><span class="cx">
</span><span class="cx"> homeRoot = storePath.child("ho").child("me").child("home1")
</span><span class="lines">@@ -456,8 +458,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/notification/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/notification/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -474,8 +476,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/notification/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/notification/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -698,7 +700,7 @@
</span><span class="cx"> calendarProperties = (yield home.calendarWithName(name)).properties()
</span><span class="cx"> self.assertEqual(len(calendarProperties), 0)
</span><span class="cx"> # notify is called prior to commit
</span><del>- self.assertTrue("/CalDAV/example.com/home1/" in self.notifierFactory.history)
</del><ins>+ self.assertTrue(("/CalDAV/example.com/home1/", PushPriority.high) in self.notifierFactory.history)
</ins><span class="cx"> yield self.commit()
</span><span class="cx">
</span><span class="cx"> # Make sure it's available in a new transaction; i.e. test the commit.
</span><span class="lines">@@ -741,10 +743,10 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
- "/CalDAV/example.com/home1/calendar_2/",
- "/CalDAV/example.com/home1/calendar_empty/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_2/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_empty/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -918,8 +920,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -1474,8 +1476,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span><span class="lines">@@ -1593,8 +1595,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CalDAV/example.com/home1/",
- "/CalDAV/example.com/home1/calendar_1/",
</del><ins>+ ("/CalDAV/example.com/home1/", PushPriority.high),
+ ("/CalDAV/example.com/home1/calendar_1/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx"> yield self.commit()
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcarddavdatastoretestcommonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/carddav/datastore/test/common.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/carddav/datastore/test/common.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/carddav/datastore/test/common.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -39,7 +39,9 @@
</span><span class="cx"> from txdav.common.icommondatastore import ObjectResourceNameAlreadyExistsError
</span><span class="cx"> from txdav.idav import IPropertyStore, IDataStore
</span><span class="cx"> from txdav.xml.element import WebDAVUnknownElement
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> storePath = FilePath(__file__).parent().child("addressbook_store")
</span><span class="cx">
</span><span class="cx"> home1Root = storePath.child("ho").child("me").child("home1")
</span><span class="lines">@@ -372,7 +374,7 @@
</span><span class="cx"> yield home.removeAddressBookWithName(name)
</span><span class="cx"> self.assertNotIdentical((yield home.addressbookWithName(name)), None)
</span><span class="cx"> # notify is called prior to commit
</span><del>- self.assertTrue("/CardDAV/example.com/home1/" in self.notifierFactory.history)
</del><ins>+ self.assertTrue(("/CardDAV/example.com/home1/", PushPriority.high) in self.notifierFactory.history)
</ins><span class="cx"> yield self.commit()
</span><span class="cx">
</span><span class="cx"> # Make sure it's available in a new transaction; i.e. test the commit.
</span><span class="lines">@@ -399,8 +401,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook/",
</del><ins>+ ("/CardDAV/example.com/home1/", PushPriority.high),
+ ("/CardDAV/example.com/home1/addressbook/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -532,8 +534,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook/",
</del><ins>+ ("/CardDAV/example.com/home1/", PushPriority.high),
+ ("/CardDAV/example.com/home1/addressbook/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -693,8 +695,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook/",
</del><ins>+ ("/CardDAV/example.com/home1/", PushPriority.high),
+ ("/CardDAV/example.com/home1/addressbook/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -809,8 +811,8 @@
</span><span class="cx"> self.assertEquals(
</span><span class="cx"> set(self.notifierFactory.history),
</span><span class="cx"> set([
</span><del>- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook/",
</del><ins>+ ("/CardDAV/example.com/home1/", PushPriority.high),
+ ("/CardDAV/example.com/home1/addressbook/", PushPriority.high),
</ins><span class="cx"> ])
</span><span class="cx"> )
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx"> from txdav.common.inotifications import INotificationCollection, \
</span><span class="cx"> INotificationObject
</span><span class="cx"> from txdav.xml.parser import WebDAVDocument
</span><ins>+from txdav.idav import ChangeCategory
</ins><span class="cx">
</span><span class="cx"> from uuid import uuid4, UUID
</span><span class="cx">
</span><span class="lines">@@ -2245,7 +2246,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def notifyChanged(self):
</del><ins>+ def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx"> """
</span><span class="cx"> Send notifications, change sync token and bump last modified because
</span><span class="cx"> the resource has changed. We ensure we only do this once per object
</span><span class="lines">@@ -2269,7 +2270,7 @@
</span><span class="cx"> # push notifiers add their work items immediately
</span><span class="cx"> notifier = self._notifiers.get("push", None)
</span><span class="cx"> if notifier:
</span><del>- yield notifier.notify(self._txn)
</del><ins>+ yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @classproperty
</span><span class="lines">@@ -4306,11 +4307,11 @@
</span><span class="cx"> return self.ownerHome().notifierID()
</span><span class="cx">
</span><span class="cx">
</span><del>- def notifyChanged(self):
</del><ins>+ def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx"> """
</span><span class="cx"> Send notifications when a child resource is changed.
</span><span class="cx"> """
</span><del>- return self._notifyChanged(property_change=False)
</del><ins>+ return self._notifyChanged(property_change=False, category=category)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def notifyPropertyChanged(self):
</span><span class="lines">@@ -4321,7 +4322,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def _notifyChanged(self, property_change=False):
</del><ins>+ def _notifyChanged(self, property_change=False,
+ category=ChangeCategory.default):
</ins><span class="cx"> """
</span><span class="cx"> Send notifications, change sync token and bump last modified because
</span><span class="cx"> the resource has changed. We ensure we only do this once per object
</span><span class="lines">@@ -4357,7 +4359,7 @@
</span><span class="cx"> # push notifiers add their work items immediately
</span><span class="cx"> notifier = self._notifiers.get("push", None)
</span><span class="cx"> if notifier:
</span><del>- yield notifier.notify(self._txn)
</del><ins>+ yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @classproperty
</span><span class="lines">@@ -5171,7 +5173,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def notifyChanged(self):
</del><ins>+ def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx"> """
</span><span class="cx"> Send notifications, change sync token and bump last modified because
</span><span class="cx"> the resource has changed. We ensure we only do this once per object
</span><span class="lines">@@ -5190,7 +5192,7 @@
</span><span class="cx"> # push notifiers add their work items immediately
</span><span class="cx"> notifier = self._notifiers.get("push", None)
</span><span class="cx"> if notifier:
</span><del>- yield notifier.notify(self._txn)
</del><ins>+ yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx">
</span><span class="cx"> returnValue(None)
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresql_schemacurrentoracledialectsql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current-oracle-dialect.sql (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current-oracle-dialect.sql        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current-oracle-dialect.sql        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -346,7 +346,8 @@
</span><span class="cx"> create table PUSH_NOTIFICATION_WORK (
</span><span class="cx"> "WORK_ID" integer primary key not null,
</span><span class="cx"> "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
</span><del>- "PUSH_ID" nvarchar2(255)
</del><ins>+ "PUSH_ID" nvarchar2(255),
+ "PRIORITY" integer not null
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> create table GROUP_CACHER_POLLING_WORK (
</span><span class="lines">@@ -365,7 +366,7 @@
</span><span class="cx"> "VALUE" nvarchar2(255)
</span><span class="cx"> );
</span><span class="cx">
</span><del>-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '27');
</del><ins>+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '28');
</ins><span class="cx"> insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
</span><span class="cx"> insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
</span><span class="cx"> create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoresql_schemacurrentsql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current.sql (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current.sql        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/sql_schema/current.sql        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -663,7 +663,8 @@
</span><span class="cx"> create table PUSH_NOTIFICATION_WORK (
</span><span class="cx"> WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
</span><span class="cx"> NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
</span><del>- PUSH_ID varchar(255) not null
</del><ins>+ PUSH_ID varchar(255) not null,
+ PRIORITY integer not null -- 1:low 5:medium 10:high
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> -----------------
</span><span class="lines">@@ -698,6 +699,6 @@
</span><span class="cx"> VALUE varchar(255)
</span><span class="cx"> );
</span><span class="cx">
</span><del>-insert into CALENDARSERVER values ('VERSION', '27');
</del><ins>+insert into CALENDARSERVER values ('VERSION', '28');
</ins><span class="cx"> insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
</span><span class="cx"> insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavcommondatastoretestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/test/util.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/test/util.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/common/datastore/test/util.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -733,8 +733,8 @@
</span><span class="cx"> return "/%s/%s/%s/" % (prefix, self.hostname, id)
</span><span class="cx">
</span><span class="cx">
</span><del>- def send(self, prefix, id, txn):
- self.history.append(self.pushKeyForId(prefix, id))
</del><ins>+ def send(self, prefix, id, txn, priority):
+ self.history.append((self.pushKeyForId(prefix, id), priority))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def reset(self):
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer52devtxdavidavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/idav.py (12272 => 12273)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/idav.py        2014-01-08 22:13:14 UTC (rev 12272)
+++ CalendarServer/branches/release/CalendarServer-5.2-dev/txdav/idav.py        2014-01-08 22:20:19 UTC (rev 12273)
</span><span class="lines">@@ -34,6 +34,9 @@
</span><span class="cx"> from zope.interface import Attribute, Interface
</span><span class="cx"> from zope.interface.common.mapping import IMapping
</span><span class="cx">
</span><ins>+from twisted.python.constants import Values, ValueConstant
+from calendarserver.push.util import PushPriority
+
</ins><span class="cx"> #
</span><span class="cx"> # Exceptions
</span><span class="cx"> #
</span><span class="lines">@@ -231,6 +234,19 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+class ChangeCategory(Values):
+ """
+ Constants to use for notifyChanged's category parameter. Maps
+ types of changes to the appropriate push priority level.
+ TODO: make these values configurable in plist perhaps.
+ """
+ default = ValueConstant(PushPriority.high)
+ inbox = ValueConstant(PushPriority.medium)
+ attendeeITIPUpdate = ValueConstant(PushPriority.medium)
+ organizerITIPUpdate = ValueConstant(PushPriority.medium)
+
+
+
</ins><span class="cx"> class INotifier(Interface):
</span><span class="cx"> """
</span><span class="cx"> Interface for an object that can send change notifications. Notifiers are associated with specific notifier factories
</span><span class="lines">@@ -260,9 +276,12 @@
</span><span class="cx"> @rtype: L{IStoreNotifier} or C{None}
</span><span class="cx"> """
</span><span class="cx">
</span><del>- def notifyChanged(): #@NoSelf
</del><ins>+ def notifyChanged(category): #@NoSelf
</ins><span class="cx"> """
</span><span class="cx"> Send a change notification to any notifiers assigned to the object.
</span><ins>+
+ @param category: the kind of change triggering this notification
+ @type: L{ChangeCategory}
</ins><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> def notifierID(): #@NoSelf
</span></span></pre>
</div>
</div>
</body>
</html>