Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authenticate/Inviting #1

Merged
merged 11 commits into from
Sep 8, 2019
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ gem 'rails', '~> 5.2.3'
gem 'pg', '>= 0.18', '< 2.0'
gem 'puma', '~> 3.11'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'haml-rails', '~> 2.0'
gem 'bcrypt', '~> 3.1.7'
gem 'jwt', '2.2.1'

group :development, :test do
gem 'pry-byebug'
Expand All @@ -20,4 +23,8 @@ group :development do
gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
gem 'database_cleaner'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
27 changes: 27 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,18 @@ GEM
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
bcrypt (3.1.13)
bootsnap (1.4.5)
msgpack (~> 1.0)
builder (3.2.3)
byebug (11.0.1)
coderay (1.1.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
database_cleaner (1.7.0)
diff-lcs (1.3)
erubi (1.8.0)
erubis (2.7.0)
factory_bot (5.0.2)
activesupport (>= 4.2.0)
factory_bot_rails (5.0.2)
Expand All @@ -60,8 +63,23 @@ GEM
ffi (1.11.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
haml (5.1.2)
temple (>= 0.8.0)
tilt
haml-rails (2.0.1)
actionpack (>= 5.1)
activesupport (>= 5.1)
haml (>= 4.0.6, < 6.0)
html2haml (>= 1.0.1)
railties (>= 5.1)
html2haml (2.2.0)
erubis (~> 2.7.0)
haml (>= 4.0, < 6)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jwt (2.2.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
Expand Down Expand Up @@ -139,6 +157,9 @@ GEM
rspec-support (~> 3.8.0)
rspec-support (3.8.2)
ruby_dep (1.5.0)
ruby_parser (3.13.1)
sexp_processor (~> 4.9)
sexp_processor (4.12.1)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
Expand All @@ -150,8 +171,10 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
temple (0.8.1)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
tzinfo (1.2.5)
thread_safe (~> 0.1)
websocket-driver (0.7.1)
Expand All @@ -162,8 +185,12 @@ PLATFORMS
ruby

DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.1.0)
database_cleaner
factory_bot_rails
haml-rails (~> 2.0)
jwt (= 2.2.1)
listen (>= 3.0.5, < 3.2)
pg (>= 0.18, < 2.0)
pry-byebug
Expand Down
27 changes: 8 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
# README
## Getting Started

This README would normally document whatever steps are necessary to get the
application up and running.
This section provides quick start guide.

Things you may want to cover:
### Prerequisites

* Ruby version
- [Ruby](https://www.ruby-lang.org/en/): 2.6.3
- [Ruby on Rails](https://rubyonrails.org/): 2.6.3
- [PostgreSQL](https://www.postgresql.org/) 9.4 or higher.

* System dependencies
### Standard Installation

* Configuration

* Database creation

* Database initialization

* How to run the test suite

* Services (job queues, cache servers, search engines, etc.)

* Deployment instructions

* ...
1. `bin/setup`
11 changes: 11 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# frozen_string_literal: true

class ApplicationController < ActionController::API
rescue_from BasicAuthenticate::NotAuthenticated, with: :not_authenticated

private

def authorize!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

зачем свою писать, если есть sorcery или devise?

AuthenticateByToken.new(request.headers['Authorization']).call
end

def not_authenticated
render json: { error: 'Not Authenticated' }, status: :unauthorized
end
end
9 changes: 9 additions & 0 deletions app/controllers/authentication_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AuthenticationController < ApplicationController
# POST /login
def create
token = GetToken.new(email: params[:email], password: params[:password]).call
render json: { auth_token: token }, status: :ok
end
end
9 changes: 9 additions & 0 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class HomeController < ApplicationController
before_action :authorize!
# GET /
def homepage
render json: { success: 'ok' }, status: :ok
end
end
11 changes: 11 additions & 0 deletions app/controllers/invites_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class InvitesController < ApplicationController
before_action :authorize!
# GET /send_invite
def send_invite
prefix = SecureRandom.hex(3)
InviteMailer.with(email: "#{prefix}[email protected]", password: 'qwerty').send_invite.deliver_later
render json: { success: 'invite sent' }, status: :ok
end
end
19 changes: 19 additions & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class UsersController < ApplicationController
# POST /users
def create
user = User.new(user_params)
if user.save
render json: { success: ['User created'] }, status: :ok
else
render json: { error: user.errors.full_messages }, status: :internal_server_error
end
end

private

def user_params
params.permit(:email, :password)
end
end
10 changes: 10 additions & 0 deletions app/mailers/invite_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class InviteMailer < ApplicationMailer
def send_invite
@email = params[:email]
@password = params[:password]

mail(to: @email, subject: 'Welcome')
end
end
9 changes: 9 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class User < ApplicationRecord
has_secure_password

validates :email, :password, presence: true
validates :email, uniqueness: true
validates :password, length: { in: 8..20 }
end
24 changes: 24 additions & 0 deletions app/services/authenticate_by_token.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class AuthenticateByToken
include BasicAuthenticate

attr_reader :token

def initialize(token)
@token = token
end

def call
user_id = decode_payload(token)
User.find(user_id['sub'])
rescue ActiveRecord::RecordNotFound, JWT::DecodeError
raise NotAuthenticated
end

private

def decode_payload(payload)
JWT.decode(payload, secret).first
end
end
28 changes: 28 additions & 0 deletions app/services/get_token.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

class GetToken
include BasicAuthenticate

attr_reader :email, :password

def initialize(email:, password:)
@email = email
@password = password
end

def call
user = User.find_by(email: email)
if user&.authenticate(password)
payload = { 'sub' => user.id }
encode_payload(payload)
else
raise NotAuthenticated
end
end

private

def encode_payload(payload)
JWT.encode(payload, secret)
end
end
4 changes: 4 additions & 0 deletions app/views/invite_mailer/send_invite.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
%p Ваш логин: #{@email}
%p Ваш пароль: #{@password}

Нажмите, чтобы продолжить:
9 changes: 9 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ chdir APP_ROOT do
puts "\n== Preparing database =="
system! 'bin/rails db:setup'

puts "\n== Create database =="
system! 'bin/rails db:create'

puts "\n== Updating database =="
system! 'bin/rails db:migrate'

puts "\n== Fill database =="
system! 'bin/rails db:seed'

puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear'

Expand Down
2 changes: 1 addition & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module Rock
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2

config.autoload_paths << Rails.root.join('lib')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
Expand Down
1 change: 1 addition & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
config.action_mailer.raise_delivery_errors = false

config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
Expand Down
5 changes: 4 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root 'home#homepage'
post '/login', to: 'authentication#create'
get '/send_invite', to: 'invites#send_invite'
post '/users', to: 'users#create'
end
11 changes: 11 additions & 0 deletions db/migrate/20190906052935_create_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :email, null: false, unique: true
t.string :password_digest, null: false
t.boolean :mentor, default: false

t.timestamps
end
end
end
26 changes: 26 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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: 2019_09_06_052935) 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 "email", null: false
t.string "password_digest", null: false
t.boolean "mentor", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

end
10 changes: 3 additions & 7 deletions db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
User.create(email: '[email protected]',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create!

password: 'qwerty12',
password_confirmation: 'qwerty12')
11 changes: 11 additions & 0 deletions lib/basic_authenticate.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module BasicAuthenticate
class NotAuthenticated < StandardError; end

private

def secret
@secret = Rails.application.secrets.secret_key_base
end
end
6 changes: 6 additions & 0 deletions spec/factories/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FactoryBot.define do
factory :user do
email { '[email protected]' }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gem faker

password { 'qwerty12' }
end
end
Loading