Skip to content

Commit

Permalink
Backend user auth
Browse files Browse the repository at this point in the history
  • Loading branch information
avvazana committed Nov 13, 2018
1 parent c9c8053 commit d37a9c1
Show file tree
Hide file tree
Showing 28 changed files with 5,249 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@

# Ignore master key for decrypting credentials and more.
/config/master.key
node modules/
bundle.js
bundle.js.map
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "esversion":6 }
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ gem 'jbuilder', '~> 2.5'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
gem 'pry-rails'
gem 'jquery-rails'
gem 'bcrypt'

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
Expand All @@ -46,6 +49,9 @@ group :development do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'better_errors'
gem 'binding_of_caller'
gem 'annotate'
end

group :test do
Expand Down
37 changes: 32 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,20 @@ GEM
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
annotate (2.7.4)
activerecord (>= 3.2, < 6.0)
rake (>= 10.4, < 13.0)
archive-zip (0.11.0)
io-like (~> 0.3.0)
arel (9.0.0)
bcrypt (3.1.12)
better_errors (2.5.0)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.5.0)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootsnap (1.3.2)
msgpack (~> 1.0)
builder (3.2.3)
Expand All @@ -65,15 +75,17 @@ GEM
chromedriver-helper (2.1.0)
archive-zip (~> 0.10)
nokogiri (~> 1.8)
coderay (1.1.2)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.1.2)
concurrent-ruby (1.1.3)
crass (1.0.4)
debug_inspector (0.0.3)
erubi (1.7.1)
execjs (2.7.0)
ffi (1.9.25)
Expand All @@ -85,6 +97,10 @@ GEM
jbuilder (2.8.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
jquery-rails (4.3.3)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
Expand All @@ -96,7 +112,7 @@ GEM
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.1)
method_source (0.9.2)
mimemagic (0.3.2)
mini_mime (1.0.1)
mini_portile2 (2.3.0)
Expand All @@ -107,6 +123,11 @@ GEM
nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
pg (1.1.3)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-rails (0.3.7)
pry (>= 0.10.4)
public_suffix (3.0.3)
puma (3.12.0)
rack (2.0.6)
Expand Down Expand Up @@ -143,7 +164,7 @@ GEM
regexp_parser (1.2.0)
ruby_dep (1.5.0)
rubyzip (1.2.2)
sass (3.7.0)
sass (3.7.2)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
Expand All @@ -169,7 +190,7 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.20.0)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.8)
tzinfo (1.2.5)
Expand All @@ -191,14 +212,20 @@ PLATFORMS
ruby

DEPENDENCIES
annotate
bcrypt
better_errors
binding_of_caller
bootsnap (>= 1.1.0)
byebug
capybara (>= 2.15)
chromedriver-helper
coffee-rails (~> 4.2)
jbuilder (~> 2.5)
jquery-rails
listen (>= 3.0.5, < 3.2)
pg (>= 0.18, < 2.0)
pry-rails
puma (~> 3.11)
rails (~> 5.2.1)
sass-rails (~> 5.0)
Expand All @@ -213,4 +240,4 @@ RUBY VERSION
ruby 2.3.7p456

BUNDLED WITH
1.16.1
1.17.1
3 changes: 3 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
bundle.js
bundle.js.map
5 changes: 4 additions & 1 deletion app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@
//
//= require rails-ujs
//= require activestorage
//= require_tree .
//= require_tree

//= require jquery
//= require jquery_ujs
3 changes: 3 additions & 0 deletions app/assets/javascripts/users.coffee
Original file line number Diff line number Diff line change
@@ -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/
3 changes: 3 additions & 0 deletions app/assets/stylesheets/users.scss
Original file line number Diff line number Diff line change
@@ -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/
23 changes: 23 additions & 0 deletions app/controllers/api/session_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Api::SessionsController < ApplicationController
def create
@user = User.find_by_credentials(
params[:user][:username],
params[:user][:password]
)
if @user
login!(@user)
render 'api/users/show'
else
render json: ["Invalid credentials"], status: 401
end
end

def destroy
if current_user
logout!
render json: {}
else
render json: ["No user logged in"], status: 404
end
end
end
23 changes: 23 additions & 0 deletions app/controllers/api/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Api::UsersController < ApplicationController

def create
@user = User.new(user_params)

if @user.save
login(@user)
render 'api/users/show'
else
render json: @user.errors.full_messages, status: 422
end
end

