diff --git a/Gemfile b/Gemfile index ff617e69..8ff62ee5 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,8 @@ gem 'paper_trail' # Use devise as authentification framework gem 'devise' +gem 'devise_ichain_authenticatable' + # Use omniauth to support openID authentication gem 'omniauth' gem 'omniauth-facebook' diff --git a/Gemfile.lock b/Gemfile.lock index 7b74fd6a..37ca39f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -118,6 +118,8 @@ GEM railties (>= 3.2.6, < 5) thread_safe (~> 0.1) warden (~> 1.2.3) + devise_ichain_authenticatable (0.3.1) + devise (>= 2.2) diff-lcs (1.2.5) docile (1.1.3) erubis (2.7.0) @@ -432,6 +434,7 @@ DEPENDENCIES database_cleaner delayed_job_active_record devise + devise_ichain_authenticatable factory_girl_rails font-awesome-rails formtastic (~> 2.3.0.rc3) diff --git a/app/assets/javascripts/osem.js b/app/assets/javascripts/osem.js index 68e6f55d..4d3163da 100644 --- a/app/assets/javascripts/osem.js +++ b/app/assets/javascripts/osem.js @@ -1,4 +1,9 @@ $(function () { + + $("#user_biography").bind('keyup', function() { + word_count(this, 'bio_length', 150); + } ); + /** * Displays a modal with the questions of the registration. */ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e01a9d00..a6a14473 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,24 +8,29 @@ class ApplicationController < ActionController::Base check_authorization unless: :devise_controller? def store_location - session[:return_to] = request.fullpath if request.get? && controller_name != 'user_sessions' && controller_name != 'sessions' + # store last url - this is needed for post-login redirect to whatever the user last visited. + return unless request.get? + if (request.path != '/accounts/sign_in' && + request.path != '/accounts/sign_up' && + request.path != '/accounts/password/new' && + request.path != '/accounts/password/edit' && + request.path != '/accounts/confirmation' && + request.path != '/accounts/sign_out' && + request.path != '/users/ichain_registration/ichain_sign_up' && + !request.path.starts_with?(Devise.ichain_base_url) && + !request.xhr?) # don't store ajax calls + session[:return_to] = request.fullpath + end end - def after_sign_in_path_for(resource) + def after_sign_in_path_for(_resource) if (can? :view, Conference) && (!session[:return_to] || session[:return_to] && session[:return_to] == root_path) admin_conference_index_path else - if session[:return_to] && - !session[:return_to].start_with?(user_registration_path) - logger.debug "Returning to #{session[:return_to]}" - session[:return_to] - else - logger.debug "Not returning to #{session[:return_to]} because it would loop" - super - end + session[:return_to] || root_path end end @@ -53,6 +58,13 @@ class ApplicationController < ActionController::Base redirect_to root_path, alert: exception.message end + rescue_from IChainRecordNotFound do + Rails.logger.debug('IChain Record was not Unique!') + sign_out(current_user) + flash[:error] = 'Your E-Mail adress is already registered at OSEM. Please contact the admin if you want to attach your openSUSE Account to OSEM!' + redirect_to root_path + end + def not_found raise ActionController::RoutingError.new('Not Found') end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index e19a0a18..62292bf0 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -3,55 +3,12 @@ class RegistrationsController < Devise::RegistrationsController def edit @openids = Openid.where(user_id: current_user.id).order(:provider) + super end def update @openids = Openid.where(user_id: current_user.id).order(:provider) - @user = User.find(current_user.id) - email_changed = false - - if !params[:user][:email].nil? - if @user.email != params[:user][:email] - email_changed = true - else - params[:user].delete :email - end - end - - password_changed = false - if !params[:user][:password].nil? - if !params[:user][:password].empty? - password_changed = true - else - params[:user].delete :password - params[:user].delete :password_confirmation - end - end - - if email_changed || password_changed - successfully_updated = @user.update_with_password(account_update_params) - else - params[:user].delete :current_password - successfully_updated = @user.update_without_password(account_update_params) - end - - if successfully_updated - if email_changed - unless @user.nil? - @user.update_attribute('email', params[:user][:email]) - end - set_flash_message :notice, :update_needs_confirmation - else - set_flash_message :notice, :updated - end - # Sign in the user bypassing validation in case his password changed - sign_in @user, bypass: true - redirect_to after_update_path_for(@user) - else - flash[:alert] = 'Updating account failed. ' \ - "#{@user.errors.full_messages.join('. ')}." - render 'edit' - end + super end protected @@ -67,12 +24,11 @@ class RegistrationsController < Devise::RegistrationsController def configure_permitted_parameters devise_parameter_sanitizer.for(:account_update) do |u| u. - permit(:email, :password, :password_confirmation, :current_password, :name, :biography, - :nickname, :affiliation) + permit(:email, :password, :password_confirmation, :current_password, :username) end devise_parameter_sanitizer.for(:sign_up) do |u| u. - permit(:email, :password, :password_confirmation, :name) + permit(:email, :password, :password_confirmation, :name, :username) end end end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 4412a8ae..e007b84f 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -11,11 +11,13 @@ module Users def handle(provider) auth_hash = request.env['omniauth.auth'] + uid = auth_hash[:uid] openid = Openid.find_for_oauth(auth_hash) # Get or create openid # If openid exists and is associated with a user, sign in with associated user, # even if the email of the associated user and the email of the provided openid are different unless (user = openid.user) user = User.find_for_auth(auth_hash, current_user) # Get or create users + user.username = "#{uid}@#{provider}" if user.username.blank? end begin @@ -28,7 +30,8 @@ module Users sign_in user redirect_to root_path, notice: user.email + " signed in successfully with #{provider}" rescue => e - redirect_back_or_to new_user_registration_path, alert: 'Failed' + e.message + flash[:error] = e.message + redirect_back_or_to new_user_registration_path end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 00000000..d84f77e0 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,30 @@ +class UsersController < ApplicationController + before_filter :verify_user + load_and_authorize_resource + + # GET /users/1 + def show + @events = @user.events.where(state: :confirmed) + end + + # GET /users/1/edit + def edit + end + + # PATCH/PUT /users/1 + def update + if @user.update(user_params) + redirect_to @user, notice: 'User was successfully updated.' + else + flash[:error] = "A error prohibited your Profile from being saved: #{@user.errors.full_messages.join('. ')}." + render :edit + end + end + + private + + # Only allow a trusted parameter "white list" through. + def user_params + params.require(:user).permit(:user_id, :name, :biography, :nickname, :affiliation) + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 5e4819ba..f9195773 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -123,6 +123,7 @@ class Ability end can :index, :schedule # show? + can :show, User end def signed_in(user) @@ -131,6 +132,9 @@ class Ability # Conference Registration can :manage, Registration, user_id: user.id + can :manage, User, id: user.id + can :show, User + ## Proposals # Users can manage their own proposals can :manage, Event, id: user.events.pluck(:id) diff --git a/app/models/user.rb b/app/models/user.rb index 745df91b..daaa4612 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,6 @@ +class IChainRecordNotFound < StandardError +end + class User < ActiveRecord::Base rolify include Gravtastic @@ -8,16 +11,26 @@ class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :confirmable, # :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, :confirmable, - :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github] + devise_modules = [] + + if CONFIG['authentication']['ichain']['enabled'] + devise_modules += [ :ichain_authenticatable, :ichain_registerable ] + else + devise_modules += [:database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, :confirmable, + :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github] ] + end + + devise(*devise_modules) has_and_belongs_to_many :roles has_many :openids attr_accessible :email, :password, :password_confirmation, :remember_me, :role_id, :role_ids, :name, :email_public, :biography, :nickname, :affiliation, :is_admin, - :tshirt, :mobile, :volunteer_experience, :languages + :tshirt, :mobile, :volunteer_experience, :languages, :username, :login + + attr_accessor :login has_many :event_users, dependent: :destroy has_many :events, -> { uniq }, through: :event_users @@ -29,7 +42,13 @@ class User < ActiveRecord::Base has_many :subscriptions, dependent: :destroy accepts_nested_attributes_for :roles - validates :name, presence: true + validates :email, presence: true + + validates :username, + uniqueness: { + case_sensitive: false + }, + presence: true # Returns the ticket purchased ticket # ====Returns @@ -38,6 +57,30 @@ class User < ActiveRecord::Base ticket_purchases.where(ticket_id: id).first end + def self.for_ichain_username(username, attributes) + user = find_by(username: username) + if user + user.update_attributes(email: attributes[:email]) + else + begin + user = create(username: username, email: attributes[:email]) + rescue ActiveRecord::RecordNotUnique + raise IChainRecordNotFound + end + end + user + end + + def self.find_for_database_authentication(warden_conditions) + conditions = warden_conditions.dup + login = conditions.delete(:login) + if login + where(conditions).where(['lower(username) = :value OR lower(email) = :value', { value: login.downcase }]).first + else + where(conditions).first + end + end + # Searches for user based on email. Returns found user or new user. # ====Returns # * +User::ActiveRecord_Relation+ -> user diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml index b7714d18..7168eade 100644 --- a/app/views/devise/registrations/edit.html.haml +++ b/app/views/devise/registrations/edit.html.haml @@ -1,35 +1,25 @@ +%h1 Edit your Account .row .col-md-12 = semantic_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| - = f.inputs name: 'Profile' do - = f.input :name, as: :string - = f.input :nickname, as: :string - = f.input :affiliation, as: :string, - hint: 'This could be a company, a user group, or nothing at all.' - = f.input :biography, input_html: {rows: 5, - 'onkeyup' => "word_count(this, 'biography-count', 150)"} - You have used - %span#biography-count #{current_user.biography_word_count} - words. Biographies are limited to 150 words. - %br - %br + = f.inputs name: 'Account' do + = f.input :username, required: false, input_html: { autocomplete: 'off' } + = f.input :email, required: false, input_html: { autocomplete: 'off' } + = f.input :password, hint: "(Leave blank if you don't want to change it)", input_html: { autocomplete: 'off' } + = f.input :password_confirmation, input_html: { autocomplete: 'off' } = f.inputs name: 'OpenID' do %h4 Currently the following openIDs are associated with your account - @openids.each do |openid| %li= "#{openid.provider}:#{openid.email}" %br + %h4 + To add an openID with a different email address to your account, sign in with your + openID while logged in to OSEM - if User.omniauth_providers.present? - %h4 - To add an openID with a different email address to your account, sign in with your - openID while logged in to OSEM #openidlinks = render 'devise/shared/openid' - - = f.inputs name: 'Account' do - = f.input :email, required: false, input_html: {autocomplete: "off"} - = f.input :password, hint: "(Leave blank if you don't want to change it)", input_html: {autocomplete: 'off'} - = f.input :password_confirmation, input_html: {autocomplete: 'off'} + = f.inputs name: 'Confirmation' do = f.input :current_password, input_html: {autocomplete: 'off'}, - hint: '(we need your current password to confirm password or email changes)' - = f.action :submit, as: :button, label: 'Update', button_html: {class: 'btn btn-primary'} + hint: '(we need your current password to confirm password, email or username changes)' + = f.action :submit, as: :button, label: 'Update Account', button_html: {class: 'btn btn-primary'} diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 233d62f2..3d458dd6 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -6,6 +6,7 @@ Sign Up .panel-body = semantic_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| + = f.input :username, required: true = f.input :email = f.input :name, required: true = f.input :password diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 11f55860..8988d9f8 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -6,7 +6,7 @@ Sign In .panel-body = semantic_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| - = f.input :email + = f.input :login = f.input :password - if devise_mapping.rememberable? %p.text-right.small diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index cf4d1fde..a5bf261a 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -16,7 +16,7 @@ %ul.nav.navbar-nav.navbar-right %li.dropdown %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#", id: "current-user-detail"} - - if not current_user.name.empty? + - if not current_user.name.blank? #{current_user.name} -else #{current_user.email} @@ -26,13 +26,13 @@ = render 'layouts/user_menu' - else %ul.nav.navbar-nav.navbar-right - - if current_page?(new_registration_path('user')) - %li.active - = link_to(new_registration_path('user')) do + - if CONFIG['authentication']['ichain']['enabled'] + %li{:class=> "#{active_nav_li(new_ichain_registration_path('user'))}"} + = link_to(new_ichain_registration_path('user')) do %span.fa.fa-heart Sign Up - else - %li + %li{:class=> "#{active_nav_li(new_registration_path('user'))}"} = link_to(new_registration_path('user')) do %span.fa.fa-heart Sign Up @@ -42,23 +42,29 @@ Sign In %span.caret .dropdown-menu{:style => "padding: 17px;"} - = form_tag user_session_path do - = text_field_tag 'user[email]', nil, id: 'user_email_dd' - = password_field_tag 'user[password]', nil, id: 'user_password_dd' - %p.text-right - %small - Remember me - = check_box_tag 'user[remember_me]' - %button.btn.btn-success.btn-block Sign in - - unless omniauth_configured.empty? - .divider - %h6.text-center - or - = render 'devise/shared/openid' - %p.text-right - %a.small{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"} - Need Help? - #navbar-devise-help.collapse - = link_to "Forgot your password?", new_password_path(User.new) - %li.hidden-lg - = link_to('Sign In', new_user_session_path) + - if CONFIG['authentication']['ichain']['enabled'] + = form_tag new_user_ichain_session_path do + = text_field_tag 'username', nil, id: 'user_ichain_email_dd' + = password_field_tag 'password', nil, id: 'user_ichain_password_dd' + %button.btn.btn-success.btn-block Sign in + - else + = form_tag new_user_session_path do + = text_field_tag 'user[login]', nil, id: 'user_login_dd' + = password_field_tag 'user[password]', nil, id: 'user_password_dd' + %p.text-right + %small + Remember me + = check_box_tag 'user[remember_me]' + %button.btn.btn-success.btn-block Sign in + - unless omniauth_configured.empty? + .divider + %h6.text-center + or + = render 'devise/shared/openid' + %p.text-right + %a.small{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"} + Need Help? + #navbar-devise-help.collapse + = link_to "Forgot your password?", new_password_path(User.new) + %li.hidden-lg + = link_to('Sign In', new_user_session_path) diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 882d7efe..c1ae6cea 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -1,16 +1,26 @@ +- unless CONFIG['authentication']['ichain']['enabled'] + %li + = link_to(edit_user_registration_path) do + %span.fa.fa-wrench + Edit Account %li - = link_to(edit_user_registration_path) do - %span.fa.fa-wrench - Edit Account + = link_to(edit_user_path(current_user.id)) do + %span.fa.fa-user + Edit Profil -if @conference and @conference.id %li = link_to(conference_proposal_index_path(@conference.short_title)) do %span.fa.fa-comment My Submissions %li - = link_to(destroy_user_session_path, :method=>'delete') do - %span.fa.fa-minus - Sign out + - if CONFIG['authentication']['ichain']['enabled'] + = link_to(destroy_user_ichain_session_path, :method=>'delete') do + %span.fa.fa-minus + Sign out + - else + = link_to(destroy_user_session_path, :method=>'delete') do + %span.fa.fa-minus + Sign out - if can? :index, Conference %li.divider %li diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml new file mode 100644 index 00000000..572e12fc --- /dev/null +++ b/app/views/users/edit.html.haml @@ -0,0 +1,17 @@ +%h1 Edit your profile +.row + .col-md-12 + = semantic_form_for(@user, url: user_path(@user.id)) do |f| + = f.inputs name: 'Profile' do + = f.input :name, as: :string + = f.input :nickname, as: :string + = f.input :affiliation, as: :string, + hint: 'This could be a company, a user group, or nothing at all.' + = f.input :biography, input_html: { rows: 5, 'onkeyup' => "word_count(this, 'biography-count', 150)" } + You have used + %span#bio_length + 0 + words. Biographies are limited to 150 words. + %br + %br + = f.action :submit, as: :button, label: 'Update', button_html: {class: 'btn btn-primary'} diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 00000000..7ba218bf --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,16 @@ +%h1 + = @user.name +%h4 + = @user.biography + +- if @user.events.confirmed.any? + %h3 + = "#{@user.name} presents #{pluralize(@user.events.confirmed.count, 'Event')}:" + %ul.list-unstyled + - @user.events.confirmed.each do |event| + %li + %h4 + = link_to event.title, conference_proposal_path(event.conference.short_title, event.id) + %strong + at + = event.conference.title \ No newline at end of file diff --git a/config/config.yml.example b/config/config.yml.example index 53dad8d8..787427bb 100644 --- a/config/config.yml.example +++ b/config/config.yml.example @@ -16,6 +16,11 @@ defaults: &defaults speakerdeck: 'Speakerdeck', instagram: 'Instagram' } + # If you want to use iChain to handle registration and authentication enable the next lines + authentication: + ichain: + enabled: false + development: <<: *defaults diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 7b9ecaa4..88ae8e10 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -38,7 +38,7 @@ Devise.setup do |config| # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [ :email ] + config.authentication_keys = [ :login ] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the @@ -244,4 +244,35 @@ Devise.setup do |config| # When using omniauth, Devise cannot automatically set Omniauth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = "/my_engine/users/auth" + + # You will always need to set this parameter. + config.ichain_base_url = "https://my.application.org" + + # Paths (relative to ichain_base_url) used by your proxy + # config.ichain_login_path = "ICSLogin/" + # config.ichain_registration_path = "ICSLogin/auth-up/" + # config.ichain_logout_path = "cmd/ICSLogout/" + + # The header used by your iChain proxy to pass the username. + # config.ichain_username_header = "HTTP_X_USERNAME" + + # Additional parameters, beyond the username, provided by the iChain proxy. + # HTTP_X_EMAIL is expected by default. Set to {} if no additional attributes + # are configured in the proxy. + # config.ichain_attributes_header = {:email => "HTTP_X_EMAIL"} + + # Configuration options for requests sent to the iChain proxy + # config.ichain_context = "default" + # config.ichain_proxypath = "reverse" + + # Activate the test mode, useful when no real iChain is present, like in + # testing and development environments + # config.ichain_test_mode = true + + # In test mode, you can skip asking for the user information by always + # forcing the following username. The user will be permanently signed in. + # config.ichain_force_test_username = "testuser" + + # In test mode, force the following additional attributes + # config.ichain_force_test_attributes = {:email => "testuser@example.com"} end diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 18e044e2..3b4084b4 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -17,7 +17,7 @@ en: unauthenticated: 'You need to sign in or sign up before continuing.' unconfirmed: 'You have to confirm your account before continuing.' locked: 'Your account is locked.' - invalid: 'Invalid email or password.' + invalid: 'Invalid login or password.' invalid_token: 'Invalid authentication token.' timeout: 'Your session expired, please sign in again to continue.' inactive: 'Your account was not activated yet.' diff --git a/config/routes.rb b/config/routes.rb index d3d1366f..ffa81a3e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,8 +1,16 @@ Osem::Application.routes.draw do - devise_for :users, controllers: { registrations: :registrations, - omniauth_callbacks: 'users/omniauth_callbacks' }, - path: 'accounts' + if CONFIG['authentication']['ichain']['enabled'] + devise_for :users, controllers: { registrations: :registrations } + else + devise_for :users, + controllers: { + registrations: :registrations, + omniauth_callbacks: 'users/omniauth_callbacks' }, + path: 'accounts' + end + + resources :users, except: [:new, :index, :create, :destroy] namespace :admin do resources :users diff --git a/db/migrate/20141103132913_add_username_to_users.rb b/db/migrate/20141103132913_add_username_to_users.rb new file mode 100644 index 00000000..59cd8591 --- /dev/null +++ b/db/migrate/20141103132913_add_username_to_users.rb @@ -0,0 +1,6 @@ +class AddUsernameToUsers < ActiveRecord::Migration + def change + add_column :users, :username, :string + add_index :users, :username, unique: true + end +end diff --git a/db/migrate/20141104131625_generate_username.rb b/db/migrate/20141104131625_generate_username.rb new file mode 100644 index 00000000..b598b452 --- /dev/null +++ b/db/migrate/20141104131625_generate_username.rb @@ -0,0 +1,18 @@ +class GenerateUsername < ActiveRecord::Migration + class TempUser < ActiveRecord::Base + self.table_name = 'users' + attr_accessible :username, :email + end + + def change + TempUser.all.each do |user| + if user.username.blank? + username = user.email.split('@')[0] + if TempUser.find_by(username: username) + username = username + user.id.to_s + end + user.update_attributes(username: username) + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index d2451810..32fab65b 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: 20140825093132) do +ActiveRecord::Schema.define(version: 20141104131625) do create_table "ahoy_events", force: true do |t| t.uuid "visit_id" @@ -84,13 +84,13 @@ ActiveRecord::Schema.define(version: 20140825093132) do end create_table "conferences", force: true do |t| - t.string "guid", null: false - t.string "title", null: false - t.string "short_title", null: false - t.string "timezone", null: false + t.string "guid", null: false + t.string "title", null: false + t.string "short_title", null: false + t.string "timezone", null: false t.string "html_export_path" - t.date "start_date", null: false - t.date "end_date", null: false + t.date "start_date", null: false + t.date "end_date", null: false t.integer "venue_id" t.datetime "created_at" t.datetime "updated_at" @@ -98,11 +98,11 @@ ActiveRecord::Schema.define(version: 20140825093132) do t.string "logo_content_type" t.integer "logo_file_size" t.datetime "logo_updated_at" - t.boolean "use_dietary_choices", default: false + t.boolean "use_dietary_choices", default: false t.integer "revision" - t.boolean "use_vpositions", default: false - t.boolean "use_vdays", default: false - t.boolean "use_difficulty_levels", default: false + t.boolean "use_vpositions", default: false + t.boolean "use_vdays", default: false + t.boolean "use_difficulty_levels", default: false t.boolean "use_volunteers" t.string "color" t.string "sponsor_email" @@ -504,11 +504,13 @@ ActiveRecord::Schema.define(version: 20140825093132) do t.string "languages" t.text "volunteer_experience" t.boolean "is_admin", default: false + t.string "username" end add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true add_index "users", ["email"], name: "index_users_on_email", unique: true add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + add_index "users", ["username"], name: "index_users_on_username", unique: true create_table "vchoices", force: true do |t| t.integer "vday_id" @@ -525,8 +527,8 @@ ActiveRecord::Schema.define(version: 20140825093132) do create_table "venues", force: true do |t| t.string "guid" - t.text "name", limit: 255 - t.text "address", limit: 255 + t.text "name", limit: 255 + t.text "address", limit: 255 t.string "website" t.text "description" t.string "offline_map_url" diff --git a/spec/factories/users.rb b/spec/factories/users.rb index d404aefb..e5c0b7c1 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -3,6 +3,7 @@ FactoryGirl.define do factory :user do sequence(:email) { |n| "example#{n}@example.com" } sequence(:name) { |n| "name#{n}" } + sequence(:username) { |n| "username#{n}" } password 'changeme' password_confirmation 'changeme' confirmed_at { Time.now }