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

Feature/app login #434

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ GEM
caxlsx_rails (0.6.3)
actionpack (>= 3.1)
caxlsx (>= 3.0)
childprocess (3.0.0)
childprocess (4.1.0)
cocoon (1.2.15)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
Expand Down Expand Up @@ -256,7 +256,7 @@ GEM
timeout
newrelic_rpm (8.8.0)
nio4r (2.5.8)
nokogiri (1.13.6)
nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
orm_adapter (0.5.0)
Expand Down Expand Up @@ -395,9 +395,11 @@ GEM
activerecord (>= 4.0.0)
railties (>= 4.0.0)
select2-rails (4.0.13)
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
selenium-webdriver (4.5.0)
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
shoulda-matchers (4.5.1)
activesupport (>= 4.2.0)
simple_calendar (2.4.3)
Expand Down Expand Up @@ -450,10 +452,11 @@ GEM
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webdrivers (4.5.0)
webdrivers (5.2.0)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
selenium-webdriver (~> 4.0)
websocket (1.2.9)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//= require jquery3
//= require rails-ujs
//= require turbolinks
//= require turbolinks_csp
//= require select2
//= require popper
//= require bootstrap-sprockets
Expand All @@ -29,7 +30,7 @@
//= require bootstrap_features
//= require print
//= require cocoon
//= require turbolinks_csp
//= require copy_to_clipboard
//= require cable
//= require sortablejs
//= require routes
Expand Down
37 changes: 37 additions & 0 deletions app/assets/javascripts/copy_to_clipboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
$(document).on('turbolinks:load', function() {
// Copies a string to the clipboard. Must be called from within an
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+,
// Firefox 42+, Safari 10+, Edge and Internet Explorer 10+.
// Internet Explorer: The clipboard feature may be disabled by
// an administrator. By default a prompt is shown the first
// time the clipboard is used (per session).
function copyToClipboard(text) {
if (window.clipboardData && window.clipboardData.setData) {
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
return window.clipboardData.setData("Text", text);
}
else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
const textarea = document.createElement("textarea");
textarea.textContent = text;
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
}
catch (ex) {
console.warn("Copy to clipboard failed.", ex);
return prompt("Copy to clipboard: Ctrl+C, Enter", text);
}
finally {
document.body.removeChild(textarea);
}
}
}

$('[data-copy]').on('click', function () {
copyToClipboard($(this).data('copy'));
toastr.success("Wert in Zwischenablage kopiert");
});
});
3 changes: 1 addition & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user!
before_action :check_account!
before_action :check_consents
before_action :check_not_app_login!, unless: :devise_controller?

layout :determine_layout

Expand All @@ -39,8 +40,6 @@ def current_company=(company)
@current_company = company
end



def redirect_to_referral(fallback_location: nil)
redirect_to session.delete(:return_to) || fallback_location
end
Expand Down
72 changes: 72 additions & 0 deletions app/controllers/company/app_logins_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

class Company::AppLoginsController < ApplicationController
before_action :set_company_from_param

def show
@app_login = current_company.company_members.where(role: CompanyMember::APP_LOGIN).first
if @app_login
authorize @app_login
else
authorize nil, :new?, policy_class: AppLoginPolicy
end
end

def create
authorize nil, policy_class: AppLoginPolicy
if current_company.company_members.where(role: CompanyMember::APP_LOGIN).any?
flash[:error] = I18n.t "flash.app_login.already_activated"
redirect_to company_app_login_path(current_company)
else
begin
@current_password = create_password
@app_login_user = User.create!(
email: "#{current_company.slug}@app-login.fahrzeit.com",
password: @current_password,
password_confirmation: @current_password,
name: "App Login",
skip_create_driver: true,
skip_term_validation: true)

@app_login = current_company.add_member(@app_login_user, CompanyMember::APP_LOGIN)
render :show_password
rescue StandardError => e
flash[:error] = I18n.t "flash.app_login.failed_to_create"
logger.error e
end
end
end

