mirror of
https://github.com/we-promise/sure.git
synced 2026-07-15 22:35:19 +00:00
* fix(sharing): scope import account selects to accessible_by (#1803)
Three CSV / QIF account selects in import/uploads/show.html.erb and one
PDF-import account select in imports/_pdf_import.html.erb pulled their
options from `@import.family.accounts`. That listed every account in
the family — including the family admin's unshared personal accounts —
in the dropdown shown to any member running an import. Swap each call
site to `Current.user.accessible_accounts` (owned + explicitly shared
accounts only), matching the existing scoping used by the dashboard
sidebar, transactions controller, transfers controller, etc.
Adds a regression test that signs in as family_member and asserts the
unshared-account names from the dylan_family fixtures never appear in
the rendered upload page.
* test(import): scope leak assertions to account select (#2194 CodeRabbit)
CodeRabbit nitpick: assert_match on response.body could pass/fail on
text outside the account dropdown (sidebar, breadcrumb, error message,
etc.) and gave false confidence in the refute_match exclusions. Switch
to assert_select 'select[name="import[account_id]"] option', text: …
so the assertions only see the option nodes the leak test actually
cares about.
* test(import): cover PDF account-select scoping; pluck PDF partial (#2194 review)
jjmata: the _pdf_import.html.erb scoping change was not covered by the
existing test (which only hit /import/uploads). Add a regression test
hitting GET /imports/:id with a PdfImport fixture, asserting the
account dropdown options match accessible accounts only.
Also swap the PDF partial's accounts.map { |a| [a.name, a.id] } for
.pluck(:name, :id) to match the .pluck pattern the other three CSV/QIF
selects already use.
* test(import): stub pdf_uploaded? on PDF leak test (#2194 ci)
The new regression test hit ImportsController#show which redirects to
the upload page when @import.pdf_uploaded? is false. The pdf_with_rows
fixture has neither a pdf_file attached nor a statement, so the
redirect fired before the partial under test ever rendered, failing
with 302 in CI. Stub PdfImport#pdf_uploaded? to true so the test
exercises the account-select scoping path it was written to cover.
* fix(import): scope PDF form to :import so field names match (#2194 ci)
The PDF-import account-select form was `form_with model: import` with
no explicit scope. Because the model is a PdfImport, Rails derived the
param namespace from the class name, so the rendered field was named
`pdf_import[account_id]` — not `import[account_id]`. The
ImportsController#update action accepts either via
`params.dig(:pdf_import, :account_id) || params.dig(:import,
:account_id)` so live submissions still worked, but the regression
test added in 0685bbdf asserted on `select[name="import[account_id]"]`
and matched zero options.
Add `scope: :import` to align the rendered name with both the test
selector and the convention used by the CSV/QIF forms on the upload
page (which all use `scope: :import`).
169 lines
8.8 KiB
Plaintext
169 lines
8.8 KiB
Plaintext
<%= content_for :header_nav do %>
|
||
<%= render "imports/nav", import: @import %>
|
||
<% end %>
|
||
|
||
<%= content_for :previous_path, imports_path %>
|
||
|
||
<% if @import.is_a?(SureImport) %>
|
||
<div class="space-y-4" data-controller="drag-and-drop-import">
|
||
<!-- Overlay -->
|
||
<%= render "imports/drag_drop_overlay", title: t("import.uploads.sure_import.drop_title"), subtitle: t("import.uploads.sure_import.drop_subtitle") %>
|
||
|
||
<div class="space-y-4 mx-auto max-w-md">
|
||
<div class="text-center space-y-2">
|
||
<h1 class="text-3xl text-primary font-medium"><%= t("import.uploads.sure_import.title") %></h1>
|
||
<p class="text-secondary text-sm"><%= t("import.uploads.sure_import.description") %></p>
|
||
</div>
|
||
|
||
<%= styled_form_with model: @import, scope: :import, url: import_upload_path(@import), multipart: true, class: "space-y-2", data: { drag_and_drop_import_target: "form" } do |form| %>
|
||
<div class="flex flex-col items-center justify-center w-full h-64 border border-secondary border-dashed rounded-xl cursor-pointer" data-controller="file-upload" data-action="click->file-upload#triggerFileInput" data-file-upload-target="uploadArea">
|
||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||
<div data-file-upload-target="uploadText" class="flex flex-col items-center">
|
||
<%= icon("database", size: "lg", class: "mb-4 mx-auto") %>
|
||
<p class="mb-2 text-md text-gray text-center">
|
||
<span class="font-medium text-primary"><%= t("import.uploads.sure_import.browse") %></span> <%= t("import.uploads.sure_import.browse_hint") %>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-4 items-center hidden mb-2" data-file-upload-target="fileName">
|
||
<span class="text-primary">
|
||
<%= icon("file-text", size: "lg", color: "current") %>
|
||
</span>
|
||
<p class="text-md font-medium text-primary"></p>
|
||
</div>
|
||
|
||
<%= form.file_field :ndjson_file, class: "hidden", accept: ".ndjson,.json", "data-auto-submit-form-target": "auto", "data-file-upload-target": "input", "data-drag-and-drop-import-target": "input" %>
|
||
</div>
|
||
</div>
|
||
|
||
<%= form.submit t("import.uploads.sure_import.upload_button"), disabled: @import.complete? %>
|
||
<% end %>
|
||
</div>
|
||
|
||
<div class="flex justify-center">
|
||
<span class="text-secondary text-sm">
|
||
<%= t("import.uploads.sure_import.hint_html") %>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<% elsif @import.is_a?(QifImport) %>
|
||
<%# ── QIF upload – fixed format, account required ── %>
|
||
<div class="space-y-4 mx-auto max-w-md">
|
||
<div class="text-center space-y-2">
|
||
<h1 class="text-3xl text-primary font-medium"><%= t(".qif_title") %></h1>
|
||
<p class="text-secondary text-sm"><%= t(".qif_description") %></p>
|
||
</div>
|
||
|
||
<%= styled_form_with model: @import, scope: :import, url: import_upload_path(@import), multipart: true, class: "space-y-4" do |form| %>
|
||
<%= form.select :account_id,
|
||
Current.user.accessible_accounts.visible.alphabetically.pluck(:name, :id),
|
||
{ label: t(".qif_account_label"), include_blank: t(".qif_account_placeholder"), selected: @import.account_id },
|
||
required: true %>
|
||
|
||
<label for="import_import_file" class="flex flex-col items-center justify-center w-full h-64 border border-secondary border-dashed rounded-xl cursor-pointer" data-controller="file-upload" data-file-upload-target="uploadArea">
|
||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||
<div data-file-upload-target="uploadText" class="flex flex-col items-center">
|
||
<%= icon("plus", size: "lg", class: "mb-4 mx-auto") %>
|
||
<p class="mb-2 text-md text-gray text-center">
|
||
<span class="font-medium text-primary"><%= t(".browse") %></span> <%= t(".qif_file_prompt") %>
|
||
</p>
|
||
<p class="text-xs text-secondary"><%= t(".qif_file_hint") %></p>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-4 items-center hidden mb-2" data-file-upload-target="fileName">
|
||
<span class="text-primary">
|
||
<%= icon("file-text", size: "lg", color: "current") %>
|
||
</span>
|
||
<p class="text-md font-medium text-primary"></p>
|
||
</div>
|
||
|
||
<%= form.file_field :import_file,
|
||
accept: ".qif",
|
||
id: "import_import_file",
|
||
class: "hidden",
|
||
"data-file-upload-target": "input" %>
|
||
</div>
|
||
</label>
|
||
|
||
<%= form.submit t(".qif_submit"), disabled: @import.complete? %>
|
||
<% end %>
|
||
</div>
|
||
|
||
<% else %>
|
||
<%# ── Standard CSV upload ── %>
|
||
<div class="space-y-4" data-controller="drag-and-drop-import">
|
||
<!-- Overlay -->
|
||
<%= render "imports/drag_drop_overlay", title: t(".drop_csv_title"), subtitle: t(".drop_csv_subtitle") %>
|
||
|
||
<div class="space-y-4 mx-auto max-w-md">
|
||
<div class="text-center space-y-2">
|
||
<h1 class="text-3xl text-primary font-medium"><%= t(".title") %></h1>
|
||
<p class="text-secondary text-sm"><%= t(".description") %></p>
|
||
</div>
|
||
|
||
<%= render DS::Tabs.new(active_tab: params[:tab] || "csv-upload", url_param_key: "tab", testid: "import-tabs") do |tabs| %>
|
||
<% tabs.with_nav do |nav| %>
|
||
<% nav.with_btn(id: "csv-upload", label: t(".upload_csv_tab")) %>
|
||
<% nav.with_btn(id: "csv-paste", label: t(".copy_paste_tab")) %>
|
||
<% end %>
|
||
|
||
<% tabs.with_panel(tab_id: "csv-upload") do %>
|
||
<%= styled_form_with model: @import, scope: :import, url: import_upload_path(@import), multipart: true, class: "space-y-2", data: { drag_and_drop_import_target: "form" } do |form| %>
|
||
<%= form.select :col_sep, Import.separator_options, label: true %>
|
||
|
||
<% if @import.type == "TransactionImport" || @import.type == "TradeImport" %>
|
||
<%= form.select :account_id, Current.user.accessible_accounts.visible.alphabetically.pluck(:name, :id), { label: t(".account_optional_label"), include_blank: t(".multi_account_import"), selected: @import.account_id } %>
|
||
<% end %>
|
||
|
||
<label for="import_import_file_csv" class="flex flex-col items-center justify-center w-full h-64 border border-secondary border-dashed rounded-xl cursor-pointer" data-controller="file-upload" data-file-upload-target="uploadArea">
|
||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||
<div data-file-upload-target="uploadText" class="flex flex-col items-center">
|
||
<%= icon("plus", size: "lg", class: "mb-4 mx-auto") %>
|
||
<p class="mb-2 text-md text-gray text-center">
|
||
<span class="font-medium text-primary"><%= t(".browse") %></span> <%= t(".csv_file_prompt") %>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-4 items-center hidden mb-2" data-file-upload-target="fileName">
|
||
<span class="text-primary">
|
||
<%= icon("file-text", size: "lg", color: "current") %>
|
||
</span>
|
||
<p class="text-md font-medium text-primary"></p>
|
||
</div>
|
||
|
||
<%= form.file_field :import_file, id: "import_import_file_csv", class: "hidden", "data-auto-submit-form-target": "auto", "data-file-upload-target": "input", "data-drag-and-drop-import-target": "input" %>
|
||
</div>
|
||
</label>
|
||
|
||
<%= form.submit t(".upload_csv_button"), disabled: @import.complete? %>
|
||
<% end %>
|
||
<% end %>
|
||
|
||
<% tabs.with_panel(tab_id: "csv-paste") do %>
|
||
<%= styled_form_with model: @import, scope: :import, url: import_upload_path(@import), multipart: true, class: "space-y-2" do |form| %>
|
||
<%= form.select :col_sep, Import.separator_options, label: true %>
|
||
|
||
<% if @import.type == "TransactionImport" || @import.type == "TradeImport" %>
|
||
<%= form.select :account_id, Current.user.accessible_accounts.visible.alphabetically.pluck(:name, :id), { label: t(".account_optional_label"), include_blank: t(".multi_account_import"), selected: @import.account_id } %>
|
||
<% end %>
|
||
|
||
<%= form.text_area :raw_file_str,
|
||
rows: 10,
|
||
required: true,
|
||
placeholder: t(".paste_csv_placeholder"),
|
||
"data-auto-submit-form-target": "auto" %>
|
||
|
||
<%= form.submit t(".upload_csv_button"), disabled: @import.complete? %>
|
||
<% end %>
|
||
<% end %>
|
||
<% end %>
|
||
</div>
|
||
|
||
<div class="flex justify-center">
|
||
<span class="text-secondary text-sm">
|
||
<%= link_to t(".download_sample_csv"), "/imports/#{@import.id}/upload/sample_csv", class: "text-primary underline", data: { turbo: false } %> <%= t(".to_see_format") %>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<% end %>
|