work in progress add support for groups

This commit is contained in:
Sam 2013-04-17 17:08:21 +10:00
parent a6170db443
commit 4cea92c4e9
20 changed files with 268 additions and 117 deletions

View File

@ -0,0 +1,10 @@
Discourse.AdminGroupsController = Ember.ArrayController.extend({
itemController: 'adminGroup',
edit: function(action){
this.get('content').select(action);
}
});
Discourse.AdminGroupController = Ember.ObjectController.extend({
});

View File

@ -0,0 +1,24 @@
Discourse.Group = Discourse.Model.extend({
});
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"]}));
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;
}
});

View File

@ -0,0 +1,9 @@
Discourse.AdminGroupsRoute = Discourse.Route.extend({
model: function() {
return Discourse.Group.findAll();
},
renderTemplate: function() {
this.render('admin/templates/groups',{into: 'admin/templates/admin'});
}
});

View File

@ -25,6 +25,8 @@ Discourse.Route.buildRoutes(function() {
this.route('old', { path: '/old' });
});
this.route('groups', {path: '/groups'});
this.resource('adminUsers', { path: '/users' }, function() {
this.resource('adminUser', { path: '/:username' });
this.resource('adminUsersList', { path: '/list' }, function() {

View File

@ -7,6 +7,7 @@
<li>{{#linkTo 'admin.site_settings'}}{{i18n admin.site_settings.title}}{{/linkTo}}</li>
<li>{{#linkTo 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/linkTo}}</li>
<li>{{#linkTo 'adminUsersList.active'}}{{i18n admin.users.title}}{{/linkTo}}</li>
<li>{{#linkTo 'admin.groups'}}{{i18n admin.groups.title}}{{/linkTo}}</li>
<li>{{#linkTo 'admin.email_logs'}}{{i18n admin.email_logs.title}}{{/linkTo}}</li>
<li>{{#linkTo 'adminFlags.active'}}{{i18n admin.flags.title}}{{/linkTo}}</li>
<li>{{#linkTo 'admin.customize'}}{{i18n admin.customize.title}}{{/linkTo}}</li>

View File

@ -0,0 +1,23 @@
<div class='row'>
<div class='content-list span6'>
<h3>{{i18n admin.groups.edit}}</h3>
<ul>
{{#each group in controller}}
<li>
<a href="#" {{action "edit" group}} {{bindAttr class="group.active"}}>{{group.name}}</a>
</li>
{{/each}}
</ul>
</div>
<div class='content-editor'>
{{#if content.active}}
{{#with content.active}}
{{name}}
{{view Discourse.UserSelector id="private-message-users" class="span8" placeholderKey="admin.groups.selector_placeholder" tabindex="1" usernamesBinding="usernames"}}
{{/with}}
{{else}}
nothing here yet
{{/if}}
</div>
</div>

View File

@ -0,0 +1,4 @@
Discourse.AdminGroupsView = Discourse.View.extend({
});

View File

@ -0,0 +1,19 @@
// this allows you to track the selected item in an array, ghetto for now
Discourse.SelectableArray = Em.ArrayProxy.extend({
content: [],
selectIndex: function(index){
this.select(this[index]);
},
select: function(selected){
this.content.each(function(item){
if(item === selected){
Em.set(item, "active", true)
} else {
if (item.get("active")) {
Em.set(item, "active", false)
}
}
});
this.set("active", selected);
}
});

View File

@ -28,7 +28,7 @@
{{#if content.editTitle}}
<div class='form-element clearfix'>
{{#if content.creatingPrivateMessage}}
{{view Discourse.TextField id="private-message-users" class="span8" placeholderKey="composer.users_placeholder" tabindex="1"}}
{{view Discourse.UserSelector topicIdBinding="controller.controllers.topic.content.id" excludeCurrentUser="true" id="private-message-users" class="span8" placeholderKey="composer.users_placeholder" tabindex="1" usernamesBinding="content.targetUsernames"}}
{{/if}}
{{view Discourse.TextField valueBinding="content.title" tabindex="2" id="reply-title" maxlength="255" class="span8" placeholderKey="composer.title_placeholder"}}
{{#unless content.creatingPrivateMessage}}

View File

@ -167,17 +167,7 @@ Discourse.ComposerView = Discourse.View.extend({
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
Discourse.ComposerView.trigger("initWmdEditor");
template = Handlebars.compile("<div class='autocomplete'>" +
"<ul>" +
"{{#each options}}" +
"<li>" +
"<a href='#'>{{avatar this imageSize=\"tiny\"}} " +
"<span class='username'>{{this.username}}</span> " +
"<span class='name'>{{this.name}}</span></a>" +
"</li>" +
"{{/each}}" +
"</ul>" +
"</div>");
template = Discourse.UserSelector.templateFunction();
transformTemplate = Handlebars.compile("{{avatar this imageSize=\"tiny\"}} {{this.username}}");
$wmdInput.data('init', true);
@ -193,38 +183,6 @@ Discourse.ComposerView = Discourse.View.extend({
transformComplete: function(v) { return v.username; }
});
selected = [];
$('#private-message-users').val(this.get('content.targetUsernames')).autocomplete({
template: template,
dataSource: function(term) {
return Discourse.UserSearch.search({
term: term,
topicId: _this.get('controller.controllers.topic.content.id'),
exclude: selected.concat([Discourse.get('currentUser.username')])
});
},
onChangeItems: function(items) {
items = $.map(items, function(i) {
if (i.username) {
return i.username;
} else {
return i;
}
});
_this.set('content.targetUsernames', items.join(","));
selected = items;
},
transformComplete: transformTemplate,
reverseTransform: function(i) {
return { username: i };
}
});
topic = this.get('topic');
this.editor = editor = Discourse.Markdown.createEditor({
lookupAvatar: function(username) {

View File

@ -0,0 +1,65 @@
Discourse.UserSelector = Discourse.TextField.extend({
didInsertElement: function(){
var _this = this;
var selected = [];
var transformTemplate = Handlebars.compile("{{avatar this imageSize=\"tiny\"}} {{this.username}}");
var template = Discourse.UserSelector.templateFunction();
$(this.get('element')).val(this.get('usernames')).autocomplete({
template: template,
dataSource: function(term) {
var exclude = selected;
if (_this.get('excludeCurrentUser')){
exclude = exclude.concat([Discourse.get('currentUser.username')]);
}
return Discourse.UserSearch.search({
term: term,
topicId: _this.get('topicId'),
exclude: exclude
});
},
onChangeItems: function(items) {
items = $.map(items, function(i) {
if (i.username) {
return i.username;
} else {
return i;
}
});
_this.set('usernames', items.join(","));
selected = items;
},
transformComplete: transformTemplate,
reverseTransform: function(i) {
return { username: i };
}
});
}
});
Discourse.UserSelector.reopenClass({
// I really want to move this into a template file, but I need a handlebars template here, not an ember one
templateFunction: function(){
this.compiled = this.compiled || Handlebars.compile("<div class='autocomplete'>" +
"<ul>" +
"{{#each options}}" +
"<li>" +
"<a href='#'>{{avatar this imageSize=\"tiny\"}} " +
"<span class='username'>{{this.username}}</span> " +
"<span class='name'>{{this.name}}</span></a>" +
"</li>" +
"{{/each}}" +
"</ul>" +
"</div>");
return this.compiled;
}
});

145
app/assets/stylesheets/application/compose.css.scss Normal file → Executable file
View File

@ -54,6 +54,40 @@
margin-left: 10px;
}
.autocomplete {
z-index: 9999;
position: absolute;
width: 200px;
background-color: $white;
border: 1px solid $gray;
ul {
list-style: none;
padding: 0;
margin: 0;
li {
border-bottom: 1px solid $light_gray;
a[href] {
padding: 5px;
display: block;
span.username {
color: lighten($black, 20);
}
span.name {
font-size: 11px;
}
&.selected {
background-color: $light_gray;
}
@include hover {
background-color: $light_gray;
text-decoration: none;
}
}
}
}
}
#reply-control {
.requirements-not-met {
background-color: rgba(255, 0, 0, 0.12);
@ -181,38 +215,7 @@
margin-right: auto;
float: none;
}
.autocomplete {
z-index: 999;
position: absolute;
width: 200px;
background-color: $white;
border: 1px solid $gray;
ul {
list-style: none;
padding: 0;
margin: 0;
li {
border-bottom: 1px solid $light_gray;
a[href] {
padding: 5px;
display: block;
span.username {
color: lighten($black, 20);
}
span.name {
font-size: 11px;
}
&.selected {
background-color: $light_gray;
}
@include hover {
background-color: $light_gray;
text-decoration: none;
}
}
}
}
}
// When the post is new (new topic) the sizings are different
&.edit-title {
&.open {
@ -309,50 +312,50 @@
margin-bottom: 10px;
}
#main #reply-control {
div.ac-wrap {
background-color: $white;
border: 1px solid #cccccc;
padding: 4px 10px;
@include border-radius-all(3px);
div.item {
float: left;
margin-right: 10px;
span {
padding-left: 5px;
height: 22px;
display: inline-block;
line-height: 22px;
vertical-align: bottom;
}
a {
margin-left: 4px;
font-size: 10px;
line-height: 10px;
padding: 2px 1px 1px 3px;
border-radius: 10px;
width: 10px;
display: inline-block;
border: 1px solid rgba(255, 255, 255, 0);
&:hover {
background-color: lighten($red, 45);
border: 1px solid lighten($red, 20);
text-decoration: none;
color: $white;
}
}
div.ac-wrap {
background-color: $white;
border: 1px solid #cccccc;
padding: 4px 10px;
@include border-radius-all(3px);
div.item {
float: left;
margin-right: 10px;
span {
padding-left: 5px;
height: 22px;
display: inline-block;
line-height: 22px;
vertical-align: bottom;
}
input[type="text"] {
float: left;
margin-top: 5px;
border: 0;
padding: 0;
margin: 4px 0 0;
box-shadow: none;
a {
margin-left: 4px;
font-size: 10px;
line-height: 10px;
padding: 2px 1px 1px 3px;
border-radius: 10px;
width: 10px;
display: inline-block;
border: 1px solid rgba(255, 255, 255, 0);
&:hover {
background-color: lighten($red, 45);
border: 1px solid lighten($red, 20);
text-decoration: none;
color: $white;
}
}
}
input[type="text"] {
float: left;
margin-top: 5px;
border: 0;
padding: 0;
margin: 4px 0 0;
box-shadow: none;
}
}
#reply-control.edit-title.private-message {
.wmd-controls {
top: 140px;

View File

@ -1,5 +1,3 @@
require_dependency 'sql_builder'
class Admin::FlagsController < Admin::AdminController
def index

View File

@ -0,0 +1,4 @@
class Admin::GroupsController < Admin::AdminController
def show
end
end

5
app/models/group.rb Normal file
View File

@ -0,0 +1,5 @@
class Group < ActiveRecord::Base
def self.builtin
Enum.new(:moderators, :admins, :trust_level_1, :trust_level_2)
end
end

2
app/models/group_user.rb Normal file
View File

@ -0,0 +1,2 @@
class GroupUser < ActiveRecord::Base
end

View File

@ -860,6 +860,10 @@ en:
delete_title: "delete post (if its the first post delete topic)"
flagged_by: "Flagged by"
error: "Something went wrong"
groups:
title: "Groups"
edit: "Edit Groups"
api:
title: "API"

View File

@ -27,6 +27,7 @@ Discourse::Application.routes.draw do
resources :site_settings
get 'reports/:type' => 'reports#show'
resources :groups
resources :users, id: USERNAME_ROUTE_FORMAT do
collection do
get 'list/:query' => 'users#index'

View File

@ -0,0 +1,8 @@
class CreateGroups < ActiveRecord::Migration
def change
create_table :groups do |t|
t.string :name, null: false
t.timestamps
end
end
end

View File

@ -0,0 +1,11 @@
class GroupUsers < ActiveRecord::Migration
def change
create_table :group_users do |t|
t.integer :group_id, null: false
t.integer :user_id, null: false
t.timestamps
end
add_index :group_users, [:group_id, :user_id], unique: true
end
end