def reset_password
@app_login = current_company.company_members.where(role: CompanyMember::APP_LOGIN).first
authorize @app_login, policy_class: AppLoginPolicy
@current_password = create_password
@app_login.user.password = @current_password
@app_login.user.password_confirmation = @current_password
if @app_login.user.save
flash[:success] = I18n.t "flash.app_login.new_password_set"
render 'show_password'
else
flash[:error] = I18n.t "flash.app_login.password_reset_failed"
redirect_to company_app_login_path(current_company)
end
end

def destroy
@app_login = current_company.company_members.where(role: CompanyMember::APP_LOGIN).first
authorize @app_login, policy_class: AppLoginPolicy
begin
@app_login.user.destroy!
flash[:success] = I18n.t "flash.app_login.destroyed"
rescue StandardError
flash[:error] = I18n.t "flash.app_login.not_destroyed"
end
redirect_to company_app_login_path(current_company)
end

private

def create_password
Devise.friendly_token.first(Devise.password_length.first)
end
end
2 changes: 1 addition & 1 deletion app/controllers/company/company_members_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Company::CompanyMembersController < ApplicationController

def index
authorize current_company, :index_members?
@company_members = CompanyMember.where(company: current_company)
@company_members = CompanyMember.where(company: current_company).where.not(role: CompanyMember::APP_LOGIN)
end

def create
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/concerns/constraint_router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ def check_account!
end
end

def check_not_app_login!
return unless user_signed_in?
if current_user.app_login?
redirect_to is_app_login_error_path
end
end

# Redirect to company path if user has no driver.
# This filter should be called *after* check account, otherwise
# it may raise an error if user has no company.
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/static_pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
class StaticPagesController < ApplicationController
skip_before_action :authenticate_user!, only: [:home, :demo_login]
skip_before_action :check_account!
skip_before_action :check_not_app_login!

def account_error
NewRelic::Agent.notice_error(Error.new("Account error for: User<#{current_user.id}> Drivers<#{current_user.drivers.pluck(:id).join(",")}>"))
NewRelic::Agent.notice_error(StandardError.new("Account error for: User<#{current_user.id}> Drivers<#{current_user.drivers.pluck(:id).join(",")}>"))
end

def setup
end

def is_app_login_error
end

def demo_login
end

Expand Down
1 change: 1 addition & 0 deletions app/controllers/term_acceptances_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class TermAcceptancesController < ApplicationController
skip_before_action :check_consents
skip_before_action :check_account!
skip_before_action :check_not_app_login!
before_action :set_user
layout "setup"

Expand Down
2 changes: 1 addition & 1 deletion app/helpers/company_members_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def company_member
end

def company_member_role_select_options
CompanyMember::ROLES.reject { |r| r == CompanyMember::DEMO_ACCOUNT }.map do |r|
CompanyMember::ROLES.reject { |r| r == CompanyMember::DEMO_ACCOUNT || r == CompanyMember::APP_LOGIN}.map do |r|
[t("activerecord.attributes.company_member.roles.#{r}"), r]
end
end
Expand Down
4 changes: 3 additions & 1 deletion app/models/company_member.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ class CompanyMember < ApplicationRecord
EMPLOYEE = "employee"
DRIVER = "driver"
DEMO_ACCOUNT = "demo_account"
ROLES = [OWNER, ADMINISTRATOR, DRIVER, DEMO_ACCOUNT].freeze
APP_LOGIN = "app_login"

ROLES = [OWNER, ADMINISTRATOR, DRIVER, DEMO_ACCOUNT, APP_LOGIN].freeze

belongs_to :user, optional: true # set to true in order for to conditionally validate
validates_presence_of :user, unless: :new_user?
Expand Down
10 changes: 10 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ def company_admin_or_owner?(company)
@_company_admin_or_owner = companies_for_role([CompanyMember::ADMINISTRATOR, CompanyMember::OWNER]).exists? company.id
end

