From 3b617b04b00070bbacf78776880194b31e6849b4 Mon Sep 17 00:00:00 2001 From: Robin Ward <robin.ward@gmail.com> Date: Fri, 7 Feb 2014 10:44:03 -0500 Subject: [PATCH] FEATURE: First stab at groups page with member list --- .../discourse/controllers/group_controller.js | 8 +++++ .../controllers/group_index_controller.js | 32 +++++++++++++++++++ .../javascripts/discourse/models/group.js | 15 ++++++++- .../discourse/routes/group_index_route.js | 10 +++++- .../discourse/routes/group_members_route.js | 8 +++++ .../discourse/routes/group_route.js | 8 +++++ .../templates/group/index.js.handlebars | 19 +++++++++-- .../templates/user/user.js.handlebars | 11 ++++--- .../discourse/views/group_index_view.js | 4 +++ app/controllers/groups_controller.rb | 7 ++++ app/models/group.rb | 19 ++++++++++- app/serializers/group_post_serializer.rb | 15 +++++++++ config/locales/client.en.yml | 3 ++ config/routes.rb | 1 + 14 files changed, 149 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/discourse/controllers/group_index_controller.js create mode 100644 app/assets/javascripts/discourse/views/group_index_view.js create mode 100644 app/serializers/group_post_serializer.rb diff --git a/app/assets/javascripts/discourse/controllers/group_controller.js b/app/assets/javascripts/discourse/controllers/group_controller.js index c6efff8fe..3fa523e0d 100644 --- a/app/assets/javascripts/discourse/controllers/group_controller.js +++ b/app/assets/javascripts/discourse/controllers/group_controller.js @@ -1,3 +1,11 @@ +/** + The basic controller for a group + + @class GroupController + @extends Discourse.ObjectController + @namespace Discourse + @module Discourse +**/ Discourse.GroupController = Discourse.ObjectController.extend({ // It would be nice if bootstrap marked action lists as selected when their links diff --git a/app/assets/javascripts/discourse/controllers/group_index_controller.js b/app/assets/javascripts/discourse/controllers/group_index_controller.js new file mode 100644 index 000000000..ec2d196cb --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/group_index_controller.js @@ -0,0 +1,32 @@ +/** + Handles displaying posts within a group + + @class GroupIndexController + @extends Ember.ArrayController + @namespace Discourse + @module Discourse +**/ +Discourse.GroupIndexController = Ember.ArrayController.extend({ + needs: ['group'], + loading: false, + + actions: { + loadMore: function() { + + if (this.get('loading')) { return; } + this.set('loading', true); + var posts = this.get('model'), + self = this; + if (posts && posts.length) { + var lastPostId = posts[posts.length-1].get('id'), + group = this.get('controllers.group.model'); + + group.findPosts({beforePostId: lastPostId}).then(function(newPosts) { + posts.addObjects(newPosts); + self.set('loading', false); + }); + } + } + } +}); + diff --git a/app/assets/javascripts/discourse/models/group.js b/app/assets/javascripts/discourse/models/group.js index a76dae825..5d307de07 100644 --- a/app/assets/javascripts/discourse/models/group.js +++ b/app/assets/javascripts/discourse/models/group.js @@ -126,8 +126,21 @@ Discourse.Group = Discourse.Model.extend({ var message = $.parseJSON(e.responseText).errors; bootbox.alert(message); }); - } + }, + findPosts: function(opts) { + opts = opts || {}; + + 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 posts.map(function (p) { + p.user = Discourse.User.create(p.user); + return Em.Object.create(p); + }); + }); + } }); Discourse.Group.reopenClass({ diff --git a/app/assets/javascripts/discourse/routes/group_index_route.js b/app/assets/javascripts/discourse/routes/group_index_route.js index 675b35b43..3976e0e9d 100644 --- a/app/assets/javascripts/discourse/routes/group_index_route.js +++ b/app/assets/javascripts/discourse/routes/group_index_route.js @@ -1,6 +1,14 @@ +/** + The route for the index of a Group + + @class GroupIndexRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ Discourse.GroupIndexRoute = Discourse.Route.extend({ model: function() { - return this.modelFor('group'); + return this.modelFor('group').findPosts(); }, setupController: function(controller, model) { diff --git a/app/assets/javascripts/discourse/routes/group_members_route.js b/app/assets/javascripts/discourse/routes/group_members_route.js index 3ac3a06a3..4cea70c09 100644 --- a/app/assets/javascripts/discourse/routes/group_members_route.js +++ b/app/assets/javascripts/discourse/routes/group_members_route.js @@ -1,3 +1,11 @@ +/** + Set things up to display the members of a group + + @class GroupMembersRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ Discourse.GroupMembersRoute = Discourse.Route.extend({ model: function() { return this.modelFor('group'); diff --git a/app/assets/javascripts/discourse/routes/group_route.js b/app/assets/javascripts/discourse/routes/group_route.js index 668528f7b..acbbbe823 100644 --- a/app/assets/javascripts/discourse/routes/group_route.js +++ b/app/assets/javascripts/discourse/routes/group_route.js @@ -1,3 +1,11 @@ +/** + The base route for a group + + @class GroupRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ Discourse.GroupRoute = Discourse.Route.extend({ model: function(params) { diff --git a/app/assets/javascripts/discourse/templates/group/index.js.handlebars b/app/assets/javascripts/discourse/templates/group/index.js.handlebars index 932962af7..8e73e8e3e 100644 --- a/app/assets/javascripts/discourse/templates/group/index.js.handlebars +++ b/app/assets/javascripts/discourse/templates/group/index.js.handlebars @@ -1,3 +1,16 @@ -GROUP INDEX -{{name}} - +<div class='user-stream'> + {{#groupedEach model}} + <div class='item'> + <div class='clearfix info'> + {{#link-to 'user' user class="avatar-link"}}<div class='avatar-wrapper'>{{avatar user imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div>{{/link-to}} + <span class='time'>{{unboundDate path="created_at" leaveAgo="true"}}</span> + <span class="title"> + <a href="{{unbound url}}">{{unbound title}}</a> + </span> + </div> + <p class='excerpt'> + {{{unbound cooked}}} + </p> + </div> + {{/groupedEach}} +</div> diff --git a/app/assets/javascripts/discourse/templates/user/user.js.handlebars b/app/assets/javascripts/discourse/templates/user/user.js.handlebars index 05feafb50..73e4c3567 100644 --- a/app/assets/javascripts/discourse/templates/user/user.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/user.js.handlebars @@ -44,11 +44,12 @@ <div class='bio'>{{{bio_cooked}}}</div> {{#if custom_groups}} - <div class='groups'> - {{#each custom_groups}} - {{#link-to 'group' this}}{{name}}{{/link-to}} - {{/each}} - </div> + <div class='groups'> + {{i18n groups.title count=custom_groups.length}}: + {{#each custom_groups}} + {{#link-to 'group' this}}{{name}}{{/link-to}} + {{/each}} + </div> {{/if}} {{#if isSuspended}} diff --git a/app/assets/javascripts/discourse/views/group_index_view.js b/app/assets/javascripts/discourse/views/group_index_view.js new file mode 100644 index 000000000..c73a56d43 --- /dev/null +++ b/app/assets/javascripts/discourse/views/group_index_view.js @@ -0,0 +1,4 @@ +Discourse.GroupIndexView = Discourse.View.extend(Discourse.LoadMore, { + eyelineSelector: '.user-stream .item' +}); + diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 75fff2aa3..c9fc37c50 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -6,6 +6,13 @@ class GroupsController < ApplicationController render_serialized(group, BasicGroupSerializer) end + def posts + group = Group.where(name: params.require(:group_id)).first + guardian.ensure_can_see!(group) + posts = group.posts_for(guardian, params[:before_post_id]) + render_serialized posts.to_a, GroupPostSerializer + end + def members group = Group.where(name: params.require(:group_id)).first guardian.ensure_can_see!(group) diff --git a/app/models/group.rb b/app/models/group.rb index b83144b6f..ef2c3060c 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -31,6 +31,24 @@ class Group < ActiveRecord::Base validate :alias_level, inclusion: { in: ALIAS_LEVELS.values} + def posts_for(guardian, before_post_id) + user_ids = group_users.map {|gu| gu.user_id} + result = Post.where(user_id: user_ids).includes(:user, :topic).references(:posts, :topics) + result = result.where('topics.archetype <> ?', Archetype.private_message) + + unless guardian.is_staff? + allowed_ids = guardian.allowed_category_ids + if allowed_ids.length > 0 + result = result.where('topics.category_id IS NULL or topics.category_id IN (?)', allowed_ids) + else + result = result.where('topics.category_id IS NULL') + end + end + + result = result.where('posts.id < ?', before_post_id) if before_post_id + result.order('posts.created_at desc').limit(20) + end + def self.trust_group_ids (10..19).to_a end @@ -156,7 +174,6 @@ class Group < ActiveRecord::Base end end - def self.builtin Enum.new(:moderators, :admins, :trust_level_1, :trust_level_2) end diff --git a/app/serializers/group_post_serializer.rb b/app/serializers/group_post_serializer.rb new file mode 100644 index 000000000..db451432a --- /dev/null +++ b/app/serializers/group_post_serializer.rb @@ -0,0 +1,15 @@ +class GroupPostSerializer < ApplicationSerializer + attributes :id, + :cooked, + :created_at, + :title, + :url + + has_one :user, serializer: BasicUserSerializer, embed: :objects + + def title + object.topic.title + end + +end + diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 820ca9d74..80e724f8c 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -174,6 +174,9 @@ en: sent_by_you: "Sent by <a href='{{userUrl}}'>you</a>" groups: + title: + one: "group" + other: "groups" members: "Members" posts: "Posts" alias_levels: diff --git a/config/routes.rb b/config/routes.rb index 3092ffecf..e19f563f4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -165,6 +165,7 @@ Discourse::Application.routes.draw do resources :groups do get 'members' + get 'posts' end resources :posts do