Add ActivityIntermediator table and refactor some of Activity model
- This has introduced a intermediatory table between object/target and the activity. This allows for multiple activities to be associated with one object/target. - This moves some of the methods off Activity model into a mixin which didn't need to interact with database things. - This also cleaned up the migrations as well as adding retroactive creation of activities for collection creation.
This commit is contained in:
parent
1c15126819
commit
ce46470c02
@ -29,7 +29,7 @@ from mediagoblin.db.extratypes import JSONEncoded, MutationDict
|
||||
from mediagoblin.db.migration_tools import (
|
||||
RegisterMigration, inspect_table, replace_table_hack)
|
||||
from mediagoblin.db.models import (MediaEntry, Collection, MediaComment, User,
|
||||
Privilege)
|
||||
Privilege, Generator)
|
||||
from mediagoblin.db.extratypes import JSONEncoded, MutationDict
|
||||
|
||||
|
||||
@ -578,30 +578,6 @@ PRIVILEGE_FOUNDATIONS_v0 = [{'privilege_name':u'admin'},
|
||||
{'privilege_name':u'commenter'},
|
||||
{'privilege_name':u'active'}]
|
||||
|
||||
|
||||
class Activity_R0(declarative_base()):
|
||||
__tablename__ = "core__activities"
|
||||
id = Column(Integer, primary_key=True)
|
||||
actor = Column(Integer, ForeignKey(User.id), nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
verb = Column(Unicode, nullable=False)
|
||||
content = Column(Unicode, nullable=False)
|
||||
title = Column(Unicode, nullable=True)
|
||||
target = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
object_comment = Column(Integer, ForeignKey(MediaComment.id), nullable=True)
|
||||
object_collection = Column(Integer, ForeignKey(Collection.id), nullable=True)
|
||||
object_media = Column(Integer, ForeignKey(MediaEntry.id), nullable=True)
|
||||
object_user = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
|
||||
class Generator(declarative_base()):
|
||||
__tablename__ = "core__generators"
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(Unicode, nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
object_type = Column(Unicode, nullable=False)
|
||||
|
||||
# vR1 stands for "version Rename 1". This only exists because we need
|
||||
# to deal with dropping some booleans and it's otherwise impossible
|
||||
# with sqlite.
|
||||
@ -914,17 +890,91 @@ def revert_username_index(db):
|
||||
|
||||
db.commit()
|
||||
|
||||
class Generator_R0(declarative_base()):
|
||||
__tablename__ = "core__generators"
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(Unicode, nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
object_type = Column(Unicode, nullable=False)
|
||||
|
||||
class Activity_R0(declarative_base()):
|
||||
__tablename__ = "core__activities"
|
||||
id = Column(Integer, primary_key=True)
|
||||
actor = Column(Integer, ForeignKey(User.id), nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
verb = Column(Unicode, nullable=False)
|
||||
content = Column(Unicode, nullable=False)
|
||||
title = Column(Unicode, nullable=True)
|
||||
target = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
generator = Column(Integer, ForeignKey(Generator.id), nullable=True)
|
||||
|
||||
class ActivityIntermediator_R0(declarative_base()):
|
||||
__tablename__ = "core__acitivity_intermediators"
|
||||
id = Column(Integer, primary_key=True)
|
||||
type = Column(Integer, nullable=False)
|
||||
|
||||
@RegisterMigration(24, MIGRATIONS)
|
||||
def create_activity_table(db):
|
||||
""" This will create the activity table """
|
||||
def activity_migration(db):
|
||||
"""
|
||||
Creates everything to create activities in GMG
|
||||
- Adds Activity, ActivityIntermediator and Generator table
|
||||
- Creates GMG service generator for activities produced by the server
|
||||
- Adds the activity_as_object and activity_as_target to objects/targets
|
||||
- Retroactively adds activities for what we can acurately work out
|
||||
"""
|
||||
# Set constants we'll use later
|
||||
FOREIGN_KEY = "core__acitivity_intermediators.id"
|
||||
|
||||
|
||||
# Create the new tables.
|
||||
Activity_R0.__table__.create(db.bind)
|
||||
Generator_R0.__table__.create(db.bind)
|
||||
ActivityIntermediator_R0.__table__.create(db.bind)
|
||||
db.commit()
|
||||
|
||||
# Create the GNU MediaGoblin generator
|
||||
gmg_generator = Generator(name="GNU MediaGoblin", object_type="service")
|
||||
gmg_generator.save()
|
||||
|
||||
|
||||
|
||||
# Initiate the tables we want to use later
|
||||
metadata = MetaData(bind=db.bind)
|
||||
user_table = inspect_table(metadata, "core__users")
|
||||
generator_table = inspect_table(metadata, "core__generators")
|
||||
collection_table = inspect_table(metadata, "core__collections")
|
||||
media_entry_table = inspect_table(metadata, "core__media_entries")
|
||||
media_comments_table = inspect_table(metadata, "core__media_comments")
|
||||
|
||||
|
||||
# Create the foundations for Generator
|
||||
db.execute(generator_table.insert().values(
|
||||
name="GNU Mediagoblin",
|
||||
object_type="service"
|
||||
))
|
||||
db.commit()
|
||||
|
||||
|
||||
# Now we want to modify the tables which MAY have an activity at some point
|
||||
as_object = Column("activity_as_object", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_object.create(media_entry_table)
|
||||
as_target = Column("activity_as_target", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_target.create(media_entry_table)
|
||||
|
||||
as_object = Column("activity_as_object", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_object.create(user_table)
|
||||
as_target = Column("activity_as_target", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_target.create(user_table)
|
||||
|
||||
as_object = Column("activity_as_object", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_object.create(media_comments_table)
|
||||
as_target = Column("activity_as_target", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_target.create(media_comments_table)
|
||||
|
||||
as_object = Column("activity_as_object", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_object.create(collection_table)
|
||||
as_target = Column("activity_as_target", Integer, ForeignKey(FOREIGN_KEY))
|
||||
as_target.create(collection_table)
|
||||
db.commit()
|
||||
|
||||
|
||||
# Now we want to retroactively add what activities we can
|
||||
# first we'll add activities when people uploaded media.
|
||||
for media in MediaEntry.query.all():
|
||||
@ -932,19 +982,40 @@ def create_activity_table(db):
|
||||
verb="create",
|
||||
actor=media.uploader,
|
||||
published=media.created,
|
||||
object_media=media.id,
|
||||
updated=media.created,
|
||||
generator=gmg_generator.id
|
||||
)
|
||||
activity.generate_content()
|
||||
activity.save()
|
||||
|
||||
activity.save(set_updated=False)
|
||||
activity.set_object(media)
|
||||
media.save()
|
||||
|
||||
# Now we want to add all the comments people made
|
||||
for comment in MediaComment.query.all():
|
||||
activity = Activity_R0(
|
||||
verb="comment",
|
||||
actor=comment.author,
|
||||
published=comment.created,
|
||||
updated=comment.created,
|
||||
generator=gmg_generator.id
|
||||
)
|
||||
activity.generate_content()
|
||||
activity.save()
|
||||
|
||||
activity.save(set_updated=False)
|
||||
activity.set_object(comment)
|
||||
comment.save()
|
||||
|
||||
# Create 'create' activities for all collections
|
||||
for collection in Collection.query.all():
|
||||
activity = Activity_R0(
|
||||
verb="create",
|
||||
actor=collection.creator,
|
||||
published=collection.created,
|
||||
updated=collection.created,
|
||||
generator=gmg_generator.id
|
||||
)
|
||||
activity.generate_content()
|
||||
activity.save(set_updated=False)
|
||||
activity.set_object(collection)
|
||||
collection.save()
|
||||
|
||||
db.commit()
|
||||
|
@ -39,6 +39,7 @@ from mediagoblin.tools import common, licenses
|
||||
from mediagoblin.tools.pluginapi import hook_handle
|
||||
from mediagoblin.tools.text import cleaned_markdown_conversion
|
||||
from mediagoblin.tools.url import slugify
|
||||
from mediagoblin.tools.translate import pass_to_ugettext as _
|
||||
|
||||
|
||||
class UserMixin(object):
|
||||
@ -208,7 +209,7 @@ class MediaEntryMixin(GenerateSlugMixin):
|
||||
will return self.thumb_url if original url doesn't exist"""
|
||||
if u"original" not in self.media_files:
|
||||
return self.thumb_url
|
||||
|
||||
|
||||
return mg_globals.app.public_store.file_url(
|
||||
self.media_files[u"original"]
|
||||
)
|
||||
@ -363,3 +364,109 @@ class CollectionItemMixin(object):
|
||||
Run through Markdown and the HTML cleaner.
|
||||
"""
|
||||
return cleaned_markdown_conversion(self.note)
|
||||
|
||||
class ActivityMixin(object):
|
||||
|
||||
VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite",
|
||||
"follow", "like", "post", "share", "unfavorite", "unfollow",
|
||||
"unlike", "unshare", "update", "tag"]
|
||||
|
||||
def get_url(self, request):
|
||||
return request.urlgen(
|
||||
"mediagoblin.federation.activity_view",
|
||||
username=self.get_actor.username,
|
||||
id=self.id,
|
||||
qualified=True
|
||||
)
|
||||
|
||||
def generate_content(self):
|
||||
""" Produces a HTML content for object """
|
||||
# some of these have simple and targetted. If self.target it set
|
||||
# it will pick the targetted. If they DON'T have a targetted version
|
||||
# the information in targetted won't be added to the content.
|
||||
verb_to_content = {
|
||||
"add": {
|
||||
"simple" : _("{username} added {object}"),
|
||||
"targetted": _("{username} added {object} to {target}"),
|
||||
},
|
||||
"author": {"simple": _("{username} authored {object}")},
|
||||
"create": {"simple": _("{username} created {object}")},
|
||||
"delete": {"simple": _("{username} deleted {object}")},
|
||||
"dislike": {"simple": _("{username} disliked {object}")},
|
||||
"favorite": {"simple": _("{username} favorited {object}")},
|
||||
"follow": {"simple": _("{username} followed {object}")},
|
||||
"like": {"simple": _("{username} liked {object}")},
|
||||
"post": {
|
||||
"simple": _("{username} posted {object}"),
|
||||
"targetted": _("{username} posted {object} to {targetted}"),
|
||||
},
|
||||
"share": {"simple": _("{username} shared {object}")},
|
||||
"unfavorite": {"simple": _("{username} unfavorited {object}")},
|
||||
"unfollow": {"simple": _("{username} stopped following {object}")},
|
||||
"unlike": {"simple": _("{username} unliked {object}")},
|
||||
"unshare": {"simple": _("{username} unshared {object}")},
|
||||
"update": {"simple": _("{username} updated {object}")},
|
||||
"tag": {"simple": _("{username} tagged {object}")},
|
||||
}
|
||||
|
||||
obj = self.get_object()
|
||||
target = self.get_target()
|
||||
actor = self.get_actor
|
||||
content = verb_to_content.get(self.verb, None)
|
||||
|
||||
if content is None or obj is None:
|
||||
return
|
||||
|
||||
if target is None or "targetted" not in content:
|
||||
self.content = content["simple"].format(
|
||||
username=actor.username,
|
||||
object=obj.objectType
|
||||
)
|
||||
else:
|
||||
self.content = content["targetted"].format(
|
||||
username=actor.username,
|
||||
object=obj.objectType,
|
||||
target=target.objectType,
|
||||
)
|
||||
|
||||
return self.content
|
||||
|
||||
def serialize(self, request):
|
||||
obj = {
|
||||
"id": self.id,
|
||||
"actor": self.get_actor.serialize(request),
|
||||
"verb": self.verb,
|
||||
"published": self.published.isoformat(),
|
||||
"updated": self.updated.isoformat(),
|
||||
"content": self.content,
|
||||
"url": self.get_url(request),
|
||||
"object": self.get_object().serialize(request)
|
||||
}
|
||||
|
||||
if self.generator:
|
||||
obj["generator"] = self.get_generator.seralize(request)
|
||||
|
||||
if self.title:
|
||||
obj["title"] = self.title
|
||||
|
||||
target = self.get_target()
|
||||
if target is not None:
|
||||
obj["target"] = target.seralize(request)
|
||||
|
||||
return obj
|
||||
|
||||
def unseralize(self, data):
|
||||
"""
|
||||
Takes data given and set it on this activity.
|
||||
|
||||
Several pieces of data are not written on because of security
|
||||
reasons. For example changing the author or id of an activity.
|
||||
"""
|
||||
if "verb" in data:
|
||||
self.verb = data["verb"]
|
||||
|
||||
if "title" in data:
|
||||
self.title = data["title"]
|
||||
|
||||
if "content" in data:
|
||||
self.content = data["content"]
|
||||
|
@ -35,9 +35,9 @@ from mediagoblin.db.extratypes import (PathTupleWithSlashes, JSONEncoded,
|
||||
MutationDict)
|
||||
from mediagoblin.db.base import Base, DictReadAttrProxy
|
||||
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \
|
||||
MediaCommentMixin, CollectionMixin, CollectionItemMixin
|
||||
MediaCommentMixin, CollectionMixin, CollectionItemMixin, \
|
||||
ActivityMixin
|
||||
from mediagoblin.tools.files import delete_media_files
|
||||
from mediagoblin.tools.translate import pass_to_ugettext as _
|
||||
from mediagoblin.tools.common import import_component
|
||||
|
||||
# It's actually kind of annoying how sqlalchemy-migrate does this, if
|
||||
@ -77,6 +77,11 @@ class User(Base, UserMixin):
|
||||
uploaded = Column(Integer, default=0)
|
||||
upload_limit = Column(Integer)
|
||||
|
||||
activity_as_object = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
activity_as_target = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
|
||||
## TODO
|
||||
# plugin data would be in a separate model
|
||||
|
||||
@ -313,6 +318,11 @@ class MediaEntry(Base, MediaEntryMixin):
|
||||
media_metadata = Column(MutationDict.as_mutable(JSONEncoded),
|
||||
default=MutationDict())
|
||||
|
||||
activity_as_object = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
activity_as_target = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
|
||||
## TODO
|
||||
# fail_error
|
||||
|
||||
@ -656,8 +666,14 @@ class MediaComment(Base, MediaCommentMixin):
|
||||
lazy="dynamic",
|
||||
cascade="all, delete-orphan"))
|
||||
|
||||
|
||||
activity_as_object = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
activity_as_target = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
|
||||
objectType = "comment"
|
||||
|
||||
|
||||
def serialize(self, request):
|
||||
""" Unserialize to python dictionary for API """
|
||||
media = MediaEntry.query.filter_by(id=self.media_entry).first()
|
||||
@ -722,6 +738,11 @@ class Collection(Base, CollectionMixin):
|
||||
backref=backref("collections",
|
||||
cascade="all, delete-orphan"))
|
||||
|
||||
activity_as_object = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
activity_as_target = Column(Integer,
|
||||
ForeignKey("core__acitivity_intermediators.id"))
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint('creator', 'slug'),
|
||||
{})
|
||||
@ -1069,13 +1090,13 @@ class Generator(Base):
|
||||
objects for the pump.io APIs.
|
||||
"""
|
||||
__tablename__ = "core__generators"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(Unicode, nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
published = Column(DateTime, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, default=datetime.datetime.now)
|
||||
object_type = Column(Unicode, nullable=False)
|
||||
|
||||
|
||||
def serialize(self, request):
|
||||
return {
|
||||
"id": self.id,
|
||||
@ -1084,199 +1105,144 @@ class Generator(Base):
|
||||
"updated": self.updated.isoformat(),
|
||||
"objectType": self.object_type,
|
||||
}
|
||||
|
||||
|
||||
def unserialize(self, data):
|
||||
if "displayName" in data:
|
||||
self.name = data["displayName"]
|
||||
|
||||
|
||||
|
||||
class Activity(Base):
|
||||
|
||||
class ActivityIntermediator(Base):
|
||||
"""
|
||||
This is used so that objects/targets can have a foreign key back to this
|
||||
object and activities can a foreign key to this object. This objects to be
|
||||
used multiple times for the activity object or target and also allows for
|
||||
different types of objects to be used as an Activity.
|
||||
"""
|
||||
__tablename__ = "core__acitivity_intermediators"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
type = Column(Integer, nullable=False)
|
||||
|
||||
TYPES = {
|
||||
0: User,
|
||||
1: MediaEntry,
|
||||
2: MediaComment,
|
||||
3: Collection,
|
||||
}
|
||||
|
||||
def _find_model(self, obj):
|
||||
""" Finds the model for a given object """
|
||||
for key, model in self.TYPES.items():
|
||||
if isinstance(obj, model):
|
||||
return key, model
|
||||
|
||||
return None, None
|
||||
|
||||
def set_object(self, obj):
|
||||
""" This sets itself as the object for an activity """
|
||||
key, model = self._find_model(obj)
|
||||
if key is None:
|
||||
raise ValueError("Invalid type of object given")
|
||||
|
||||
# First set self as activity
|
||||
obj.activity_as_object = self.id
|
||||
self.type = key
|
||||
|
||||
@property
|
||||
def get_object(self):
|
||||
""" Finds the object for an activity """
|
||||
if self.type is None:
|
||||
return None
|
||||
|
||||
model = self.TYPES[self.type]
|
||||
return model.query.filter_by(activity_as_object=self.id).first()
|
||||
|
||||
def set_target(self, obj):
|
||||
""" This sets itself as the target for an activity """
|
||||
key, model = self._find_model(obj)
|
||||
if key is None:
|
||||
raise ValueError("Invalid type of object given")
|
||||
|
||||
obj.activity_as_target = self.id
|
||||
self.type = key
|
||||
|
||||
@property
|
||||
def get_target(self):
|
||||
""" Gets the target for an activity """
|
||||
if self.type is None:
|
||||
return None
|
||||
|
||||
model = self.TYPES[self.type]
|
||||
return model.query.filter_by(activity_as_target=self.id).first()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.type not in self.TYPES.keys():
|
||||
raise ValueError("Invalid type set")
|
||||
Base.save(self, *args, **kwargs)
|
||||
|
||||
class Activity(Base, ActivityMixin):
|
||||
"""
|
||||
This holds all the metadata about an activity such as uploading an image,
|
||||
posting a comment, etc.
|
||||
posting a comment, etc.
|
||||
"""
|
||||
__tablename__ = "core__activities"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
actor = Column(Integer, ForeignKey(User.id), nullable=False)
|
||||
actor = Column(Integer,
|
||||
ForeignKey(User.id, use_alter=True, name="actor"),
|
||||
nullable=False)
|
||||
published = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||
verb = Column(Unicode, nullable=False)
|
||||
content = Column(Unicode, nullable=True)
|
||||
title = Column(Unicode, nullable=True)
|
||||
target = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
generator = Column(Integer, ForeignKey(Generator.id), nullable=True)
|
||||
|
||||
|
||||
# Links to other models (only one of these should have a value).
|
||||
object_comment = Column(Integer, ForeignKey(MediaComment.id), nullable=True)
|
||||
object_collection = Column(Integer, ForeignKey(Collection.id), nullable=True)
|
||||
object_media = Column(Integer, ForeignKey(MediaEntry.id), nullable=True)
|
||||
object_user = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
|
||||
# The target could also be several things
|
||||
target_comment = Column(Integer, ForeignKey(MediaComment.id), nullable=True)
|
||||
target_collection = Column(Integer, ForeignKey(Collection.id), nullable=True)
|
||||
target_media = Column(Integer, ForeignKey(MediaEntry.id), nullable=True)
|
||||
target_user = Column(Integer, ForeignKey(User.id), nullable=True)
|
||||
|
||||
get_actor = relationship(User, foreign_keys="Activity.actor")
|
||||
object = Column(Integer,
|
||||
ForeignKey(ActivityIntermediator.id), nullable=False)
|
||||
target = Column(Integer,
|
||||
ForeignKey(ActivityIntermediator.id), nullable=True)
|
||||
|
||||
get_actor = relationship(User,
|
||||
foreign_keys="Activity.actor", post_update=True)
|
||||
get_generator = relationship(Generator)
|
||||
|
||||
VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite",
|
||||
"follow", "like", "post", "share", "unfavorite", "unfollow",
|
||||
"unlike", "unshare", "update", "tag"]
|
||||
|
||||
def get_object(self):
|
||||
""" This represents the object that is given to the activity """
|
||||
# Do we have a cached version
|
||||
if getattr(self, "_cached_object", None) is not None:
|
||||
return self._cached_object
|
||||
|
||||
if self.object_comment is not None:
|
||||
obj = MediaComment.query.filter_by(id=self.object_comment).first()
|
||||
elif self.object_collection is not None:
|
||||
obj = Collection.query.filter_by(id=self.object_collection).first()
|
||||
elif self.object_media is not None:
|
||||
obj = MediaEntry.query.filter_by(id=self.object_media).first()
|
||||
elif self.object_user is not None:
|
||||
obj = User.query.filter_by(id=self.object_user).first()
|
||||
else:
|
||||
# Shouldn't happen but in case it does
|
||||
return None
|
||||
|
||||
self._cached_object = obj
|
||||
return obj
|
||||
|
||||
def get_target(self):
|
||||
""" This represents the target given on the activity (if any) """
|
||||
if getattr(self, "_cached_target", None) is not None:
|
||||
return self._cached_target
|
||||
|
||||
if self.target_comment is not None:
|
||||
target = MediaComment.query.filter_by(id=self.target_comment).first()
|
||||
elif self.target_collection is not None:
|
||||
target = Collection.query.filter_by(id=self.target_collection).first()
|
||||
elif self.target_media is not None:
|
||||
target = MediaEntry.query.filter_by(id=self.target_media).first()
|
||||
elif self.target_user is not None:
|
||||
target = User.query.filter_by(id=self.target_user).first()
|
||||
else:
|
||||
# Shouldn't happen but in case it does
|
||||
return None
|
||||
|
||||
self._cached_target = target
|
||||
return self._cached_target
|
||||
|
||||
|
||||
def url(self, request):
|
||||
actor = User.query.filter_by(id=self.actor).first()
|
||||
return request.urlgen(
|
||||
"mediagoblin.federation.activity_view",
|
||||
username=actor.username,
|
||||
id=self.id,
|
||||
qualified=True
|
||||
)
|
||||
|
||||
def generate_content(self):
|
||||
"""
|
||||
Produces a HTML content for object
|
||||
TODO: Can this be moved to a mixin?
|
||||
"""
|
||||
# some of these have simple and targetted. If self.target it set
|
||||
# it will pick the targetted. If they DON'T have a targetted version
|
||||
# the information in targetted won't be added to the content.
|
||||
verb_to_content = {
|
||||
"add": {
|
||||
"simple" : _("{username} added {object}"),
|
||||
"targetted": _("{username} added {object} to {target}"),
|
||||
},
|
||||
"author": {"simple": _("{username} authored {object}")},
|
||||
"create": {"simple": _("{username} created {object}")},
|
||||
"delete": {"simple": _("{username} deleted {object}")},
|
||||
"dislike": {"simple": _("{username} disliked {object}")},
|
||||
"favorite": {"simple": _("{username} favorited {object}")},
|
||||
"follow": {"simple": _("{username} followed {object}")},
|
||||
"like": {"simple": _("{username} liked {object}")},
|
||||
"post": {
|
||||
"simple": _("{username} posted {object}"),
|
||||
"targetted": _("{username} posted {object} to {targetted}"),
|
||||
},
|
||||
"share": {"simple": _("{username} shared {object}")},
|
||||
"unfavorite": {"simple": _("{username} unfavorited {object}")},
|
||||
"unfollow": {"simple": _("{username} stopped following {object}")},
|
||||
"unlike": {"simple": _("{username} unliked {object}")},
|
||||
"unshare": {"simple": _("{username} unshared {object}")},
|
||||
"update": {"simple": _("{username} updated {object}")},
|
||||
"tag": {"simple": _("{username} tagged {object}")},
|
||||
}
|
||||
|
||||
obj = self.get_object()
|
||||
target = self.get_target()
|
||||
actor = self.get_actor
|
||||
content = verb_to_content.get(self.verb, None)
|
||||
|
||||
if content is None or obj is None:
|
||||
|
||||
def set_object(self, *args, **kwargs):
|
||||
if self.object is None:
|
||||
ai = ActivityIntermediator()
|
||||
ai.set_object(*args, **kwargs)
|
||||
ai.save()
|
||||
self.object = ai.id
|
||||
return
|
||||
|
||||
if target is None or "targetted" not in content:
|
||||
self.content = content["simple"].format(
|
||||
username=actor.username,
|
||||
object=obj.objectType
|
||||
)
|
||||
else:
|
||||
self.content = content["targetted"].format(
|
||||
username=actor.username,
|
||||
object=obj.objectType,
|
||||
target=target.objectType,
|
||||
)
|
||||
|
||||
return self.content
|
||||
|
||||
def serialize(self, request):
|
||||
obj = {
|
||||
"id": self.id,
|
||||
"actor": self.get_actor.serialize(request),
|
||||
"verb": self.verb,
|
||||
"published": self.published.isoformat(),
|
||||
"updated": self.updated.isoformat(),
|
||||
"content": self.content,
|
||||
"url": self.url(request),
|
||||
"object": self.get_object().serialize(request)
|
||||
}
|
||||
|
||||
if self.generator:
|
||||
obj["generator"] = generator.seralize(request)
|
||||
|
||||
if self.title:
|
||||
obj["title"] = self.title
|
||||
|
||||
target = self.get_target()
|
||||
if target is not None:
|
||||
obj["target"] = target.seralize(request)
|
||||
|
||||
return obj
|
||||
|
||||
def unseralize(self, data):
|
||||
"""
|
||||
Takes data given and set it on this activity.
|
||||
|
||||
Several pieces of data are not written on because of security
|
||||
reasons. For example changing the author or id of an activity.
|
||||
"""
|
||||
if "verb" in data:
|
||||
self.verb = data["verb"]
|
||||
|
||||
if "title" in data:
|
||||
self.title = data["title"]
|
||||
|
||||
if "content" in data:
|
||||
self.content = data["content"]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.updated = datetime.datetime.now()
|
||||
super(Activity, self).save(*args, **kwargs)
|
||||
|
||||
self.object.set_object(*args, **kwargs)
|
||||
self.object.save()
|
||||
|
||||
@property
|
||||
def get_object(self):
|
||||
return self.object.get_object
|
||||
|
||||
def set_target(self, *args, **kwargs):
|
||||
if self.target is None:
|
||||
ai = ActivityIntermediator()
|
||||
ai.set_target(*args, **kwargs)
|
||||
ai.save()
|
||||
self.object = ai.id
|
||||
return
|
||||
|
||||
self.target.set_object(*args, **kwargs)
|
||||
self.targt.save()
|
||||
|
||||
@property
|
||||
def get_target(self):
|
||||
if self.target is None:
|
||||
return None
|
||||
|
||||
return self.target.get_target
|
||||
|
||||
def save(self, set_updated=True, *args, **kwargs):
|
||||
if set_updated:
|
||||
self.updated = datetime.datetime.now()
|
||||
super(Activity, self).save(*args, **kwargs)
|
||||
|
||||
MODELS = [
|
||||
User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
|
||||
@ -1285,7 +1251,7 @@ MODELS = [
|
||||
CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan,
|
||||
Privilege, PrivilegeUserAssociation,
|
||||
RequestToken, AccessToken, NonceTimestamp,
|
||||
Activity, Generator]
|
||||
Activity, ActivityIntermediator, Generator]
|
||||
|
||||
"""
|
||||
Foundations are the default rows that are created immediately after the tables
|
||||
|
Loading…
x
Reference in New Issue
Block a user