[CalendarServer-changes] [6166] CalendarServer/trunk/txcaldav/calendarstore
source_changes at macosforge.org
source_changes at macosforge.org
Fri Aug 20 15:57:15 PDT 2010
Revision: 6166
http://trac.macosforge.org/projects/calendarserver/changeset/6166
Author: sagen at apple.com
Date: 2010-08-20 15:57:14 -0700 (Fri, 20 Aug 2010)
Log Message:
-----------
Copied sharing and invite db code from calendars to addressbook.
Modified Paths:
--------------
CalendarServer/trunk/txcaldav/calendarstore/postgres.py
CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql
Modified: CalendarServer/trunk/txcaldav/calendarstore/postgres.py
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/postgres.py 2010-08-20 21:32:52 UTC (rev 6165)
+++ CalendarServer/trunk/txcaldav/calendarstore/postgres.py 2010-08-20 22:57:14 UTC (rev 6166)
@@ -2575,7 +2575,306 @@
)
+class PostgresLegacyABInvitesEmulator(object):
+ """
+ Emulator for the implicit interface specified by
+ L{twistedcaldav.sharing.InvitesDatabase}.
+ """
+
+ def __init__(self, addressbook):
+ self._addressbook = addressbook
+
+
+ @property
+ def _txn(self):
+ return self._addressbook._txn
+
+
+ def create(self):
+ "No-op, because the index implicitly always exists in the database."
+
+
+ def remove(self):
+ "No-op, because the index implicitly always exists in the database."
+
+
+ def allRecords(self):
+ for row in self._txn.execSQL(
+ """
+ select
+ INVITE.INVITE_UID, INVITE.NAME, INVITE.RECIPIENT_ADDRESS,
+ ADDRESSBOOK_HOME.OWNER_UID, ADDRESSBOOK_BIND.BIND_MODE,
+ ADDRESSBOOK_BIND.BIND_STATUS, ADDRESSBOOK_BIND.MESSAGE
+ from
+ INVITE, ADDRESSBOOK_HOME, ADDRESSBOOK_BIND
+ where
+ INVITE.RESOURCE_ID = %s and
+ INVITE.HOME_RESOURCE_ID =
+ ADDRESSBOOK_HOME.RESOURCE_ID and
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID =
+ INVITE.RESOURCE_ID and
+ ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID =
+ INVITE.HOME_RESOURCE_ID
+ order by
+ INVITE.NAME asc
+ """, [self._addressbook._resourceID]):
+ [inviteuid, common_name, userid, ownerUID,
+ bindMode, bindStatus, summary] = row
+ # FIXME: this is really the responsibility of the protocol layer.
+ state = {
+ _BIND_STATUS_INVITED: "NEEDS-ACTION",
+ _BIND_STATUS_ACCEPTED: "ACCEPTED",
+ _BIND_STATUS_DECLINED: "DECLINED",
+ _BIND_STATUS_INVALID: "INVALID",
+ }[bindStatus]
+ access = {
+ _BIND_MODE_READ: "read-only",
+ _BIND_MODE_WRITE: "read-write"
+ }[bindMode]
+ principalURL = "/principals/__uids__/%s/" % (ownerUID,)
+ yield Invite(
+ inviteuid, userid, principalURL, common_name,
+ access, state, summary
+ )
+
+
+ def recordForUserID(self, userid):
+ for record in self.allRecords():
+ if record.userid == userid:
+ return record
+
+
+ def recordForPrincipalURL(self, principalURL):
+ for record in self.allRecords():
+ if record.principalURL == principalURL:
+ return record
+
+
+ def recordForInviteUID(self, inviteUID):
+ for record in self.allRecords():
+ if record.inviteuid == inviteUID:
+ return record
+
+
+ def addOrUpdateRecord(self, record):
+ bindMode = {'read-only': _BIND_MODE_READ,
+ 'read-write': _BIND_MODE_WRITE}[record.access]
+ bindStatus = {
+ "NEEDS-ACTION": _BIND_STATUS_INVITED,
+ "ACCEPTED": _BIND_STATUS_ACCEPTED,
+ "DECLINED": _BIND_STATUS_DECLINED,
+ "INVALID": _BIND_STATUS_INVALID,
+ }[record.state]
+ # principalURL is derived from a directory record's principalURL() so
+ # it will always contain the UID. The form is '/principals/__uids__/x'
+ # (and may contain a trailing slash).
+ principalUID = record.principalURL.split("/")[3]
+ shareeHome = self._txn.addressbookHomeWithUID(principalUID, create=True)
+ rows = self._txn.execSQL(
+ "select RESOURCE_ID, HOME_RESOURCE_ID from INVITE where RECIPIENT_ADDRESS = %s",
+ [record.userid]
+ )
+ if rows:
+ [[resourceID, homeResourceID]] = rows
+ # Invite(inviteuid, userid, principalURL, common_name, access, state, summary)
+ self._txn.execSQL("""
+ update ADDRESSBOOK_BIND set BIND_MODE = %s,
+ BIND_STATUS = %s, MESSAGE = %s
+ where
+ ADDRESSBOOK_RESOURCE_ID = %s and
+ ADDRESSBOOK_HOME_RESOURCE_ID = %s
+ """, [bindMode, bindStatus, record.summary,
+ resourceID, homeResourceID])
+ self._txn.execSQL("""
+ update INVITE set NAME = %s, INVITE_UID = %s
+ where RECIPIENT_ADDRESS = %s
+ """,
+ [record.name, record.inviteuid, record.userid]
+ )
+ else:
+ self._txn.execSQL(
+ """
+ insert into INVITE (
+ INVITE_UID, NAME,
+ HOME_RESOURCE_ID, RESOURCE_ID,
+ RECIPIENT_ADDRESS
+ )
+ values (%s, %s, %s, %s, %s)
+ """,
+ [
+ record.inviteuid, record.name,
+ shareeHome._resourceID, self._addressbook._resourceID,
+ record.userid
+ ])
+ self._txn.execSQL(
+ """
+ insert into ADDRESSBOOK_BIND
+ (
+ ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID,
+ ADDRESSBOOK_RESOURCE_NAME, BIND_MODE, BIND_STATUS,
+ SEEN_BY_OWNER, SEEN_BY_SHAREE, MESSAGE
+ )
+ values (%s, %s, %s, %s, %s, %s, %s, %s)
+ """,
+ [
+ shareeHome._resourceID,
+ self._addressbook._resourceID,
+ None, # this is NULL because it is not bound yet, let's be
+ # explicit about that.
+ bindMode,
+ bindStatus,
+ False,
+ False,
+ record.summary
+ ])
+
+
+ def removeRecordForUserID(self, userid):
+ rec = self.recordForUserID(userid)
+ self.removeRecordForInviteUID(rec.inviteuid)
+
+
+ def removeRecordForPrincipalURL(self, principalURL):
+ raise NotImplementedError("removeRecordForPrincipalURL")
+
+
+ def removeRecordForInviteUID(self, inviteUID):
+ rows = self._txn.execSQL("""
+ select HOME_RESOURCE_ID, RESOURCE_ID from INVITE where
+ INVITE_UID = %s
+ """, [inviteUID])
+ if rows:
+ [[homeID, resourceID]] = rows
+ self._txn.execSQL(
+ "delete from ADDRESSBOOK_BIND where "
+ "ADDRESSBOOK_HOME_RESOURCE_ID = %s and ADDRESSBOOK_RESOURCE_ID = %s",
+ [homeID, resourceID])
+ self._txn.execSQL("delete from INVITE where INVITE_UID = %s",
+ [inviteUID])
+
+
+
+class PostgresLegacyABSharesEmulator(object):
+
+ def __init__(self, home):
+ self._home = home
+
+
+ @property
+ def _txn(self):
+ return self._home._txn
+
+
+ def create(self):
+ pass
+
+
+ def remove(self):
+ pass
+
+
+ def allRecords(self):
+ # This should have been a smart join that got all these columns at
+ # once, but let's not bother to fix it, since the actual query we
+ # _want_ to do (just look for addressbook binds in a particular homes) is
+ # much simpler anyway; we should just do that.
+ shareRows = self._txn.execSQL(
+ """
+ select ADDRESSBOOK_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME, MESSAGE
+ from ADDRESSBOOK_BIND
+ where ADDRESSBOOK_HOME_RESOURCE_ID = %s and
+ BIND_MODE != %s and
+ ADDRESSBOOK_RESOURCE_NAME is not null
+ """, [self._home._resourceID, _BIND_MODE_OWN])
+ for resourceID, resourceName, summary in shareRows:
+ [[shareuid]] = self._txn.execSQL(
+ """
+ select INVITE_UID
+ from INVITE
+ where RESOURCE_ID = %s and HOME_RESOURCE_ID = %s
+ """, [resourceID, self._home._resourceID])
+ sharetype = 'I'
+ [[ownerHomeID, ownerResourceName]] = self._txn.execSQL(
+ """
+ select ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME
+ from ADDRESSBOOK_BIND
+ where ADDRESSBOOK_RESOURCE_ID = %s and
+ BIND_MODE = %s
+ """, [resourceID, _BIND_MODE_OWN]
+ )
+ [[ownerUID]] = self._txn.execSQL(
+ "select OWNER_UID from ADDRESSBOOK_HOME where RESOURCE_ID = %s",
+ [ownerHomeID])
+ hosturl = '/addressbooks/__uids__/%s/%s' % (
+ ownerUID, ownerResourceName
+ )
+ localname = resourceName
+ record = SharedCollectionRecord(
+ shareuid, sharetype, hosturl, localname, summary
+ )
+ yield record
+
+
+ def _search(self, **kw):
+ [[key, value]] = kw.items()
+ for record in self.allRecords():
+ if getattr(record, key) == value:
+ return record
+
+ def recordForLocalName(self, localname):
+ return self._search(localname=localname)
+
+ def recordForShareUID(self, shareUID):
+ return self._search(shareuid=shareUID)
+
+
+ def addOrUpdateRecord(self, record):
+# print '*** SHARING***: Adding or updating this record:'
+# import pprint
+# pprint.pprint(record.__dict__)
+ # record.hosturl -> /addressbooks/__uids__/<uid>/<addressbookname>
+ splithost = record.hosturl.split('/')
+ ownerUID = splithost[3]
+ ownerAddressBookName = splithost[4]
+ ownerHome = self._txn.addressbookHomeWithUID(ownerUID)
+ ownerAddressBook = ownerHome.addressbookWithName(ownerAddressBookName)
+ addressbookResourceID = ownerAddressBook._resourceID
+
+ # There needs to be a bind already, one that corresponds to the
+ # invitation. The invitation's UID is the same as the share UID. I
+ # just need to update its 'localname', i.e.
+ # ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME.
+
+ self._txn.execSQL(
+ """
+ update ADDRESSBOOK_BIND set ADDRESSBOOK_RESOURCE_NAME = %s
+ where ADDRESSBOOK_HOME_RESOURCE_ID = %s and ADDRESSBOOK_RESOURCE_ID = %s
+ """,
+ [record.localname, self._home._resourceID, addressbookResourceID]
+ )
+
+
+ def removeRecordForLocalName(self, localname):
+ self._txn.execSQL(
+ "delete from ADDRESSBOOK_BIND where ADDRESSBOOK_RESOURCE_NAME = %s "
+ "and ADDRESSBOOK_HOME_RESOURCE_ID = %s",
+ [localname, self._home._resourceID]
+ )
+
+
+ def removeRecordForShareUID(self, shareUID):
+ pass
+# c = self._home._cursor()
+# c.execute(
+# "delete from ADDRESSBOOK_BIND where ADDRESSBOOK_RESOURCE_NAME = %s "
+# "and ADDRESSBOOK_HOME_RESOURCE_ID = %s",
+# [self._home._resourceID]
+# )
+
+
+
+
class PostgresAddressBook(AddressbookSyncTokenHelper):
implements(IAddressBook)
@@ -2598,7 +2897,7 @@
def retrieveOldInvites(self):
- return PostgresLegacyInvitesEmulator(self)
+ return PostgresLegacyABInvitesEmulator(self)
def retrieveOldIndex(self):
return PostgresLegacyABIndexEmulator(self)
@@ -2794,7 +3093,7 @@
def retrieveOldShares(self):
- return PostgresLegacySharesEmulator(self)
+ return PostgresLegacyABSharesEmulator(self)
def uid(self):
Modified: CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql 2010-08-20 21:32:52 UTC (rev 6165)
+++ CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql 2010-08-20 22:57:14 UTC (rev 6166)
@@ -290,7 +290,11 @@
create table ADDRESSBOOK_BIND (
ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK,
- ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+
+ -- An invitation which hasn't been accepted yet will not yet have a resource
+ -- name, so this field may be null.
+
+ ADDRESSBOOK_RESOURCE_NAME varchar(255),
BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
SEEN_BY_OWNER boolean not null,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100820/b3261454/attachment-0001.html>
More information about the calendarserver-changes
mailing list