diff --git a/app/assets/javascripts/admin/controllers/admin_groups_controller.js b/app/assets/javascripts/admin/controllers/admin_groups_controller.js
index e0b75168d2a..1d8f755c1f0 100644
--- a/app/assets/javascripts/admin/controllers/admin_groups_controller.js
+++ b/app/assets/javascripts/admin/controllers/admin_groups_controller.js
@@ -1,10 +1,22 @@
Discourse.AdminGroupsController = Ember.ArrayController.extend({
itemController: 'adminGroup',
- edit: function(action){
- this.get('content').select(action);
+
+ edit: function(group){
+ this.get('model').select(group);
+ group.loadUsers();
+ },
+
+ refreshAutoGroups: function(){
+ var controller = this;
+
+ this.set('refreshingAutoGroups', true);
+ Discourse.ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(function(){
+ controller.set('model', Discourse.Group.findAll());
+ controller.set('refreshingAutoGroups',false);
+ });
}
});
-Discourse.AdminGroupController = Ember.ObjectController.extend({
+Discourse.AdminGroupController = Ember.Controller.extend({
});
diff --git a/app/assets/javascripts/admin/models/group.js b/app/assets/javascripts/admin/models/group.js
index 70e13815b2a..e5601535935 100644
--- a/app/assets/javascripts/admin/models/group.js
+++ b/app/assets/javascripts/admin/models/group.js
@@ -1,4 +1,34 @@
Discourse.Group = Discourse.Model.extend({
+ userCountDisplay: function(){
+ var c = this.get('user_count');
+ // don't display zero its ugly
+ if(c > 0) {
+ return c;
+ }
+ }.property('user_count'),
+
+ loadUsers: function() {
+ var group = this;
+
+ Discourse.ajax('/admin/groups/' + this.get('id') + '/users').then(function(payload){
+ var users = Em.A()
+ payload.each(function(user){
+ users.addObject(Discourse.User.create(user));
+ });
+ group.set('users', users)
+ });
+ },
+
+ usernames: function() {
+ var users = this.get('users');
+ var usernames = "";
+ if(users) {
+ usernames = $.map(users, function(user){
+ return user.get('username');
+ }).join(',')
+ }
+ return usernames;
+ }.property('users')
});
@@ -6,19 +36,22 @@ Discourse.Group.reopenClass({
findAll: function(){
var list = Discourse.SelectableArray.create();
- list.addObject(Discourse.Group.create({id: 1, name: "all mods", members: ["A","b","c"]}));
- list.addObject(Discourse.Group.create({id: 2, name: "other mods", members: ["A","b","c"]}));
+ Discourse.ajax("/admin/groups").then(function(groups){
+ groups.each(function(group){
+ list.addObject(Discourse.Group.create(group));
+ });
+ });
return list;
},
find: function(id) {
var promise = new Em.Deferred();
-
+
setTimeout(function(){
promise.resolve(Discourse.Group.create({id: 1, name: "all mods", members: ["A","b","c"]}));
}, 1000);
-
+
return promise;
}
});
diff --git a/app/assets/javascripts/admin/routes/admin_groups_routes.js b/app/assets/javascripts/admin/routes/admin_groups_routes.js
index a0f7022d8ea..535c280e6bd 100644
--- a/app/assets/javascripts/admin/routes/admin_groups_routes.js
+++ b/app/assets/javascripts/admin/routes/admin_groups_routes.js
@@ -1,9 +1,10 @@
Discourse.AdminGroupsRoute = Discourse.Route.extend({
- model: function() {
- return Discourse.Group.findAll();
- },
renderTemplate: function() {
this.render('admin/templates/groups',{into: 'admin/templates/admin'});
+ },
+
+ setupController: function(controller, model) {
+ controller.set('model', Discourse.Group.findAll());
}
});
diff --git a/app/assets/javascripts/admin/templates/groups.js.handlebars b/app/assets/javascripts/admin/templates/groups.js.handlebars
index f5a53ea524f..1832c1feb74 100644
--- a/app/assets/javascripts/admin/templates/groups.js.handlebars
+++ b/app/assets/javascripts/admin/templates/groups.js.handlebars
@@ -3,20 +3,23 @@
{{i18n admin.groups.edit}}
+
+
+
- {{#if content.active}}
- {{#with content.active}}
-
{{name}}
+ {{#if model.active}}
+ {{#with model.active}}
+ {{name}}
{{view Discourse.UserSelector id="private-message-users" class="span8" placeholderKey="admin.groups.selector_placeholder" tabindex="1" usernamesBinding="usernames"}}
-
+
{{/with}}
{{else}}
diff --git a/app/assets/javascripts/discourse/models/selectable_array.js b/app/assets/javascripts/discourse/models/selectable_array.js
index 733ea685630..eaa4c6bd404 100644
--- a/app/assets/javascripts/discourse/models/selectable_array.js
+++ b/app/assets/javascripts/discourse/models/selectable_array.js
@@ -1,6 +1,9 @@
// this allows you to track the selected item in an array, ghetto for now
Discourse.SelectableArray = Em.ArrayProxy.extend({
- content: [],
+ init: function() {
+ this.content = [];
+ this._super();
+ },
selectIndex: function(index){
this.select(this[index]);
},
diff --git a/app/assets/stylesheets/admin/admin_base.scss b/app/assets/stylesheets/admin/admin_base.scss
index cf7edbfdbbb..c0b0a76c941 100644
--- a/app/assets/stylesheets/admin/admin_base.scss
+++ b/app/assets/stylesheets/admin/admin_base.scss
@@ -3,6 +3,17 @@
@import "foundation/mixins";
@import "foundation/helpers";
+
+.content-list li a span.count {
+ font-size: 12px;
+ float: right;
+ margin-right: 10px;
+ background-color: #eee;
+ padding: 2px 5px;
+ border-radius: 5px;
+ color: #555;
+}
+
.admin-content {
margin-bottom: 50px;
.admin-contents {
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 12702c4de59..08d8cfd2000 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -1,4 +1,19 @@
class Admin::GroupsController < Admin::AdminController
+ def index
+ groups = Group.order(:name).all
+ render_serialized(groups, AdminGroupSerializer)
+ end
+
+ def refresh_automatic_groups
+ Group.refresh_automatic_groups!
+ render json: "ok"
+ end
+
def show
end
+
+ def users
+ group = Group.find(params[:group_id].to_i)
+ render_serialized(group.users, BasicUserSerializer)
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 970c6e5312c..22830f2d3d9 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -25,11 +25,12 @@ class Group < ActiveRecord::Base
id = AUTO_GROUPS[name]
unless group = self[name]
- group = Group.new(name: name.to_s, automatic: true)
+ group = Group.new(name: "", automatic: true)
group.id = id
group.save!
end
+ group.name = I18n.t("groups.default_names.#{name}")
real_ids = case name
when :admins
@@ -55,9 +56,15 @@ class Group < ActiveRecord::Base
end
group.save!
+
+ # we want to ensure consistency
+ Group.reset_counters(group.id, :group_users)
end
def self.refresh_automatic_groups!(*args)
+ if args.length == 0
+ args = AUTO_GROUPS.map{|k,v| k}
+ end
args.each do |group|
refresh_automatic_group!(group)
end
diff --git a/app/models/group_user.rb b/app/models/group_user.rb
index 0c93905c8aa..4b87ec1f21c 100644
--- a/app/models/group_user.rb
+++ b/app/models/group_user.rb
@@ -1,4 +1,4 @@
class GroupUser < ActiveRecord::Base
- belongs_to :group
+ belongs_to :group, counter_cache: "user_count"
belongs_to :user
end
diff --git a/app/serializers/admin_group_serializer.rb b/app/serializers/admin_group_serializer.rb
new file mode 100644
index 00000000000..bb62c38b1d6
--- /dev/null
+++ b/app/serializers/admin_group_serializer.rb
@@ -0,0 +1,3 @@
+class AdminGroupSerializer < ApplicationSerializer
+ attributes :id, :automatic, :name, :user_count
+end
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 8a1e4c7f0d6..07aea4be8a5 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -44,6 +44,17 @@ en:
rss_topics_in_category: "RSS feed of topics in the '%{category}' category"
author_wrote: "%{author} wrote:"
+ groups:
+ default_names:
+ admins: "admins"
+ moderators: "moderators"
+ staff: "staff"
+ trust_level_1: "trust_level_1"
+ trust_level_2: "trust_level_2"
+ trust_level_3: "trust_level_3"
+ trust_level_4: "trust_level_4"
+ trust_level_5: "trust_level_5"
+
education:
until_posts:
one: "post"
diff --git a/config/routes.rb b/config/routes.rb
index 611fca97d56..ac02614b0bd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -29,7 +29,13 @@ Discourse::Application.routes.draw do
get 'reports/:type' => 'reports#show'
- resources :groups, constraints: AdminConstraint.new
+ resources :groups, constraints: AdminConstraint.new do
+ collection do
+ post 'refresh_automatic_groups' => 'groups#refresh_automatic_groups'
+ end
+ get 'users'
+ end
+
resources :users, id: USERNAME_ROUTE_FORMAT do
collection do
get 'list/:query' => 'users#index'
diff --git a/db/migrate/20130508040235_add_user_count_to_groups.rb b/db/migrate/20130508040235_add_user_count_to_groups.rb
new file mode 100644
index 00000000000..cae58bc21e3
--- /dev/null
+++ b/db/migrate/20130508040235_add_user_count_to_groups.rb
@@ -0,0 +1,5 @@
+class AddUserCountToGroups < ActiveRecord::Migration
+ def change
+ add_column :groups, :user_count, :integer, null: false, default: 0
+ end
+end
diff --git a/lib/jobs/ensure_db_consistency.rb b/lib/jobs/ensure_db_consistency.rb
index df414823bf3..154fdf62298 100644
--- a/lib/jobs/ensure_db_consistency.rb
+++ b/lib/jobs/ensure_db_consistency.rb
@@ -1,9 +1,10 @@
module Jobs
- # checks to see if any users need to be promoted
+ # various consistency checks
class EnsureDbConsistency < Jobs::Base
def execute(args)
TopicUser.ensure_consistency!
UserVisit.ensure_consistency!
+ Group.refresh_automatic_groups!
end
end
end
diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb
new file mode 100644
index 00000000000..b9a85b6389d
--- /dev/null
+++ b/spec/controllers/admin/groups_controller_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Admin::GroupsController do
+ it "is a subclass of AdminController" do
+ (Admin::GroupsController < Admin::AdminController).should be_true
+ end
+
+ it "produces valid json for groups" do
+ admin = log_in(:admin)
+ group = Fabricate.build(:group, name: "test")
+ group.add(admin)
+ group.save
+
+ xhr :get, :index
+ response.status.should == 200
+ ::JSON.parse(response.body).should == [{
+ "id"=>group.id,
+ "name"=>group.name,
+ "user_count"=>1,
+ "automatic"=>false
+ }]
+ end
+
+ it "is able to refresh automatic groups" do
+ admin = log_in(:admin)
+ Group.expects(:refresh_automatic_groups!).returns(true)
+
+ xhr :post, :refresh_automatic_groups
+ response.status.should == 200
+ end
+end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 1236fb4404d..9760927fc17 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -54,4 +54,30 @@ describe Group do
Group[:trust_level_2].user_ids.sort.should == [user.id, user2.id].sort
end
+ it "Correctly updates all automatic groups upon request" do
+ admin = Fabricate(:admin)
+ user = Fabricate(:user)
+ user.change_trust_level!(:regular)
+
+ Group.exec_sql("update groups set user_count=0 where id = #{Group::AUTO_GROUPS[:trust_level_2]}")
+
+ Group.refresh_automatic_groups!
+
+ groups = Group.includes(:users).to_a
+ groups.count.should == Group::AUTO_GROUPS.count
+
+ g = groups.find{|g| g.id == Group::AUTO_GROUPS[:admins]}
+ g.users.count.should == 1
+ g.user_count.should == 1
+
+ g = groups.find{|g| g.id == Group::AUTO_GROUPS[:staff]}
+ g.users.count.should == 1
+ g.user_count.should == 1
+
+ g = groups.find{|g| g.id == Group::AUTO_GROUPS[:trust_level_2]}
+ g.users.count.should == 1
+ g.user_count.should == 1
+
+ end
+
end