diff --git a/app/assets/javascripts/application/posts.js b/app/assets/javascripts/application/posts.js index 71d26223..bee108d0 100644 --- a/app/assets/javascripts/application/posts.js +++ b/app/assets/javascripts/application/posts.js @@ -50,5 +50,11 @@ function addPost(group_id, membership_id, post_type_id) { button.disabled = false }); } + if(response.status == 403){ + response.json().then(data => { + UIkit.notify({message: data.message, timeout: 3000, status: 'danger'}) + button.disabled = false + }) + } }) } diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 5f55c833..27003ed0 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -23,15 +23,23 @@ def create membership = Membership.find(params[:membership_id]) post_type_id = params[:post_type_id].to_i authorize Post.new(membership: membership, post_type_id: post_type_id) - - new_post = CreatePost.call(group, membership, post_type_id) + begin + new_post = CreatePost.call(group, membership, post_type_id) + rescue CreatePost::PostAlreadyTaken + post_taken = true + end respond_to do |format| format.html do - return redirect_to group_path(group) if new_post.leader? + flash[:notice] = t('services.create_post.post_already_taken') if post_taken + return redirect_to group_path(group) if new_post&.leader? + + redirect_to group_membership_posts_path(group, membership) + end + format.json do + return render status: :forbidden, json: { message: t('services.create_post.post_already_taken') } if post_taken - redirect_back fallback_location: group_path(group) + render json: { post_id: new_post.id } end - format.json { render json: { post_id: new_post.id } } end end diff --git a/app/services/create_post.rb b/app/services/create_post.rb index e55c7e78..ce4eeedc 100644 --- a/app/services/create_post.rb +++ b/app/services/create_post.rb @@ -1,5 +1,6 @@ class CreatePost class InvalidPostType < StandardError; end + class PostAlreadyTaken < StandardError; end def self.call(group, membership, post_type_id) raise InvalidPostType unless group.has_post_type?(post_type_id) @@ -9,6 +10,9 @@ def self.call(group, membership, post_type_id) remove_leader(group) remove_past_leader_post(membership) end + if post_type_id == PostType::FINANCIAL_OFFICER_POST_ID + raise PostAlreadyTaken unless financial_officer_count_for(group).zero? + end Post.create(membership_id: membership.id, post_type_id: post_type_id) end end @@ -21,4 +25,10 @@ def self.remove_leader(group) def self.remove_past_leader_post(membership) Post.where(membership_id: membership.id, post_type_id: PostType::PAST_LEADER_ID).destroy_all end + + def self.financial_officer_count_for(group) + Post.where('memberships.group_id': group.id, + post_type_id: PostType::FINANCIAL_OFFICER_POST_ID) + .joins(:membership).count + end end diff --git a/config/locales/hu.yml b/config/locales/hu.yml index fa42ea89..0c3c4b65 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -91,3 +91,6 @@ hu: next: "Következő »" last: "Utolsó" truncate: "..." + services: + create_post: + post_already_taken: 'Ezt a posztot már kiosztottad valakinek! Vissza kell venned a jelenlegi posztot, hogy újra kiosztható legyen.' diff --git a/db/migrate/20220520160742_remove_financial_officers_if_more_then_one.rb b/db/migrate/20220520160742_remove_financial_officers_if_more_then_one.rb new file mode 100644 index 00000000..7e8d77c8 --- /dev/null +++ b/db/migrate/20220520160742_remove_financial_officers_if_more_then_one.rb @@ -0,0 +1,17 @@ +class RemoveFinancialOfficersIfMoreThenOne < ActiveRecord::Migration[6.0] + def up + groups_with_fo_count = Group.joins(memberships: :posts) + .where('posts.post_type_id': PostType::FINANCIAL_OFFICER_POST_ID) + .group('memberships.group_id').count('groups.id') + group_ids_with_more_fo = groups_with_fo_count.select { |k, v| v > 1 }.keys + groups_with_more_fo = Group.where(id: group_ids_with_more_fo) + groups_with_more_fo.each do |group| + fo_posts = Post.where('memberships.group_id': group.id, + post_type_id: PostType::FINANCIAL_OFFICER_POST_ID) + .joins(:membership).order('posts.id': :asc) + fo_posts[0..-2].each { |post| post.destroy! } + end + end + + def down;end +end diff --git a/db/structure.sql b/db/structure.sql index b69be919..d07c4c68 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1527,6 +1527,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200722173131'), ('20201223070757'), ('20210307164901'), -('20210905120558'); +('20210905120558'), +('20220520160742'); diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index bfe8819d..1e471f53 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -49,6 +49,7 @@ config.before(:suite) do FactoryBot.create(:post_type_leader) + FactoryBot.create(:post_type_financial_officer) FactoryBot.create(:post_type_newbie) FactoryBot.create(:post_type_evaluation_helper) FactoryBot.create(:group_svie) @@ -63,6 +64,7 @@ end config.after(:suite) do + # Post.delete_all PostType.delete_all Group.delete_all User.delete_all diff --git a/spec/requests/post_type_controller_spec.rb b/spec/requests/post_type_controller_spec.rb index d86e971b..737b1fc2 100644 --- a/spec/requests/post_type_controller_spec.rb +++ b/spec/requests/post_type_controller_spec.rb @@ -55,6 +55,7 @@ let(:group) { create(:group) } let(:user) { group.leader.user } before(:each) { login_as(user) } + # before(:each) { PostType.destroy(PostType::FINANCIAL_OFFICER_POST_ID) } it 'redirects back' do post "/groups/#{group.id}/post_types", params: { diff --git a/spec/requests/posts_controller_spec_spec.rb b/spec/requests/posts_controller_spec_spec.rb index 9e8d6beb..000a3471 100644 --- a/spec/requests/posts_controller_spec_spec.rb +++ b/spec/requests/posts_controller_spec_spec.rb @@ -15,6 +15,65 @@ expect(response).to have_http_status :ok expect(response).to render_template :group_posts end + + describe '#create' do + let(:membership) { group.memberships.first } + it 'creates a post and redirects' do + expect { + post "/groups/#{group.id}/memberships/#{membership.id}/posts", + params: { post_type_id: PostType::FINANCIAL_OFFICER_POST_ID } + }.to change { + membership.posts.count + }.by(1) + expect(response).to redirect_to("/groups/#{group.id}/memberships/#{membership.id}/posts") + end + + it 'when the post is for the leader it redirects to the group page' do + post "/groups/#{group.id}/memberships/#{membership.id}/posts", + params: { post_type_id: PostType::LEADER_POST_ID } + + expect(response).to redirect_to("/groups/#{group.id}") + end + + context 'when FINANCIAL_OFFICER is present' do + before(:each) do + CreatePost::call(group, membership, PostType::FINANCIAL_OFFICER_POST_ID) + end + it 'creating another FINANCIAL_OFFICER is not processed' do + expect { + post "/groups/#{group.id}/memberships/#{membership.id}/posts", + params: { post_type_id: PostType::FINANCIAL_OFFICER_POST_ID } + }.to change { + membership.posts.count + }.by(0) + + expect(flash[:notice]).to eql(I18n.t('services.create_post.post_already_taken')) + expect(response).to redirect_to("/groups/#{group.id}/memberships/#{membership.id}/posts") + end + end + + context 'when format is json ' do + it 'sends back the post id' do + post "/groups/#{group.id}/memberships/#{membership.id}/posts.json", + params: { post_type_id: PostType::FINANCIAL_OFFICER_POST_ID } + + expect(response.body).to eql({ post_id: Post.last.id }.to_json) + end + + context 'when FINANCIAL_OFFICER is present' do + before(:each) do + CreatePost::call(group, membership, PostType::FINANCIAL_OFFICER_POST_ID) + end + it 'creating another FINANCIAL_OFFICER is forbidden' do + post "/groups/#{group.id}/memberships/#{membership.id}/posts.json", + params: { post_type_id: PostType::FINANCIAL_OFFICER_POST_ID } + + expect(response).to have_http_status :forbidden + expect(response.body).to eql({ message: I18n.t('services.create_post.post_already_taken') }.to_json) + end + end + end + end end end end diff --git a/test/factories/post_types.rb b/test/factories/post_types.rb index 6222f93c..196eb7a1 100644 --- a/test/factories/post_types.rb +++ b/test/factories/post_types.rb @@ -7,7 +7,15 @@ sequence(:id, 150) end - factory :post_type_leader, parent: :post_type do + factory :common_post_type, parent: :post_type do + group { nil } + end + factory :post_type_financial_officer, parent: :common_post_type do + id { PostType::FINANCIAL_OFFICER_POST_ID } + name { 'Gazdasagis' } + end + + factory :post_type_leader, parent: :common_post_type do id { PostType::LEADER_POST_ID } name { 'Korvezeto' } end @@ -17,20 +25,19 @@ name { 'Feldolgozas alatt' } end - factory :post_type_pek_admin, parent: :post_type do + factory :post_type_pek_admin, parent: :common_post_type do group { Group.kirdev } id { PostType::PEK_ADMIN_ID } name { 'PeK admin' } end - factory :post_type_new_member, parent: :post_type do + factory :post_type_new_member, parent: :common_post_type do id { PostType::NEW_MEMBER_ID } name { 'Ujonc' } end - factory :post_type_evaluation_helper, parent: :post_type do + factory :post_type_evaluation_helper, parent: :common_post_type do id { PostType::EVALUATION_HELPER_ID } - group { nil } name { 'Pontozó' } end end