Skip to content

Commit ebb5f3f

Browse files
committed
Initial implementation of admin console and site settings
1 parent fe1124f commit ebb5f3f

23 files changed

+399
-91
lines changed

Gemfile

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ gem 'aws-sdk'
2121
gem 'paperclip'
2222
gem 'remotipart'
2323
gem 'jquery-rails'
24+
gem 'enumerize'
2425

2526
# Making the world a better, more stable place
2627
gem 'airbrake'
@@ -42,6 +43,7 @@ group :development do
4243
gem 'awesome_print'
4344
gem 'better_errors'
4445
gem 'binding_of_caller'
46+
gem 'debugger'
4547
end
4648

4749
group :test do

Gemfile.lock

+12
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,17 @@ GEM
7474
coffee-script-source
7575
execjs
7676
coffee-script-source (1.4.0)
77+
columnize (0.3.6)
7778
cookiejar (0.3.0)
7879
daemons (1.1.9)
7980
database_cleaner (0.9.1)
81+
debugger (1.2.3)
82+
columnize (>= 0.3.1)
83+
debugger-linecache (~> 1.1.1)
84+
debugger-ruby_core_source (~> 1.1.5)
85+
debugger-linecache (1.1.2)
86+
debugger-ruby_core_source (>= 1.1.1)
87+
debugger-ruby_core_source (1.1.6)
8088
devise (1.5.3)
8189
bcrypt-ruby (~> 3.0)
8290
orm_adapter (~> 0.0.3)
@@ -98,6 +106,8 @@ GEM
98106
http_parser.rb (>= 0.5.3)
99107
em-socksify (0.2.1)
100108
eventmachine (>= 1.0.0.beta.4)
109+
enumerize (0.5.1)
110+
activesupport (>= 3.2)
101111
erubis (2.7.0)
102112
eventmachine (1.0.0)
103113
execjs (1.4.0)
@@ -271,9 +281,11 @@ DEPENDENCIES
271281
cloudfuji
272282
coffee-rails
273283
database_cleaner
284+
debugger
274285
devise
275286
devise_cloudfuji_authenticatable
276287
eco
288+
enumerize
277289
execjs
278290
factory_girl_rails
279291
faker
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
$(document).ready ->
2+

app/assets/javascripts/application.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919
//= require lib/backbone
2020
//= require backbone/kandan
2121
//= require_tree .
22+
//= stub admin/admin
2223
//= require lib/jquery.atwho
2324
//= require lib/jquery.caret

app/assets/javascripts/backbone/kandan.js.coffee.erb

-16
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,13 @@ window.Kandan =
123123
Kandan.Plugins.Mentions.initUsersMentions(Kandan.Helpers.ActiveUsers.all())
124124
return
125125

126-
setCurrentUser: ()->
127-
template = JST['current_user']
128-
currentUser = Kandan.Helpers.Users.currentUser()
129-
displayName = "#{currentUser.first_name} #{currentUser.last_name}" if currentUser.first_name?
130-
displayName ||= currentUser.email
131-
$(".header .user").html template({
132-
gravatarHash: currentUser.gravatar_hash,
133-
name: displayName
134-
})
135-
136126
registerUtilityEvents: ()->
137127
window.setInterval(=>
138128
for el in $(".posted_at")
139129
$(el).text (new Date($(el).data("timestamp"))).toRelativeTime(@options.nowThreshold)
140130
, @options.timestampRefreshInterval)
141131

