From 0c93cceae6b2f254f865efa88f78f227cde323dc Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Tue, 10 Apr 2018 11:51:41 -0700 Subject: [PATCH 01/18] typo --- docs/source/userguide/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/userguide/introduction.rst b/docs/source/userguide/introduction.rst index 67cb03a..7f47158 100644 --- a/docs/source/userguide/introduction.rst +++ b/docs/source/userguide/introduction.rst @@ -49,11 +49,11 @@ The main takeaway points are: .. note:: For more info, see the specifications for `activity `_ and `object `_. -**Sunspear** also implements parts of some extensions to the specificiations. More specifically, `Audience Targeting `_ and `Responses `_. +**Sunspear** also implements parts of some extensions to the specification. More specifically, `Audience Targeting `_ and `Responses `_. What it isn't -------------- **Sunspear** strictly deals with storage and retrival of JSON activity stream items. It does not include all adquate indexes that allow you to build a fully fledged feed system. -For indexing, you'll probably want to use something like `Sandsnake `_, a sorted index backed by `redis `_. \ No newline at end of file +For indexing, you'll probably want to use something like `Sandsnake `_, a sorted index backed by `redis `_. From 156e9d9ca7910da0a742666ff3ee4bc4d7f156e5 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 25 Apr 2018 11:17:53 -0700 Subject: [PATCH 02/18] unused imports --- sunspear/backends/base.py | 1 + sunspear/backends/database/db.py | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sunspear/backends/base.py b/sunspear/backends/base.py index 811d5ab..d5e78c8 100644 --- a/sunspear/backends/base.py +++ b/sunspear/backends/base.py @@ -17,6 +17,7 @@ class BaseBackend(object): + def clear_all_objects(self): """ Clears all objects from the backend. diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index d455b71..1c29217 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -17,7 +17,6 @@ """ from __future__ import absolute_import, unicode_literals -import calendar import copy import datetime import json @@ -29,10 +28,9 @@ from sqlalchemy import create_engine, sql from sqlalchemy.pool import QueuePool from sunspear.activitystreams.models import Activity, Model, Object -from sunspear.backends.base import SUB_ACTIVITY_MAP, BaseBackend -from sunspear.exceptions import (SunspearDuplicateEntryException, - SunspearOperationNotSupportedException, - SunspearValidationException) +from sunspear.backends.base import BaseBackend +from sunspear.exceptions import SunspearOperationNotSupportedException + from . import schema From a96d52d76be869e4a0f8bbb7a3a15e3f71a63344 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 25 Apr 2018 13:36:21 -0700 Subject: [PATCH 03/18] style --- sunspear/backends/database/db.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 1c29217..d838949 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -63,10 +63,13 @@ class DatabaseBackend(BaseBackend): - def __init__(self, db_connection_string=None, verbose=False, poolsize=10, - max_overflow=5, **kwargs): - self._engine = create_engine(db_connection_string, echo=verbose, poolclass=QueuePool, - pool_size=poolsize, max_overflow=max_overflow, convert_unicode=True) + def __init__(self, db_connection_string=None, verbose=False, poolsize=10, max_overflow=5, **kwargs): + self._engine = create_engine(db_connection_string, + echo=verbose, + poolclass=QueuePool, + pool_size=poolsize, + max_overflow=max_overflow, + convert_unicode=True) @property def engine(self): From 1c8a72a4248652e73955d15dedb57308cb2e2d98 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Thu, 26 Apr 2018 11:16:54 -0700 Subject: [PATCH 04/18] updates objects table name --- sunspear/backends/database/schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index 12ea5cc..81d8d5f 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -4,7 +4,7 @@ metadata = MetaData() -objects_table = Table('objects', metadata, +objects_table = Table('sgactivitystream_objects', metadata, Column('id', String(32), primary_key=True), Column('object_type', String(256), nullable=False), Column('display_name', String(256)), From a132beaa6694ead543aac9ba2fb4391f4eb6b666 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Thu, 26 Apr 2018 15:09:54 -0700 Subject: [PATCH 05/18] Upsert in the least safe way FIXME --- sunspear/backends/database/db.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index d838949..aeb5d2d 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -64,12 +64,13 @@ class DatabaseBackend(BaseBackend): def __init__(self, db_connection_string=None, verbose=False, poolsize=10, max_overflow=5, **kwargs): - self._engine = create_engine(db_connection_string, - echo=verbose, - poolclass=QueuePool, - pool_size=poolsize, - max_overflow=max_overflow, - convert_unicode=True) + self._engine = create_engine( + db_connection_string, + echo=verbose, + poolclass=QueuePool, + pool_size=poolsize, + max_overflow=max_overflow, + convert_unicode=True) @property def engine(self): @@ -114,7 +115,10 @@ def obj_create(self, obj, **kwargs): obj_dict = self._get_parsed_and_validated_obj_dict(obj) obj_db_schema_dict = self._obj_dict_to_db_schema(obj_dict) - self.engine.execute(self.objects_table.insert(), [obj_db_schema_dict]) + if self.obj_exists(obj): + self.obj_update(obj) + else: + self.engine.execute(self.objects_table.insert(), [obj_db_schema_dict]) return obj_dict From de910174a62312db6427f3fcfe0dc2ea3ef5d172 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Thu, 26 Apr 2018 16:36:01 -0700 Subject: [PATCH 06/18] work on activity table a little --- sunspear/backends/base.py | 3 +-- sunspear/backends/database/db.py | 2 ++ sunspear/backends/database/schema.py | 14 +++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sunspear/backends/base.py b/sunspear/backends/base.py index d5e78c8..06c8068 100644 --- a/sunspear/backends/base.py +++ b/sunspear/backends/base.py @@ -100,7 +100,7 @@ def create_activity(self, activity, **kwargs): new_obj = self.create_obj(value) objs_created.append(new_obj) except Exception: - #there was an error, undo everything we just did + # there was an error, undo everything we just did self._rollback(objs_created, objs_modified) raise @@ -228,7 +228,6 @@ def create_obj(self, obj, **kwargs): :type obj: dict :param obj: obj we want to store in the backend - :raises: ``SunspearDuplicateEntryException`` if the record already exists in the database. :return: dict representing the new obj. """ obj_id = self._extract_id(obj) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index aeb5d2d..9e6e477 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -25,8 +25,10 @@ import six from dateutil import tz from dateutil.parser import parse + from sqlalchemy import create_engine, sql from sqlalchemy.pool import QueuePool +from sqlalchemy.sql.expression import insert from sunspear.activitystreams.models import Activity, Model, Object from sunspear.backends.base import BaseBackend from sunspear.exceptions import SunspearOperationNotSupportedException diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index 81d8d5f..d166b4e 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -14,15 +14,15 @@ Column('image', custom_types.JSONSmallDict(4096)), Column('other_data', custom_types.JSONDict())) -activities_table = Table('activities', metadata, +activities_table = Table('sgactivitystream_activities', metadata, Column('id', String(32), primary_key=True), Column('verb', String(256), nullable=False), - Column('actor', ForeignKey('objects.id', ondelete='CASCADE'), nullable=False), - Column('object', ForeignKey('objects.id', ondelete='SET NULL')), - Column('target', ForeignKey('objects.id', ondelete='SET NULL')), - Column('author', ForeignKey('objects.id', ondelete='SET NULL')), - Column('generator', ForeignKey('objects.id', ondelete='SET NULL')), - Column('provider', ForeignKey('objects.id', ondelete='SET NULL')), + Column('actor', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), + Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('target', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('author', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('generator', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('provider', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('content', Text), Column('published', DateTime(timezone=True), nullable=False), Column('updated', DateTime(timezone=True)), From c2368141792f31338f300272dc44d496befc3cee Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Thu, 26 Apr 2018 16:41:25 -0700 Subject: [PATCH 07/18] more sgactivitystream --- sunspear/backends/database/schema.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index d166b4e..4aa476c 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -31,8 +31,8 @@ replies_table = Table('replies', metadata, Column('id', String(32), primary_key=True), - Column('in_reply_to', ForeignKey('activities.id', ondelete='CASCADE'), nullable=False), - Column('actor', ForeignKey('objects.id', ondelete='CASCADE'), nullable=False), + Column('in_reply_to', ForeignKey('sgactivitiystream_activities.id', ondelete='CASCADE'), nullable=False), + Column('actor', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), Column('published', DateTime(timezone=True), nullable=False), Column('updated', DateTime(timezone=True)), Column('content', Text), @@ -40,8 +40,8 @@ likes_table = Table('likes', metadata, Column('id', String(32), primary_key=True), - Column('in_reply_to', ForeignKey('activities.id', ondelete='CASCADE'), nullable=False), - Column('actor', ForeignKey('objects.id', ondelete='CASCADE'), nullable=False), + Column('in_reply_to', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'), nullable=False), + Column('actor', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), Column('published', DateTime(timezone=True), nullable=False), Column('content', Text), Column('other_data', custom_types.JSONDict()), @@ -49,23 +49,23 @@ to_table = Table('to', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('activities.id', ondelete='CASCADE'))) + Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) bto_table = Table('bto', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('activities.id', ondelete='CASCADE'))) + Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) cc_table = Table('cc', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('activities.id', ondelete='CASCADE'))) + Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) bcc_table = Table('bcc', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('activities.id', ondelete='CASCADE'))) + Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) tables = { 'objects': objects_table, From 81ffa8db433677502c16a95ec9b6c3a8bbfaceaa Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Thu, 26 Apr 2018 18:39:40 -0700 Subject: [PATCH 08/18] Allow for Django to change the name of fields Consider passing in the names to Sunspear on init? --- sunspear/backends/database/schema.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index 4aa476c..5a9d31b 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -17,12 +17,12 @@ activities_table = Table('sgactivitystream_activities', metadata, Column('id', String(32), primary_key=True), Column('verb', String(256), nullable=False), - Column('actor', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), - Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('target', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('author', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('generator', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('provider', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('actor_id', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), + Column('object_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('target_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('author_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('generator_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), + Column('provider_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('content', Text), Column('published', DateTime(timezone=True), nullable=False), Column('updated', DateTime(timezone=True)), From 878df8f08e608de6318f4f8d51fb16e182520093 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Fri, 27 Apr 2018 17:31:58 -0700 Subject: [PATCH 09/18] come on --- sunspear/backends/database/db.py | 45 ++++++++++++++-------------- sunspear/backends/database/schema.py | 21 ++++++------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 9e6e477..9f45968 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -28,7 +28,6 @@ from sqlalchemy import create_engine, sql from sqlalchemy.pool import QueuePool -from sqlalchemy.sql.expression import insert from sunspear.activitystreams.models import Activity, Model, Object from sunspear.backends.base import BaseBackend from sunspear.exceptions import SunspearOperationNotSupportedException @@ -48,12 +47,12 @@ DB_ACTIVITY_FIELD_MAPPING = { 'id': 'id', 'verb': 'verb', - 'actor': 'actor', - 'object': 'object', - 'target': 'target', - 'author': 'author', - 'generator': 'generator', - 'provider': 'provider', + 'actor': 'actor_id', + 'object': 'object_id', + 'target': 'target_id', + 'author': 'author_id', + 'generator': 'generator_id', + 'provider': 'provider_id', 'content': 'content', 'published': 'published', 'updated': 'updated', @@ -120,7 +119,7 @@ def obj_create(self, obj, **kwargs): if self.obj_exists(obj): self.obj_update(obj) else: - self.engine.execute(self.objects_table.insert(), [obj_db_schema_dict]) + self.engine.execute(self.objects_table.insert(), [obj_db_schema_dict]).close() return obj_dict @@ -167,7 +166,7 @@ def activity_exists(self, activity, **kwargs): def activity_create(self, activity, **kwargs): """ - Creates an activity. This assumes the activity is already dehydrated (ie has refrences + Creates an activity. This assumes the activity is already dehydrated (ie has references to the objects and not the actual objects itself) """ activity = Activity(activity, backend=self) @@ -177,7 +176,7 @@ def activity_create(self, activity, **kwargs): activity_db_schema_dict = self._activity_dict_to_db_schema(activity_dict) - self.engine.execute(self.activities_table.insert(), [activity_db_schema_dict]) + self.engine.execute(self.activities_table.insert(), [activity_db_schema_dict]).close() return self.get_activity(activity_dict) @@ -224,7 +223,7 @@ def create_activity(self, activity, **kwargs): activity[key] = activity_audience_targeting_objs # For all of the objects in the activity, find out which ones actually already have existing - # objects in the database + # entries in the database obj_ids = self._flatten([ids_of_objs_with_no_dict, activity_objs.keys()]) s = self._get_select_multiple_objects_query(obj_ids) @@ -235,20 +234,20 @@ def create_activity(self, activity, **kwargs): objs_need_to_be_updated = [] for obj_id, obj in activity_objs.items(): - parsed_validated_schema_dict = self._get_parsed_and_validated_obj_dict(obj) - parsed_validated_schema_dict = self._obj_dict_to_db_schema(parsed_validated_schema_dict) - if obj_id not in results: - objs_need_to_be_inserted.append(parsed_validated_schema_dict) - else: - objs_need_to_be_updated.append(parsed_validated_schema_dict) + # parsed_validated_schema_dict = self._get_parsed_and_validated_obj_dict(obj) + self.obj_create(obj) + # if obj_id not in results: + # objs_need_to_be_inserted.append(parsed_validated_schema_dict) + # else: + # objs_need_to_be_updated.append(parsed_validated_schema_dict) # Upsert all objects for the activity - with self.engine.begin() as connection: - if objs_need_to_be_inserted: - connection.execute(self.objects_table.insert(), objs_need_to_be_inserted) - for obj in objs_need_to_be_updated: - connection.execute( - self.objects_table.update().where(self.objects_table.c.id == self._extract_id(obj)).values(**obj)) + # with self.engine.begin() as connection: + # if objs_need_to_be_inserted: + # connection.execute(self.objects_table.insert(), objs_need_to_be_inserted) + # for obj in objs_need_to_be_updated: + # connection.execute( + # self.objects_table.update().where(self.objects_table.c.id == self._extract_id(obj)).values(**obj)) return_val = self.activity_create(activity, **kwargs) diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index 5a9d31b..ca3702a 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -1,3 +1,4 @@ +from datetime import datetime from sqlalchemy import Table, Column, DateTime, Integer, String, Text, MetaData, ForeignKey, UniqueConstraint import types as custom_types @@ -7,12 +8,12 @@ objects_table = Table('sgactivitystream_objects', metadata, Column('id', String(32), primary_key=True), Column('object_type', String(256), nullable=False), - Column('display_name', String(256)), - Column('content', Text), + Column('display_name', String(256), default=''), + Column('content', Text, default=''), Column('published', DateTime(timezone=True), nullable=False), - Column('updated', DateTime(timezone=True)), - Column('image', custom_types.JSONSmallDict(4096)), - Column('other_data', custom_types.JSONDict())) + Column('updated', DateTime(timezone=True), default=datetime.now(), onupdate=datetime.now()), + Column('image', custom_types.JSONSmallDict(4096), default={}), + Column('other_data', custom_types.JSONDict(), default={})) activities_table = Table('sgactivitystream_activities', metadata, Column('id', String(32), primary_key=True), @@ -23,11 +24,11 @@ Column('author_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('generator_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('provider_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('content', Text), + Column('content', Text, default-''), Column('published', DateTime(timezone=True), nullable=False), - Column('updated', DateTime(timezone=True)), - Column('icon', custom_types.JSONSmallDict(4096)), - Column('other_data', custom_types.JSONDict())) + Column('updated', DateTime(timezone=True), default=datetime.now(), onupdate=datetime.now()), + Column('icon', custom_types.JSONSmallDict(4096), default={}), + Column('other_data', custom_types.JSONDict(), default={})) replies_table = Table('replies', metadata, Column('id', String(32), primary_key=True), @@ -35,7 +36,7 @@ Column('actor', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE'), nullable=False), Column('published', DateTime(timezone=True), nullable=False), Column('updated', DateTime(timezone=True)), - Column('content', Text), + Column('content', Text, nullable=False), Column('other_data', custom_types.JSONDict())) likes_table = Table('likes', metadata, From 25335e37b30c65d6970a8f3f81152e8c920b14c3 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Mon, 30 Apr 2018 12:08:10 -0700 Subject: [PATCH 10/18] Implement activity delete --- sunspear/backends/database/db.py | 7 +++++++ sunspear/backends/database/schema.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 9f45968..8b9e867 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -152,6 +152,7 @@ def obj_get(self, obj, **kwargs): return results + def obj_delete(self, obj, **kwargs): obj_id = self._extract_id(obj) @@ -180,6 +181,12 @@ def activity_create(self, activity, **kwargs): return self.get_activity(activity_dict) + def activity_delete(self, activity, **kwargs): + activity_id = activity['id'] + statement = self.activities_table.delete().where( + self.activities_table.c.id == activity_id) + self.engine.execute(statement) + def _extract_activity_obj_key(self, obj_or_value): activity_obj = None diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index ca3702a..0478a1f 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -24,7 +24,7 @@ Column('author_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('generator_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), Column('provider_id', ForeignKey('sgactivitystream_objects.id', ondelete='SET NULL')), - Column('content', Text, default-''), + Column('content', Text, default=''), Column('published', DateTime(timezone=True), nullable=False), Column('updated', DateTime(timezone=True), default=datetime.now(), onupdate=datetime.now()), Column('icon', custom_types.JSONSmallDict(4096), default={}), From 27f52ce5301cabc21debc8f0bb2041b951753274 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Mon, 30 Apr 2018 16:44:27 -0700 Subject: [PATCH 11/18] Use inheritance --- sunspear/backends/database/db.py | 12 +----------- sunspear/backends/riak.py | 8 -------- sunspear/clients.py | 7 +++++-- tests/test_rfc3339.py | 4 ++-- 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 8b9e867..1b3719a 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -20,7 +20,6 @@ import copy import datetime import json -import uuid import six from dateutil import tz @@ -308,19 +307,10 @@ def hydrate_activities(self, activities): # replace the object ids with the hydrated objects for activity in activities: - activity = self._dehydrate_object_keys(activity, objects_dict) + self._dehydrate_object_keys(activity, objects_dict) return activities - def get_new_id(self): - """ - Generates a new unique ID. The default implementation uses uuid1 to - generate a unique ID. - - :return: a new id - """ - return uuid.uuid1().hex - def _get_raw_activities(self, activity_ids, **kwargs): activity_ids = map(self._extract_id, activity_ids) if not activity_ids: diff --git a/sunspear/backends/riak.py b/sunspear/backends/riak.py index 089755f..7483bb7 100644 --- a/sunspear/backends/riak.py +++ b/sunspear/backends/riak.py @@ -621,11 +621,3 @@ def _get_timestamp(self): dt_obj = datetime.datetime.utcnow() return long((calendar.timegm(dt_obj.utctimetuple()) * 1000)) + (dt_obj.microsecond / 1000) - def get_new_id(self): - """ - Generates a new unique ID. The default implementation uses uuid1 to - generate a unique ID. - - :return: a new id - """ - return uuid.uuid1().hex diff --git a/sunspear/clients.py b/sunspear/clients.py index 491e4ac..c996629 100644 --- a/sunspear/clients.py +++ b/sunspear/clients.py @@ -120,7 +120,7 @@ def get_objects(self, object_ids=[]): """ return self._backend.get_obj(object_ids) - def get_activities(self, activity_ids=[], **kwargs): + def get_activities(self, activity_ids, **kwargs): """ Gets a list of activities. Specific backends may support other arguments. Please see reference of the specific backends to see all ``kwargs`` supported. @@ -128,7 +128,10 @@ def get_activities(self, activity_ids=[], **kwargs): :type activity_ids: list :param activity_ids: The list of activities you want to retrieve """ - return self._backend.get_activity(activity_ids=activity_ids, **kwargs) + # if activity_ids is None: + # activity_ids = [] + + return self._backend.get_activity(activity_ids, **kwargs) def get_backend(self): """ diff --git a/tests/test_rfc3339.py b/tests/test_rfc3339.py index 197cefe..5faef18 100644 --- a/tests/test_rfc3339.py +++ b/tests/test_rfc3339.py @@ -9,10 +9,10 @@ class TestRFC3339(object): - ''' + """ Test the use of the timezone saved locally. Since it is hard to test using doctest. - ''' + """ def setUp(self): local_utcoffset = _utc_offset(datetime.datetime.now(), True) From 4cfc1b9ffa6ba3e13d7c1c7b22062d7aa2a61b8e Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Mon, 30 Apr 2018 16:46:09 -0700 Subject: [PATCH 12/18] remove some dead code --- sunspear/backends/database/db.py | 31 ++----------------------------- tests/test_db.py | 1 - 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 1b3719a..77bbb87 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -151,7 +151,6 @@ def obj_get(self, obj, **kwargs): return results - def obj_delete(self, obj, **kwargs): obj_id = self._extract_id(obj) @@ -228,42 +227,16 @@ def create_activity(self, activity, **kwargs): ids_of_objs_with_no_dict.append(activity_obj_id) activity[key] = activity_audience_targeting_objs - # For all of the objects in the activity, find out which ones actually already have existing - # entries in the database - obj_ids = self._flatten([ids_of_objs_with_no_dict, activity_objs.keys()]) - - s = self._get_select_multiple_objects_query(obj_ids) - results = self.engine.execute(s).fetchall() - results = self._flatten(results) - - objs_need_to_be_inserted = [] - objs_need_to_be_updated = [] - for obj_id, obj in activity_objs.items(): - # parsed_validated_schema_dict = self._get_parsed_and_validated_obj_dict(obj) self.obj_create(obj) - # if obj_id not in results: - # objs_need_to_be_inserted.append(parsed_validated_schema_dict) - # else: - # objs_need_to_be_updated.append(parsed_validated_schema_dict) - - # Upsert all objects for the activity - # with self.engine.begin() as connection: - # if objs_need_to_be_inserted: - # connection.execute(self.objects_table.insert(), objs_need_to_be_inserted) - # for obj in objs_need_to_be_updated: - # connection.execute( - # self.objects_table.update().where(self.objects_table.c.id == self._extract_id(obj)).values(**obj)) - return_val = self.activity_create(activity, **kwargs) - - return return_val + return self.activity_create(activity, **kwargs) def activity_get(self, activity_ids, **kwargs): activity_ids = self._listify(activity_ids) activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) - + # assert len(activities) == 1, "activity_get should return exactly 1 activity" return activities def sub_activity_create(self, activity, actor, content, extra={}, sub_activity_verb="", published=None, **kwargs): diff --git a/tests/test_db.py b/tests/test_db.py index 7270599..8a783dc 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -507,7 +507,6 @@ def test_create_like(self): sub_activity_exists = self._engine.execute(sql.select([sql.exists().where(self._backend.likes_table.c.id == like_activity_dict['id'])])).scalar() ok_(sub_activity_exists) - def _datetime_to_db_compatibal_str(self, datetime_instance): return datetime_instance.strftime('%Y-%m-%d %H:%M:%S') From 82397e4763bb980d89aa3aef1734958a44d92e7f Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 2 May 2018 14:36:28 -0700 Subject: [PATCH 13/18] moving in the (right?) direction --- sunspear/activitystreams/models.py | 4 +++- sunspear/backends/database/db.py | 21 ++++++++++++++++++--- sunspear/backends/riak.py | 17 +++++++++-------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/sunspear/activitystreams/models.py b/sunspear/activitystreams/models.py index 4065bae..63e26e2 100644 --- a/sunspear/activitystreams/models.py +++ b/sunspear/activitystreams/models.py @@ -11,6 +11,7 @@ class Model(object): + _required_fields = [] _media_fields = [] _reserved_fields = [] @@ -137,6 +138,7 @@ def __getitem__(self, key): class Activity(Model): + _required_fields = ['verb', 'actor', 'object'] _media_fields = ['icon'] _reserved_fields = ['updated'] @@ -157,7 +159,7 @@ def _set_defaults(self, model_dict): def get_parsed_sub_activity_dict(self, actor, content="", verb="reply", object_type="reply", \ collection="replies", activity_class=None, extra={}, published=None, **kwargs): - #TODO: Doesn't feel like this should be here Feels like it belongs in the backend. + # TODO: Doesn't feel like this should be here Feels like it belongs in the backend. if published is None: published = datetime.datetime.utcnow() diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 77bbb87..20e1332 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -232,8 +232,23 @@ def create_activity(self, activity, **kwargs): return self.activity_create(activity, **kwargs) - def activity_get(self, activity_ids, **kwargs): - activity_ids = self._listify(activity_ids) + def activity_get(self, + activity_ids, + raw_filters=None, + filters="", + include_public=False, + audience_targeting=None, + aggregation_pipeline=None, + **kwargs): + if filters is None: + filters = {} + if audience_targeting is None: + audience_targeting = [] + if aggregation_pipeline is None: + aggregation_pipeline = [] + activity_ids = self._listify(activity_ids) # TODO: likely don't need to listify here. + + activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) # assert len(activities) == 1, "activity_get should return exactly 1 activity" @@ -285,7 +300,7 @@ def hydrate_activities(self, activities): return activities def _get_raw_activities(self, activity_ids, **kwargs): - activity_ids = map(self._extract_id, activity_ids) + activity_ids = map(self._extract_id, activity_ids) # Likely don't need to do this if not activity_ids: return [] diff --git a/sunspear/backends/riak.py b/sunspear/backends/riak.py index 7483bb7..9b64aed 100644 --- a/sunspear/backends/riak.py +++ b/sunspear/backends/riak.py @@ -20,7 +20,6 @@ import calendar import copy import datetime -import uuid from riak import RiakClient from sunspear.activitystreams.models import Activity, Model, Object @@ -144,6 +143,7 @@ class RiakBackend(BaseBackend): + def __init__( self, protocol="pbc", nodes=[], objects_bucket_name="objects", activities_bucket_name="activities", **kwargs): @@ -224,7 +224,7 @@ def obj_create(self, obj, **kwargs): riak_obj.store() - #finally save the data + # finally save the data return obj_dict def set_general_indexes(self, riak_object): @@ -330,7 +330,7 @@ def activity_update(self, activity, **kwargs): return self.activity_create(activity, **kwargs) def activity_get( - self, activity_ids=[], raw_filter="", filters={}, include_public=False, + self, activity_ids, raw_filter="", filters={}, include_public=False, audience_targeting={}, aggregation_pipeline=[], **kwargs): """ Gets a list of activities. You can also group activities by providing a list of attributes to group @@ -343,7 +343,7 @@ def activity_get( Filters do not work for nested dictionaries. :type raw_filter: string :param raw_filter: allows you to specify a javascript function as a string. The function should return ``true`` if the activity should be included in the result set - or ``false`` it shouldn't. If you specify a raw filter, the filters specified in ``filters`` will not run. How ever, the results will still be filtered based on + or ``false`` it shouldn't. If you specify a raw filter, the filters specified in ``filters`` will not run. However, the results will still be filtered based on the ``audience_targeting`` parameter. :type include_public: boolean :param include_public: If ``True``, and the ``audience_targeting`` dictionary is defined, activities that are @@ -575,7 +575,7 @@ def _get_many_activities(self, activity_ids=[], raw_filter="", filters=None, inc :param activity_ids: The list of activities you want to retrieve :type raw_filter: string :param raw_filter: allows you to specify a javascript function as a string. The function should return ``true`` if the activity should be included in the result set - or ``false`` it shouldn't. If you specify a raw filter, the filters specified in ``filters`` will not run. How ever, the results will still be filtered based on + or ``false`` it shouldn't. If you specify a raw filter, the filters specified in ``filters`` will not run. However, the results will still be filtered based on the ``audience_targeting`` parameter. :type filters: dict :param filters: filters list of activities by key, value pair. For example, ``{'verb': 'comment'}`` would only return activities where the ``verb`` was ``comment``. @@ -598,9 +598,10 @@ def _get_many_activities(self, activity_ids=[], raw_filter="", filters=None, inc results = results.reduce(JS_REDUCE_FILTER_AUD_TARGETTING, options={'arg': {'public': include_public, 'filters': audience_targeting}}) if filters or raw_filter: - # An empty `filters` dict would cause all activities to be filtered out. If you wanted that effect, you - # wouldn't have to call this function, so let's assume that an empty dict is a typical default value and - # should denote that there are no filters to apply. + # An empty `filters` dict would cause all activities to be filtered out. If you + # wanted that effect, you wouldn't have to call this function, so let's assume that + # an empty dict is a typical default value and should denote that there are no + # filters to apply. filters = filters or None results = results.reduce(JS_REDUCE_FILTER_PROP, options={'arg': {'raw_filter': raw_filter, 'filters': filters}}) From ee48df6e6b4516577df6eab971cb09c537acf3bf Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 9 May 2018 14:08:26 -0700 Subject: [PATCH 14/18] connect to CC, BCC, To, and BTO tables --- sunspear/activitystreams/models.py | 2 +- sunspear/backends/database/db.py | 2 +- sunspear/backends/database/schema.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sunspear/activitystreams/models.py b/sunspear/activitystreams/models.py index 63e26e2..6004a94 100644 --- a/sunspear/activitystreams/models.py +++ b/sunspear/activitystreams/models.py @@ -214,7 +214,7 @@ def get_parsed_sub_activity_dict(self, actor, content="", verb="reply", object_t return _activity, parent_activity def parse_data(self, data, *args, **kwargs): - #TODO Rename to jsonify_dict + # TODO Rename to jsonify_dict _parsed_data = super(Activity, self).parse_data(data, *args, **kwargs) for response_field in self._response_fields: if response_field in _parsed_data: diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 20e1332..0070f93 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -247,9 +247,9 @@ def activity_get(self, if aggregation_pipeline is None: aggregation_pipeline = [] activity_ids = self._listify(activity_ids) # TODO: likely don't need to listify here. + activities = self._get_raw_activities(activity_ids, **kwargs) - activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) # assert len(activities) == 1, "activity_get should return exactly 1 activity" return activities diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index 0478a1f..f127cf5 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -48,22 +48,22 @@ Column('other_data', custom_types.JSONDict()), UniqueConstraint('actor', 'in_reply_to')) -to_table = Table('to', metadata, +to_table = Table('sgactivitystream_to', metadata, Column('id', Integer, primary_key=True), Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) -bto_table = Table('bto', metadata, +bto_table = Table('sgactivitystream_bto', metadata, Column('id', Integer, primary_key=True), Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) -cc_table = Table('cc', metadata, +cc_table = Table('sgactivitystream_cc', metadata, Column('id', Integer, primary_key=True), Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) -bcc_table = Table('bcc', metadata, +bcc_table = Table('sgactivitystream_bcc', metadata, Column('id', Integer, primary_key=True), Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) From c3dd9dd6c86ee95a4a574cf174d73c7a2222e93a Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 9 May 2018 16:23:28 -0700 Subject: [PATCH 15/18] properly create bcc, cc, bto, to tables --- sunspear/backends/database/db.py | 16 ++++++++++++---- sunspear/backends/database/schema.py | 16 ++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 0070f93..d31e586 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -163,12 +163,12 @@ def activity_exists(self, activity, **kwargs): return self.engine.execute(sql.select([sql.exists().where(activities_db_table.c.id == activity_id)])).scalar() - def activity_create(self, activity, **kwargs): + def activity_create(self, activity_dict, **kwargs): """ Creates an activity. This assumes the activity is already dehydrated (ie has references to the objects and not the actual objects itself) """ - activity = Activity(activity, backend=self) + activity = Activity(activity_dict, backend=self) activity.validate() activity_dict = activity.get_parsed_dict() @@ -177,6 +177,16 @@ def activity_create(self, activity, **kwargs): self.engine.execute(self.activities_table.insert(), [activity_db_schema_dict]).close() + obj_id = activity_dict['object'] + activity_id = activity_dict['id'] + for audience_field in ['cc', 'bcc', 'to', 'bto']: + if audience_field in activity_dict: + table = schema.tables[audience_field] + self.engine.execute(table.insert(), dict( + obj_id=obj_id, + activity_id=activity_id + )).close() + return self.get_activity(activity_dict) def activity_delete(self, activity, **kwargs): @@ -248,8 +258,6 @@ def activity_get(self, aggregation_pipeline = [] activity_ids = self._listify(activity_ids) # TODO: likely don't need to listify here. activities = self._get_raw_activities(activity_ids, **kwargs) - - activities = self.hydrate_activities(activities) # assert len(activities) == 1, "activity_get should return exactly 1 activity" return activities diff --git a/sunspear/backends/database/schema.py b/sunspear/backends/database/schema.py index f127cf5..f96d70d 100644 --- a/sunspear/backends/database/schema.py +++ b/sunspear/backends/database/schema.py @@ -50,23 +50,23 @@ to_table = Table('sgactivitystream_to', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) + Column('obj_id', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity_id', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) bto_table = Table('sgactivitystream_bto', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) + Column('obj_id', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity_id', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) cc_table = Table('sgactivitystream_cc', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) + Column('obj_id', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity_id', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) bcc_table = Table('sgactivitystream_bcc', metadata, Column('id', Integer, primary_key=True), - Column('object', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), - Column('activity', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) + Column('obj_id', ForeignKey('sgactivitystream_objects.id', ondelete='CASCADE')), + Column('activity_id', ForeignKey('sgactivitystream_activities.id', ondelete='CASCADE'))) tables = { 'objects': objects_table, From c97f1bdcc9b85c90be7ef615e50e23bef9f96954 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 9 May 2018 17:09:56 -0700 Subject: [PATCH 16/18] Try to respect audience targetting --- sunspear/backends/database/db.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index d31e586..77e5029 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -92,6 +92,22 @@ def likes_table(self): def replies_table(self): return schema.tables['replies'] + @property + def cc_table(self): + return schema.tables['cc'] + + @property + def bcc_table(self): + return schema.tables['bcc'] + + @property + def to_table(self): + return schema.tables['to'] + + @property + def bto_table(self): + return schema.tables['bto'] + def _get_connection(self): return self.engine.connect() @@ -253,13 +269,21 @@ def activity_get(self, if filters is None: filters = {} if audience_targeting is None: - audience_targeting = [] + audience_targeting = {} if aggregation_pipeline is None: aggregation_pipeline = [] activity_ids = self._listify(activity_ids) # TODO: likely don't need to listify here. + + assert len(audience_targeting) == 1, "I can't be wrong about this assumption, right?" + + for audience_type, object_id in audience_targeting.items(): + audience_table = schema[audience_type] + + sql.select(['*']).where(audience_table.c.obj_id == object_id) + activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) - # assert len(activities) == 1, "activity_get should return exactly 1 activity" + return activities def sub_activity_create(self, activity, actor, content, extra={}, sub_activity_verb="", published=None, **kwargs): From 425a50db602516d635b1c1383ffc2bb83198399e Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Mon, 21 May 2018 14:46:06 -0700 Subject: [PATCH 17/18] i hope --- sunspear/backends/database/db.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index 77e5029..a58fbd7 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -274,13 +274,23 @@ def activity_get(self, aggregation_pipeline = [] activity_ids = self._listify(activity_ids) # TODO: likely don't need to listify here. - assert len(audience_targeting) == 1, "I can't be wrong about this assumption, right?" + assert len(audience_targeting) == 1 or len(audience_targeting) == 0, "I can't be wrong about this. I hope" + audience_activity_ids = None for audience_type, object_id in audience_targeting.items(): - audience_table = schema[audience_type] + # audience_table = schema.tables[audience_type] + # audience_query = sql.select([audience_table.c.activity_id]).where( + # audience_table.c.obj_id == object_id) - sql.select(['*']).where(audience_table.c.obj_id == object_id) + audience_activity_ids = self.engine.execute(sql.select([self.activities_table.c.id]).where( + self.activities_table.c.actor_id.in_(audience_targeting[audience_type]) + )).fetchall() + # audience_activities_query = sql.select(['*']).where(self.activities_table.c.id.in_(audience_query)) + # result_proxy = self.engine.execute(audience_activities_query) + + if audience_activity_ids is not None and not include_public: # only filter then?? + activity_ids = list(set(audience_activity_ids).intersection(set(activity_ids))) activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) From b71868938be006ec3d12ddfc54a057d31ecac427 Mon Sep 17 00:00:00 2001 From: Nicholas Kobald Date: Wed, 23 May 2018 16:40:56 -0700 Subject: [PATCH 18/18] push --- sunspear/backends/base.py | 2 -- sunspear/backends/database/db.py | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/sunspear/backends/base.py b/sunspear/backends/base.py index 06c8068..08a2b48 100644 --- a/sunspear/backends/base.py +++ b/sunspear/backends/base.py @@ -400,8 +400,6 @@ def _listify(self, list_or_string): """ if not isinstance(list_or_string, (list, tuple, set)): list_or_string = [list_or_string] - else: - list_or_string = list_or_string return list_or_string diff --git a/sunspear/backends/database/db.py b/sunspear/backends/database/db.py index a58fbd7..f51b363 100644 --- a/sunspear/backends/database/db.py +++ b/sunspear/backends/database/db.py @@ -266,6 +266,7 @@ def activity_get(self, audience_targeting=None, aggregation_pipeline=None, **kwargs): + if filters is None: filters = {} if audience_targeting is None: @@ -276,6 +277,7 @@ def activity_get(self, assert len(audience_targeting) == 1 or len(audience_targeting) == 0, "I can't be wrong about this. I hope" + """ audience_activity_ids = None for audience_type, object_id in audience_targeting.items(): # audience_table = schema.tables[audience_type] @@ -288,14 +290,23 @@ def activity_get(self, # audience_activities_query = sql.select(['*']).where(self.activities_table.c.id.in_(audience_query)) # result_proxy = self.engine.execute(audience_activities_query) + """ + # if audience_activity_ids is not None and not include_public: # only filter then?? + # activity_ids = list(set(audience_activity_ids) & (set(activity_ids))) + self.filter_activities_by_audience(activity_ids, audience_targeting) - if audience_activity_ids is not None and not include_public: # only filter then?? - activity_ids = list(set(audience_activity_ids).intersection(set(activity_ids))) activities = self._get_raw_activities(activity_ids, **kwargs) activities = self.hydrate_activities(activities) return activities + def filter_activities_by_audience(self, activity_ids, audience_targeting): + # s = sql.select(['*']).where(self.objects_table.c.id.in_(obj_ids)) + # TODO: bcc, bto, etc.. + cc_query = sql.select(['*']).where(self.cc_table.c.activity_id.in_(activity_ids)) + res = self.engine.execute(cc_query).fetchall() + return None + def sub_activity_create(self, activity, actor, content, extra={}, sub_activity_verb="", published=None, **kwargs): object_type = kwargs.get('object_type', sub_activity_verb) sub_activity_model = self.get_sub_activity_model(sub_activity_verb)