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)
+ 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)
+ object = Column(Integer,
+ ForeignKey("core__activity_intermediators.id"),
+ nullable=False)
+ target = Column(Integer,
+ ForeignKey("core__activity_intermediators.id"),
+ nullable=True)
class ActivityIntermediator_R0(declarative_base()):
- __tablename__ = "core__acitivity_intermediators"
+ __tablename__ = "core__activity_intermediators"
id = Column(Integer, primary_key=True)
- type = Column(Integer, nullable=False)
+ type = Column(Unicode, nullable=False)
@RegisterMigration(24, MIGRATIONS)
def activity_migration(db):
- Retroactively adds activities for what we can acurately work out
"""
# Set constants we'll use later
- FOREIGN_KEY = "core__acitivity_intermediators.id"
+ FOREIGN_KEY = "core__activity_intermediators.id"
# Create the new tables.
- Activity_R0.__table__.create(db.bind)
- Generator_R0.__table__.create(db.bind)
ActivityIntermediator_R0.__table__.create(db.bind)
+ Generator_R0.__table__.create(db.bind)
+ Activity_R0.__table__.create(db.bind)
db.commit()
# Initiate the tables we want to use later
metadata = MetaData(bind=db.bind)
user_table = inspect_table(metadata, "core__users")
+ activity_table = inspect_table(metadata, "core__activities")
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")
+ ai_table = inspect_table(metadata, "core__activity_intermediators")
# Create the foundations for Generator
db.execute(generator_table.insert().values(
name="GNU Mediagoblin",
- object_type="service"
+ object_type="service",
+ published=datetime.datetime.now(),
+ updated=datetime.datetime.now()
))
db.commit()
+ # Get the ID of that generator
+ gmg_generator = db.execute(generator_table.select(
+ generator_table.c.name==u"GNU Mediagoblin")).first()
+
# 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))
# 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():
- activity = Activity_R0(
- verb="create",
- actor=media.uploader,
- published=media.created,
- updated=media.created,
- generator=gmg_generator.id
- )
- activity.generate_content()
- activity.save(set_updated=False)
- activity.set_object(media)
- media.save()
+ # these can't have content as it's not fesible to get the
+ # correct content strings.
+ for media in db.execute(media_entry_table.select()):
+ # Now we want to create the intermedaitory
+ db_ai = db.execute(ai_table.insert().values(
+ type="media",
+ ))
+ db_ai = db.execute(ai_table.select(
+ ai_table.c.id==db_ai.inserted_primary_key[0]
+ )).first()
+
+ # Add the activity
+ activity = {
+ "verb": "create",
+ "actor": media.uploader,
+ "published": media.created,
+ "updated": media.created,
+ "generator": gmg_generator.id,
+ "object": db_ai.id
+ }
+ db.execute(activity_table.insert().values(**activity))
+
+ # Add the AI to the media.
+ db.execute(media_entry_table.update().values(
+ activity_as_object=db_ai.id
+ ).where(id=media.id))
# 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(set_updated=False)
- activity.set_object(comment)
- comment.save()
+ for comment in db.execute(media_comments_table.select()):
+ # Get the MediaEntry for the comment
+ media_entry = db.execute(
+ media_entry_table.select(id=comment.media_entry_id))
+
+ # Create an AI for target
+ db_ai_media = db.execute(ai_table.insert().values(
+ type="media"
+ ))
+ db_ai_media = db.execute(ai_table.select(
+ ai_table.c.id==db_ai_media.inserted_primary_key[0]
+ ))
+
+ db.execute(
+ media_entry_table.update().values(
+ activity_as_target=db_ai_media.id
+ ).where(id=media_entry.id))
+
+ # Now create the AI for the comment
+ db_ai_comment = db.execute(ai_table.insert().values(
+ type="comment"
+ ))
+
+ activity = {
+ "verb": "comment",
+ "actor": comment.author,
+ "published": comment.created,
+ "updated": comment.created,
+ "generator": gmg_generator.id,
+ "object": db_ai_comment.id,
+ "target": db_ai_media.id,
+ }
+
+ # Now add the comment object
+ db.execute(media_comments_table.insert().values(**activity))
# 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()
+ for collection in db.execute(collection_table.select()):
+ # create AI
+ db_ai = db.execute(ai_table.insert().values(
+ type="collection"
+ ))
+
+ # Now add link the collection to the AI
+ db.execute(collection_table.update().values(
+ activity_as_object=db_ai.id
+ ).where(id=collection.id))
+
+ activity = {
+ "verb": "create",
+ "actor": collection.creator,
+ "published": collection.created,
+ "updated": collection.created,
+ "generator": gmg_generator.id,
+ "object": db_ai.id,
+ }
+
+ db.execute(activity_table.insert().values(**activity))
+
+
db.commit()
class UserMixin(object):
+ object_type = "person"
+
@property
def bio_html(self):
return cleaned_markdown_conversion(self.bio)
return check_media_slug_used(self.uploader, slug, self.id)
+ @property
+ def object_type(self):
+ """ Converts media_type to pump-like type - don't use internally """
+ return self.media_type.split(".")[-1]
+
@property
def description_html(self):
"""
class MediaCommentMixin(object):
+ object_type = "comment"
+
@property
def content_html(self):
"""
class CollectionMixin(GenerateSlugMixin):
+ object_type = "collection"
+
def check_slug_used(self, slug):
# import this here due to a cyclic import issue
# (db.models -> db.mixin -> db.util -> db.models)
return cleaned_markdown_conversion(self.note)
class ActivityMixin(object):
+ object_type = "activity"
VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite",
"follow", "like", "post", "share", "unfavorite", "unfollow",
"updated": self.updated.isoformat(),
"content": self.content,
"url": self.get_url(request),
- "object": self.get_object().serialize(request)
+ "object": self.get_object().serialize(request),
+ "objectType": self.object_type,
}
if self.generator:
upload_limit = Column(Integer)
activity_as_object = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
activity_as_target = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
## TODO
# plugin data would be in a separate model
- objectType = "person"
-
def __repr__(self):
return '<{0} #{1} {2} {3} "{4}">'.format(
self.__class__.__name__,
"id": "acct:{0}@{1}".format(self.username, request.host),
"preferredUsername": self.username,
"displayName": "{0}@{1}".format(self.username, request.host),
- "objectType": self.objectType,
+ "objectType": self.object_type,
"pump_io": {
"shared": False,
"followed": False,
default=MutationDict())
activity_as_object = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
activity_as_target = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
## TODO
# fail_error
# pass through commit=False/True in kwargs
super(MediaEntry, self).delete(**kwargs)
- @property
- def objectType(self):
- """ Converts media_type to pump-like type - don't use internally """
- return self.media_type.split(".")[-1]
-
def serialize(self, request, show_comments=True):
""" Unserialize MediaEntry to object """
author = self.get_uploader
context = {
"id": self.id,
"author": author.serialize(request),
- "objectType": self.objectType,
+ "objectType": self.object_type,
"url": self.url_for_self(request.urlgen),
"image": {
"url": request.host_url + self.thumb_url[1:],
"self": {
"href": request.urlgen(
"mediagoblin.federation.object",
- objectType=self.objectType,
+ object_type=self.objectType,
id=self.id,
qualified=True
),
context["license"] = self.license
if show_comments:
- comments = [comment.serialize(request) for comment in self.get_comments()]
+ comments = [
+ comment.serialize(request) for comment in self.get_comments()]
total = len(comments)
context["replies"] = {
"totalItems": total,
"items": comments,
"url": request.urlgen(
"mediagoblin.federation.object.comments",
- objectType=self.objectType,
+ object_type=self.object_type,
id=self.id,
qualified=True
),
creator=Tag.find_or_new
)
- objectType = "tag"
-
def __init__(self, name=None, slug=None):
Base.__init__(self)
if name is not None:
activity_as_object = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
activity_as_target = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
-
- objectType = "comment"
+ ForeignKey("core__activity_intermediators.id"))
def serialize(self, request):
""" Unserialize to python dictionary for API """
author = self.get_author
context = {
"id": self.id,
- "objectType": self.objectType,
+ "objectType": self.object_type,
"content": self.content,
"inReplyTo": media.serialize(request, show_comments=False),
"author": author.serialize(request)
cascade="all, delete-orphan"))
activity_as_object = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
activity_as_target = Column(Integer,
- ForeignKey("core__acitivity_intermediators.id"))
+ ForeignKey("core__activity_intermediators.id"))
__table_args__ = (
UniqueConstraint('creator', 'slug'),
{})
- objectType = "collection"
-
def get_collection_items(self, ascending=False):
#TODO, is this still needed with self.collection_items being available?
order_col = CollectionItem.position
primary_key=True)
class Generator(Base):
- """
- This holds the information about the software used to create
- objects for the pump.io APIs.
- """
+ """ Information about what created an activity """
__tablename__ = "core__generators"
id = Column(Integer, primary_key=True)
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"
+ __tablename__ = "core__activity_intermediators"
id = Column(Integer, primary_key=True)
- type = Column(Integer, nullable=False)
+ type = Column(Unicode, nullable=False)
TYPES = {
- 0: User,
- 1: MediaEntry,
- 2: MediaComment,
- 3: Collection,
+ "user": User,
+ "media": MediaEntry,
+ "comment": MediaComment,
+ "collection": Collection,
}
def _find_model(self, obj):
id = Column(Integer, primary_key=True)
actor = Column(Integer,
- ForeignKey(User.id, use_alter=True, name="actor"),
+ ForeignKey("core__users.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=True)
title = Column(Unicode, nullable=True)
- generator = Column(Integer, ForeignKey(Generator.id), nullable=True)
+ generator = Column(Integer,
+ ForeignKey("core__generators.id"),
+ nullable=True)
object = Column(Integer,
- ForeignKey(ActivityIntermediator.id), nullable=False)
+ ForeignKey("core__activity_intermediators.id"),
+ nullable=False)
target = Column(Integer,
- ForeignKey(ActivityIntermediator.id), nullable=True)
+ ForeignKey("core__activity_intermediators.id"),
+ nullable=True)
get_actor = relationship(User,
foreign_keys="Activity.actor", post_update=True)
self.object = ai.id
return
- self.object.set_object(*args, **kwargs)
- self.object.save()
+ ai = ActivityIntermediator.query.filter_by(id=self.object).first()
+ ai.set_object(*args, **kwargs)
+ ai.save()
@property
def get_object(self):
self.object = ai.id
return
- self.target.set_object(*args, **kwargs)
- self.targt.save()
+ ai = ActivityIntermediator.query.filter_by(id=self.target).first()
+ ai.set_object(*args, **kwargs)
+ ai.save()
@property
def get_target(self):
# object endpoints
add_route(
"mediagoblin.federation.object",
- "/api/<string:objectType>/<string:id>",
+ "/api/<string:object_type>/<string:id>",
"mediagoblin.federation.views:object_endpoint"
)
add_route(
"mediagoblin.federation.object.comments",
- "/api/<string:objectType>/<string:id>/comments",
+ "/api/<string:object_type>/<string:id>/comments",
"mediagoblin.federation.views:object_comments"
)
def user_endpoint(request):
""" This is /api/user/<username> - This will get the user """
user, user_profile = get_profile(request)
-
+
if user is None:
username = request.matchdict["username"]
return json_error(
"No such 'user' with username '{0}'".format(username),
status=404
)
-
+
return json_response({
"nickname": user.username,
"updated": user.created.isoformat(),
@oauth_required
def object_endpoint(request):
""" Lookup for a object type """
- object_type = request.matchdict["objectType"]
+ object_type = request.matchdict["object_type"]
try:
object_id = int(request.matchdict["id"])
except ValueError:
media = MediaEntry.query.filter_by(id=request.matchdict["id"]).first()
if media is None:
return json_error("Can't find '{0}' with ID '{1}'".format(
- request.matchdict["objectType"],
+ request.matchdict["object_type"],
request.matchdict["id"]
), 404)
- comments = response.serialize(request)
+ comments = media.serialize(request)
comments = comments.get("replies", {
"totalItems": 0,
"items": [],
"url": request.urlgen(
"mediagoblin.federation.object.comments",
- objectType=media.objectType,
+ object_type=media.object_type,
id=media.id,
qualified=True
)
@require_active_login
def activity_view(request):
""" /<username>/activity/<id> - Display activity
-
+
This should display a HTML presentation of the activity
this is NOT an API endpoint.
"""
# Get the user object.
username = request.matchdict["username"]
user = User.query.filter_by(username=username).first()
-
+
activity_id = request.matchdict["id"]
-
+
if request.user is None:
return render_404(request)
-
- activity = Activity.query.filter_by(id=activity_id).first()
+
+ activity = Activity.query.filter_by(
+ id=activity_id,
+ author=user.id
+ ).first()
if activity is None:
return render_404(request)
-
+
return render_to_response(
request,
"mediagoblin/federation/activity.html",
{"activity": activity}
)
-
-
+
+