From e586cd66c005e7ccb2af7244fe8be393befcf010 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 20 Dec 2006 14:04:52 -0500 Subject: [PATCH] Add activity objects to the data store --- services/datastore/datastore.py | 53 +++++++++++++++++++++++++++++---- sugar/datastore/datastore.py | 25 +++++++++++++--- tests/test-datastore.py | 33 ++++++++++++++++++-- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/services/datastore/datastore.py b/services/datastore/datastore.py index ff688c82..aa03035a 100644 --- a/services/datastore/datastore.py +++ b/services/datastore/datastore.py @@ -20,6 +20,7 @@ import dbus, dbus.glib, gobject import logging import sqlite import dbus_helpers +import string have_sugar = False try: @@ -28,6 +29,21 @@ try: except ImportError: pass +def is_hex(s): + return s.strip(string.hexdigits) == '' + +ACTIVITY_ID_LEN = 40 + +def validate_activity_id(actid): + """Validate an activity ID.""" + if not isinstance(actid, str) and not isinstance(actid, unicode): + return False + if len(actid) != ACTIVITY_ID_LEN: + return False + if not is_hex(actid): + return False + return True + _DS_SERVICE = "org.laptop.sugar.DataStore" _DS_DBUS_INTERFACE = "org.laptop.sugar.DataStore" @@ -75,9 +91,21 @@ class DataStoreDBusHelper(dbus.service.Object): return _create_op(self._parent.get(uid)) @dbus.service.method(_DS_DBUS_INTERFACE, - in_signature="aya{sv}", out_signature="o") - def create(self, data, prop_dict): - uid = self._parent.create(data, prop_dict) + in_signature="s", out_signature="o") + def getActivityObject(self, activity_id): + if not validate_activity_id(activity_id): + raise ValueError("invalid activity id") + return _create_op(self._parent.get_activity_object(activity_id)) + + @dbus.service.method(_DS_DBUS_INTERFACE, + in_signature="aya{sv}s", out_signature="o") + def create(self, data, prop_dict, activity_id): + if len(activity_id): + if not validate_activity_id(activity_id): + raise ValueError("invalid activity id") + else: + activity_id = None + uid = self._parent.create(data, prop_dict, activity_id) return _create_op(uid) @dbus.service.method(_DS_DBUS_INTERFACE, @@ -181,6 +209,7 @@ class DataStore(object): self._dbcx.commit() curs.execute('CREATE TABLE objects (' \ 'uid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' \ + 'activity_id VARCHAR(50), ' \ 'data BLOB' \ ');') curs.execute('CREATE TABLE properties (' \ @@ -202,10 +231,24 @@ class DataStore(object): return uid raise NotFoundError("Object %d was not found." % uid) - def create(self, data, prop_dict=None): + def get_activity_object(self, activity_id): + curs = self._dbcx.cursor() + curs.execute("SELECT uid FROM objects WHERE activity_id='%s';" % activity_id) + res = curs.fetchall() + self._dbcx.commit() + if len(res) > 0: + del curs + return res[0][0] + del curs + raise NotFoundError("Object for activity %s was not found." % activity_id) + + def create(self, data, prop_dict=None, activity_id=None): curs = self._dbcx.cursor() data = sqlite.encode(_get_data_as_string(data)) - curs.execute("INSERT INTO objects (uid, data) VALUES (NULL, '%s');" % data) + if not activity_id: + curs.execute("INSERT INTO objects (uid, data) VALUES (NULL, '%s');" % data) + else: + curs.execute("INSERT INTO objects (uid, data, activity_id) VALUES (NULL, '%s', '%s');" % (data, activity_id)) curs.execute("SELECT last_insert_rowid();") rows = curs.fetchall() self._dbcx.commit() diff --git a/sugar/datastore/datastore.py b/sugar/datastore/datastore.py index 3aa007e1..7a776870 100644 --- a/sugar/datastore/datastore.py +++ b/sugar/datastore/datastore.py @@ -15,6 +15,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import dbus, dbus.glib, gobject +from sugar import util class ObjectCache(object): def __init__(self): @@ -159,11 +160,27 @@ class DataStore(gobject.GObject): # FIXME pass - def get(self, uid): - return self._new_object(self._ds.get(int(uid))) + def get(self, uid=None, activity_id=None): + if not activity_id and not uid: + raise ValueError("At least one of activity_id or uid must be specified") + if activity_id and uid: + raise ValueError("Only one of activity_id or uid can be specified") + if activity_id: + if not util.validate_activity_id(activity_id): + raise ValueError("activity_id must be valid") + return self._new_object(self._ds.getActivityObject(activity_id)) + elif uid: + if not len(uid): + raise ValueError("uid must be valid") + return self._new_object(self._ds.get(int(uid))) + raise RuntimeError("At least one of activity_id or uid must be specified") - def create(self, data, prop_dict={}): - op = self._ds.create(dbus.ByteArray(data), dbus.Dictionary(prop_dict)) + def create(self, data, prop_dict={}, activity_id=None): + if activity_id and not util.validate_activity_id(activity_id): + raise ValueError("activity_id must be valid") + if not activity_id: + activity_id = "" + op = self._ds.create(dbus.ByteArray(data), dbus.Dictionary(prop_dict), activity_id) return self._new_object(op) def delete(self, obj): diff --git a/tests/test-datastore.py b/tests/test-datastore.py index f915a605..b0ab9339 100755 --- a/tests/test-datastore.py +++ b/tests/test-datastore.py @@ -17,6 +17,7 @@ import unittest from sugar.datastore import datastore +from sugar import util import dbus class NotFoundError(dbus.DBusException): pass @@ -26,8 +27,8 @@ _ds = datastore.get_instance() class DataStoreTestCase(unittest.TestCase): _TEST_DATA = "adsfkjadsfadskjasdkjf" _TEST_PROPS = {'foo': 1, 'bar': 'baz'} - def _create_test_object(self): - obj = _ds.create(self._TEST_DATA, self._TEST_PROPS) + def _create_test_object(self, activity_id=None): + obj = _ds.create(self._TEST_DATA, self._TEST_PROPS, activity_id=activity_id) self.assert_(obj) return obj @@ -36,6 +37,31 @@ class DataStoreTestCase(unittest.TestCase): self.assert_(obj.uid()) _ds.delete(obj) + def testObjectCreateWithActivityId(self): + # Try known good create + act_id = util.unique_id('afdkjakjddasf') + obj = self._create_test_object(act_id) + self.assert_(obj.uid()) + _ds.delete(obj) + + def testObjectCreateWithBadActivityId(self): + # try malformed activity id + try: + uid = self._create_test_object("adfadf") + except ValueError: + pass + else: + self.fail("Expected ValueError") + + def testObjectGetActivityObject(self): + # create a new object + act_id = util.unique_id('afdkjakjddasf') + obj = self._create_test_object(act_id) + self.assert_(obj.uid()) + obj2 = _ds.get(activity_id=act_id) + self.assert_(obj2) + _ds.delete(obj) + def testObjectGet(self): # create a new object obj = self._create_test_object() @@ -94,7 +120,10 @@ class DataStoreTestCase(unittest.TestCase): def main(): dsTestSuite = unittest.TestSuite() dsTestSuite.addTest(DataStoreTestCase('testObjectCreate')) + dsTestSuite.addTest(DataStoreTestCase('testObjectCreateWithActivityId')) + dsTestSuite.addTest(DataStoreTestCase('testObjectCreateWithBadActivityId')) dsTestSuite.addTest(DataStoreTestCase('testObjectGet')) + dsTestSuite.addTest(DataStoreTestCase('testObjectGetActivityObject')) dsTestSuite.addTest(DataStoreTestCase('testObjectDelete')) dsTestSuite.addTest(DataStoreTestCase('testObjectFind')) dsTestSuite.addTest(DataStoreTestCase('testObjectGetData'))