import: drop guards for a blank group, a stray slot, a lost row
import_picker allowed for an import with no group, which Staged.open
always names. Staged's paths checked a slot only constants name and an
index Roda's Integer matcher cannot make negative, and walk_on read a
row missing from its own walk as the first. The checks go, and the
missing row raises.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kqo9sKAi4DnKCQkrtYoAwM
diff --git a/lib/pro_tacts/import/staged.rb b/lib/pro_tacts/import/staged.rb
index 9831491..c5f21c4 100644
--- a/lib/pro_tacts/import/staged.rb
+++ b/lib/pro_tacts/import/staged.rb
@@ -22,17 +22,14 @@ module ProTacts
# them but the screens of the import that wrote them.
DIRECTORY = "imports" #: String
+ # The cards' two slots, each a directory holding a file per card
+ # named by its place in the file, so a screen reads the one card
+ # it shows rather than every card the upload held.
ORIGINAL = "original" #: String
REVISED = "revised" #: String
+ # The walk's notes, a JSON file each.
SAVED = "saved" #: String
ROWS = "rows" #: String
- # The walk's notes, a JSON file each.
- SLOTS = [SAVED, ROWS].freeze #: Array[String]
-
- # The cards' two slots, each a directory holding a file per card
- # named by its place in the file, so a screen reads the one card
- # it shows rather than every card the upload held.
- CARDS = [ORIGINAL, REVISED].freeze #: Array[String]
# One row of the walk's list as it was last read: what the row is
# called and sorted by, off the card as it will be written, and
@@ -201,24 +198,20 @@ module ProTacts
root / id
end
- # One slot's file. The slot is checked as narrowly as the id,
- # for the reason the id is.
+ # One slot's file, or none for an id this never wrote. The id is
+ # the check; a slot is always one of the constants above.
#: (String id, String slot) -> Pathname?
def self.path(id, slot)
directory = import_root(id)
- return nil if directory.nil? || !SLOTS.include?(slot)
-
- directory / file_name(slot)
+ directory / file_name(slot) if directory
end
- # One card's file in a cards slot, checked as #path checks: the
- # place is an Integer the route matched, and never below zero.
+ # One card's file in a cards slot, #path's check: the place is
+ # the digits Roda's Integer matcher took, so never below zero.
#: (String id, String slot, Integer index) -> Pathname?
def self.card_path(id, slot, index)
directory = import_root(id)
- return nil if directory.nil? || !CARDS.include?(slot) || index.negative?
-
- directory / slot / "#{index}.vcf"
+ directory / slot / "#{index}.vcf" if directory
end
# One slot, rewritten. Both refusals name which of the two
diff --git a/lib/pro_tacts/web/import.rb b/lib/pro_tacts/web/import.rb
index 8e88f08..d8f0a81 100644
--- a/lib/pro_tacts/web/import.rb
+++ b/lib/pro_tacts/web/import.rb
@@ -319,7 +319,7 @@ module ProTacts
#: (String group, Array[String]? joined, Array[String]? named, ?member: Contact?, ?tags: Array[String]) -> Admin::ImportGroups
def import_picker(group, joined, named, member: nil, tags: [])
choices = store.group_choices
- lot = group.empty? ? nil : choices.find { it.name == group }
+ lot = choices.find { it.name == group }
everyone = choices.find { it.name == Group::EVERYONE }
none = [] #: Array[String]
was = member ? store.groups_of(member.id).map(&:id) : none
@@ -426,7 +426,7 @@ module ProTacts
joined: ticked, named: wanted)
end
- edited = Admin::CardForm.contact_card(contact, first, middle, last, r.params)
+ edited = Admin::CardForm.contact_card(contact, first, middle, last, card_form_params)
if target
# A stored contact, whose birthday the model holds: the contact
# editor's own save (#apply_edit), down to its one refusal.
@@ -506,7 +506,8 @@ module ProTacts
# render.
order = walk_order(rows)
remaining = order.reject { |i| saved.key?(i.to_s) || i == index }
- below = order.drop(order.index(index).to_i + 1)
+ at = order.index(index) or raise "row #{index} is not in its own walk"
+ below = order.drop(at + 1)
r.redirect "/import/#{upload}/#{below.find { remaining.include?(it) } || remaining.fetch(0)}", 303
end