diff --git a/app/assets/javascripts/discourse/components/stream-item.js.es6 b/app/assets/javascripts/discourse/components/stream-item.js.es6
index d81366bec78..26d1e6f8e5a 100644
--- a/app/assets/javascripts/discourse/components/stream-item.js.es6
+++ b/app/assets/javascripts/discourse/components/stream-item.js.es6
@@ -2,13 +2,7 @@ import { propertyEqual } from 'discourse/lib/computed';
 import { actionDescription } from "discourse/components/small-action";
 
 export default Ember.Component.extend({
-  classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"],
+  classNameBindings: [":item", "item.hidden", "item.deleted:deleted", "moderatorAction"],
   moderatorAction: propertyEqual("item.post_type", "site.post_types.moderator_action"),
   actionDescription: actionDescription("item.action_code", "item.created_at", "item.username"),
-
-  actions: {
-    removeBookmark(userAction) {
-      this.sendAction("removeBookmark", userAction);
-    }
-  }
 });
diff --git a/app/assets/javascripts/discourse/components/user-stream.js.es6 b/app/assets/javascripts/discourse/components/user-stream.js.es6
index c9871ecadb6..0b37142ff66 100644
--- a/app/assets/javascripts/discourse/components/user-stream.js.es6
+++ b/app/assets/javascripts/discourse/components/user-stream.js.es6
@@ -1,6 +1,7 @@
 import LoadMore from "discourse/mixins/load-more";
 import ClickTrack from 'discourse/lib/click-track';
 import { selectedText } from 'discourse/lib/utilities';
