From 0d42079611ed2aeacd71b926580fdc3b943cf1ba Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 6 Apr 2014 12:22:11 -0400 Subject: make editing user permissions work --- app/controllers/users_controller.rb | 36 ++++++--- app/helpers/sessions_helper.rb | 4 +- app/models/user.rb | 157 ++++++++++++++++++++++++------------ app/views/users/_form.html.erb | 34 +++++--- 4 files changed, 153 insertions(+), 78 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index bcb45aa..dd66c18 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -24,17 +24,29 @@ class UsersController < ApplicationController # POST /users # POST /users.json def create - if simple_captcha_valid? - @user = User.new(user_params) + @user = User.new(user_params) + unless (simple_captcha_valid?) respond_to do |format| - if @user.save - sign_in @user - format.html { redirect_to root_path, notice: 'User was successfully created.' } - format.json { render action: 'show', status: :created, location: @user } - else - format.html { render action: 'new', status: :unprocessable_entity } - format.json { render json: @user.errors, status: :unprocessable_entity } + format.html { render action: 'new', status: :unprocessable_entity } + format.json { render json: @user.errors, status: :unprocessable_entity } + end + return + end + + @user.permissions = 0 + respond_to do |format| + if @user.save + sign_in @user + if @user.id == 1 + # This is the first user, so give them all the power + @user.permissions = 0xFFFFFFFF + @user.save end + format.html { redirect_to root_path, notice: 'User was successfully created.' } + format.json { render action: 'show', status: :created, location: @user } + else + format.html { render action: 'new', status: :unprocessable_entity } + format.json { render json: @user.errors, status: :unprocessable_entity } end end end @@ -75,6 +87,10 @@ class UsersController < ApplicationController # Never trust parameters from the scary internet, only allow the white list through. def user_params - params.require(:user).permit(:name, :email, :user_name, :password, :password_confirmation) + permitted = [ :name, :email, :user_name, :password, :password_confirmation ] + if current_user.can? :edit_permissions + permitted.push(:abilities => User.permission_bits.keys) + end + params.require(:user).permit(permitted) end end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index ac62cdc..499e988 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -20,7 +20,7 @@ module SessionsHelper def current_user @token ||= Session.hash_token(cookies[:remember_token]) @session ||= Session.find_by(token: @token) - @current_user ||= (@session.nil? ? NilUser.new : @session.user) + @current_user ||= (@session.nil? ? User::NilUser.new : @session.user) end # checks if someone is currently signed in @@ -32,7 +32,7 @@ module SessionsHelper if signed_in? @session.destroy end - @current_user = NilUser.new + @current_user = User::NilUser.new cookies.delete(:remember_token) end diff --git a/app/models/user.rb b/app/models/user.rb index 64dd7ed..626e4bf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,57 +9,108 @@ class User < ActiveRecord::Base before_save { self.email = email.downcase } before_save { self.user_name = user_name } - def after_initialize - self.permissions = 0 - end + def self.permission_bits + return { + :create_tournament => 1, + :edit_tournament => 2, + :join_tournament => 3, + :delete_tournament => 4, - def can?(action) - return true - case action - when :create_tournament - return true - when :edit_tournament - return true - when :join_tournament - return true - when :delete_tournament + :create_game => 5, + :edit_game => 6, + :delete_game => 7, - when :create_game - when :edit_game - when :delete_game + :create_user => 8, + :edit_user => 9, + :delete_user => 10, - when :create_user - return false - when :edit_user - when :delete_user + :create_alert => 11, + :edit_alert => 12, + :delete_alert => 13, - when :create_alert - when :edit_alert - when :delete_alert + :create_pm => 14, + :edit_pm => 15, + :delete_pm => 16, - when :create_pm - when :edit_pm - when :delete_pm + :create_session => 17, + :delete_session => 18, - when :create_session - return false - when :delete_session + :edit_permissions => 19, + } + end - else + def can?(action) + bit = User.permission_bits[action] + if bit.nil? return false + else + return (self.permissions & (2**bit) != 0) + end + end + + def add_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + self.permissions |= 2**bit + end + end + + def remove_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + self.permissions &= ~ (2**bit) + end + end + + + # A representation of the permission bits as a mock-array. + def abilities + @abilities ||= Abilities.new(self) + end + def abilities=(new) + new.each do |k,v| + if v == "0" + v = false + end + abilities[k] = v + end + end + + # A thin array-like wrapper around the permission bits to make it + # easy to modify them using a form. + class Abilities + def initialize(user) + @user = user + end + def [](ability) + return @user.can?(ability) + end + def []=(ability, val) + if val + @user.add_ability(ability) + else + @user.remove_ability(ability) + end + end + def keys + User.permission_bits.keys + end + def method_missing(name, *args) + if name.to_s.ends_with?('=') + self[name.to_s.sub(/=$/, '').to_sym] = args.first + else + return self[name.to_sym] + end end end - ## # VAILD_EMAIL is the regex used to validate a user given email. VALID_EMAIL_REG = /\A\S+@\S+\.\S+\z/i - ## # VALID_USER_NAME checks to make sure a user's user_name # is in the proper format. VALID_USER_NAME_REG = /\A[a-zA-Z0-9\-]+\z/ - ## # The following lines put a user account through a series of # validations in order to make sure all of their information # is in the proper format. @@ -78,7 +129,6 @@ class User < ActiveRecord::Base format: {with: VALID_USER_NAME_REG }, uniqueness: {case_sensitive: false }) - ## # Instead of adding password and password_confirmation # attributes, requiring the presence of a password, # requiring that pw and pw_com match, and add an authenticate @@ -88,26 +138,27 @@ class User < ActiveRecord::Base has_secure_password validates :password, length: { minimum: 6 } -end -class NilUser - def nil? - return true - end - def can?(action) - case action - when :create_user - return true - when :create_session + + class NilUser + def nil? return true - else - return false end - end - def method_missing(name, *args) - # Throw an error if User doesn't have this method - super unless User.new.respond_to?(name) - # User has this method -- return a blank value - # 'false' if the method ends with '?'; 'nil' otherwise. - name.ends_with?('?') ? false : nil + def can?(action) + case action + when :create_user + return true + when :create_session + return true + else + return false + end + end + def method_missing(name, *args) + # Throw an error if User doesn't have this method + super unless User.new.respond_to?(name) + # User has this method -- return a blank value + # 'false' if the method ends with '?'; 'nil' otherwise. + name.to_s.ends_with?('?') ? false : nil + end end end diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index ae63f06..40f8f09 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -1,37 +1,45 @@ <%= form_for(@user) do |f| %> - <% if @user.errors.any? %> -
-

<%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

- - -
- <% end %> + <%= render "common/error_messages", :target => @user %>
<%= f.label :name %>
<%= f.text_field :name %>
+
<%= f.label :email %>
<%= f.text_field :email %>
+
<%= f.label :user_name %>
<%= f.text_field :user_name %>
-

+ +

<%= f.label(:password, "New Password (or use old)") %>
<%= f.password_field :password %> -

+
<%= f.label(:password_confirmation, "Confirm Password") %>
<%= f.password_field :password_confirmation %>
+ + <% if current_user.can? :edit_permissions %> +
+ User permissions + +
+ <% end %> +
<%= f.submit %>
+ <% end %> -- cgit v1.1-4-g5e80