diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 6811f77..dbfa98b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -2,6 +2,7 @@ class ProjectsController < ApplicationController before_action :set_project, only: [:show, :edit, :update, :destroy] before_action :authenticate_user! + # GET /projects # GET /projects.json diff --git a/app/controllers/whitelists_controller.rb b/app/controllers/whitelists_controller.rb new file mode 100644 index 0000000..2b621fc --- /dev/null +++ b/app/controllers/whitelists_controller.rb @@ -0,0 +1,87 @@ +class WhitelistsController < ApplicationController + before_action :check_if_coach + + # GET /whitelists + def index + @permitted_users = User.all + end + + # GET /whitelists/new + def new + @authorized_user = Whitelist.new(user_params) + end + + # POST /whitelists/ + def create + username = params[:username] + if Whitelist.has_username?(username) + flash[:notice] = "User #{username} already exists in whitelist. " + else + begin + Whitelist.create!(username: username) + flash[:notice] = "Add user #{username} successfully." + rescue ActiveRecord::RecordInvalid + flash[:notice] = "Invalid username format." + end + end + redirect_to whitelists_path + end + + # DELETE /whitelists/ + def destroy + user = Whitelist.find(params[:id]) + if user.username.eql?(current_user.provider_username) + flash[:notice] = "Delete yourself from the whitelist is not allowed. " + else + user.destroy! + flash[:notice] = "User is deleted successfully." + end + redirect_to whitelists_path + end + + def check_if_coach + unless current_user.role.eql?("admin") or current_user.role.eql?("coach") + flash[:notice] = "You have no privilege to manipulate privilege control." + redirect_to projects_url + end + end + + def upgrade + unless current_user.role.eql?("admin") or current_user.role.eql?("coach") + flash[:alert] = "You do not have privilege to change other user's role. " + redirect_to whitelists_path + return + end + user = User.find(params[:id]) + if user.role.eql?("admin") + flash[:alert] = "Admin role cannot be changed." + end + if user.role.eql?("student") + user.change_role("coach") + end + redirect_to whitelists_path + end + + def downgrade + unless current_user.role.eql?("admin") or current_user.role.eql?("coach") + flash[:alert] = "You do not have privilege to change other user's role. " + redirect_to whitelists_path + return + end + user = User.find(params[:id]) + if user.role.eql?("admin") + flash[:alert] = "Admin role cannot be changed." + end + if user.role.eql?("coach") + user.change_role("student") + end + redirect_to whitelists_path + end + + private + + def user_params + params.require(:whitelist).permit(:username) + end + +end diff --git a/app/models/user.rb b/app/models/user.rb index 9767930..ecbfc8e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -36,6 +36,7 @@ class User < ActiveRecord::Base ADMIN = "admin" COACH = "coach" + STUDENT = "student" def self.from_omniauth(auth) email = auth.info.email.nil? ? auth.extra.raw_info.email : auth.info.email @@ -59,6 +60,11 @@ def is_admin? self.role == ADMIN end + def change_role(role) + self.role = role + self.save! + end + def preferred_projects self.selected_projects = Project.all if self.selected_projects.empty? self.selected_projects diff --git a/app/models/whitelist.rb b/app/models/whitelist.rb new file mode 100644 index 0000000..455fcd6 --- /dev/null +++ b/app/models/whitelist.rb @@ -0,0 +1,15 @@ +# == Schema Information +# +# Table name: whitelists +# +# id :integer not null, primary key +# username :string +# + +class Whitelist < ActiveRecord::Base + validates_format_of :username,:with => /\A[a-z0-9\-_]+\z/i + + def self.has_username?(username) + return !Whitelist.find_by_username(username).nil? + end +end diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index c310194..703fb48 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -6,6 +6,7 @@

Welcome to ProjectScope