142-
$(".user_menu_link").click (e)->
143-
e.preventDefault()
144-
$(".user_menu").toggle()
145-
false
146-
147132
init: ->
148-
@setCurrentUser()
149133
channels = new Kandan.Collections.Channels()
150134
channels.fetch({
151135
success: (channelsCollection)=>
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
$(document).ready ->
2+
$(".user_menu_link").click (e)->
3+
e.preventDefault()
4+
$(".user_menu").toggle()
5+
false
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module Admin
2+
class AdminController < BaseController
3+
4+
def index
5+
@settings = Setting.my_settings
6+
@all_users = User.find(:all, :conditions => ["id != ?", current_user.id])
7+
8+
# Note that this reject! will remove users from all_users in order to show users in 2 different tables
9+
@waiting_for_approval_users = @all_users.reject!{|user| user.status.waiting_approval? } || []
10+
end
11+
12+
def update
13+
14+
max_rooms = params[:setting][:max_rooms].to_i
15+
public_site = params[:setting][:public_site] == "1"
16+
17+
Setting.set_values(:max_rooms => max_rooms, :public_site => public_site)
18+
19+
redirect_to :admin_root
20+
end
21+
22+
def update_users
23+
24+
end
25+
26+
end
27+
end
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Admin
2+
class BaseController < ApplicationController
3+
before_filter :authenticate_admin!
4+
5+
private
6+
7+
def authenticate_admin!
8+
redirect_to root_url unless current_user.try(:is_admin?)
9+
end
10+
11+
end
12+
end

app/helpers/admin/admin_helper.rb

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Admin::AdminHelper
2+
def user_status user
3+
"<div class='#{user.status}'>#{user.status}</div>".html_safe
4+
end
5+
6+
def user_action user
7+
8+
end
9+
end

app/models/setting.rb

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class Setting < ActiveRecord::Base
2+
attr_accessible :values
3+
serialize :values, Hash
4+
5+
before_create :set_default_values
6+
before_create :ensure_only_one_settings
7+
before_destroy :ensure_only_one_settings
8+
9+
before_save :validate_max_rooms, :validate_public_site
10+
11+
def max_rooms
12+
self.values[:max_rooms]
13+
end
14+
15+
def public_site?
16+
self.values[:public_site]
17+
end
18+
19+
alias_method :public_site, :public_site?
20+
21+
def set_default_values
22+
self.values.merge!(self.class.default_values)
23+
end
24+
25+
def ensure_only_one_settings
26+
return false if Setting.count >= 1
27+
end
28+
29+
# Making sure the max_rooms is an integer and is never less than the current number of rooms
30+
def validate_max_rooms
31+
self.values[:max_rooms].is_a?(Integer) && self.values[:max_rooms] >= Channel.count unless self.new_record?
32+
end
33+
34+
# Making sure the public site is a boolean
35+
def validate_public_site
36+
!!self.values[:public_site] == self.values[:public_site] unless self.new_record?
37+
end
38+
39+
def self.default_values
40+
return {:max_rooms => 99, :public_site => false }
41+
end
42+
43+
# Helper methods to be used while we don't need to deal with multi-tenancy
44+
def self.my_settings
45+
self.first_or_create
46+
end
47+
48+
def self.get_value(k)
49+
setting = self.my_settings
50+
setting.values[k]
51+
end
52+
53+
def self.set_values(values)
54+
setting = self.my_settings
55+
56+
values.each do |k,v|
57+
setting.values[k.to_sym] = v
58+
end
59+
60+
setting.save!
61+
end
62+
63+
end

app/models/user.rb

+33
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
class User < ActiveRecord::Base
2+
extend Enumerize
3+
4+
# Being pesimistic here and making the default waiting for approval for security reasons
5+
enumerize :status, in: [:active, :suspended, :waiting_approval], :default => :waiting_approval
26

37
has_many :activities
48
before_save :ensure_authentication_token
59
before_save :ensure_gravatar_hash
10+
before_save :mark_status_depending_on_app_settings
611

12+
after_create :ensure_at_least_one_admin
13+
after_destroy :ensure_at_least_one_admin
14+
715
validates :username, :presence => true, :uniqueness => true
16+
validates :first_name, :presence => true
17+
validates :last_name, :presence => true
818

919

1020
# Kandan.devise_modules is defined in config/initializers/kandan.rb
@@ -13,17 +23,40 @@ class User < ActiveRecord::Base
1323
# Setup accessible (or protected) attributes for your model
1424
attr_accessible :id, :username, :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :locale, :gravatar_hash
1525

26+
def full_name
27+
"#{self.first_name.to_s} #{self.last_name.to_s}".titlecase
28+
end
29+
30+
def full_name_or_username
31+
self.full_name.blank? ? self.username : self.full_name
32+
end
33+
1634
def cloudfuji_extra_attributes(extra_attributes)
1735
self.first_name = extra_attributes["first_name"].to_s
1836
self.last_name = extra_attributes["last_name"].to_s
1937
self.email = extra_attributes["email"]
2038
self.locale = extra_attributes["locale"]
2139
end
2240

41+
# Callback to mark the user status depending on the settings of the app
42+
def mark_status_depending_on_app_settings
43+
# If the site is public we will make the user active. Otherwise we will make the user as waiting_approval
44+
self.status = Setting.my_settings.public_site? ? :active : :waiting_approval
45+
end
46+
2347
def ensure_gravatar_hash
2448
self.gravatar_hash = Digest::MD5.hexdigest self.email
2549
end
2650

51+
# We never want an app without an admin so let's ensure there is at least one user
52+
def ensure_at_least_one_admin
53+
if User.count == 1
54+
u = User.first
55+
u.is_admin = true
56+
u.save!
57+
end
58+
end
59+
2760
def active_for_authentication?
2861
super && active?
2962
end

app/views/admin/admin/index.html.erb

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<% content_for :javascript_includes do %>
2+
<%= javascript_include_tag "admin/admin" %>
3+
<% end %>
4+
5+
<div class="admin-main-area">
6+
<%= form_for @settings, :url => admin_update_path do |f| %>
7+
<%= f.label :max_rooms, 'Max number of rooms' %>:
8+
<%= f.text_field :max_rooms %><br />
9+
<%= f.label :public_site, 'Is this a public site?' %>:
10+
<%= f.check_box :public_site %><br />
11+
<%= f.submit %>
12+
<% end %>
13+
14+
<div class="waiting-for-approval-users">
15+
<% if @waiting_for_approval_users.any? %>
16+
<table cellspacing="0" cellpadding="0" border="0">
17+
<thead>
18+
<tr>
19+
<th class="">Username</th>
20+
<th class="">First Name</th>
21+
<th class="">Last Name</th>
22+
<th class="">Email</th>
23+
<th class="">Status</th>
24+
<th class="">Action</th>
25+
</tr>
26+
</thead>
27+
<tbody>
28+
<% @all_users.each do |user| %>
29+
<tr class="<%= cycle('odd', 'even')%>" data-user-id="<%= user.id%>">
30+
<td>
31+
<%= user.username %>
32+
</td>
33+
<td>
34+
<%= user.first_name %>
35+
</td>
36+
<td>
37+
<%= user.last_name %>
38+
</td>
39+
<td>
40+
<%= user.email %>
41+
</td>
42+
<td>
43+
<%= user_status(user) %>
44+
</td>
45+
<td>
46+
47+
</td>
48+
</tr>
49+
<% end %>
50+
</tbody>
51+
</table>
52+
<% else %>
53+
<div>There are no users. Invite others to join Kandan!</div>
54+
<% end %>
55+
</div>
56+
57+
<div class="approved-users">
58+
<% if @all_users.any? %>
59+
<table cellspacing="0" cellpadding="0" border="0">
60+
<thead>
61+
<tr>
62+
<th class="">Username</th>
63+
<th class="">First Name</th>
64+
<th class="">Last Name</th>
65+
<th class="">Email</th>
66+
<th class="">Status</th>
67+
<th class="">Action</th>
68+
</tr>
69+
</thead>
70+
<tbody>
71+
<% @all_users.each do |user| %>
72+
<tr class="<%= cycle('odd', 'even')%>" data-user-id="<%= user.id%>">
73+
<td>
74+
<%= user.username %>
75+
</td>
76+
<td>
77+
<%= user.first_name %>
78+
</td>
79+
<td>
80+
<%= user.last_name %>
81+
</td>
82+
<td>
83+
<%= user.email %>
84+
</td>
85+
<td>
86+
<%= user_status(user) %>
87+
</td>
88+
<td>
89+
90+
</td>
91+
</tr>
92+
<% end %>
93+
</tbody>
94+
</table>
95+
<% else %>
96+
<div>There are no users. Invite others to join Kandan!</div>
97+
<% end %>
98+
</div>
99+
</div>

app/views/devise/registrations/edit.html.erb

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
66
<%= devise_error_messages! %>
77

8+
<p><%= f.label :first_name %><br />
9+
<%= f.text_field :first_name %></p>
10+
11+
<p><%= f.label :last_name %><br />
12+
<%= f.text_field :last_name %></p>
13+
814
<p><%= f.label :email %><br />
915
<%= f.email_field :email %></p>
1016

0 commit comments

Comments
 (0)