def app_login?(company = nil)

if company.nil?
@_company_app_login = companies_for_role([CompanyMember::APP_LOGIN]).any?
else
@_company_app_login = companies_for_role([CompanyMember::APP_LOGIN]).exists? company.id
end

end

def company_member?(company)
return false if company.nil?
return @_company_member if @_company_member
Expand Down
28 changes: 28 additions & 0 deletions app/policies/app_login_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

class AppLoginPolicy < ApplicationPolicy
def new?
auth_context.company_admin_or_owner?
end

def create?
auth_context.company_admin_or_owner?
end

def show?
company_admin_or_owner?(record.company)
end

def reset_password?
company_admin_or_owner?(record.company)
end

def destroy?
company_admin_or_owner?(record.company)
end

def permitted_attributes
[:name, :has_value, :value_label]
end

end
4 changes: 4 additions & 0 deletions app/policies/application_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,8 @@ def company_member?(company = nil)
def is_demo(company = nil)
auth_context.is_demo(company)
end

def is_app_login(company = nil)
auth_context.app_login?(company)
end
end
5 changes: 5 additions & 0 deletions app/policies/auth_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ def company_admin_or_owner?(company = nil)
end
memoize :company_admin_or_owner?

def app_login?(company = nil)
user.app_login?(company || self.company)
end
memoize :app_login?

def company_member?(company = nil)
user.company_member?(company || self.company)
end
Expand Down
8 changes: 4 additions & 4 deletions app/policies/drive_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ def new?
end

def create?
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company)
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company) || is_app_login(record_company)
end

def show?
own_record? || company_member?(record_company) || is_demo(record_company)
own_record? || company_member?(record_company) || is_demo(record_company) || is_app_login(record_company)
end

def update?
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company)
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company) || is_app_login(record_company)
end

def destroy?
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company)
own_record? || company_admin_or_owner?(record_company) || is_demo(record_company) || is_app_login(record_company)
end

def finish?
Expand Down
8 changes: 4 additions & 4 deletions app/policies/tour_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ def new?
end

def create?
own_record? || company_admin_or_owner?(company) || is_demo(company)
own_record? || company_admin_or_owner?(company) || is_demo(company) || is_app_login(company)
end

def show?
own_record? || company_member?(company)
own_record? || company_member?(company) || is_app_login(company)
end

def update?
own_record? || company_admin_or_owner?(company) || is_demo(company)
own_record? || company_admin_or_owner?(company) || is_demo(company) || is_app_login(company)
end

def destroy?
own_record? || company_admin_or_owner?(company) || is_demo(company)
own_record? || company_admin_or_owner?(company) || is_demo(company) || is_app_login(company)
end

# Scopes:
Expand Down
4 changes: 3 additions & 1 deletion app/services/drivers_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class DriversService

def self.driver_scope(user)
full_permitted_companies = user.companies_for_role([CompanyMember::ADMINISTRATOR, CompanyMember::OWNER, CompanyMember::DEMO_ACCOUNT]).select(:id)
full_permitted_companies = user.companies_for_role([CompanyMember::ADMINISTRATOR, CompanyMember::OWNER, CompanyMember::DEMO_ACCOUNT, CompanyMember::APP_LOGIN]).select(:id)
own_drivers = user.drivers.select(:id)

Driver.where(id: own_drivers).or(Driver.where(company_id: full_permitted_companies))
Expand All @@ -23,6 +23,8 @@ def drivers_for(user, company)
Driver.where(company_id: company.id)
when CompanyMember::DEMO_ACCOUNT
Driver.where(company_id: company.id)
when CompanyMember::APP_LOGIN
Driver.where(company_id: company.id)
when CompanyMember::DRIVER
Driver.where(company_id: company.id).joins(:driver_login).where(driver_logins: { user_id: user.id })
else
Expand Down
Loading