From 7ddf93578efebc955447f778dcc0a8b77fd11610 Mon Sep 17 00:00:00 2001 From: Mark Moser Date: Fri, 23 Oct 2015 19:34:59 -0500 Subject: [PATCH] sqlite3, test coverage improvements, auto auth --- Gemfile | 10 ++---- Gemfile.lock | 48 ++++++++++++++------------ README.md | 9 +++-- app/controllers/oauths_controller.rb | 41 ++++++++++++++++++----- app/models/authentication.rb | 3 +- app/models/person.rb | 6 +++- app/views/users/edit.html.haml | 2 +- app/views/users/new.html.haml | 2 +- config/database.yml | 15 ++++----- config/initializers/sorcery.rb | 2 +- db/schema.rb | 50 ++++++++++++++-------------- test/fixtures/people.yml | 7 ++++ test/models/child_test.rb | 15 +++++++++ test/models/person_test.rb | 15 +++++++++ version.md | 1 + 15 files changed, 143 insertions(+), 83 deletions(-) create mode 100644 test/models/child_test.rb create mode 100644 version.md diff --git a/Gemfile b/Gemfile index 1a3e445..3698bf3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby "2.2.2" +ruby "2.2.3" gem 'figaro', '~> 1.1.1' gem 'bcrypt', '~> 3.1.7' @@ -13,19 +13,13 @@ gem 'haml-rails', "~> 0.9" gem 'jquery-rails' gem 'json', '~> 1.8.3' gem 'mailjet', '~> 1.1.0' -gem 'mysql2', '~> 0.3.20' gem 'responders', '~> 2.1.0' gem 'sass-rails', '~> 5.0' gem 'sorcery', '~> 0.9.1' +gem 'sqlite3', '~> 1.3.11' gem 'twilio-ruby', '~> 4.3.0' gem 'uglifier', '>= 1.3.0' -# gem 'faraday' -# gem 'faraday_middleware' -# gem 'rack-protection', '~> 1.5.3' -# gem 'rabl-rails', '~> 0.4.1' -# gem 'jbuilder', '~> 2.0' - group :development, :test do gem 'awesome_print' gem 'binding_of_caller' diff --git a/Gemfile.lock b/Gemfile.lock index 33044c7..b5bef1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -71,7 +71,7 @@ GEM erubis (2.7.0) eventmachine (1.0.8) execjs (2.6.0) - faraday (0.9.1) + faraday (0.9.2) multipart-post (>= 1.2, < 3) ffi (1.9.10) figaro (1.1.1) @@ -89,9 +89,10 @@ GEM shellany (~> 0.0) thor (>= 0.18.1) guard-compat (1.2.1) - guard-livereload (2.4.0) + guard-livereload (2.5.0) em-websocket (~> 0.5) guard (~> 2.8) + guard-compat (~> 1.0) multi_json (~> 1.8) guard-minitest (2.4.4) guard-compat (~> 1.2) @@ -105,7 +106,7 @@ GEM guard-shell (0.7.1) guard (>= 2.0.0) guard-compat (~> 1.0) - haml (4.0.6) + haml (4.0.7) tilt haml-rails (0.9.0) actionpack (>= 4.0.1) @@ -131,7 +132,7 @@ GEM railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) - jwt (1.4.1) + jwt (1.5.1) listen (3.0.3) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) @@ -145,10 +146,10 @@ GEM rack (>= 1.4.0) rest-client method_source (0.8.2) - mime-types (2.6.1) + mime-types (2.6.2) mini_portile (0.6.2) - minitest (5.8.0) - minitest-reporters (1.0.16) + minitest (5.8.1) + minitest-reporters (1.1.4) ansi builder minitest (>= 5.0) @@ -156,12 +157,11 @@ GEM multi_json (1.11.2) multi_xml (0.5.5) multipart-post (2.0.0) - mysql2 (0.3.20) nenv (0.2.0) netrc (0.10.3) nokogiri (1.6.6.2) mini_portile (~> 0.6.0) - notiffany (0.0.7) + notiffany (0.0.8) nenv (~> 0.1) shellany (~> 0.0) oauth (0.4.7) @@ -171,10 +171,10 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) - parser (2.2.2.6) + parser (2.2.3.0) ast (>= 1.1, < 3.0) powerpack (0.1.1) - pry (0.10.1) + pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) @@ -214,7 +214,7 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (2.0.0) rake (10.4.2) - rb-fsevent (0.9.5) + rb-fsevent (0.9.6) rb-inotify (0.9.5) ffi (>= 0.5.0) responders (2.1.0) @@ -223,16 +223,16 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 3.0) netrc (~> 0.7) - rubocop (0.33.0) + rubocop (0.34.2) astrolabe (~> 1.3) parser (>= 2.2.2.5, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.4) ruby-progressbar (1.7.5) - ruby_parser (3.6.6) + ruby_parser (3.7.1) sexp_processor (~> 4.1) - sass (3.4.18) + sass (3.4.19) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) sass (~> 3.1) @@ -242,24 +242,25 @@ GEM scss-lint (0.30.0) rainbow (~> 2.0) sass (~> 3.4.0) - sexp_processor (4.5.1) + sexp_processor (4.6.0) shellany (0.0.1) slop (3.6.0) sorcery (0.9.1) bcrypt (~> 3.1) oauth (~> 0.4, >= 0.4.4) oauth2 (>= 0.8.0) - spring (1.3.6) - sprockets (3.3.4) - rack (~> 1.0) + spring (1.4.0) + sprockets (3.4.0) + rack (> 1, < 3) sprockets-rails (2.3.3) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) + sqlite3 (1.3.11) sysexits (1.2.0) - thin (1.6.3) + thin (1.6.4) daemons (~> 1.0, >= 1.0.9) - eventmachine (~> 1.0) + eventmachine (~> 1.0, >= 1.0.4) rack (~> 1.0) thor (0.19.1) thread_safe (0.3.5) @@ -306,7 +307,6 @@ DEPENDENCIES json (~> 1.8.3) mailjet (~> 1.1.0) minitest-reporters - mysql2 (~> 0.3.20) pry-byebug pry-rails rack-livereload @@ -316,8 +316,12 @@ DEPENDENCIES sass-rails (~> 5.0) sorcery (~> 0.9.1) spring + sqlite3 (~> 1.3.11) thin (~> 1.6.3) turbolinks twilio-ruby (~> 4.3.0) uglifier (>= 1.3.0) web-console (~> 2.0) + +BUNDLED WITH + 1.10.6 diff --git a/README.md b/README.md index b32cfe2..94d76bb 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,15 @@ A simple app to send sms messages with [twillio](https://www.twilio.com/). ### Secrets file: -`config/secrets.yml` is read at boot and shoves the values into `ENV`. +`config/application.yml` is read at boot and shoves the values into `ENV`. -1. Copy `config/secrets.yml.sample` and rename to `config/secrets.yml`. +1. Copy `config/application.yml.sample` and rename to `config/application.yml`. 2. Edit file and set/define as many secrets as you need. The sample file has the minimum expected keys. 3. Make *ABSOLUTE* certain that this file is not checked into your repository. ## TODO - -* sorcery or a lower oauth solution +* activation flag on user edit +* verify roles access * application log -* app version file - milestone 0.9.0 * task runner - delayedjob or sidekiq or activerecord newness? * milestone 1.0.0 diff --git a/app/controllers/oauths_controller.rb b/app/controllers/oauths_controller.rb index 299dde0..a74f2b4 100644 --- a/app/controllers/oauths_controller.rb +++ b/app/controllers/oauths_controller.rb @@ -10,21 +10,44 @@ class OauthsController < ApplicationController @user = login_from(provider) if @user - redirect_to root_path, notice: "Logged in from #{provider.titleize}!" + redirect_to root_path, notice: login_msg(@user, provider) else - msg = "Your account must be pre-approved. Please contact the administrator." - redirect_to root_path, notice: msg + @user = auth_and_login(provider) + redirect_to root_path, notice: login_msg(@user, provider) end end private - # def create_and_login provider - # @user = create_from(provider) - # reset_session # protect from session fixation attack - # auto_login(@user) - # redirect_to root_path, notice: "Logged in from #{provider.titleize}!" - # end + def login_msg user, provider = 'oAuth' + if user.active? + "Logged in from #{provider.titleize}!" + else + "Your account must be activated by an administrator." + end + end + + def auth_and_login provider + user = create_auth_from(provider, auth_info) + reset_session # protect from session fixation attack + auto_login(user) if user.active? + user + end + + def create_auth_from provider, auth + user = Person.find_by_email auth[:user_info]["email"] + user.authentications.create(provider: provider, uid: auth[:uid]) + user + end + + def auth_info + @auth_info ||= google_hash + end + + def google_hash + ga = Sorcery::Providers::Google.new + ga.get_user_hash access_token + end def auth_params params.permit(:code, :provider) diff --git a/app/models/authentication.rb b/app/models/authentication.rb index 69a2df1..8aa459d 100644 --- a/app/models/authentication.rb +++ b/app/models/authentication.rb @@ -1,3 +1,4 @@ class Authentication < ActiveRecord::Base - belongs_to :user + belongs_to :person + validates :uid, presence: true, uniqueness: { scope: :provider } end diff --git a/app/models/person.rb b/app/models/person.rb index 7f2a5bf..8aa58ba 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -11,7 +11,7 @@ class Person < ActiveRecord::Base validates :phone, presence: true scope :with_name, lambda { |name| - where("concat(first_name, ' ', last_name) RLIKE ?", name) + where("first_name || ' ' || last_name LIKE ?", "%#{name}%") } scope :just_parents, lambda { @@ -34,6 +34,10 @@ class Person < ActiveRecord::Base id end + def active? + activation_state == "active" + end + private ## SorceryCore expects the model to hold a crypted_password field diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 36fce4c..234167c 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -1,3 +1,3 @@ %h2 Edit #{@user.name} -= render partial: 'form', locals: {form_action: edit_user_path} += render partial: 'form', locals: { form_action: edit_user_path } diff --git a/app/views/users/new.html.haml b/app/views/users/new.html.haml index 8ed0b55..ca2cc80 100644 --- a/app/views/users/new.html.haml +++ b/app/views/users/new.html.haml @@ -1,3 +1,3 @@ %h2 Register a new User -= render partial: 'form', locals: {form_action: add_user_path} += render partial: 'form', locals: { form_action: add_user_path } diff --git a/config/database.yml b/config/database.yml index 9610906..60a32c7 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,22 +1,19 @@ --- default: &default - adapter: mysql2 + adapter: sqlite3 + database: db/default.sqlite3 encoding: utf8 - reconnect: false pool: 5 - host: localhost - # socket: /tmp/mysql.sock + timeout: 5000 development: <<: *default - database: sms-pager-dev + database: db/development.sqlite3 test: <<: *default - database: sms-pager-test + database: db/test.sqlite3 production: <<: *default - database: sms-pager-api - username: <%= ENV["mysql_usr"] %> - password: <%= ENV["mysql_pwd"] %> + database: db/production.sqlite3 diff --git a/config/initializers/sorcery.rb b/config/initializers/sorcery.rb index db80049..6a97688 100644 --- a/config/initializers/sorcery.rb +++ b/config/initializers/sorcery.rb @@ -131,7 +131,7 @@ Rails.application.config.sorcery.configure do |config| config.google.key = ENV["google_key"] config.google.secret = ENV["google_secret"] config.google.callback_url = "http://localhost:3000/oauth/callback?provider=google" - config.google.user_info_mapping = { email: "email" } + config.google.user_info_mapping = { email: "email", first_name: "given_name", last_name: "family_name" } # config.vk.key = "" # config.vk.secret = "" diff --git a/db/schema.rb b/db/schema.rb index 885630b..a4b8414 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -14,51 +14,51 @@ ActiveRecord::Schema.define(version: 20151008022535) do create_table "authentications", force: :cascade do |t| - t.integer "person_id", limit: 4, null: false - t.string "provider", limit: 255, null: false - t.string "uid", limit: 255, null: false + t.integer "person_id", null: false + t.string "provider", null: false + t.string "uid", null: false t.datetime "created_at" t.datetime "updated_at" end - add_index "authentications", ["provider", "uid"], name: "index_authentications_on_provider_and_uid", using: :btree + add_index "authentications", ["provider", "uid"], name: "index_authentications_on_provider_and_uid" create_table "children", force: :cascade do |t| - t.string "first_name", limit: 255 - t.string "last_name", limit: 255 + t.string "first_name" + t.string "last_name" end create_table "pages", force: :cascade do |t| - t.integer "user_id", limit: 4 - t.integer "person_id", limit: 4 - t.string "to", limit: 255 - t.string "message", limit: 255 - t.string "status", limit: 255 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id" + t.integer "person_id" + t.string "to" + t.string "message" + t.string "status" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "parenthoods", force: :cascade do |t| - t.integer "person_id", limit: 4 - t.integer "child_id", limit: 4 + t.integer "person_id" + t.integer "child_id" end - add_index "parenthoods", ["person_id", "child_id"], name: "parentship", using: :btree + add_index "parenthoods", ["person_id", "child_id"], name: "parentship" create_table "people", force: :cascade do |t| - t.string "first_name", limit: 255 - t.string "last_name", limit: 255 - t.string "phone", limit: 255 - t.string "email", limit: 255, null: false + t.string "first_name" + t.string "last_name" + t.string "phone" + t.string "email", null: false t.boolean "admin" t.boolean "staff" - t.string "activation_state", limit: 255 - t.string "activation_token", limit: 255 + t.string "activation_state" + t.string "activation_token" t.datetime "activation_token_expires_at" end - add_index "people", ["activation_token"], name: "index_people_on_activation_token", using: :btree - add_index "people", ["email"], name: "index_people_on_email", unique: true, using: :btree - add_index "people", ["phone"], name: "index_people_on_phone", using: :btree + add_index "people", ["activation_token"], name: "index_people_on_activation_token" + add_index "people", ["email"], name: "index_people_on_email", unique: true + add_index "people", ["phone"], name: "index_people_on_phone" end diff --git a/test/fixtures/people.yml b/test/fixtures/people.yml index a40dab2..409adce 100644 --- a/test/fixtures/people.yml +++ b/test/fixtures/people.yml @@ -42,3 +42,10 @@ sarah: email: sarah.smith@mailinator.com phone: 5005550006 children: sally, nemo +mmoser: + first_name: Mark + last_name: Moser + email: markamoser@gmail.com + phone: 3093634474 + admin: true + activation_state: active diff --git a/test/models/child_test.rb b/test/models/child_test.rb new file mode 100644 index 0000000..d86be9f --- /dev/null +++ b/test/models/child_test.rb @@ -0,0 +1,15 @@ +require 'test_helper' + +class ChildTest < ActiveSupport::TestCase + def test_sanity + assert Child + end + + def test_relations + non_relatives = Child.not_related_to people(:marlin) + smiths_count = non_relatives.where(last_name: 'smith').count + + assert_equal 0, smiths_count + assert_equal 1, non_relatives.count + end +end diff --git a/test/models/person_test.rb b/test/models/person_test.rb index bfd2b29..6cf0da8 100644 --- a/test/models/person_test.rb +++ b/test/models/person_test.rb @@ -10,4 +10,19 @@ class PersonTest < ActiveSupport::TestCase assert parents.count > 1, "Did not find more than one parent" end + + def test_name_first + assert_equal 1, Person.with_name('admin').count + end + + def test_name_last + smiths_count = Person.where(last_name: 'Smith').count + smiths = Person.with_name 'smith' + + assert_equal smiths_count, smiths.count + end + + def test_name_full + assert_equal 1, Person.with_name('wanda worker').count + end end diff --git a/version.md b/version.md new file mode 100644 index 0000000..89758a5 --- /dev/null +++ b/version.md @@ -0,0 +1 @@ +version 0.9.0