Skip to content

Commit 8fd13c2

Browse files
authored
Merge pull request #322 from iragm/march-2025-fixes
More CSV fixes
2 parents 2b1c8f0 + 548f955 commit 8fd13c2

File tree

3 files changed

+67
-54
lines changed

3 files changed

+67
-54
lines changed

auctions/models.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,12 @@ def delete(self, *args, **kwargs):
734734
self.is_deleted = True
735735
self.save()
736736

737+
def save(self, *args, **kwargs):
738+
if self.date_start.year < 2000:
739+
current_year = timezone.now().year
740+
self.date_start = self.date_start.replace(year=current_year)
741+
super().save(*args, **kwargs)
742+
737743
@property
738744
def location_qs(self):
739745
"""All locations associated with this auction"""
@@ -1760,7 +1766,7 @@ def check_number_in_auction(number):
17601766
# self.print_reminder_email_sent = True
17611767
# self.second_confirm_email_sent = True
17621768
if self.email and not self.user:
1763-
self.user = User.objects.filter(active=True, email=self.email).first()
1769+
self.user = User.objects.filter(is_active=True, email=self.email).first()
17641770
# fill out some fields from user, if set
17651771
# There is a huge security concern here: <<<< ATTENTION!!!
17661772
# If someone creates an auction and adds every email address that's public

auctions/templates/auctions/bulk_add_users.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
<br>
99

1010
<div class="btn-group">
11-
{% if request.user.is_superuser %}<input type="file" name="csv_file" id="csv_file" accept=".csv" hx-encoding="multipart/form-data" hx-post="{% url 'bulk_add_users' auction.slug %}" hx-swap="outerHTML" hx-target="body" style="display: none;">
12-
<button class="btn btn-primary btn-sm ms-2 me-2" onclick="document.getElementById('csv_file').click()"><i class="bi bi-person-fill-up"></i> Import from CSV</button>{% endif %}
11+
<input type="file" name="csv_file" id="csv_file" accept=".csv" hx-encoding="multipart/form-data" hx-post="{% url 'bulk_add_users' auction.slug %}" hx-swap="outerHTML" hx-target="body" style="display: none;">
12+
<button class="btn btn-primary btn-sm ms-2 me-2" onclick="document.getElementById('csv_file').click()"><i class="bi bi-person-fill-up"></i> Import from CSV</button>
1313
<div class="dropdown">
1414
<button class="btn btn-sm btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
1515
<i class="bi bi-person-fill-add"></i> Import from old auctions

auctions/views.py

+58-51
Original file line numberDiff line numberDiff line change
@@ -2674,14 +2674,13 @@ def extract_info(row, field_name_list, default_response=""):
26742674
pass
26752675
return default_response
26762676

2677-
def columns_exist_in_csv(csv_reader, columns):
2677+
def columns_exist(field_names, columns):
26782678
"""returns True if any value in the list `columns` exists in the file"""
2679-
first_row = next(csv_reader)
2680-
result = extract_info(first_row, columns, None)
2681-
if result is None:
2682-
return False
2683-
else:
2684-
return True
2679+
case_insensitive_row = {k.lower() for k in field_names}
2680+
for column in columns:
2681+
if column in case_insensitive_row:
2682+
return True
2683+
return False
26852684