def show
@user = User.find(params[:id])
render :show
end

private
def user_params
params.require(:user).permit(:username, :email, :password)
end
end
25 changes: 25 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,27 @@
class ApplicationController < ActionController::Base
helper_method :logged_in?, :current_user

def current_user
@current_user ||= User.find_by_session_token(session[:session_token])
end

def logged_in?
!!current_user
end

def ensure_logged_in
unless current_user
render json: {base: ['invalid credentials']}, status: 401
end
end

def login!(user)
session[:session_token] = user.reset_session_token!
@current_user = user
end

def logout!
current_user.reset_session_token!
session[:session_token] = nil
end
end
4 changes: 4 additions & 0 deletions app/controllers/static_pages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class StaticPagesController < ApplicationController
def root
end
end
2 changes: 2 additions & 0 deletions app/helpers/users_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module UsersHelper
end
32 changes: 32 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class User < ApplicationRecord
validates :username, :session_token, :email, presence: true, uniqueness: true
validates :password_digest, presence: {message: "Password can't be blank"}
validates :password, length: {minimum: 6, allow_nil: true}

after_initialize :ensure_session_token
attr_reader :password

def password=(password)
@password = password
self.password_digest = BCrypt::Password.create(password)
end

def self.find_by_credentials(username, password)
user = User.find_by(username: username)
user && user.is_password?(password) ? user : nil
end

def is_password?(password)
BCrypt::Password.new(self.password_digest).is_password?(password)
end

def ensure_session_token
self.session_token ||= SecureRandom.urlsafe_base64(16)
end

def reset_session_token!
self.session_token = SecureRandom.urlsafe_base64(16)
self.save!
self.session_token
end
end
1 change: 1 addition & 0 deletions app/views/api/users/_user.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.extract! user, :id, :username
2 changes: 2 additions & 0 deletions app/views/api/users/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
debugger
json.partial! 'api/users/user', user: @user
1 change: 1 addition & 0 deletions app/views/static_pages/root.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id='root'></div>
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: "static_pages#root"

namespace :api, defaults: { format: :json } do
resources :users, only: [:show, :create]
end
end
16 changes: 16 additions & 0 deletions db/migrate/20181113164249_create_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string 'username', null: false
t.string 'email', null: false
t.string 'password_digest', null: false
t.string 'session_token', null: false
t.string 'profile_pic_url'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.index ['email'], name: 'index_users_email', unique: true
t.index ['session_token'], name: 'index_users_session_token', unique: true
t.index ['username'], name: 'index_users_username', unique: true
end
end
end
31 changes: 31 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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: 2018_11_13_164249) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "users", force: :cascade do |t|
t.string "username", null: false
t.string "email", null: false
t.string "password_digest", null: false
t.string "session_token", null: false
t.string "profile_pic_url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_email", unique: true
t.index ["session_token"], name: "index_users_session_token", unique: true
t.index ["username"], name: "index_users_username", unique: true
end

end
43 changes: 43 additions & 0 deletions frontend/actions/session_actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as SessionApiUtil from '../util/session_api_util';

export const RECEIVE_CURRENT_USER = "RECEIVE_CURRENT_USER";
export const RECEIVE_USER = 'RECEIVE_USER';
export const LOGOUT_CURRENT_USER = "LOGOUT_CURRENT_USER";

export const receiveCurrentUser = user => ({
type: RECEIVE_CURRENT_USER,
user
});

export const receiveUser = user => ({
type: RECEIVE_USER,
user
});

const logoutCurrentUser = () => ({
type: LOGOUT_CURRENT_USER
});

export const signup = user => dispatch => {
return SessionApiUtil.signup(user)
.then(user => dispatch(receiveCurrentUser(user)),
err => dispatch(receiveSignupErrors(err.responseJSON)));
};

export const login = user => dispatch => {
return SessionApiUtil.login(user)
.then(user => dispatch(receiveCurrentUser(user)),
err => dispatch(receiveSigninErrors(err.responseJSON)));
};

export const logout = () => dispatch => {
return SessionApiUtil.logout()
.then( () => dispatch(logoutCurrentUser()),
err => console.log(err.responseJSON))
};

export const fetchUser = id => dispatch => {
return SessionApiUtil.logout()
.then( user => dispatch(receiveUser(user)),
err => console.log(err.responseJSON))
};
Loading

0 comments on commit d37a9c1

Please sign in to comment.