+ <%= render "devise/shared/links" %>
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 70e49c4..588b408 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -12,6 +12,7 @@ <%= link_to "Sign up", new_registration_path(resource_name) %>
<% end -%> + <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
<% end -%> diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml index 14a820d..22577a7 100644 --- a/app/views/projects/index.html.haml +++ b/app/views/projects/index.html.haml @@ -20,6 +20,17 @@ = '%.2f'.try(:%,sample.try(:score) || 0.0) #{raw sample.try(:image)} -%br/ +-unless current_user.role.eql?("coach") or current_user.role.eql?("admin") + %br/ + + = link_to 'Create New Project', new_project_path, :class => "btn btn-primary" + +-else + %br/ + + = link_to 'Privilege Control', whitelists_path, :class => "btn btn-primary" + + %br/ + + = link_to 'Create New Project', new_project_path, :class => "btn btn-primary" -= link_to 'Create New Project', new_project_path, :class => "btn btn-primary" diff --git a/app/views/whitelists/_add.html.haml b/app/views/whitelists/_add.html.haml new file mode 100644 index 0000000..0e811ed --- /dev/null +++ b/app/views/whitelists/_add.html.haml @@ -0,0 +1,5 @@ += form_tag whitelists_path do + = field_set_tag do + = label_tag :username, 'GitHub username' + = text_field_tag :username + = submit_tag 'Add' \ No newline at end of file diff --git a/app/views/whitelists/index.html.haml b/app/views/whitelists/index.html.haml new file mode 100644 index 0000000..e7af39f --- /dev/null +++ b/app/views/whitelists/index.html.haml @@ -0,0 +1,50 @@ +:css + #Users{ + border-collapse: collapse; + width: 80%; + margin-right: auto; + } + + #Users td, #Users th { + border: 1px solid #ddd; + padding: 8px; + } + + #Users tr:nth-child(even){background-color: #f2f2f2;} + + #Users tr:hover {background-color: #ddd;} + + #Users th { + padding-top: 12px; + padding-bottom: 12px; + text-align: left; + background-color: #337ab7; + color: white; + } + #Users tr { + text-align: left; + } + +%h1 Privilege Control + +%table#Users + %thead + %tr + %th GitHub Account + %th Role + %th Action + + %tbody + - @permitted_users.each do |user| + %tr + %td= user.provider_username + %td= user.role + -if user.role.eql?("coach") + %td= link_to "Downgrade to student", downgrade_user_path(user), :method => :get, data: { confirm: "Do you want to downgrade user #{user.provider_username} from the whitelist?" }, :user => user + -elsif user.role.eql?("student") + %td= link_to "Upgrade to coach", upgrade_user_path(user), :method => :get, data: { confirm: "Do you want to upgrade user #{user.provider_username} from the whitelist?" }, :user => user + -else + %td + +%br/ += link_to 'Back to project page', projects_url diff --git a/app/views/whitelists/new.html.erb b/app/views/whitelists/new.html.erb new file mode 100644 index 0000000..5a87a72 --- /dev/null +++ b/app/views/whitelists/new.html.erb @@ -0,0 +1,6 @@ +

Authorize Users to have access to ProjectScope

