diff --git a/app/controllers/concerns/ptime/people_controller.rb b/app/controllers/concerns/ptime/people_controller.rb new file mode 100644 index 000000000..500d4c8cf --- /dev/null +++ b/app/controllers/concerns/ptime/people_controller.rb @@ -0,0 +1,13 @@ +module Ptime + module PeopleController + def show + super + Ptime::PeopleEmployees.new.update_person_data(@person) + end + + def new + @person = Ptime::PeopleEmployees.new.find_or_create(params[:ptime_employee_id]) + redirect_to(@person) + end + end +end diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index 6d1fed1b8..ac1f70999 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -8,8 +8,6 @@ class PeopleController < CrudController self.permitted_attrs = [:birthdate, :location, :marital_status, :updated_by, :name, :nationality, :nationality2, :title, :competence_notes, :company_id, :email, :department_id, :shortname, :picture, :picture_cache, - { person_roles_attributes: [:role_id, :person_role_level_id, - :percent, :id, :_destroy] }, { person_roles_attributes: [:role_id, :person_role_level_id, :percent, :id, :_destroy] }, { language_skills_attributes: @@ -27,14 +25,8 @@ def show @person = Person.includes(projects: :project_technologies, person_roles: [:role, :person_role_level]).find(params.fetch(:id)) - super - end - def new super - %w[DE EN FR].each do |language| - @person.language_skills.push(LanguageSkill.new({ language: language })) - end end def create diff --git a/app/domain/ptime/client.rb b/app/domain/ptime/client.rb index 00edffe95..584207ddc 100644 --- a/app/domain/ptime/client.rb +++ b/app/domain/ptime/client.rb @@ -15,7 +15,7 @@ def request(method, endpoint, params = {}) if last_ptime_error_more_than_5_minutes_ago? send_request_and_parse_response(method, url, params) else - raise CustomExceptions::PTimeClientError, 'Error' + raise CustomExceptions::PTimeTemporarilyUnavailableError, 'PTime is temporarily unavailable' end end diff --git a/app/domain/ptime/people_employees.rb b/app/domain/ptime/people_employees.rb new file mode 100644 index 000000000..6195b4ce9 --- /dev/null +++ b/app/domain/ptime/people_employees.rb @@ -0,0 +1,44 @@ +module Ptime + class PeopleEmployees + ATTRIBUTES_MAPPING = { full_name: :name, shortname: :shortname, email: :email, marital_status: + :marital_status, graduation: :title, birthdate: :birthdate, + location: :location }.freeze + def find_or_create(ptime_employee_id) + raise 'No ptime_employee_id provided' unless ptime_employee_id + + person = Person.find_by(ptime_employee_id: ptime_employee_id) + return person unless person.nil? + + new_person = Person.new(ptime_employee_id: ptime_employee_id) + + update_person_data(new_person) + end + + # rubocop:disable Metrics + def update_person_data(person) + raise 'Person has no ptime_employee_id' unless person.ptime_employee_id + + ptime_employee = Ptime::Client.new.request(:get, "employees/#{person.ptime_employee_id}") + rescue CustomExceptions::PTimeTemporarilyUnavailableError + # Ignored + else + ptime_employee[:attributes].each do |key, value| + if key.to_sym.in?(ATTRIBUTES_MAPPING.keys) + person[ATTRIBUTES_MAPPING[key.to_sym]] = (value.presence || '-') + end + end + set_additional_attributes(person, ptime_employee) + person.save! + person + end + # rubocop:enable Metrics + + def set_additional_attributes(person, ptime_employee) + ptime_employee_employed = ptime_employee[:attributes][:is_employed] + person.company = Company.find_by(name: ptime_employee_employed ? 'Firma' : 'Ex-Mitarbeiter') + ptime_employee_nationalities = ptime_employee[:attributes][:nationalities] + person.nationality = ptime_employee_nationalities[0] + person.nationality2 = ptime_employee_nationalities[1] + end + end +end diff --git a/app/exceptions/custom_exceptions.rb b/app/exceptions/custom_exceptions.rb index b59a9ef87..e33678fbd 100644 --- a/app/exceptions/custom_exceptions.rb +++ b/app/exceptions/custom_exceptions.rb @@ -1,5 +1,6 @@ module CustomExceptions class PTimeClientError < StandardError; end + class PTimeTemporarilyUnavailableError < StandardError; end end diff --git a/app/models/person.rb b/app/models/person.rb index 09a88f47c..6ba682c40 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -27,6 +27,8 @@ class Person < ApplicationRecord include PgSearch::Model + after_initialize :set_default_languages + belongs_to :company belongs_to :department, optional: true @@ -103,4 +105,12 @@ def picture_size errors.add(:picture, 'grösse kann maximal 10MB sein') end + + def set_default_languages + if new_record? + %w[DE EN FR].each do |language| + language_skills.push(LanguageSkill.new({ language: language, level: 'Keine' })) + end + end + end end diff --git a/config/application.rb b/config/application.rb index d25c78c3a..2284f8e1a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,7 +14,7 @@ module Skills def self.ptime_available? - ActiveModel::Type::Boolean.new.cast(ENV.fetch('PTIME_API_ACCESSIBLE', true)) + %w[true True 1].include?(ENV.fetch('PTIME_API_ACCESSIBLE', false)) end class Application < Rails::Application diff --git a/config/initializers/ptime.rb b/config/initializers/ptime.rb new file mode 100644 index 000000000..ba93a57b1 --- /dev/null +++ b/config/initializers/ptime.rb @@ -0,0 +1,3 @@ +Rails.application.config.after_initialize do + PeopleController.prepend Ptime::PeopleController if Skills.ptime_available? +end \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index c54c7c2ce..8568cb03a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,7 +41,7 @@ services: /bin/bash -c " curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs && - npm install -g yarn && yarn add nodemon esbuild && bin/assets && + npm install -g yarn && bin/assets && sleep infinity" volumes: - ./:/myapp diff --git a/spec/domain/ptime/people_employees_spec.rb b/spec/domain/ptime/people_employees_spec.rb new file mode 100644 index 000000000..07da0800a --- /dev/null +++ b/spec/domain/ptime/people_employees_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe Ptime::PeopleEmployees do + it 'should raise error when no ptime_employee_id is passed to new action' do + expect{ Ptime::PeopleEmployees.new.find_or_create(nil) }.to raise_error(RuntimeError, 'No ptime_employee_id provided') + end + + it 'should return person if it has the given ptime_employee_id' do + person_wally = people(:wally) + person_wally.ptime_employee_id = 123 + person_wally.save! + + new_person = Ptime::PeopleEmployees.new.find_or_create(person_wally.ptime_employee_id) + expect(person_wally.attributes.except(*%w[created_at updated_at])).to eql(new_person.attributes.except(*%w[created_at updated_at])) + end +end \ No newline at end of file diff --git a/spec/fixtures/files/json/wally.json b/spec/fixtures/files/json/wally.json new file mode 100644 index 000000000..582642fcd --- /dev/null +++ b/spec/fixtures/files/json/wally.json @@ -0,0 +1,23 @@ +{ + "data": { + "id": 50, + "type": "employee", + "attributes": { + "shortname": "CAL", + "firstname": "Changed Wally", + "lastname": "Allround", + "full_name": "Changed Wally Allround", + "email": "changedwally@example.com", + "marital_status": "single", + "nationalities": [ + "DE", "DK" + ], + "graduation": "Quarter-Stack Developer", + "department_shortname": "SYS", + "employment_roles2": [], + "is_employed": false, + "birthdate": "1.1.2000", + "location": "Basel" + } + } +} \ No newline at end of file diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index 6246e060d..4bd807888 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -113,4 +113,12 @@ expect(person.errors[:shortname].first).to eq('ist zu lang (mehr als 100 Zeichen)') end end + + context 'language_skills' do + it 'should automatically add default language on person creation' do + new_person = Person.new + expect(new_person.language_skills.length).to eq(3) + expect(new_person.language_skills.map(&:language)).to eql(%w[DE EN FR]) + end + end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d57d07b37..43ba3a7e7 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -78,6 +78,7 @@ # Helpers from gems config.include(Devise::Test::IntegrationHelpers, type: :feature) + config.include(Devise::Test::IntegrationHelpers, type: :request) config.include(Devise::Test::ControllerHelpers, type: :controller) config.include(ActionView::RecordIdentifier, type: :feature) diff --git a/spec/requests/people_employees_spec.rb b/spec/requests/people_employees_spec.rb new file mode 100644 index 000000000..b52e8a59a --- /dev/null +++ b/spec/requests/people_employees_spec.rb @@ -0,0 +1,79 @@ +require "rails_helper" + +describe 'Update or create person' do + before(:each) do + sign_in auth_users(:user), scope: :auth_user + end + + before(:all) do + PeopleController.prepend(Ptime::PeopleController) + end + + after(:all) do + Ptime::PeopleController.remove_method(:new) + Ptime::PeopleController.remove_method(:show) + end + + it 'should update person when visited' do + stub_ptime_request(fixture_data("wally").to_json, "employees/50", 200) + + Company.create!(name: "Ex-Mitarbeiter") + person_wally = people(:wally) + person_wally.ptime_employee_id = 50 + person_wally.save! + expect(person_wally.name).to eq('Wally Allround') + expect(person_wally.email).to eq('wally@example.com') + + get "/people/#{person_wally.id}" + expect(response).to render_template(:show) + + person_wally.reload + expect(person_wally.name).to eq('Changed Wally Allround') + expect(person_wally.shortname).to eq('CAL') + expect(person_wally.email).to eq('changedwally@example.com') + expect(person_wally.marital_status).to eq('single') + expect(person_wally.title).to eq('Quarter-Stack Developer') + expect(person_wally.birthdate).to eq('1.1.2000') + expect(person_wally.location).to eq('Basel') + expect(person_wally.nationality).to eq('DE') + expect(person_wally.nationality2).to eq('DK') + end + + it 'should create person when visited' do + stub_ptime_request(fixture_data("wally").to_json, "employees/50", 200) + + Company.create!(name: "Ex-Mitarbeiter") + person_wally = people(:wally) + person_wally.destroy! + expect(Person.find_by(name: "Wally Allround")).to be_nil + + get "/people/new?ptime_employee_id=50" + + new_wally = Person.find_by(name: "Changed Wally Allround") + expect(new_wally.name).to eq('Changed Wally Allround') + expect(new_wally.shortname).to eq('CAL') + expect(new_wally.email).to eq('changedwally@example.com') + expect(new_wally.marital_status).to eq('single') + expect(new_wally.title).to eq('Quarter-Stack Developer') + expect(new_wally.birthdate).to eq('1.1.2000') + expect(new_wally.location).to eq('Basel') + expect(new_wally.nationality).to eq('DE') + expect(new_wally.nationality2).to eq('DK') + end + + it 'should not update but still show person if ptime temporarily unavailable' do + stub_env_var('LAST_PTIME_ERROR', 1.minute.ago) + stub_ptime_request(fixture_data("wally").to_json, "employees/50", 500) + + Company.create!(name: "Ex-Mitarbeiter") + person_wally = people(:wally) + person_wally.ptime_employee_id = 50 + person_wally.save! + + get "/people/#{person_wally.id}" + + expect(response).to render_template(:show) + + expect(person_wally.attributes.except(*%w[created_at updated_at])).to eq(Person.find(person_wally.id).attributes.except(*%w[created_at updated_at])) + end +end \ No newline at end of file