Skip to content

Commit 43d36a4

Browse files
committed
Merge branch 'release/0.31-stable' into 0.31-backports
2 parents 3ebcf5e + 783c0e3 commit 43d36a4

101 files changed

Lines changed: 1945 additions & 738 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/spelling/expect.txt

Lines changed: 13 additions & 151 deletions
Large diffs are not rendered by default.

decidim-admin/app/controllers/decidim/admin/organization_controller.rb

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,6 @@ def update
3333
end
3434
end
3535
end
36-
37-
def users
38-
search(current_organization.users.available)
39-
end
40-
41-
private
42-
43-
def search(relation)
44-
respond_to do |format|
45-
format.json do
46-
if (term = params[:term].to_s).present?
47-
query = if term.start_with?("@")
48-
nickname = term.delete("@")
49-
relation.where("nickname LIKE ?", "#{nickname}%")
50-
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("similarity(nickname, '#{nickname}') DESC")))
51-
else
52-
relation.where("name ILIKE ?", "%#{term}%").or(
53-
relation.where("email ILIKE ?", "%#{term}%")
54-
)
55-
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("GREATEST(similarity(name, '#{term}'), similarity(email, '#{term}')) DESC")))
56-
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("(similarity(name, '#{term}') + similarity(email, '#{term}')) / 2 DESC")))
57-
end
58-
render json: query.all.collect { |u| { value: u.id, label: "#{u.name} (@#{u.nickname})" } }
59-
else
60-
render json: []
61-
end
62-
end
63-
end
64-
end
6536
end
6637
end
6738
end

decidim-admin/app/packs/src/decidim/admin/admin_autocomplete.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ import AutoComplete from "src/decidim/refactor/moved/autocomplete";
1010
* - name: assembly_member[user_id],
1111
* - options: [],
1212
* - placeholder: "Select a participant",
13-
* - searchURL: "http://..."
1413
* - selected: "",
1514
*
1615
* @param {HTMLElement} el The element to generate the autocomplete for.
1716
* @returns {AutoComplete} An instance of the AutoComplete class.
1817
*/
1918
const autoConfigure = (el) => {
2019
const config = JSON.parse(el.dataset.autocomplete);
21-
const searchUrl = new URL(config.searchURL);
2220
const textInput = document.createElement("input");
2321
textInput.type = "text";
2422
textInput.className = "autocomplete-input";
@@ -46,16 +44,24 @@ const autoConfigure = (el) => {
4644
}
4745
}
4846

