mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
work in progress ... groups
This commit is contained in:
@ -1,10 +1,22 @@
|
|||||||
Discourse.AdminGroupsController = Ember.ArrayController.extend({
|
Discourse.AdminGroupsController = Ember.ArrayController.extend({
|
||||||
itemController: 'adminGroup',
|
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({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,34 @@
|
|||||||
Discourse.Group = Discourse.Model.extend({
|
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,8 +36,11 @@ Discourse.Group.reopenClass({
|
|||||||
findAll: function(){
|
findAll: function(){
|
||||||
var list = Discourse.SelectableArray.create();
|
var list = Discourse.SelectableArray.create();
|
||||||
|
|
||||||
list.addObject(Discourse.Group.create({id: 1, name: "all mods", members: ["A","b","c"]}));
|
Discourse.ajax("/admin/groups").then(function(groups){
|
||||||
list.addObject(Discourse.Group.create({id: 2, name: "other mods", members: ["A","b","c"]}));
|
groups.each(function(group){
|
||||||
|
list.addObject(Discourse.Group.create(group));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
Discourse.AdminGroupsRoute = Discourse.Route.extend({
|
Discourse.AdminGroupsRoute = Discourse.Route.extend({
|
||||||
model: function() {
|
|
||||||
return Discourse.Group.findAll();
|
|
||||||
},
|
|
||||||
renderTemplate: function() {
|
renderTemplate: function() {
|
||||||
this.render('admin/templates/groups',{into: 'admin/templates/admin'});
|
this.render('admin/templates/groups',{into: 'admin/templates/admin'});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.set('model', Discourse.Group.findAll());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,20 +3,23 @@
|
|||||||
<div class='content-list span6'>
|
<div class='content-list span6'>
|
||||||
<h3>{{i18n admin.groups.edit}}</h3>
|
<h3>{{i18n admin.groups.edit}}</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{{#each group in controller}}
|
{{#each group in model}}
|
||||||
<li>
|
<li>
|
||||||
<a href="#" {{action "edit" group}} {{bindAttr class="group.active"}}>{{group.name}}</a>
|
<a href="#" {{action "edit" group}} {{bindAttr class="group.active"}}>{{group.name}} <span class="count">{{group.userCountDisplay}}</span></a>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
<div>
|
||||||
|
<button {{bindAttr disabled="refreshingAutoGroups"}} {{action "refreshAutoGroups"}}>Refresh Automatic Groups</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='content-editor'>
|
<div class='content-editor'>
|
||||||
{{#if content.active}}
|
{{#if model.active}}
|
||||||
{{#with content.active}}
|
{{#with model.active}}
|
||||||
<h3>{{name}}</h3>
|
<h3>{{name}}</h3>
|
||||||
{{view Discourse.UserSelector id="private-message-users" class="span8" placeholderKey="admin.groups.selector_placeholder" tabindex="1" usernamesBinding="usernames"}}
|
{{view Discourse.UserSelector id="private-message-users" class="span8" placeholderKey="admin.groups.selector_placeholder" tabindex="1" usernamesBinding="usernames"}}
|
||||||
<button>Save</button>
|
<button {{bindAttr disabled="allowSave"}}>Save</button>
|
||||||
|
|
||||||
{{/with}}
|
{{/with}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// this allows you to track the selected item in an array, ghetto for now
|
// this allows you to track the selected item in an array, ghetto for now
|
||||||
Discourse.SelectableArray = Em.ArrayProxy.extend({
|
Discourse.SelectableArray = Em.ArrayProxy.extend({
|
||||||
content: [],
|
init: function() {
|
||||||
|
this.content = [];
|
||||||
|
this._super();
|
||||||
|
},
|
||||||
selectIndex: function(index){
|
selectIndex: function(index){
|
||||||
this.select(this[index]);
|
this.select(this[index]);
|
||||||
},
|
},
|
||||||
|
@ -3,6 +3,17 @@
|
|||||||
@import "foundation/mixins";
|
@import "foundation/mixins";
|
||||||
@import "foundation/helpers";
|
@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 {
|
.admin-content {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
.admin-contents {
|
.admin-contents {
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
class Admin::GroupsController < Admin::AdminController
|
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
|
def show
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def users
|
||||||
|
group = Group.find(params[:group_id].to_i)
|
||||||
|
render_serialized(group.users, BasicUserSerializer)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -25,11 +25,12 @@ class Group < ActiveRecord::Base
|
|||||||
id = AUTO_GROUPS[name]
|
id = AUTO_GROUPS[name]
|
||||||
|
|
||||||
unless group = self[name]
|
unless group = self[name]
|
||||||
group = Group.new(name: name.to_s, automatic: true)
|
group = Group.new(name: "", automatic: true)
|
||||||
group.id = id
|
group.id = id
|
||||||
group.save!
|
group.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
group.name = I18n.t("groups.default_names.#{name}")
|
||||||
|
|
||||||
real_ids = case name
|
real_ids = case name
|
||||||
when :admins
|
when :admins
|
||||||
@ -55,9 +56,15 @@ class Group < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
group.save!
|
group.save!
|
||||||
|
|
||||||
|
# we want to ensure consistency
|
||||||
|
Group.reset_counters(group.id, :group_users)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.refresh_automatic_groups!(*args)
|
def self.refresh_automatic_groups!(*args)
|
||||||
|
if args.length == 0
|
||||||
|
args = AUTO_GROUPS.map{|k,v| k}
|
||||||
|
end
|
||||||
args.each do |group|
|
args.each do |group|
|
||||||
refresh_automatic_group!(group)
|
refresh_automatic_group!(group)
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
class GroupUser < ActiveRecord::Base
|
class GroupUser < ActiveRecord::Base
|
||||||
belongs_to :group
|
belongs_to :group, counter_cache: "user_count"
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
end
|
end
|
||||||
|
3
app/serializers/admin_group_serializer.rb
Normal file
3
app/serializers/admin_group_serializer.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class AdminGroupSerializer < ApplicationSerializer
|
||||||
|
attributes :id, :automatic, :name, :user_count
|
||||||
|
end
|
@ -44,6 +44,17 @@ en:
|
|||||||
rss_topics_in_category: "RSS feed of topics in the '%{category}' category"
|
rss_topics_in_category: "RSS feed of topics in the '%{category}' category"
|
||||||
author_wrote: "%{author} wrote:"
|
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:
|
education:
|
||||||
until_posts:
|
until_posts:
|
||||||
one: "post"
|
one: "post"
|
||||||
|
@ -29,7 +29,13 @@ Discourse::Application.routes.draw do
|
|||||||
|
|
||||||
get 'reports/:type' => 'reports#show'
|
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
|
resources :users, id: USERNAME_ROUTE_FORMAT do
|
||||||
collection do
|
collection do
|
||||||
get 'list/:query' => 'users#index'
|
get 'list/:query' => 'users#index'
|
||||||
|
5
db/migrate/20130508040235_add_user_count_to_groups.rb
Normal file
5
db/migrate/20130508040235_add_user_count_to_groups.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AddUserCountToGroups < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :groups, :user_count, :integer, null: false, default: 0
|
||||||
|
end
|
||||||
|
end
|
@ -1,9 +1,10 @@
|
|||||||
module Jobs
|
module Jobs
|
||||||
# checks to see if any users need to be promoted
|
# various consistency checks
|
||||||
class EnsureDbConsistency < Jobs::Base
|
class EnsureDbConsistency < Jobs::Base
|
||||||
def execute(args)
|
def execute(args)
|
||||||
TopicUser.ensure_consistency!
|
TopicUser.ensure_consistency!
|
||||||
UserVisit.ensure_consistency!
|
UserVisit.ensure_consistency!
|
||||||
|
Group.refresh_automatic_groups!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
31
spec/controllers/admin/groups_controller_spec.rb
Normal file
31
spec/controllers/admin/groups_controller_spec.rb
Normal file
@ -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
|
@ -54,4 +54,30 @@ describe Group do
|
|||||||
Group[:trust_level_2].user_ids.sort.should == [user.id, user2.id].sort
|
Group[:trust_level_2].user_ids.sort.should == [user.id, user2.id].sort
|
||||||
end
|
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
|
end
|
||||||
|
Reference in New Issue
Block a user