Create activity model and add activity creation
This creates the Activity and Genrator models from the Activity Streams spec and. I then created a migration which retro-actively create activities for media uploaded and comments created. Through out the code I've added so automatically activties are created when a user peforms an action (uploading media, commenting, etc.).
This commit is contained in:
parent
51f4911855
commit
b949201152
@ -579,6 +579,29 @@ PRIVILEGE_FOUNDATIONS_v0 = [{'privilege_name':u'admin'},
|
|||||||
{'privilege_name':u'active'}]
|
{'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
|
# vR1 stands for "version Rename 1". This only exists because we need
|
||||||
# to deal with dropping some booleans and it's otherwise impossible
|
# to deal with dropping some booleans and it's otherwise impossible
|
||||||
# with sqlite.
|
# with sqlite.
|
||||||
@ -890,3 +913,38 @@ def revert_username_index(db):
|
|||||||
db.rollback()
|
db.rollback()
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
@RegisterMigration(24, MIGRATIONS)
|
||||||
|
def create_activity_table(db):
|
||||||
|
""" This will create the activity table """
|
||||||
|
Activity_R0.__table__.create(db.bind)
|
||||||
|
Generator_R0.__table__.create(db.bind)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
# Create the GNU MediaGoblin generator
|
||||||
|
gmg_generator = Generator(name="GNU MediaGoblin", object_type="service")
|
||||||
|
gmg_generator.save()
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
object_media=media.id,
|
||||||
|
)
|
||||||
|
activity.generate_content()
|
||||||
|
activity.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,
|
||||||
|
)
|
||||||
|
activity.generate_content()
|
||||||
|
activity.save()
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
@ -37,6 +37,7 @@ from mediagoblin.db.base import Base, DictReadAttrProxy
|
|||||||
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \
|
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \
|
||||||
MediaCommentMixin, CollectionMixin, CollectionItemMixin
|
MediaCommentMixin, CollectionMixin, CollectionItemMixin
|
||||||
from mediagoblin.tools.files import delete_media_files
|
from mediagoblin.tools.files import delete_media_files
|
||||||
|
from mediagoblin.tools.translate import pass_to_ugettext as _
|
||||||
from mediagoblin.tools.common import import_component
|
from mediagoblin.tools.common import import_component
|
||||||
|
|
||||||
# It's actually kind of annoying how sqlalchemy-migrate does this, if
|
# It's actually kind of annoying how sqlalchemy-migrate does this, if
|
||||||
@ -79,6 +80,8 @@ class User(Base, UserMixin):
|
|||||||
## TODO
|
## TODO
|
||||||
# plugin data would be in a separate model
|
# plugin data would be in a separate model
|
||||||
|
|
||||||
|
objectType = "person"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<{0} #{1} {2} {3} "{4}">'.format(
|
return '<{0} #{1} {2} {3} "{4}">'.format(
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
@ -143,7 +146,7 @@ class User(Base, UserMixin):
|
|||||||
"id": "acct:{0}@{1}".format(self.username, request.host),
|
"id": "acct:{0}@{1}".format(self.username, request.host),
|
||||||
"preferredUsername": self.username,
|
"preferredUsername": self.username,
|
||||||
"displayName": "{0}@{1}".format(self.username, request.host),
|
"displayName": "{0}@{1}".format(self.username, request.host),
|
||||||
"objectType": "person",
|
"objectType": self.objectType,
|
||||||
"pump_io": {
|
"pump_io": {
|
||||||
"shared": False,
|
"shared": False,
|
||||||
"followed": False,
|
"followed": False,
|
||||||
@ -651,13 +654,15 @@ class MediaComment(Base, MediaCommentMixin):
|
|||||||
lazy="dynamic",
|
lazy="dynamic",
|
||||||
cascade="all, delete-orphan"))
|
cascade="all, delete-orphan"))
|
||||||
|
|
||||||
|
objectType = "comment"
|
||||||
|
|
||||||
def serialize(self, request):
|
def serialize(self, request):
|
||||||
""" Unserialize to python dictionary for API """
|
""" Unserialize to python dictionary for API """
|
||||||
media = MediaEntry.query.filter_by(id=self.media_entry).first()
|
media = MediaEntry.query.filter_by(id=self.media_entry).first()
|
||||||
author = self.get_author
|
author = self.get_author
|
||||||
context = {
|
context = {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"objectType": "comment",
|
"objectType": self.objectType,
|
||||||
"content": self.content,
|
"content": self.content,
|
||||||
"inReplyTo": media.serialize(request, show_comments=False),
|
"inReplyTo": media.serialize(request, show_comments=False),
|
||||||
"author": author.serialize(request)
|
"author": author.serialize(request)
|
||||||
@ -1054,13 +1059,196 @@ class PrivilegeUserAssociation(Base):
|
|||||||
ForeignKey(Privilege.id),
|
ForeignKey(Privilege.id),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
|
|
||||||
|
class Generator(Base):
|
||||||
|
"""
|
||||||
|
This holds the information about the software used to create
|
||||||
|
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)
|
||||||
|
object_type = Column(Unicode, nullable=False)
|
||||||
|
|
||||||
|
def serialize(self, request):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"displayName": self.name,
|
||||||
|
"published": self.published.isoformat(),
|
||||||
|
"updated": self.updated.isoformat(),
|
||||||
|
"objectType": self.object_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
def unserialize(self, data):
|
||||||
|
if "displayName" in data:
|
||||||
|
self.name = data["displayName"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Activity(Base):
|
||||||
|
"""
|
||||||
|
This holds all the metadata about an activity such as uploading an image,
|
||||||
|
posting a comment, etc.
|
||||||
|
"""
|
||||||
|
__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)
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite",
|
||||||
|
"follow", "like", "post", "share", "unfavorite", "unfollow",
|
||||||
|
"unlike", "unshare", "update", "tag"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def 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 incase it does
|
||||||
|
return None
|
||||||
|
|
||||||
|
self._cached_object = obj
|
||||||
|
return obj
|
||||||
|
|
||||||
|
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?
|
||||||
|
"""
|
||||||
|
verb_to_content = {
|
||||||
|
"add": _("{username} added {object} to {destination}"),
|
||||||
|
"author": _("{username} authored {object}"),
|
||||||
|
"create": _("{username} created {object}"),
|
||||||
|
"delete": _("{username} deleted {object}"),
|
||||||
|
"dislike": _("{username} disliked {object}"),
|
||||||
|
"favorite": _("{username} favorited {object}"),
|
||||||
|
"follow": _("{username} followed {object}"),
|
||||||
|
"like": _("{username} liked {object}"),
|
||||||
|
"post": _("{username} posted {object}"),
|
||||||
|
"share": _("{username} shared {object}"),
|
||||||
|
"unfavorite": _("{username} unfavorited {object}"),
|
||||||
|
"unfollow": _("{username} stopped following {object}"),
|
||||||
|
"unlike": _("{username} unliked {object}"),
|
||||||
|
"unshare": _("{username} unshared {object}"),
|
||||||
|
"update": _("{username} updated {object}"),
|
||||||
|
"tag": _("{username} tagged {object}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
actor = User.query.filter_by(id=self.actor).first()
|
||||||
|
|
||||||
|
if self.verb == "add" and self.object.objectType == "collection":
|
||||||
|
media = MediaEntry.query.filter_by(id=self.object.media_entry)
|
||||||
|
content = verb_to_content[self.verb]
|
||||||
|
self.content = content.format(
|
||||||
|
username=actor.username,
|
||||||
|
object=media.objectType,
|
||||||
|
destination=self.object.objectType,
|
||||||
|
)
|
||||||
|
elif self.verb in verb_to_content:
|
||||||
|
content = verb_to_content[self.verb]
|
||||||
|
self.content = content.format(
|
||||||
|
username=actor.username,
|
||||||
|
object=self.object.objectType
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
def serialize(self, request):
|
||||||
|
# Lookup models
|
||||||
|
actor = User.query.filter_by(id=self.actor).first()
|
||||||
|
generator = Generator.query.filter_by(id=self.generator).first()
|
||||||
|
|
||||||
|
obj = {
|
||||||
|
"id": self.id,
|
||||||
|
"actor": actor.serialize(request),
|
||||||
|
"verb": self.verb,
|
||||||
|
"published": self.published.isoformat(),
|
||||||
|
"updated": self.updated.isoformat(),
|
||||||
|
"content": self.content,
|
||||||
|
"url": self.url(request),
|
||||||
|
"object": self.object.serialize(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.generator:
|
||||||
|
obj["generator"] = generator.seralize(request)
|
||||||
|
|
||||||
|
if self.title:
|
||||||
|
obj["title"] = self.title
|
||||||
|
|
||||||
|
if self.target:
|
||||||
|
target = User.query.filter_by(id=self.target).first()
|
||||||
|
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()
|
||||||
|
if self.content is None:
|
||||||
|
self.generate_content()
|
||||||
|
super(Activity, self).save(*args, **kwargs)
|
||||||
|
|
||||||
MODELS = [
|
MODELS = [
|
||||||
User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
|
User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
|
||||||
MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData,
|
MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData,
|
||||||
Notification, CommentNotification, ProcessingNotification, Client,
|
Notification, CommentNotification, ProcessingNotification, Client,
|
||||||
CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan,
|
CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan,
|
||||||
Privilege, PrivilegeUserAssociation,
|
Privilege, PrivilegeUserAssociation,
|
||||||
RequestToken, AccessToken, NonceTimestamp]
|
RequestToken, AccessToken, NonceTimestamp,
|
||||||
|
Activity, Generator]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Foundations are the default rows that are created immediately after the tables
|
Foundations are the default rows that are created immediately after the tables
|
||||||
|
@ -77,3 +77,9 @@ add_route(
|
|||||||
"/api/whoami",
|
"/api/whoami",
|
||||||
"mediagoblin.federation.views:whoami"
|
"mediagoblin.federation.views:whoami"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_route(
|
||||||
|
"mediagoblin.federation.activity_view",
|
||||||
|
"/<string:username>/activity/<string:id>",
|
||||||
|
"mediagoblin.federation.views:activity_view"
|
||||||
|
)
|
@ -20,10 +20,11 @@ import mimetypes
|
|||||||
|
|
||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
|
|
||||||
from mediagoblin.decorators import oauth_required
|
from mediagoblin.decorators import oauth_required, require_active_login
|
||||||
from mediagoblin.federation.decorators import user_has_privilege
|
from mediagoblin.federation.decorators import user_has_privilege
|
||||||
from mediagoblin.db.models import User, MediaEntry, MediaComment
|
from mediagoblin.db.models import User, MediaEntry, MediaComment, Activity
|
||||||
from mediagoblin.tools.response import redirect, json_response, json_error
|
from mediagoblin.tools.response import redirect, json_response, json_error, \
|
||||||
|
render_404, render_to_response
|
||||||
from mediagoblin.meddleware.csrf import csrf_exempt
|
from mediagoblin.meddleware.csrf import csrf_exempt
|
||||||
from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \
|
from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \
|
||||||
api_add_to_feed
|
api_add_to_feed
|
||||||
@ -340,21 +341,8 @@ def feed_endpoint(request):
|
|||||||
"items": [],
|
"items": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for activity in Activity.query.filter_by(actor=request.user.id):
|
||||||
# Look up all the media to put in the feed (this will be changed
|
feed["items"].append(activity.serialize(request))
|
||||||
# when we get real feeds/inboxes/outboxes/activites)
|
|
||||||
for media in MediaEntry.query.all():
|
|
||||||
item = {
|
|
||||||
"verb": "post",
|
|
||||||
"object": media.serialize(request),
|
|
||||||
"actor": media.get_uploader.serialize(request),
|
|
||||||
"content": "{0} posted a picture".format(request.user.username),
|
|
||||||
"id": media.id,
|
|
||||||
}
|
|
||||||
item["updated"] = item["object"]["updated"]
|
|
||||||
item["published"] = item["object"]["published"]
|
|
||||||
item["url"] = item["object"]["url"]
|
|
||||||
feed["items"].append(item)
|
|
||||||
feed["totalItems"] = len(feed["items"])
|
feed["totalItems"] = len(feed["items"])
|
||||||
|
|
||||||
return json_response(feed)
|
return json_response(feed)
|
||||||
@ -467,3 +455,31 @@ def whoami(request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return redirect(request, location=profile)
|
return redirect(request, location=profile)
|
||||||
|
|
||||||
|
@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()
|
||||||
|
if activity is None:
|
||||||
|
return render_404(request)
|
||||||
|
|
||||||
|
return render_to_response(
|
||||||
|
request,
|
||||||
|
"mediagoblin/federation/activity.html",
|
||||||
|
{"activity": activity}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ from werkzeug.datastructures import FileStorage
|
|||||||
from mediagoblin import mg_globals
|
from mediagoblin import mg_globals
|
||||||
from mediagoblin.tools.response import json_response
|
from mediagoblin.tools.response import json_response
|
||||||
from mediagoblin.tools.text import convert_to_tag_list_of_dicts
|
from mediagoblin.tools.text import convert_to_tag_list_of_dicts
|
||||||
|
from mediagoblin.tools.federation import create_activity
|
||||||
from mediagoblin.db.models import MediaEntry, ProcessingMetaData
|
from mediagoblin.db.models import MediaEntry, ProcessingMetaData
|
||||||
from mediagoblin.processing import mark_entry_failed
|
from mediagoblin.processing import mark_entry_failed
|
||||||
from mediagoblin.processing.task import ProcessMedia
|
from mediagoblin.processing.task import ProcessMedia
|
||||||
@ -199,6 +200,9 @@ def submit_media(mg_app, user, submitted_file, filename,
|
|||||||
run_process_media(entry, feed_url)
|
run_process_media(entry, feed_url)
|
||||||
|
|
||||||
add_comment_subscription(user, entry)
|
add_comment_subscription(user, entry)
|
||||||
|
|
||||||
|
# Create activity
|
||||||
|
create_activity("post", entry)
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
@ -289,4 +293,8 @@ def api_add_to_feed(request, entry):
|
|||||||
|
|
||||||
run_process_media(entry, feed_url)
|
run_process_media(entry, feed_url)
|
||||||
add_comment_subscription(request.user, entry)
|
add_comment_subscription(request.user, entry)
|
||||||
|
|
||||||
|
# Create activity
|
||||||
|
create_activity("post", entry)
|
||||||
|
|
||||||
return json_response(entry.serialize(request))
|
return json_response(entry.serialize(request))
|
||||||
|
42
mediagoblin/templates/mediagoblin/federation/activity.html
Normal file
42
mediagoblin/templates/mediagoblin/federation/activity.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{#
|
||||||
|
# GNU MediaGoblin -- federated, autonomous media hosting
|
||||||
|
# Copyright (C) 2014 MediaGoblin contributors. See AUTHORS.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{%- extends "mediagoblin/base.html" %}
|
||||||
|
|
||||||
|
{% block mediagoblin_head %}
|
||||||
|
{% template_hook("media_head") %}
|
||||||
|
{% endblock mediagoblin_head %}
|
||||||
|
|
||||||
|
{% block mediagoblin_content %}
|
||||||
|
<div class="media_pane eleven columns">
|
||||||
|
<h2 class="media_title">
|
||||||
|
{% if activity.title %}{{ activity.title }}{% endif %}
|
||||||
|
</h2>
|
||||||
|
{% autoescape False %}
|
||||||
|
<p> {{ activity.content }} </p>
|
||||||
|
{% endautoescape %}
|
||||||
|
|
||||||
|
<div class="media_sidebar">
|
||||||
|
{% block mediagoblin_after_added_sidebar %}
|
||||||
|
<a href="{{ activity.url(request) }}"
|
||||||
|
class="button_action"
|
||||||
|
id="button_reportmedia">
|
||||||
|
View {{ activity.object.objectType }}
|
||||||
|
</a>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -26,6 +26,7 @@ from mediagoblin.tools.response import render_to_response, render_404, \
|
|||||||
from mediagoblin.tools.text import cleaned_markdown_conversion
|
from mediagoblin.tools.text import cleaned_markdown_conversion
|
||||||
from mediagoblin.tools.translate import pass_to_ugettext as _
|
from mediagoblin.tools.translate import pass_to_ugettext as _
|
||||||
from mediagoblin.tools.pagination import Pagination
|
from mediagoblin.tools.pagination import Pagination
|
||||||
|
from mediagoblin.tools.federation import create_activity
|
||||||
from mediagoblin.user_pages import forms as user_forms
|
from mediagoblin.user_pages import forms as user_forms
|
||||||
from mediagoblin.user_pages.lib import (send_comment_email,
|
from mediagoblin.user_pages.lib import (send_comment_email,
|
||||||
add_media_to_collection, build_report_object)
|
add_media_to_collection, build_report_object)
|
||||||
@ -199,7 +200,7 @@ def media_post_comment(request, media):
|
|||||||
_('Your comment has been posted!'))
|
_('Your comment has been posted!'))
|
||||||
|
|
||||||
trigger_notification(comment, media, request)
|
trigger_notification(comment, media, request)
|
||||||
|
create_activity("post", comment)
|
||||||
add_comment_subscription(request.user, media)
|
add_comment_subscription(request.user, media)
|
||||||
|
|
||||||
return redirect_obj(request, media)
|
return redirect_obj(request, media)
|
||||||
@ -261,6 +262,7 @@ def media_collect(request, media):
|
|||||||
collection.creator = request.user.id
|
collection.creator = request.user.id
|
||||||
collection.generate_slug()
|
collection.generate_slug()
|
||||||
collection.save()
|
collection.save()
|
||||||
|
create_activity("create", collection)
|
||||||
|
|
||||||
# Otherwise, use the collection selected from the drop-down
|
# Otherwise, use the collection selected from the drop-down
|
||||||
else:
|
else:
|
||||||
@ -287,7 +289,7 @@ def media_collect(request, media):
|
|||||||
% (media.title, collection.title))
|
% (media.title, collection.title))
|
||||||
else: # Add item to collection
|
else: # Add item to collection
|
||||||
add_media_to_collection(collection, media, form.note.data)
|
add_media_to_collection(collection, media, form.note.data)
|
||||||
|
create_activity("add", media)
|
||||||
messages.add_message(request, messages.SUCCESS,
|
messages.add_message(request, messages.SUCCESS,
|
||||||
_('"%s" added to collection "%s"')
|
_('"%s" added to collection "%s"')
|
||||||
% (media.title, collection.title))
|
% (media.title, collection.title))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user