47+
const graphqlEscapedQuery = (query) => query.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
48+
4949
const dataSource = (query, callback) => {
50-
const params = new URLSearchParams({
51-
...Object.fromEntries(searchUrl.searchParams),
52-
term: query
53-
});
54-
fetch(`${searchUrl.origin}${searchUrl.pathname}?${params.toString()}`, {
55-
method: "GET",
56-
headers: { "Content-Type": "application/json" }
50+
const apiPath = window.Decidim.config.get("api_path");
51+
fetch(apiPath, {
52+
method: "POST",
53+
headers: { "Content-Type": "application/json" },
54+
body: JSON.stringify({
55+
query: `{users(filter:{wildcard:"${graphqlEscapedQuery(query)}"}){id,nickname,name,__typename}}`
56+
})
5757
}).then((response) => response.json()).then((data) => {
58-
callback(data)
58+
const users = data?.data?.users || [];
59+
callback(users.map((user) => ({
60+
value: user.id,
61+
label: `${user.name} (${user.nickname})`
62+
})))
63+
}).catch(() => {
64+
callback([])
5965
});
6066
};
6167

decidim-admin/config/routes.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
resources :content_blocks, only: [:edit, :update, :destroy, :create], controller: "organization_homepage_content_blocks"
99
end
1010
resource :external_domain_allowlist, only: [:edit, :update], controller: "organization_external_domain_allowlist"
11-
12-
member do
13-
get :users
14-
end
1511
end
1612

1713
resources :static_pages do

decidim-admin/lib/decidim/admin/form_builder.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class FormBuilder < Decidim::FormBuilder
1919
# - :class (string) You can provide custom class name for the container (ex. autocomplete-field--results-inline)
2020
# @param [Hash] prompt_options
2121
# Prompt configuration. A hash with options:
22-
# - :url (String) The url where the ajax endpoint to fill the select
2322
# - :placeholder (String) Text to use as placeholder
2423
# - :no_results (String) (optional) Text to use when there are no matching results (default: No results found)
2524
# - :search_prompt (String) (optional) Text to prompt for search input (default: Type at least three characters to search)
@@ -30,7 +29,7 @@ class FormBuilder < Decidim::FormBuilder
3029
# - label: This will be the label of the option select.
3130
#
3231
# @example How to use it
33-
# <% prompt_options = { url: users_url, text: t(".select_user") }
32+
# <% prompt_options = { placeholder: t(".select_user") }
3433
# options = { label: t(".user") } %>
3534
# <%= form.autocomplete_select(:user_id, form.object.user.presence, options, prompt_options) do |user|
3635
# { value: user.id, label: "#{user.name} (#{user.nickname})" }
@@ -48,7 +47,6 @@ def autocomplete_select(attribute, selected = nil, options = {}, prompt_options
4847
name: options[:name] || "#{@object_name}[#{attribute}]",
4948
options: (options[:default_options].to_a + [selected]).compact,
5049
placeholder: prompt_options[:placeholder],
51-
searchURL: prompt_options[:url],
5250
changeURL: prompt_options[:change_url],
5351
selected: selected ? selected[:value] : "",
5452
searchPromptText: options[:search_prompt] || I18n.t("autocomplete.search_prompt", scope: "decidim.admin"),
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
module Decidim
6+
module Admin
7+
describe OrganizationController do
8+
routes { Decidim::Admin::Engine.routes }
9+
10+
let(:organization) { create(:organization) }
11+
let(:current_user) { create(:user, :admin, :confirmed, organization:) }
12+
13+
before do
14+
request.env["decidim.current_organization"] = organization
15+
sign_in current_user, scope: :user
16+
end
17+
18+
describe "GET #edit" do
19+
it "renders the edit template" do
20+
get :edit
21+
22+
expect(response).to render_template(:edit)
23+
expect(assigns(:form).id).to eq(organization.id)
24+
expect(assigns(:form).name).to eq(organization.name)
25+
end
26+
end
27+
28+
describe "PATCH #update" do
29+
let(:attributes) { attributes_for(:organization) }
30+
let(:params) do
31+
{
32+
organization: attributes.merge(
33+
name: attributes[:name].merge(en: "My updated organization"),
34+
description: attributes[:description].merge(en: "Updated description")
35+
)
36+
}
37+
end
38+
39+
it "updates the organization and redirects" do
40+
patch(:update, params:)
41+
42+
expect(response).to redirect_to(edit_organization_path)
43+
expect(flash[:notice]).to eq(I18n.t("organization.update.success", scope: "decidim.admin"))
44+
expect(translated(organization.reload.name)).to eq("My updated organization")
45+
end
46+
47+
it "renders edit when invalid" do
48+
patch :update, params: params.deep_merge(organization: { name: { en: "" } })
49+
50+
expect(response).to have_http_status(:unprocessable_entity)
51+
expect(response).to render_template(:edit)
52+
expect(flash.now[:alert]).to eq(I18n.t("organization.update.error", scope: "decidim.admin"))
53+
end
54+
end
55+
end
56+
end
57+
end

decidim-admin/spec/controllers/organizations_controller_spec.rb

Lines changed: 0 additions & 122 deletions
This file was deleted.

decidim-admin/spec/lib/admin/form_builder_spec.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def self.model_name
3434
let(:category) { nil }
3535
let(:selected) { category }
3636
let(:options) { {} }
37-
let(:prompt_options) { { url: "/some/url", text: "Pick a category", change_url: "/some/other/url" } }
37+
let(:prompt_options) { { text: "Pick a category", change_url: "/some/other/url" } }
3838
let(:output) { builder.autocomplete_select(:category_id, selected, options, prompt_options) }
3939
let(:autocomplete_data) { JSON.parse(subject.xpath("//div[@data-autocomplete]/@data-autocomplete").first.value) }
4040

@@ -59,7 +59,6 @@ def self.model_name
5959
"options" => [],
6060
"placeholder" => nil,
6161
"searchPromptText" => t("autocomplete.search_prompt", scope: "decidim.admin"),
62-
"searchURL" => "/some/url",
6362
"selected" => ""
6463
)
6564
end

decidim-admin/spec/system/autocomplete/multiselect_spec.rb

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
describe "Autocomplete multiselect" do
66
let(:organization) { create(:organization) }
77
let(:user) { create(:user, :admin, :confirmed, organization:) }
8-
let(:path) { URI.parse(decidim_admin.users_organization_url).path }
9-
let(:url) { "http://#{organization.host}:#{Capybara.current_session.server.port}#{path}" }
8+
let(:api_path) { "/api" }
109
let(:selected) { '""' }
1110

1211
before do
@@ -34,15 +33,16 @@
3433
"mode": "multi",
3534
"options":[],
3635
"placeholder":"Select user",
37-
"searchURL":"#{url}",
3836
"selected":#{selected}
3937
}'
4038
data-autocomplete-for="user_id" data-plugin="autocomplete">
4139
</div>
4240
)
4341
end
4442

45-
let(:html_head) { "" }
43+
let(:html_head) do
44+
%(<script>window.Decidim = { config: { get: (key) => key === "api_path" ? "#{api_path}" : null } };</script>)
45+
end
4646
let(:html_document) do
4747
head_extra = html_head
4848
body_extra = autocomplete_multifield_select
@@ -104,16 +104,6 @@
104104
text_input = find("input[type='text']")
105105
expect(text_input.value).to eq("")
106106
end
107-
108-
context "when the URL has extra parameters in it" do
109-
let(:url) { "http://#{organization.host}:#{Capybara.current_session.server.port}#{path}?locale=ca" }
110-
111-
it "shows selected participant" do
112-
find("input[type='text']").fill_in with: participant.name.slice(0..2)
113-
find(".autoComplete_wrapper ul#autoComplete_list_1 li", match: :first, wait: 2).click
114-
expect(page).to have_content(participant.name)
115-
end
116-
end
117107
end
118108

119109
describe "remove selected item" do

decidim-api/app/controllers/decidim/api/queries_controller.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def context
3636
end
3737

3838
def api_user
39-
@api_user = current_api_user || current_user
39+
@api_user ||= organization_user(current_api_user || current_user)
4040
end
4141

4242
# Determines the scopes for the user for API requests.
@@ -84,6 +84,13 @@ def prepare_variables(variables_param)
8484
raise ArgumentError, "Unexpected parameter: #{variables_param}"
8585
end
8686
end
87+
88+
def organization_user(user)
89+
return if user.blank? || current_organization.blank?
90+
return unless user.decidim_organization_id == current_organization.id
91+
92+
user
93+
end
8794
end
8895
end
8996
end

0 commit comments

Comments
 (0)