Compare commits

...

3 Commits

Author SHA1 Message Date
dfd51c1343 [birds] Add small js file for form
Some checks failed
build & deploy / test (push) Failing after 1m7s
build & deploy / build-and-deploy (push) Has been skipped
2026-05-15 12:50:32 -04:00
e47328e572 [scrobbles] Fix circular dep problem in saving log data 2026-05-15 12:38:59 -04:00
e85d6ec779 [birds] Fix importer not finishing, and add formjs 2026-05-15 12:20:27 -04:00
5 changed files with 45 additions and 3 deletions

View File

@ -1,3 +1,5 @@
from datetime import timedelta
import pytest
from birds.importer import (
import_birding_csv,
@ -111,6 +113,13 @@ class TestImportBirdingCSV:
goose = next(b for b in birds if b["quantity"] == 6)
assert goose is not None
def test_import_sets_stop_timestamp(self, user, birding_csv_file):
import_birding_csv(birding_csv_file, user.id)
scrobble = Scrobble.objects.filter(source="Birding CSV Import").first()
assert scrobble.stop_timestamp is not None
expected = scrobble.timestamp + timedelta(minutes=9)
assert scrobble.stop_timestamp == expected
class TestBirdingCSVImportModel:
def test_create_import_model(self, db, user):

View File

@ -2,7 +2,7 @@ import csv
import logging
import re
from collections import defaultdict
from datetime import datetime
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from django.contrib.auth import get_user_model
@ -122,9 +122,10 @@ def import_birding_csv(file_path, user_id):
)
birds_data.append(entry.asdict)
duration_minutes = parse_duration(first_row.get("Duration", ""))
logdata = BirdSightingLogData(
birds=birds_data,
duration_minutes=parse_duration(first_row.get("Duration", "")),
duration_minutes=duration_minutes,
observation_type=first_row.get("Observation Type", "").strip() or None,
distance=first_row.get("Distance", "").strip() or None,
area=first_row.get("Area", "").strip() or None,
@ -134,9 +135,12 @@ def import_birding_csv(file_path, user_id):
log_dict = logdata.asdict
stop_timestamp = timestamp + timedelta(minutes=duration_minutes) if duration_minutes else None
scrobble = Scrobble(
user=user,
timestamp=timestamp,
stop_timestamp=stop_timestamp,
source="Birding CSV Import",
birding_location=location,
log=log_dict,

View File

@ -0,0 +1,27 @@
document.addEventListener("DOMContentLoaded", function () {
var widget = document.querySelector(".bird-sightings-widget");
if (!widget) return;
var list = widget.querySelector(".bird-sightings-list");
widget.addEventListener("click", function (e) {
if (e.target.classList.contains("add-sighting-row")) {
var rows = list.querySelectorAll(".bird-sighting-row");
var template = rows[rows.length - 1];
if (!template) return;
var clone = template.cloneNode(true);
clone.querySelectorAll("select, input").forEach(function (el) {
el.value = "";
});
clone.querySelector('input[name$="_quantity"]').value = "1";
list.appendChild(clone);
}
if (e.target.classList.contains("remove-sighting")) {
var rows = list.querySelectorAll(".bird-sighting-row");
if (rows.length > 1) {
e.target.closest(".bird-sighting-row").remove();
}
}
});
});

View File

@ -948,7 +948,7 @@ class ScrobbleDetailView(DetailView):
original_value = (self.object.log or {}).get(field_name)
data[field_name] = original_value
if data.get("with_people_ids", False):
if data.get("with_people_ids") is not None:
data["with_people_ids"] = [p.id for p in data["with_people_ids"]]
if data.get("platform_id", False):

View File

@ -136,3 +136,5 @@
</div>
{% endblock %}
{% block extra_js %}{{ block.super }}{{ log_form.media }}{% endblock %}