Default undated photo uploads to today
This commit is contained in:
@@ -173,8 +173,8 @@ iOS Shortcuts can blank that EXIF field while creating the ZIP, `photo_dates`
|
|||||||
supplies the same Photos-library metadata explicitly, one ISO 8601 value per
|
supplies the same Photos-library metadata explicitly, one ISO 8601 value per
|
||||||
image in archive order. `date_taken` overrides both sources for the whole batch;
|
image in archive order. `date_taken` overrides both sources for the whole batch;
|
||||||
it accepts a year, calendar date, or ISO timestamp and is intended for analog
|
it accepts a year, calendar date, or ISO timestamp and is intended for analog
|
||||||
photos. An upload without any date source is rejected instead of
|
photos. When none of these date sources is available, the service uses the upload
|
||||||
being placed under the upload year. Re-sharing the same images, caption, and
|
date. Re-sharing the same images, caption, and
|
||||||
highlight with dates replaces the earlier undated upload. Captions are plain
|
highlight with dates replaces the earlier undated upload. Captions are plain
|
||||||
text and optional.
|
text and optional.
|
||||||
An optional highlight name (up to 200 characters) adds one link to **Highlights**,
|
An optional highlight name (up to 200 characters) adds one link to **Highlights**,
|
||||||
|
|||||||
+4
-4
@@ -347,6 +347,7 @@ def create_app(data_dir=None, token=None):
|
|||||||
if kind == "snippet":
|
if kind == "snippet":
|
||||||
digest.update(b"\0snippet\0" + text.encode())
|
digest.update(b"\0snippet\0" + text.encode())
|
||||||
temporary = Path(tempfile.mkdtemp(dir=data / "temporary"))
|
temporary = Path(tempfile.mkdtemp(dir=data / "temporary"))
|
||||||
|
received_at = datetime.now(timezone.utc)
|
||||||
try:
|
try:
|
||||||
(temporary / "originals").mkdir()
|
(temporary / "originals").mkdir()
|
||||||
(temporary / "images").mkdir()
|
(temporary / "images").mkdir()
|
||||||
@@ -359,7 +360,8 @@ def create_app(data_dir=None, token=None):
|
|||||||
embedded_date = web_image(raw, temporary / "images" / f"{index:02}.jpg")
|
embedded_date = web_image(raw, temporary / "images" / f"{index:02}.jpg")
|
||||||
if kind == "photo":
|
if kind == "photo":
|
||||||
capture_dates.append(batch_date or
|
capture_dates.append(batch_date or
|
||||||
(supplied_dates[index] if supplied_dates else embedded_date))
|
(supplied_dates[index] if supplied_dates else embedded_date) or
|
||||||
|
received_at)
|
||||||
except (UnidentifiedImageError, OSError, ValueError, SyntaxError,
|
except (UnidentifiedImageError, OSError, ValueError, SyntaxError,
|
||||||
Image.DecompressionBombError, Image.DecompressionBombWarning,
|
Image.DecompressionBombError, Image.DecompressionBombWarning,
|
||||||
ImageCms.PyCMSError):
|
ImageCms.PyCMSError):
|
||||||
@@ -374,7 +376,7 @@ def create_app(data_dir=None, token=None):
|
|||||||
normalized_dates = "\n".join(taken.isoformat() for taken in supplied_dates)
|
normalized_dates = "\n".join(taken.isoformat() for taken in supplied_dates)
|
||||||
digest.update(b"\0photo_dates\0" + normalized_dates.encode())
|
digest.update(b"\0photo_dates\0" + normalized_dates.encode())
|
||||||
job = digest.hexdigest()
|
job = digest.hexdigest()
|
||||||
date = datetime.now(timezone.utc).isoformat()
|
date = received_at.isoformat()
|
||||||
manifest = {"id": job, "date": date, "caption": caption,
|
manifest = {"id": job, "date": date, "caption": caption,
|
||||||
"highlight": highlight, "count": len(photos)}
|
"highlight": highlight, "count": len(photos)}
|
||||||
if ((batch_date or supplied_dates) and undated_job != job and
|
if ((batch_date or supplied_dates) and undated_job != job and
|
||||||
@@ -384,8 +386,6 @@ def create_app(data_dir=None, token=None):
|
|||||||
manifest.update(kind=kind, text=text)
|
manifest.update(kind=kind, text=text)
|
||||||
atomic_json(temporary / "manifest.json", manifest)
|
atomic_json(temporary / "manifest.json", manifest)
|
||||||
if kind == "photo":
|
if kind == "photo":
|
||||||
if any(taken is None for taken in capture_dates):
|
|
||||||
abort(400, "Photo capture date is missing; send date_taken or photo_dates")
|
|
||||||
capture_dates = distinct_photo_dates(capture_dates)
|
capture_dates = distinct_photo_dates(capture_dates)
|
||||||
manifest["capture_dates"] = [taken.isoformat() for taken in capture_dates]
|
manifest["capture_dates"] = [taken.isoformat() for taken in capture_dates]
|
||||||
atomic_json(temporary / "manifest.json", manifest)
|
atomic_json(temporary / "manifest.json", manifest)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import io
|
import io
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -191,8 +192,9 @@ def test_photo_dates_can_come_from_photos_library_metadata(service):
|
|||||||
assert "valid ISO dates" in invalid.json["error"]
|
assert "valid ISO dates" in invalid.json["error"]
|
||||||
|
|
||||||
missing = upload(client, [photo(exif=Image.Exif())])
|
missing = upload(client, [photo(exif=Image.Exif())])
|
||||||
assert missing.status_code == 400
|
assert missing.status_code == 202
|
||||||
assert "capture date is missing" in missing.json["error"]
|
manifest = json.loads((data / "submissions" / missing.json["id"] / "manifest.json").read_text())
|
||||||
|
assert datetime.fromisoformat(manifest["capture_dates"][0]).date() == datetime.now(timezone.utc).date()
|
||||||
|
|
||||||
|
|
||||||
def test_batch_date_taken_overrides_metadata_for_analog_photos(service):
|
def test_batch_date_taken_overrides_metadata_for_analog_photos(service):
|
||||||
|
|||||||
Reference in New Issue
Block a user