+import Post from 'discourse/models/post';
 
 export default Ember.Component.extend(LoadMore, {
   loading: false,
@@ -44,6 +45,13 @@ export default Ember.Component.extend(LoadMore, {
   }.on('willDestroyElement'),
 
   actions: {
+    removeBookmark(userAction) {
+      const stream = this.get('stream');
+      Post.updateBookmark(userAction.get("post_id"), false).then(() => {
+        stream.remove(userAction);
+      });
+    },
+
     loadMore() {
       if (this.get('loading')) { return; }
 
diff --git a/app/assets/javascripts/discourse/models/admin-post.js.es6 b/app/assets/javascripts/discourse/models/admin-post.js.es6
deleted file mode 100644
index 8de331ac955..00000000000
--- a/app/assets/javascripts/discourse/models/admin-post.js.es6
+++ /dev/null
@@ -1,26 +0,0 @@
-import Post from 'discourse/models/post';
-
-export default Post.extend({
-
-  _attachCategory: function () {
-    const categoryId = this.get("category_id");
-    if (categoryId) {
-      this.set("category", Discourse.Category.findById(categoryId));
-    }
-  }.on("init"),
-
-  presentName: Ember.computed.or('name', 'username'),
-
-  sameUser: function() {
-    return this.get("username") === Discourse.User.currentProp("username");
-  }.property("username"),
-
-  descriptionKey: function () {
-    if (this.get("reply_to_post_number")) {
-      return this.get("sameUser") ? "you_replied_to_post" : "user_replied_to_post";
-    } else {
-      return this.get("sameUser") ? "you_replied_to_topic" : "user_replied_to_topic";
-    }
-  }.property("reply_to_post_number", "sameUser")
-
-});
diff --git a/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6
index cd552d35dbf..6a96803bdde 100644
--- a/app/assets/javascripts/discourse/models/user-posts-stream.js.es6
+++ b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6
@@ -1,6 +1,6 @@
 import { ajax } from 'discourse/lib/ajax';
 import { url } from 'discourse/lib/computed';
-import AdminPost from 'discourse/models/admin-post';
+import UserAction from 'discourse/models/user-action';
 
 export default Discourse.Model.extend({
   loaded: false,
@@ -36,7 +36,7 @@ export default Discourse.Model.extend({
 
     return ajax(this.get("url"), { cache: false }).then(function (result) {
       if (result) {
-        const posts = result.map(function (post) { return AdminPost.create(post); });
+        const posts = result.map(function (post) { return UserAction.create(post); });
         self.get("content").pushObjects(posts);
         self.setProperties({
           loaded: true,
diff --git a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
index 4fbf8e4300c..13fe328d302 100644
--- a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
@@ -19,26 +19,9 @@ export default Discourse.Route.extend(ViewingActionType, {
   },
 
   actions: {
-
     didTransition() {
       this.controllerFor("user-activity")._showFooter();
       return true;
-    },
-
-    removeBookmark(userAction) {
-      var user = this.modelFor("user");
-      Discourse.Post.updateBookmark(userAction.get("post_id"), false)
-        .then(function() {
-          // remove the user action from the stream
-          user.get("stream").remove(userAction);
-          // update the counts
-          user.get("stats").forEach(function (stat) {
-            if (stat.get("action_type") === userAction.action_type) {
-              stat.decrementProperty("count");
-            }
-          });
-        });
-    },
-
+    }
   }
 });
diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs
index fed530753ef..bb321a9ef35 100644
--- a/app/assets/javascripts/discourse/templates/components/stream-item.hbs
+++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs
@@ -6,6 +6,14 @@
     <a href={{item.postUrl}}>{{{item.title}}}</a>
   </span>
   <div class="category">{{category-link item.category}}</div>
+  {{#if item.deleted_by}}
+    <span class="delete-info">
+      {{fa-icon "trash-o"}}
+      {{avatar item.deleted_by imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}
+      {{format-date item.deleted_at leaveAgo="true"}}
+    </span>
+  {{/if}}
+
   {{plugin-outlet name="user-stream-item-header" args=(hash item=item)}}
 </div>
 
@@ -20,7 +28,7 @@
     <i class="icon {{child.icon}}"></i>
     {{#each child.items as |grandChild|}}
       {{#if grandChild.removableBookmark}}
-        <button class="btn btn-default remove-bookmark" {{action "removeBookmark" grandChild}}>
+        <button class="btn btn-default remove-bookmark" {{action removeBookmark grandChild}}>
           {{fa-icon 'times'}} {{i18n "bookmarks.remove"}}
         </button>
       {{else}}
diff --git a/app/assets/javascripts/discourse/templates/components/user-stream.hbs b/app/assets/javascripts/discourse/templates/components/user-stream.hbs
new file mode 100644
index 00000000000..31783b50bdd
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/user-stream.hbs
@@ -0,0 +1,3 @@
+{{#each stream.content as |item|}}
+  {{stream-item item=item removeBookmark=(action "removeBookmark")}}
+{{/each}}
diff --git a/app/assets/javascripts/discourse/templates/user/posts.hbs b/app/assets/javascripts/discourse/templates/user/posts.hbs
index 08fc6f5f275..b1743bf0771 100644
--- a/app/assets/javascripts/discourse/templates/user/posts.hbs
+++ b/app/assets/javascripts/discourse/templates/user/posts.hbs
@@ -1,30 +1 @@
-{{#user-stream stream=model}}
-  {{#each model.content as |p|}}
-    <div class="item {{if p.hidden 'hidden'}} {{if p.deleted 'deleted'}} {{if p.moderator_action 'moderator-action'}}">
-      <div class="clearfix info">
-        <a href="{{unbound p.usernameUrl}}" class="avatar-link">
-          <div class="avatar-wrapper">
-            {{avatar p imageSize="large" extraClasses="actor" ignoreTitle="true"}}
-          </div>
-        </a>
-        <span class="time">
-          {{format-date p.created_at leaveAgo="true"}}
-        </span>
-        <span class="title">
-          <a href="{{unbound p.url}}">{{unbound p.topic_title}}</a>
-        </span>
-        <span class="category">
-          {{category-link p.category}}
-        </span>
-        {{#if p.deleted}}
-          <span class="delete-info">
-            <i class="fa fa-trash-o"></i> {{avatar p.deleted_by imageSize="tiny" extraClasses="actor" ignoreTitle="true"}} {{format-date p.deleted_at leaveAgo="true"}}
-          </span>
-        {{/if}}
-      </div>
-      <p class="excerpt">
-        {{{p.excerpt}}}
-      </p>
-    </div>
-  {{/each}}
-{{/user-stream}}
+{{user-stream stream=model}}
diff --git a/app/assets/javascripts/discourse/templates/user/stream.hbs b/app/assets/javascripts/discourse/templates/user/stream.hbs
index 220ae57ba8a..2801c293baf 100644
--- a/app/assets/javascripts/discourse/templates/user/stream.hbs
+++ b/app/assets/javascripts/discourse/templates/user/stream.hbs
@@ -3,8 +3,4 @@
     {{{model.noContentHelp}}}
   </div>
 {{/if}}
-{{#user-stream stream=model}}
-  {{#each model.content as |item|}}
-    {{stream-item item=item removeBookmark="removeBookmark"}}
-  {{/each}}
-{{/user-stream}}
+{{user-stream stream=model}}
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 5f74ecd57b7..5e18b575203 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -445,7 +445,7 @@ class PostsController < ApplicationController
                                    .where(disagreed_at: nil)
                                    .select(:post_id))
 
-    render_serialized(posts, AdminPostSerializer)
+    render_serialized(posts, AdminUserActionSerializer)
   end
 
   def deleted_posts
@@ -458,7 +458,7 @@ class PostsController < ApplicationController
 
     posts = user_posts(guardian, user.id, offset: offset, limit: limit).where.not(deleted_at: nil)
 
-    render_serialized(posts, AdminPostSerializer)
+    render_serialized(posts, AdminUserActionSerializer)
   end
 
   protected
diff --git a/app/serializers/admin_post_serializer.rb b/app/serializers/admin_user_action_serializer.rb
similarity index 71%
rename from app/serializers/admin_post_serializer.rb
rename to app/serializers/admin_user_action_serializer.rb
index a06328d832f..606e4fed324 100644
--- a/app/serializers/admin_post_serializer.rb
+++ b/app/serializers/admin_user_action_serializer.rb
@@ -1,17 +1,29 @@
-class AdminPostSerializer < ApplicationSerializer
+class AdminUserActionSerializer < ApplicationSerializer
 
-  attributes :id,
-             :created_at,
-             :post_number,
-             :name, :username, :avatar_template,
-             :topic_id, :topic_slug, :topic_title,
-             :category_id,
-             :excerpt,
-             :hidden,
-             :moderator_action,
-             :deleted_at, :deleted_by,
-             :reply_to_post_number,
-             :action_type
+  attributes(
+    :id,
+    :created_at,
+    :post_number,
+    :name,
+    :username,
+    :avatar_template,
+    :topic_id,
+    :slug,
+    :title,
+    :category_id,
+    :excerpt,
+    :hidden,
+    :moderator_action,
+    :deleted,
+    :deleted_at,
+    :deleted_by,
+    :reply_to_post_number,
+    :action_type
+  )
+
+  def deleted
+    deleted_at.present?
+  end
 
   def name
     object.user.name
@@ -29,11 +41,11 @@ class AdminPostSerializer < ApplicationSerializer
     object.user.avatar_template
   end
 
-  def topic_slug
+  def slug
     topic.slug
   end
 
-  def topic_title
+  def title
     topic.title
   end
 
diff --git a/app/serializers/user_action_serializer.rb b/app/serializers/user_action_serializer.rb
index 965f4e61e4a..01de8083d67 100644
--- a/app/serializers/user_action_serializer.rb
+++ b/app/serializers/user_action_serializer.rb
@@ -3,6 +3,7 @@ class UserActionSerializer < ApplicationSerializer
   attributes :action_type,
              :created_at,
              :excerpt,
+             :truncated,
              :avatar_template,
              :acting_avatar_template,
              :slug,
@@ -29,9 +30,21 @@ class UserActionSerializer < ApplicationSerializer
              :closed,
              :archived
 
+  def cooked
+    @cooked ||= object.cooked || PrettyText.cook(object.raw)
+  end
+
   def excerpt
-    cooked = object.cooked || PrettyText.cook(object.raw)
-    PrettyText.excerpt(cooked, 300, keep_emoji_images: true) if cooked
+    return nil unless cooked
+    @excerpt ||= PrettyText.excerpt(cooked, 300, keep_emoji_images: true)
+  end
+
+  def truncated
+    true
+  end
+
+  def include_truncated?
+    excerpt != cooked
   end
 
   def avatar_template