+ +<%= render 'add' %> + + +<%= link_to 'Back', whitelists_path %> diff --git a/config/routes.rb b/config/routes.rb index 6e6493e..c293161 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,12 @@ Rails.application.routes.draw do resources :users, :only => [:show, :update], :path => "u" devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }, :skip => [:password] - + resources :projects root 'projects#index' + resources :whitelists + + get '/whitelists/upgrade/:id', :to => 'whitelists#upgrade', :as => 'upgrade_user' + get '/whitelists/downgrade/:id', :to => 'whitelists#downgrade', :as => 'downgrade_user' + end diff --git a/db/migrate/20161020034239_add_role_to_users.rb b/db/migrate/20161020034239_add_role_to_users.rb index ea24805..b785826 100644 --- a/db/migrate/20161020034239_add_role_to_users.rb +++ b/db/migrate/20161020034239_add_role_to_users.rb @@ -1,5 +1,5 @@ class AddRoleToUsers < ActiveRecord::Migration def change - add_column :users, :role, :string, null: false, default: "coach" + add_column :users, :role, :string, null: false, default: "student" end end diff --git a/db/migrate/20161020040440_create_root_user.rb b/db/migrate/20161020040440_create_root_user.rb index d9bf218..64fb5ab 100644 --- a/db/migrate/20161020040440_create_root_user.rb +++ b/db/migrate/20161020040440_create_root_user.rb @@ -4,16 +4,22 @@ def up password: Devise.friendly_token[0,20], provider_username: "DrakeW", provider: "github", - role: "admin") + role: "coach") User.create!(email: "fox@cs.berkeley.edu", password: Devise.friendly_token[0,20], provider_username: "armandofox", provider: "github", role: "admin") + User.create!(email: "jiachengwu@berkeley.edu", + password: Devise.friendly_token[0,20], + provider_username: "ysiad", + provider: "github", + role: "coach") end def down User.where(email: "junyuw@berkeley.edu", provider: "github").first.destroy User.where(email: "fox@cs.berkeley.edu", provider: "github").first.destroy + User.where(email: "jiachengwu@berkeley.edu", provider: "github").first.destroy end end diff --git a/db/migrate/20161022053537_create_whitelists.rb b/db/migrate/20161022053537_create_whitelists.rb new file mode 100644 index 0000000..b385a78 --- /dev/null +++ b/db/migrate/20161022053537_create_whitelists.rb @@ -0,0 +1,9 @@ +class CreateWhitelists < ActiveRecord::Migration + def change + create_table :whitelists, :force => true do |t| + t.string :username # default: "", null: false + end + add_index :whitelists, :username + end +end + diff --git a/db/migrate/20161022053828_create_authorized_user.rb b/db/migrate/20161022053828_create_authorized_user.rb new file mode 100644 index 0000000..a933bf1 --- /dev/null +++ b/db/migrate/20161022053828_create_authorized_user.rb @@ -0,0 +1,11 @@ +class CreateAuthorizedUser < ActiveRecord::Migration + def up + Whitelist.create!(username: "DrakeW") + Whitelist.create!(username: "armandofox") + end + + def down + Whitelist.where(username: "DrakeW").first.destroy + Whitelist.where(username: "armandofox").first.destroy + end +end diff --git a/db/schema.rb b/db/schema.rb index 66f6a3a..8222ae3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -79,4 +79,10 @@ add_index "users", ["provider_username"], name: "index_users_on_provider_username", unique: true add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + create_table "whitelists", force: :cascade do |t| + t.string "username" + end + + add_index "whitelists", ["username"], name: "index_whitelists_on_username" + end diff --git a/features/github_user_login.feature b/features/github_user_login.feature index e0c86ec..8331dcd 100644 --- a/features/github_user_login.feature +++ b/features/github_user_login.feature @@ -5,6 +5,7 @@ Feature: GitHub User Login Scenario: github user login with email Given I am on the login page + And "test-coach" is in the whitelist And I have a valid github account with email "test-coach@test.com" username "test-coach" When I follow "Sign in with GitHub" Then I should be on the home page @@ -12,6 +13,7 @@ Scenario: github user login with email Scenario: github user login without email Given I am on the login page + And "test-coach" is in the whitelist And I have a valid github account with email "" username "test-coach" When I follow "Sign in with GitHub" Then I should be on the home page diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index 6bbdc55..193dfca 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -56,6 +56,7 @@ end And(/^I am logged in$/) do + Whitelist.create :username => "test-coach" visit path_to("the login page") OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new( { diff --git a/features/step_definitions/whitelist_steps.rb b/features/step_definitions/whitelist_steps.rb new file mode 100644 index 0000000..aedb525 --- /dev/null +++ b/features/step_definitions/whitelist_steps.rb @@ -0,0 +1,16 @@ +Given(/^"([^"]*)" is in the whitelist$/) do |username| + Whitelist.create!(username: username) +end + +Then /^I should be admin$/ do + expect(current_user.role).to eq "admin" +end + +Given /^I enter the whitelist page$/ do + visit path_to("the whitelist page") + sleep(1) +end + +When /^I follow the first "Delete"$/ do + first(:link, "Delete").click +end \ No newline at end of file diff --git a/features/support/paths.rb b/features/support/paths.rb index 429951b..8fea221 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -21,6 +21,10 @@ def path_to(page_name) "/projects/#{Project.find_by(name: $1).id}/edit" when /^the login page/ then '/users/sign_in' + when /^the whitelist page/ then + '/whitelists' + when /^the whitelist management page/ then + '/whitelists/new' # Add more mappings here. # Here is an example that pulls values out of the Regexp: # diff --git a/features/whitelist.feature b/features/whitelist.feature new file mode 100644 index 0000000..9ea4567 --- /dev/null +++ b/features/whitelist.feature @@ -0,0 +1,70 @@ +@omniauth +Feature: Whitelist + As a whitelist user, I will be able to login to the projectscope and see the whitelist. + If I am not a whitelist user, I will not be able to login and manipulate the whitelist. + +Background: + Given "test-admin" is in the whitelist + And "ysiad" is in the whitelist + +Scenario: Users in the whitelist should be able to login + Given I am on the login page + And I have a valid github account with email "test-coach@test.com" username "test-admin" + When I follow "Sign in with GitHub" + Then I should be on the home page + And I should see "Signed in successfully." + +Scenario: Users that are not in the whitelist will not be able to login + Given I am on the login page + And I have a valid github account with email "test-coach@test.com" username "test-coach" + When I follow "Sign in with GitHub" + Then I should be on the login page + And I should see "You are not authorized." + +Scenario: Not whitelist user cannot see the whitelist + Given I am on the login page + When I go to the whitelist page + Then I should see "You are not authorized to manipulate whitelist." + +Scenario: Whitelist users can see the whitelist + Given I am logged in + Then I should be on the home page + And I should see "Whitelist" + When I follow "Whitelist" + Then I should be on the whitelist page + Then I should see "ysiad" + Then I should see "test-admin" + +Scenario: Whitelist users add a user to the whitelist + Given I am logged in + And I enter the whitelist page + Then I should see "Add user to whitelist" + When I follow "Add user to whitelist" + Then I should be on the whitelist management page + When I fill in "username" with "daisy" + And I press "Add" + Then I should be on the whitelist page + And I should see "daisy" + + Scenario: Whitelist users delete a user from the whitelist + Given I am logged in + And I enter the whitelist page + Then I should see "test-admin" + When I follow the first "Delete" + Then I should see "User is deleted successfully." + And I should not see "test-admin" + + Scenario: Whitelist users are unable to delete themselves from the whitelist + Given I am logged in + And I enter the whitelist page + Then I should see "test-admin" + Then I should see "ysiad" + Then I should see "test-coach" + When I follow the first "Delete" + Then I should not see "test-admin" + When I follow the first "Delete" + Then I should not see "ysiad" + Then I should not see "Delete" + + + diff --git a/users b/users new file mode 100644 index 0000000..e69de29