26862685
csv_file.seek(0)
26872686
csv_reader = csv.DictReader(TextIOWrapper(csv_file.file))
@@ -2697,73 +2696,81 @@ def columns_exist_in_csv(csv_reader, columns):
26972696
# order matters here - the most important columns should be validated last,
26982697
# so the error refers to the most important missing column
26992698
try:
2700-
if not columns_exist_in_csv(csv_reader, phone_field_names):
2699+
if not columns_exist(csv_reader.fieldnames, phone_field_names):
27012700
error = "Warning: This file does not contain a phone column"
27022701
else:
27032702
some_columns_exist = True
2704-
if not columns_exist_in_csv(csv_reader, address_field_names):
2703+
if not columns_exist(csv_reader.fieldnames, address_field_names):
27052704
error = "Warning: This file does not contain an address column"
27062705
else:
27072706
some_columns_exist = True
2708-
if not columns_exist_in_csv(csv_reader, name_field_names):
2707+
if not columns_exist(csv_reader.fieldnames, name_field_names):
27092708
error = "Warning: This file does not contain a name column"
27102709
else:
27112710
some_columns_exist = True
2712-
if not columns_exist_in_csv(csv_reader, email_field_names):
2711+
if not columns_exist(csv_reader.fieldnames, email_field_names):
27132712
error = "Warning: This file does not contain an email column"
27142713
else:
27152714
some_columns_exist = True
27162715
if not some_columns_exist:
27172716
error = (
27182717
"Unable to read information from this CSV file. Make sure it contains an email and a name column"
27192718
)
2720-
except UnicodeDecodeError as e:
2719+
2720+
total_tos = 0
2721+
total_skipped = 0
2722+
for row in csv_reader:
2723+
bidder_number = extract_info(row, bidder_number_fields)
2724+
email = extract_info(row, email_field_names)
2725+
name = extract_info(row, name_field_names)
2726+
phone = extract_info(row, phone_field_names)
2727+
address = extract_info(row, address_field_names)
2728+
is_club_member = extract_info(row, is_club_member_fields)
2729+
if is_club_member.lower() in ["yes", "true", "member", "club member"]:
2730+
is_club_member = True
2731+
else:
2732+
is_club_member = False
2733+
if email or name or phone or address:
2734+
if self.tos_is_in_auction(self.auction, name, email):
2735+
logger.debug("CSV import skipping %s", name)
2736+
total_skipped += 1
2737+
else:
2738+
logger.debug("CSV import adding %s", name)
2739+
if bidder_number:
2740+
if AuctionTOS.objects.filter(auction=self.auction, bidder_number=bidder_number).first():
2741+
bidder_number = ""
2742+
AuctionTOS.objects.create(
2743+
auction=self.auction,
2744+
pickup_location=self.auction.location_qs.first(),
2745+
manually_added=True,
2746+
bidder_number=bidder_number,
2747+
name=name,
2748+
phone_number=phone,
2749+
email=email,
2750+
address=address,
2751+
is_club_member=is_club_member,
2752+
)
2753+
total_tos += 1
2754+
if error:
2755+
messages.error(self.request, error)
2756+
msg = f"{total_tos} users added"
2757+
if total_skipped:
2758+
msg += (
2759+
f", {total_skipped} users are already in this auction (matched by email, or name if email not set)"
2760+
)
2761+
messages.info(self.request, msg)
2762+
url = reverse("auction_tos_list", kwargs={"slug": self.auction.slug})
2763+
response = HttpResponse(status=200)
2764+
response["HX-Redirect"] = url
2765+
return response
2766+
except (UnicodeDecodeError, ValueError) as e:
27212767
messages.error(
27222768
self.request, f"Unable to read file. Make sure this is a valid UTF-8 CSV file. Error was: {e}"
27232769
)
27242770
url = reverse("bulk_add_users", kwargs={"slug": self.auction.slug})
27252771
response = HttpResponse(status=200)
27262772
response["HX-Redirect"] = url
27272773
return response
2728-
total_tos = 0
2729-
total_skipped = 0
2730-
for row in csv_reader:
2731-
bidder_number = extract_info(row, bidder_number_fields)
2732-
email = extract_info(row, email_field_names)
2733-
name = extract_info(row, name_field_names)
2734-
phone = extract_info(row, phone_field_names)
2735-
address = extract_info(row, address_field_names)
2736-
is_club_member = extract_info(row, is_club_member_fields)
2737-
if is_club_member.lower() in ["yes", "true", "member", "club member"]:
2738-
is_club_member = True
2739-
else:
2740-
is_club_member = False
2741-
if email or name or phone or address:
2742-
if self.tos_is_in_auction(self.auction, name, email):
2743-
total_skipped += 1
2744-
else:
2745-
AuctionTOS.objects.create(
2746-
auction=self.auction,
2747-
pickup_location=self.auction.location_qs.first(),
2748-
manually_added=True,
2749-
bidder_number=bidder_number,
2750-
name=name,
2751-
phone_number=phone,
2752-
email=email,
2753-
address=address,
2754-
is_club_member=is_club_member,
2755-
)
2756-
total_tos += 1
2757-
if error:
2758-
messages.error(self.request, error)
2759-
msg = f"{total_tos} users added"
2760-
if total_skipped:
2761-
msg += f", {total_skipped} users are already in this auction (matched by email, or name if email not set)"
2762-
messages.info(self.request, msg)
2763-
url = reverse("auction_tos_list", kwargs={"slug": self.auction.slug})
2764-
response = HttpResponse(status=200)
2765-
response["HX-Redirect"] = url
2766-
return response
27672774

27682775
# The code below would populate the formset with the info from the CSV.
27692776
# This process is simply not working, and it fails silently with no log.

0 commit comments

Comments
 (0)