diff --git a/Gemfile b/Gemfile index 4aa8f6b..9dd0452 100644 --- a/Gemfile +++ b/Gemfile @@ -25,7 +25,7 @@ gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 3.0' # Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' +gem 'bcrypt', '~> 3.1.7' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development diff --git a/Gemfile.lock b/Gemfile.lock index ef205d8..ff0ff7b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,6 +39,7 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) arel (7.1.4) + bcrypt (3.1.11) builder (3.2.2) byebug (9.0.6) coffee-rails (4.2.1) @@ -154,6 +155,7 @@ PLATFORMS ruby DEPENDENCIES + bcrypt (~> 3.1.7) byebug coffee-rails (~> 4.2) jbuilder (~> 2.5) diff --git a/app/assets/javascripts/admin.coffee b/app/assets/javascripts/admin.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/admin.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/sessions.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/users.coffee b/app/assets/javascripts/users.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/users.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss new file mode 100644 index 0000000..0f4f3b2 --- /dev/null +++ b/app/assets/stylesheets/admin.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Admin controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/scaffolds.scss b/app/assets/stylesheets/scaffolds.scss new file mode 100644 index 0000000..4ce4266 --- /dev/null +++ b/app/assets/stylesheets/scaffolds.scss @@ -0,0 +1,89 @@ +body { + background-color: #fff; + color: #333; + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; + margin: 33px; +} + +p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; + margin: 33px; +} + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +a { + color: #000; + + &:visited { + color: #666; + } + + &:hover { + color: #fff; + background-color: #000; + } +} + +th { + padding-bottom: 5px; +} + +td { + padding-bottom: 7px; + padding-left: 5px; + padding-right: 5px; +} + +div { + &.field, &.actions { + margin-bottom: 10px; + } +} + +#notice { + color: green; +} + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; + + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0; + background-color: #c00; + color: #fff; + } + + ul li { + font-size: 12px; + list-style: square; + } +} + +label { + display: block; +} diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000..ccb1ed2 --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Sessions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 0000000..31a2eac --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 0000000..c2a9ad9 --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -0,0 +1,4 @@ +class AdminController < ApplicationController + def index + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c07694..ddb10c9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,12 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception + + before_action :authorize + + protected + def authorize + unless User.find_by(id: session[:user_id]) + redirect_to login_url + end + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..7383491 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,20 @@ +class SessionsController < ApplicationController + skip_before_action :authorize + + def new + end + + def create + user = User.find_by(name: params[:name]) + if user&.authenticate(params[:password]) + session[:user_id] = user.id + redirect_to admin_url + else + redirect_to login_url + end + end + + def destroy + session[:user_id] = nil + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..6e49a73 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,74 @@ +class UsersController < ApplicationController + before_action :set_user, only: [:show, :edit, :update, :destroy] + + # GET /users + # GET /users.json + def index + @users = User.order(:name) + end + + # GET /users/1 + # GET /users/1.json + def show + end + + # GET /users/new + def new + @user = User.new + end + + # GET /users/1/edit + def edit + end + + # POST /users + # POST /users.json + def create + @user = User.new(user_params) + + respond_to do |format| + if @user.save + format.html { redirect_to @user, notice: 'User was successfully created.' } + format.json { render :show, status: :created, location: @user } + else + format.html { render :new } + format.json { render json: @user.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /users/1 + # PATCH/PUT /users/1.json + def update + respond_to do |format| + if @user.update(user_params) + format.html { redirect_to @user, notice: 'User was successfully updated.' } + format.json { render :show, status: :ok, location: @user } + else + format.html { render :edit } + format.json { render json: @user.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /users/1 + # DELETE /users/1.json + def destroy + @user.destroy + respond_to do |format| + format.html { redirect_to users_url, notice: 'User was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_user + @user = User.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def user_params + params.require(:user).permit(:name, :password, :password_confirmation) + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb new file mode 100644 index 0000000..d5c6d35 --- /dev/null +++ b/app/helpers/admin_helper.rb @@ -0,0 +1,2 @@ +module AdminHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..309f8b2 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..d67da20 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,3 @@ +class User < ApplicationRecord + has_secure_password +end diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb new file mode 100644 index 0000000..e5328b7 --- /dev/null +++ b/app/views/admin/index.html.erb @@ -0,0 +1,2 @@ +

Admin#index

+

Find me in app/views/admin/index.html.erb

diff --git a/app/views/sessions/create.html.erb b/app/views/sessions/create.html.erb new file mode 100644 index 0000000..c251174 --- /dev/null +++ b/app/views/sessions/create.html.erb @@ -0,0 +1,2 @@ +

Sessions#create

+

Find me in app/views/sessions/create.html.erb

diff --git a/app/views/sessions/destroy.html.erb b/app/views/sessions/destroy.html.erb new file mode 100644 index 0000000..d75237d --- /dev/null +++ b/app/views/sessions/destroy.html.erb @@ -0,0 +1,2 @@ +

Sessions#destroy

+

Find me in app/views/sessions/destroy.html.erb

diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000..30388d0 --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,15 @@ +<%= form_tag do %> +
+ <%= label_tag :name %> + <%= text_field_tag :name %> +
+ +
+ <%= label_tag :password %> + <%= password_field_tag :password %> +
+ +
+ <%= submit_tag 'Login' %> +
+<% end %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb new file mode 100644 index 0000000..00362d7 --- /dev/null +++ b/app/views/users/_form.html.erb @@ -0,0 +1,32 @@ +<%= form_for(user) do |f| %> + <% if user.errors.any? %> +
+

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

+ + +
+ <% end %> + +
+ <%= f.label :name %> + <%= f.text_field :name %> +
+ +
+ <%= f.label :password %> + <%= f.password_field :password %> +
+ +
+ <%= f.label :password_confirmation %> + <%= f.password_field :password_confirmation %> +
+ +
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder new file mode 100644 index 0000000..d5f4ffe --- /dev/null +++ b/app/views/users/_user.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! user, :id, :name, :created_at, :updated_at +json.url user_url(user, format: :json) \ No newline at end of file diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 0000000..1a5c2a6 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,6 @@ +

Editing User

+ +<%= render 'form', user: @user %> + +<%= link_to 'Show', @user %> | +<%= link_to 'Back', users_path %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 0000000..ac0b9c6 --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,27 @@ +

<%= notice %>

+ +

Users

+ + + + + + + + + + + <% @users.each do |user| %> + + + + + + + <% end %> + +
Name
<%= user.name %><%= link_to 'Show', user %><%= link_to 'Edit', edit_user_path(user) %><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New User', new_user_path %> diff --git a/app/views/users/index.json.jbuilder b/app/views/users/index.json.jbuilder new file mode 100644 index 0000000..d6891e6 --- /dev/null +++ b/app/views/users/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @users, partial: 'users/user', as: :user \ No newline at end of file diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..844c39b --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,5 @@ +

New User

+ +<%= render 'form', user: @user %> + +<%= link_to 'Back', users_path %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000..3f5c2a2 --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,9 @@ +

<%= notice %>

+ +

+ Name: + <%= @user.name %> +

+ +<%= link_to 'Edit', edit_user_path(@user) %> | +<%= link_to 'Back', users_path %> diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder new file mode 100644 index 0000000..a2e64e0 --- /dev/null +++ b/app/views/users/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "users/user", user: @user \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 787824f..0beec77 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,3 +1,14 @@ Rails.application.routes.draw do + root 'users#index', as: 'users_index' + + get 'admin/index' + + controller :sessions do + get 'login' => :new + post 'login' => :create + delete 'logout' => :destroy + end + + resources :users # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end diff --git a/db/migrate/20161124123704_create_users.rb b/db/migrate/20161124123704_create_users.rb new file mode 100644 index 0000000..18cba87 --- /dev/null +++ b/db/migrate/20161124123704_create_users.rb @@ -0,0 +1,10 @@ +class CreateUsers < ActiveRecord::Migration[5.0] + def change + create_table :users do |t| + t.string :name + t.string :password_digest + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..6d09b2f --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,22 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20161124123704) do + + create_table "users", force: :cascade do |t| + t.string "name" + t.string "password_digest" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/test/controllers/admin_controller_test.rb b/test/controllers/admin_controller_test.rb new file mode 100644 index 0000000..a5841cc --- /dev/null +++ b/test/controllers/admin_controller_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class AdminControllerTest < ActionDispatch::IntegrationTest + test "should get index" do + get admin_index_url + assert_response :success + end + +end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb new file mode 100644 index 0000000..c6251b0 --- /dev/null +++ b/test/controllers/sessions_controller_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class SessionsControllerTest < ActionDispatch::IntegrationTest + test "should get new" do + get sessions_new_url + assert_response :success + end + + test "should get create" do + get sessions_create_url + assert_response :success + end + + test "should get destroy" do + get sessions_destroy_url + assert_response :success + end + +end diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..93c384c --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,48 @@ +require 'test_helper' + +class UsersControllerTest < ActionDispatch::IntegrationTest + setup do + @user = users(:one) + end + + test "should get index" do + get users_url + assert_response :success + end + + test "should get new" do + get new_user_url + assert_response :success + end + + test "should create user" do + assert_difference('User.count') do + post users_url, params: { user: { name: @user.name, password: 'secret', password_confirmation: 'secret' } } + end + + assert_redirected_to user_url(User.last) + end + + test "should show user" do + get user_url(@user) + assert_response :success + end + + test "should get edit" do + get edit_user_url(@user) + assert_response :success + end + + test "should update user" do + patch user_url(@user), params: { user: { name: @user.name, password: 'secret', password_confirmation: 'secret' } } + assert_redirected_to user_url(@user) + end + + test "should destroy user" do + assert_difference('User.count', -1) do + delete user_url(@user) + end + + assert_redirected_to users_url + end +end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..a3724e6 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,9 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + password_digest: <%= BCrypt::Password.create('secret') %> + +two: + name: MyString + password_digest: <%= BCrypt::Password.create('secret') %> diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..82f61e0 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end