From 4a4119c8da21c5211b0087f4e054a44ee438641a Mon Sep 17 00:00:00 2001 From: quentinchampenois <26109239+Quentinchampenois@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:02:17 +0100 Subject: [PATCH] backport: PR Decidim 11474 --- config/application.rb | 1 + .../models/decidim/budgets/project_extend.rb | 19 +++ spec/models/decidim/budgets/project_spec.rb | 113 ++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 lib/extends/models/decidim/budgets/project_extend.rb create mode 100644 spec/models/decidim/budgets/project_spec.rb diff --git a/config/application.rb b/config/application.rb index 0ba9a737a4..0de8ecf190 100644 --- a/config/application.rb +++ b/config/application.rb @@ -50,6 +50,7 @@ class Application < Rails::Application require "extends/helpers/decidim/icon_helper_extends" require "extends/commands/decidim/initiatives/admin/update_initiative_answer_extends" require "extends/controllers/decidim/initiatives/committee_requests_controller_extends" + require "extends/models/decidim/budgets/project_extend" Decidim::GraphiQL::Rails.config.tap do |config| config.initial_query = "{\n deployment {\n version\n branch\n remote\n upToDate\n currentCommit\n latestCommit\n locallyModified\n }\n}".html_safe diff --git a/lib/extends/models/decidim/budgets/project_extend.rb b/lib/extends/models/decidim/budgets/project_extend.rb new file mode 100644 index 0000000000..2be6cd3747 --- /dev/null +++ b/lib/extends/models/decidim/budgets/project_extend.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "active_support/concern" +module ProjectExtends + extend ActiveSupport::Concern + + included do + def self.ordered_ids(ids) + # Make sure each ID in the matching text has a "," character as their + # delimiter. Otherwise e.g. ID 2 would match ID "26" in the original + # array. This is why we search for match ",2," instead to get the actual + # position for ID 2. + concat_ids = connection.quote(",#{ids.join(",")},") + order(Arel.sql("position(concat(',', decidim_budgets_projects.id::text, ',') in #{concat_ids})")) + end + end +end + +Decidim::Budgets::Project.include(ProjectExtends) diff --git a/spec/models/decidim/budgets/project_spec.rb b/spec/models/decidim/budgets/project_spec.rb new file mode 100644 index 0000000000..04f9334f52 --- /dev/null +++ b/spec/models/decidim/budgets/project_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim::Budgets + describe Project do + subject { project } + + let(:project) { create(:project) } + + include_examples "has reference" + include_examples "resourceable" + + it { is_expected.to be_valid } + it { is_expected.to be_versioned } + + context "without a budget" do + let(:project) { build(:project, budget: nil) } + + it { is_expected.not_to be_valid } + end + + context "when the scope is from another organization" do + let(:scope) { create(:scope) } + let(:project) { build(:project, scope: scope) } + + it { is_expected.not_to be_valid } + end + + context "when the category is from another organization" do + let(:category) { create(:category) } + let(:project) { build(:project, category: category) } + + it { is_expected.not_to be_valid } + end + + describe ".ordered_ids" do + let(:budget) { create(:budget, total_budget: 1_000_000) } + let(:category) { create(:category, participatory_space: budget.participatory_space) } + let(:projects) { create_list(:project, 50, budget: budget, budget_amount: 100_000, category: category) } + let(:test_ids) do + first = described_class.where(budget: budget).order(:id).pluck(:id)[0..3] + ids = described_class.where(budget: budget).pluck(:id).shuffle + + # Put the first items at the end of the IDs array in order to get + # possibly "conflicting" matches for them at earlier array positions. + # As we have 50 projects, we should have IDs starting with 1, 2, 3 and 4 + # which is why we put the first 4 items at the end. + (ids - first) + first + end + + before do + # Reset the project IDs to start from 1 in order to get possibly + # "conflicting" ID sequences for the `.ordered_ids` call. In the past, + # e.g. IDs such as "2", and "23" (containing "2") would have caused the + # wrong order in case "23" comes first in the ordered IDs list. + ActiveRecord::Base.connection.reset_pk_sequence!(described_class.table_name) + + # Create the projects after the sequence has been reset + projects + end + + it "returns the correctly ordered projects" do + expect(described_class.ordered_ids(test_ids).pluck(:id)).to eq(test_ids) + end + + it "returns the correctly ordered projects after filtering by category" do + expect(described_class.with_any_category([category.id]).ordered_ids(test_ids).pluck(:id)).to eq(test_ids) + end + end + + describe "#orders_count" do + let(:project) { create(:project, budget_amount: 75_000_000) } + let(:order) { create(:order, budget: project.budget) } + let(:unfinished_order) { create(:order, budget: project.budget) } + let!(:line_item) { create(:line_item, project: project, order: order) } + let!(:line_item1) { create(:line_item, project: project, order: unfinished_order) } + + it "return number of finished orders for this project" do + order.reload.update!(checked_out_at: Time.current) + expect(project.confirmed_orders_count).to eq(1) + end + end + + describe "#users_to_notify_on_comment_created" do + let!(:follows) { create_list(:follow, 3, followable: subject) } + + it "returns the followers" do + expect(subject.users_to_notify_on_comment_created).to match_array(follows.map(&:user)) + end + end + + describe "#selected?" do + let(:project) { create(:project, selected_at: selected_at) } + + context "when selected_at is blank" do + let(:selected_at) { nil } + + it "returns true" do + expect(project.selected?).to be false + end + end + + context "when selected_at is present" do + let(:selected_at) { Time.current } + + it "returns true" do + expect(project.selected?).to be true + end + end + end + end +end