From d1a5d8ea625ac0469f4b8fcee77efc6954e334f1 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 1 Dec 2015 16:52:43 +1100 Subject: [PATCH] FEATURE: show group mentions and topics in groups page --- .../discourse/controllers/group.js.es6 | 50 +++++++++++++++++-- .../discourse/controllers/group/index.js.es6 | 8 +-- .../controllers/group/mentions.js.es6 | 3 ++ .../discourse/controllers/group/topics.js.es6 | 3 ++ .../javascripts/discourse/models/group.js.es6 | 4 +- .../discourse/routes/app-route-map.js.es6 | 2 + .../discourse/routes/group-index.js.es6 | 2 +- .../discourse/routes/group-mentions.js.es6 | 11 ++++ .../discourse/routes/group-topics.js.es6 | 11 ++++ .../templates/components/group-post.hbs | 18 +++++++ .../javascripts/discourse/templates/group.hbs | 36 +++++++------ .../discourse/templates/group/index.hbs | 21 +------- .../discourse/templates/group/members.hbs | 2 +- .../discourse/templates/group/mentions.hbs | 6 +++ .../discourse/templates/group/topics.hbs | 5 ++ .../discourse/views/group-mentions.js.es6 | 6 +++ .../discourse/views/group-topics.js.es6 | 6 +++ app/controllers/groups_controller.rb | 15 ++++++ app/models/group.rb | 13 +++++ app/models/group_mention.rb | 4 ++ app/models/post.rb | 1 + app/services/post_alerter.rb | 10 ++++ config/routes.rb | 2 + .../20151201035631_add_group_mentions.rb | 12 +++++ spec/services/post_alerter_spec.rb | 3 ++ 25 files changed, 202 insertions(+), 52 deletions(-) create mode 100644 app/assets/javascripts/discourse/controllers/group/mentions.js.es6 create mode 100644 app/assets/javascripts/discourse/controllers/group/topics.js.es6 create mode 100644 app/assets/javascripts/discourse/routes/group-mentions.js.es6 create mode 100644 app/assets/javascripts/discourse/routes/group-topics.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/group-post.hbs create mode 100644 app/assets/javascripts/discourse/templates/group/mentions.hbs create mode 100644 app/assets/javascripts/discourse/templates/group/topics.hbs create mode 100644 app/assets/javascripts/discourse/views/group-mentions.js.es6 create mode 100644 app/assets/javascripts/discourse/views/group-topics.js.es6 create mode 100644 app/models/group_mention.rb create mode 100644 db/migrate/20151201035631_add_group_mentions.rb diff --git a/app/assets/javascripts/discourse/controllers/group.js.es6 b/app/assets/javascripts/discourse/controllers/group.js.es6 index dcd408673dc..fa85decd355 100644 --- a/app/assets/javascripts/discourse/controllers/group.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group.js.es6 @@ -1,9 +1,49 @@ +import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; + +var Tab = Em.Object.extend({ + @computed('name') + location(name) { + return 'group.' + name; + } +}); + + export default Ember.Controller.extend({ counts: null, - showing: null, + showing: 'posts', - // It would be nice if bootstrap marked action lists as selected when their links - // were 'active' not the `li` tags. - showingIndex: Em.computed.equal('showing', 'index'), - showingMembers: Em.computed.equal('showing', 'members') + @observes('counts') + countsChanged() { + const counts = this.get('counts'); + this.get('tabs').forEach(tab => { + tab.set('count', counts.get(tab.get('name'))); + }); + }, + + @observes('showing') + showingChanged() { + const showing = this.get('showing'); + + this.get('tabs').forEach(tab => { + tab.set('active', showing === tab.get('name')); + }); + + }, + + tabs: [ + Tab.create({ + active: true, + name: 'posts', + 'location': 'group.index' + }), + Tab.create({ + name: 'topics' + }), + Tab.create({ + name: 'mentions' + }), + Tab.create({ + name: 'members' + }) + ] }); diff --git a/app/assets/javascripts/discourse/controllers/group/index.js.es6 b/app/assets/javascripts/discourse/controllers/group/index.js.es6 index 7cac5408459..60df6a2cdf1 100644 --- a/app/assets/javascripts/discourse/controllers/group/index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group/index.js.es6 @@ -1,10 +1,5 @@ /** Handles displaying posts within a group - - @class GroupIndexController - @extends Ember.ArrayController - @namespace Discourse - @module Discourse **/ export default Ember.ArrayController.extend({ needs: ['group'], @@ -21,7 +16,8 @@ export default Ember.ArrayController.extend({ var lastPostId = posts[posts.length-1].get('id'), group = this.get('controllers.group.model'); - group.findPosts({beforePostId: lastPostId}).then(function(newPosts) { + var opts = {beforePostId: lastPostId, type: this.get('type')}; + group.findPosts(opts).then(function(newPosts) { posts.addObjects(newPosts); self.set('loading', false); }); diff --git a/app/assets/javascripts/discourse/controllers/group/mentions.js.es6 b/app/assets/javascripts/discourse/controllers/group/mentions.js.es6 new file mode 100644 index 00000000000..81fa5a8ffda --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/group/mentions.js.es6 @@ -0,0 +1,3 @@ +import IndexController from 'discourse/controllers/group/index'; + +export default IndexController.extend({type: 'mentions'}); diff --git a/app/assets/javascripts/discourse/controllers/group/topics.js.es6 b/app/assets/javascripts/discourse/controllers/group/topics.js.es6 new file mode 100644 index 00000000000..9423350320d --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/group/topics.js.es6 @@ -0,0 +1,3 @@ +import IndexController from 'discourse/controllers/group/index'; + +export default IndexController.extend({type: 'topics'}); diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6 index 49f0e4ae0d6..b8979d2b78f 100644 --- a/app/assets/javascripts/discourse/models/group.js.es6 +++ b/app/assets/javascripts/discourse/models/group.js.es6 @@ -121,10 +121,12 @@ const Group = Discourse.Model.extend({ findPosts(opts) { opts = opts || {}; + const type = opts['type'] || 'posts'; + var data = {}; if (opts.beforePostId) { data.before_post_id = opts.beforePostId; } - return Discourse.ajax("/groups/" + this.get('name') + "/posts.json", { data: data }).then(function (posts) { + return Discourse.ajax(`/groups/${this.get('name')}/${type}.json`, { data: data }).then(function (posts) { return posts.map(function (p) { p.user = Discourse.User.create(p.user); return Em.Object.create(p); diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 64078554fd2..e76b33296fa 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -48,6 +48,8 @@ export default function() { }); this.resource('group', { path: '/groups/:name' }, function() { + this.route('topics'); + this.route('mentions'); this.route('members'); }); diff --git a/app/assets/javascripts/discourse/routes/group-index.js.es6 b/app/assets/javascripts/discourse/routes/group-index.js.es6 index 89dec1edd2b..bb8ecaeb03c 100644 --- a/app/assets/javascripts/discourse/routes/group-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-index.js.es6 @@ -9,6 +9,6 @@ export default Discourse.Route.extend({ setupController(controller, model) { controller.set("model", model); - this.controllerFor("group").set("showing", "index"); + this.controllerFor("group").set("showing", "posts"); } }); diff --git a/app/assets/javascripts/discourse/routes/group-mentions.js.es6 b/app/assets/javascripts/discourse/routes/group-mentions.js.es6 new file mode 100644 index 00000000000..1054fb18d3a --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-mentions.js.es6 @@ -0,0 +1,11 @@ +export default Discourse.Route.extend({ + + model() { + return this.modelFor("group").findPosts({type: 'mentions'}); + }, + + setupController(controller, model) { + controller.set("model", model); + this.controllerFor("group").set("showing", "mentions"); + } +}); diff --git a/app/assets/javascripts/discourse/routes/group-topics.js.es6 b/app/assets/javascripts/discourse/routes/group-topics.js.es6 new file mode 100644 index 00000000000..397572e77bf --- /dev/null +++ b/app/assets/javascripts/discourse/routes/group-topics.js.es6 @@ -0,0 +1,11 @@ +export default Discourse.Route.extend({ + + model() { + return this.modelFor("group").findPosts({type: 'topics'}); + }, + + setupController(controller, model) { + controller.set("model", model); + this.controllerFor("group").set("showing", "topics"); + } +}); diff --git a/app/assets/javascripts/discourse/templates/components/group-post.hbs b/app/assets/javascripts/discourse/templates/components/group-post.hbs new file mode 100644 index 00000000000..78abb6b538e --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/group-post.hbs @@ -0,0 +1,18 @@ +
+
+
{{avatar post.user imageSize="large" extraClasses="actor" ignoreTitle="true"}}
+ {{format-date post.created_at leaveAgo="true"}} + + {{unbound post.title}} + + {{category-link post.category}} +
+ {{#if post.user_long_name}} + {{post.user_long_name}}{{#if post.user_title}}, {{post.user_title}}{{/if}} + {{/if}} +
+
+

+ {{{unbound post.cooked}}} +

+
diff --git a/app/assets/javascripts/discourse/templates/group.hbs b/app/assets/javascripts/discourse/templates/group.hbs index 67455f5f94e..22cd3d6fea4 100644 --- a/app/assets/javascripts/discourse/templates/group.hbs +++ b/app/assets/javascripts/discourse/templates/group.hbs @@ -1,28 +1,26 @@
-
-
diff --git a/app/assets/javascripts/discourse/templates/group/index.hbs b/app/assets/javascripts/discourse/templates/group/index.hbs index 5ed985396c7..8aab2faec65 100644 --- a/app/assets/javascripts/discourse/templates/group/index.hbs +++ b/app/assets/javascripts/discourse/templates/group/index.hbs @@ -1,22 +1,5 @@
- {{#each p in controller}} -
-
-
{{avatar p.user imageSize="large" extraClasses="actor" ignoreTitle="true"}}
- {{format-date p.created_at leaveAgo="true"}} - - {{unbound p.title}} - - {{category-link p.category}} -
- {{#if p.user_long_name}} - {{p.user_long_name}}{{#if p.user_title}}, {{p.user_title}}{{/if}} - {{/if}} -
-
-

- {{{unbound p.cooked}}} -

-
+ {{#each controller as |post|}} + {{group-post post=post}} {{/each}}
diff --git a/app/assets/javascripts/discourse/templates/group/members.hbs b/app/assets/javascripts/discourse/templates/group/members.hbs index 405125993f3..7d91ec3e911 100644 --- a/app/assets/javascripts/discourse/templates/group/members.hbs +++ b/app/assets/javascripts/discourse/templates/group/members.hbs @@ -20,7 +20,7 @@ {{user-small user=m}} {{#if m.owner}} {{i18n "groups.owner"}} - {{/if}} + {{/if}} {{bound-date m.last_posted_at}} diff --git a/app/assets/javascripts/discourse/templates/group/mentions.hbs b/app/assets/javascripts/discourse/templates/group/mentions.hbs new file mode 100644 index 00000000000..49dabf33efc --- /dev/null +++ b/app/assets/javascripts/discourse/templates/group/mentions.hbs @@ -0,0 +1,6 @@ +
+ {{#each controller as |post|}} + {{group-post post=post}} + {{/each}} +
+ diff --git a/app/assets/javascripts/discourse/templates/group/topics.hbs b/app/assets/javascripts/discourse/templates/group/topics.hbs new file mode 100644 index 00000000000..8aab2faec65 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/group/topics.hbs @@ -0,0 +1,5 @@ +
+ {{#each controller as |post|}} + {{group-post post=post}} + {{/each}} +
diff --git a/app/assets/javascripts/discourse/views/group-mentions.js.es6 b/app/assets/javascripts/discourse/views/group-mentions.js.es6 new file mode 100644 index 00000000000..4e25173395f --- /dev/null +++ b/app/assets/javascripts/discourse/views/group-mentions.js.es6 @@ -0,0 +1,6 @@ +import ScrollTop from 'discourse/mixins/scroll-top'; +import LoadMore from "discourse/mixins/load-more"; + +export default Ember.View.extend(ScrollTop, LoadMore, { + eyelineSelector: '.user-stream .item', +}); diff --git a/app/assets/javascripts/discourse/views/group-topics.js.es6 b/app/assets/javascripts/discourse/views/group-topics.js.es6 new file mode 100644 index 00000000000..4e25173395f --- /dev/null +++ b/app/assets/javascripts/discourse/views/group-topics.js.es6 @@ -0,0 +1,6 @@ +import ScrollTop from 'discourse/mixins/scroll-top'; +import LoadMore from "discourse/mixins/load-more"; + +export default Ember.View.extend(ScrollTop, LoadMore, { + eyelineSelector: '.user-stream .item', +}); diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 605d04b7d25..f9a7dfcba16 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -7,6 +7,8 @@ class GroupsController < ApplicationController def counts group = find_group(:group_id) render json: {counts: { posts: group.posts_for(guardian).count, + topics: group.posts_for(guardian).where(post_number: 1).count, + mentions: group.mentioned_posts_for(guardian).count, members: group.users.count } } end @@ -16,6 +18,19 @@ class GroupsController < ApplicationController render_serialized posts.to_a, GroupPostSerializer end + def topics + group = find_group(:group_id) + posts = group.posts_for(guardian, params[:before_post_id]).where(post_number: 1).limit(20) + render_serialized posts.to_a, GroupPostSerializer + end + + def mentions + group = find_group(:group_id) + posts = group.mentioned_posts_for(guardian, params[:before_post_id]).limit(20) + render_serialized posts.to_a, GroupPostSerializer + end + + def members group = find_group(:group_id) diff --git a/app/models/group.rb b/app/models/group.rb index acb7945d428..82ab38952e8 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -3,6 +3,7 @@ class Group < ActiveRecord::Base has_many :category_groups, dependent: :destroy has_many :group_users, dependent: :destroy + has_many :group_mentions, dependent: :destroy has_many :categories, through: :category_groups has_many :users, through: :group_users @@ -80,6 +81,18 @@ class Group < ActiveRecord::Base result.order('posts.created_at desc') end + def mentioned_posts_for(guardian, before_post_id=nil) + result = Post.joins(:group_mentions) + .includes(:user, :topic, :topic => :category) + .references(:posts, :topics, :category) + .where('topics.archetype <> ?', Archetype.private_message) + .where(post_type: Post.types[:regular]) + + result = guardian.filter_allowed_categories(result) + result = result.where('posts.id < ?', before_post_id) if before_post_id + result.order('posts.created_at desc') + end + def self.trust_group_ids (10..19).to_a end diff --git a/app/models/group_mention.rb b/app/models/group_mention.rb new file mode 100644 index 00000000000..65faeb6f03f --- /dev/null +++ b/app/models/group_mention.rb @@ -0,0 +1,4 @@ +class GroupMention < ActiveRecord::Base + belongs_to :post + belongs_to :group +end diff --git a/app/models/post.rb b/app/models/post.rb index 5d121f39736..7b3a0b3c8d8 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -32,6 +32,7 @@ class Post < ActiveRecord::Base has_many :replies, through: :post_replies has_many :post_actions has_many :topic_links + has_many :group_mentions, dependent: :destroy has_many :post_uploads has_many :uploads, through: :post_uploads diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index a8d7f20fdfc..4f5c0d58c9f 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -64,6 +64,16 @@ class PostAlerter notify_post_users(post, notified) end + sync_group_mentions(post, mentioned_groups) + end + + def sync_group_mentions(post, mentioned_groups) + GroupMention.where(post_id: post.id).destroy_all + return if mentioned_groups.blank? + + mentioned_groups.each do |group| + GroupMention.create(post_id: post.id, group_id: group.id) + end end def unread_posts(user, topic) diff --git a/config/routes.rb b/config/routes.rb index ad61e068234..afbfc21954a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -342,6 +342,8 @@ Discourse::Application.routes.draw do resources :groups do get 'members' get 'posts' + get 'topics' + get 'mentions' get 'counts' member do diff --git a/db/migrate/20151201035631_add_group_mentions.rb b/db/migrate/20151201035631_add_group_mentions.rb new file mode 100644 index 00000000000..4e3900387a2 --- /dev/null +++ b/db/migrate/20151201035631_add_group_mentions.rb @@ -0,0 +1,12 @@ +class AddGroupMentions < ActiveRecord::Migration + def change + create_table :group_mentions do |t| + t.integer :post_id + t.integer :group_id + t.timestamps + end + + add_index :group_mentions, [:post_id, :group_id], unique: true + add_index :group_mentions, [:group_id, :post_id], unique: true + end +end diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb index 34c5e498582..e5d446d4b95 100644 --- a/spec/services/post_alerter_spec.rb +++ b/spec/services/post_alerter_spec.rb @@ -103,12 +103,15 @@ describe PostAlerter do create_post_with_alerts(raw: "Hello @group how are you?") }.to change(evil_trout.notifications, :count).by(1) + expect(GroupMention.count).to eq(1) group.update_columns(alias_level: Group::ALIAS_LEVELS[:members_mods_and_admins]) expect { create_post_with_alerts(raw: "Hello @group you are not mentionable") }.to change(evil_trout.notifications, :count).by(0) + + expect(GroupMention.count).to eq(2) end end