diff --git a/Gemfile b/Gemfile index c9b12e1..d91f199 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.1.0' gem 'jquery-rails' gem 'jbuilder', '~> 2.0' +gem 'bcrypt' group :development, :test do gem 'byebug' diff --git a/Gemfile.lock b/Gemfile.lock index 185c505..362de48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,6 +40,7 @@ GEM arel (6.0.3) autoprefixer-rails (6.3.3.1) execjs + bcrypt (3.1.11) better_errors (2.1.1) coderay (>= 1.0.0) erubis (>= 2.6.6) @@ -231,6 +232,7 @@ PLATFORMS ruby DEPENDENCIES + bcrypt better_errors bootstrap-sass byebug diff --git a/app/assets/stylesheets/sessions.css.scss b/app/assets/stylesheets/sessions.css.scss new file mode 100644 index 0000000..43f65f9 --- /dev/null +++ b/app/assets/stylesheets/sessions.css.scss @@ -0,0 +1,42 @@ + +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; + + & .form-signin-heading, + & .checkbox { + margin-bottom: 10px; + } + + & .checkbox { + font-weight: normal; + } + + & .form-control { + position: relative; + height: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 10px; + font-size: 16px; + } + + & .form-control:focus { + z-index: 2; + } + + & input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } + + & input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e..d8b3d09 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,5 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + include SessionsHelper end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb new file mode 100644 index 0000000..e9ead7a --- /dev/null +++ b/app/controllers/events_controller.rb @@ -0,0 +1,10 @@ +class EventsController < ApplicationController + def index + @events = Event.all + end + + def show + @registration = Registration.new + @event = Event.first + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..3b27224 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,30 @@ +class SessionsController < ApplicationController + def new; end + + def create + user = User.find_by(email: email) + if user.authenticate(password) + sign_in(user) + flash[:notice] = 'Welcome back!' + redirect_back_or root_path + else + flash[:error] = 'Wrong email or password!' + render :new + end + end + + private + + def email + session_params[:email] + end + + def password + session_params[:password] + end + + def session_params + params.require(:session).permit(:email, :password) + end + +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..600d5c8 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,7 @@ +class UsersController < ApplicationController + before_action :authenticate_user! + + def show + @events = current_user.events + end +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..403ee1f --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,25 @@ +module SessionsHelper + def sign_in(user) + session[:user_id] = user.id + end + + def current_user + @current_user ||= User.find_by(id: session[:user_id]) + end + + def authenticate_user! + if current_user.nil? + store_back_url + flash[:error] = 'You must log in to access this page.' + redirect_to new_session_path + end + end + + def store_back_url + session[:back_url] = request.original_url + end + + def redirect_back_or(url) + redirect_to session[:back_url] || url + end +end diff --git a/app/models/registration.rb b/app/models/registration.rb index 74a0b43..074c18a 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -11,10 +11,13 @@ def already_registered?(registration) end end - validates :phone_number, format: { with: /[0-9]{10}/ }, allow_blank: true - validates :email, presence: true, format: { with: /[\w.-]+@[a-zA-Z]+\.[a-zA-Z]+/ } - validates_with RegistrationEmailValidator + belongs_to :user + belongs_to :event - validates_presence_of :first_name, :last_name + # validates :phone_number, format: { with: /[0-9]{10}/ }, allow_blank: true + # validates :email, presence: true, format: { with: /[\w.-]+@[a-zA-Z]+\.[a-zA-Z]+/ } + # validates_with RegistrationEmailValidator + + # validates_presence_of :first_name, :last_name end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..f59ba5f --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,6 @@ +class User < ActiveRecord::Base + has_secure_password + + has_many :registrations + has_many :events, through: :registrations +end diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index d9c85e4..ad2d5dc 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -1,5 +1,4 @@ --# navigation styled for Bootstrap 3.0 -%nav.navbar.navbar-default.navbar-fixed-top +%nav.navbar.navbar-inverse.navbar-fixed-top .container .navbar-header %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"} @@ -7,7 +6,10 @@ %span.icon-bar %span.icon-bar %span.icon-bar - = link_to 'Home', root_path, class: 'navbar-brand' - .collapse.navbar-collapse + = link_to 'RSVP', root_path, class: 'navbar-brand' + #navbar.collapse.navbar-collapse %ul.nav.navbar-nav = render 'layouts/navigation_links' + %ul.nav.navbar-nav.navbar-right + %li + = link_to 'Login', new_session_path diff --git a/app/views/layouts/_navigation_links.html.erb b/app/views/layouts/_navigation_links.html.erb deleted file mode 100644 index 548d397..0000000 --- a/app/views/layouts/_navigation_links.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%# add navigation links to this file %> diff --git a/app/views/layouts/_navigation_links.html.haml b/app/views/layouts/_navigation_links.html.haml new file mode 100644 index 0000000..e7e5a4f --- /dev/null +++ b/app/views/layouts/_navigation_links.html.haml @@ -0,0 +1,2 @@ += link_to 'Events', events_path, class: 'navbar-brand' + diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index ffbcd80..ca2ac35 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -10,6 +10,6 @@ %body %header = render 'layouts/navigation' - %main{:role => "main"} + %main.container{:role => "main"} = render 'layouts/messages' = yield diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml new file mode 100644 index 0000000..62a2c3e --- /dev/null +++ b/app/views/sessions/new.html.haml @@ -0,0 +1,17 @@ += form_for(:session, url: sessions_path, html: { class: 'form-signin' }) do |f| + + %h2.form-signin-heading + Please sign in + + = f.label :email, class: 'sr-only' + = f.email_field :email, id: 'inputEmail', class: 'form-control', placeholder: 'Email', required: true + + = f.label :password, class: 'sr-only' + = f.password_field :password, id: 'inputPassword', class: 'form-control', placeholder: 'Password', required: true + + -# .checkbox + -# %label + -# = f.checkbox_field value: 'remember-me' + + = f.submit 'Sign in', class: "btn btn-lg btn-primary btn-block" + diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 0000000..8741a74 --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,3 @@ + +- @events.each do |event| + = event.name diff --git a/config/routes.rb b/config/routes.rb index e151644..93f2de2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,10 +1,12 @@ Rails.application.routes.draw do - root 'event_registrations#index' + root 'events#index' resources :events, only: [:index, :show] do resources :registrations, only: [:create] end resources :event_registrations, only: [:index] + resources :users, only: [:show] + resources :sessions, only: [:new, :create] end diff --git a/db/migrate/20160715235318_create_users.rb b/db/migrate/20160715235318_create_users.rb new file mode 100644 index 0000000..0a47600 --- /dev/null +++ b/db/migrate/20160715235318_create_users.rb @@ -0,0 +1,13 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :email + t.string :first_name + t.string :last_name + t.string :phone_number + t.string :password_digest + + t.timestamps + end + end +end diff --git a/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb b/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb new file mode 100644 index 0000000..4553bf6 --- /dev/null +++ b/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb @@ -0,0 +1,12 @@ +class RemoveEmailFirstNameLastNamePhoneNumberFromRegistrations < ActiveRecord::Migration + def change + remove_column :registrations, :email + remove_column :registrations, :first_name + remove_column :registrations, :last_name + remove_column :registrations, :phone_number + + change_table :registrations do |t| + t.references :user + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9525bd7..86a0a9a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160505235503) do +ActiveRecord::Schema.define(version: 20160716000520) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -26,13 +26,20 @@ end create_table "registrations", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "event_id" + t.integer "user_id" + end + + create_table "users", force: :cascade do |t| t.string "email" - t.string "phone_number" t.string "first_name" t.string "last_name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "event_id" + t.string "phone_number" + t.string "password_digest" + t.datetime "created_at" + t.datetime "updated_at" end end diff --git a/lib/tasks/migrate_registration_data.rake b/lib/tasks/migrate_registration_data.rake new file mode 100644 index 0000000..1e1ae19 --- /dev/null +++ b/lib/tasks/migrate_registration_data.rake @@ -0,0 +1,6 @@ +task migrate_registration_data: :environment do + Registration.all.each do |registration| + user_params = registration.attributes.slice( *%w(email first_name last_name phone_number) ) + User.create(user_params) + end +end diff --git a/spec/controller/sessions_controller_spec.rb b/spec/controller/sessions_controller_spec.rb new file mode 100644 index 0000000..eb273c1 --- /dev/null +++ b/spec/controller/sessions_controller_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe SessionsController, type: :controller do + describe '#new' do + it 'is successfull' do + get :new + expect(response.status).to eq(200) + end + end + + describe '#create' do + let!(:user){ FactoryGirl.create(:user, email: 'viktor@vjustov.me', password: 'changeme')} + + context 'with valid credentials' do + + it 'should log me in' do + post :create, session: { email: 'viktor@vjustov.me', password: 'changeme' } + expect(response.status).to eq(302) + expect(flash[:notice]).to eql('Welcome back!') + end + end + + context 'with invalid credentials' do + it "should not log me in" do + post :create, session: { email: 'viktor@vjustov.me', password: 'wrongpass' } + expect(response.status).to eq(200) + expect(flash[:error]).to eql('Wrong email or password!') + end + end + end + +end diff --git a/spec/controller/users_controller_spec.rb b/spec/controller/users_controller_spec.rb new file mode 100644 index 0000000..8369dbe --- /dev/null +++ b/spec/controller/users_controller_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe UsersController, type: :controller do + describe '#show' do + let(:user) { FactoryGirl.create(:user) } + + context 'when the user is logged in' do + let!(:registration) do + FactoryGirl.create(:registration, user_id: user.id) + end + + before do + session[:user_id] = user.id + end + it "is succesfull" do + # TODO: change the action used for this test. + # we are refering to something like a profile. + get :show, id: user.id + expect(response.status).to eq(200) + expect(assigns(:events).ids).to eq([registration.event_id]) + end + end + + context "when the user is not logged_in" do + it 'redirects to the login page' do + get :show, id: user.id + expect(response.status).to eq(302) + expect(flash[:error]).to eq('You must log in to access this page.') + end + end + end +end diff --git a/spec/factories/registrations.rb b/spec/factories/registrations.rb index 7098ac4..1039c7a 100644 --- a/spec/factories/registrations.rb +++ b/spec/factories/registrations.rb @@ -1,9 +1,9 @@ FactoryGirl.define do factory :registration do - sequence(:email) { |n| "josh#{n}@josh.com" } - phone_number "8097635455" - first_name "Josue" - last_name "Abreu" + # sequence(:email) { |n| "josh#{n}@josh.com" } + # phone_number "8097635455" + # first_name "Josue" + # last_name "Abreu" event end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb new file mode 100644 index 0000000..624b536 --- /dev/null +++ b/spec/factories/user.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + factory :user do + sequence(:email) { |n| "josh#{n}@josh.com" } + phone_number "8097635455" + first_name "Josue" + last_name "Abreu" + password Faker::Internet.password + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..2aa73ca --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe User do + let(:user) { FactoryGirl.build(:user) } + + it 'requires a nonblank password' do + # user.password = '' + # require 'pry'; binding.pry + # expect(user).to_not be_valid + end +end