Add better support for targets on Activities
authorJessica Tallon <jessica@megworld.co.uk>
Tue, 26 Aug 2014 07:53:28 +0000 (08:53 +0100)
committerJessica Tallon <jessica@megworld.co.uk>
Tue, 26 Aug 2014 09:19:39 +0000 (10:19 +0100)
This adds betters upport for targets in the content generation
and on the model itself. Adding getters for properties which would
otherwise require looking up e.g. get_author.

mediagoblin/db/models.py
mediagoblin/user_pages/views.py

index 89dc2de71a71930b3358a4e0b75b3a8f003a9fdd..aadd3fea8c65729e246b78b37b33f1c512629af6 100644 (file)
@@ -610,6 +610,8 @@ class MediaTag(Base):
         creator=Tag.find_or_new
         )
 
+    objectType = "tag"
+
     def __init__(self, name=None, slug=None):
         Base.__init__(self)
         if name is not None:
@@ -724,6 +726,8 @@ class Collection(Base, CollectionMixin):
         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
@@ -1099,7 +1103,7 @@ class Activity(Base):
     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)
@@ -1111,12 +1115,20 @@ class Activity(Base):
     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")
+    get_generator = relationship(Generator)
+    
     VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite", 
                    "follow", "like", "post", "share", "unfavorite", "unfollow",
                    "unlike", "unshare", "update", "tag"]
     
-    @property
-    def object(self):
+    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:
@@ -1131,12 +1143,33 @@ class Activity(Base):
         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
+            # 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(
@@ -1151,60 +1184,66 @@ class Activity(Base):
         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": _("{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}"), 
+            "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)
         
-        actor = User.query.filter_by(id=self.actor).first()
+        if content is None or obj is None:
+            return
         
-        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(
+        if target is None or "targetted" not in content:
+            self.content = content["simple"].format(
                 username=actor.username,
-                object=media.objectType,
-                destination=self.object.objectType,
+                object=obj.objectType
             )
-        elif self.verb in verb_to_content:
-            content = verb_to_content[self.verb]
-            self.content = content.format(
+        else:
+            self.content = content["targetted"].format(
                 username=actor.username,
-                object=self.object.objectType
+                object=obj.objectType,
+                target=target.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),
+            "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.object.serialize(request)
+            "object": self.get_object().serialize(request)
         }
         
         if self.generator:
@@ -1213,8 +1252,8 @@ class Activity(Base):
         if self.title:
             obj["title"] = self.title
         
-        if self.target:
-            target = User.query.filter_by(id=self.target).first()
+        target = self.get_target()
+        if target is not None:
             obj["target"] = target.seralize(request)
         
         return obj
@@ -1237,8 +1276,6 @@ class Activity(Base):
     
     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 = [
index 8203cfa7d5c791bf6182699eddc0c838947535c4..cd0e843d8329d0f385134393379f0020a71fa80d 100644 (file)
@@ -289,7 +289,7 @@ def media_collect(request, media):
                              % (media.title, collection.title))
     else: # Add item to collection
         add_media_to_collection(collection, media, form.note.data)
-        create_activity("add", media)
+        create_activity("add", media, target=collection)
         messages.add_message(request, messages.SUCCESS,
                              _('"%s" added to collection "%s"')
                              % (media.title, collection.title))