2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2025-12-14 21:47:12 +00:00

encryption round-trip works

This commit is contained in:
2025-01-20 02:07:26 +00:00
parent 79cf342d33
commit 4d49eefccb
9 changed files with 186 additions and 6 deletions

View File

@@ -52,6 +52,7 @@ from troggle.parsers.imports import (
import_logbook, import_logbook,
import_logbooks, import_logbooks,
import_people, import_people,
import_users,
import_QMs, import_QMs,
import_survex, import_survex,
import_survex_checks, import_survex_checks,
@@ -221,6 +222,7 @@ class JobQueue:
"reinit", "reinit",
"caves", "caves",
"people", "people",
"users",
"logbooks", "logbooks",
"QMs", "QMs",
"scans", "scans",
@@ -247,6 +249,8 @@ class JobQueue:
if module in ["runlabel", "date", "test", "TOTAL"]: if module in ["runlabel", "date", "test", "TOTAL"]:
continue continue
# print(i, module, f"length={len(self.results[module])} ") # print(i, module, f"length={len(self.results[module])} ")
if module == "users":
continue
if self.results[module][i]: if self.results[module][i]:
total += float(self.results[module][i]) total += float(self.results[module][i])
return total return total
@@ -425,6 +429,7 @@ def usage():
init - initialisation. Automatic if you run reset. init - initialisation. Automatic if you run reset.
caves - read in the caves (must run first after initialisation) caves - read in the caves (must run first after initialisation)
people - read in the people from folk.csv (must run after 'caves') people - read in the people from folk.csv (must run after 'caves')
users - read in registered troggle users from file (emails encrypted)
logbooks - read in the logbooks logbooks - read in the logbooks
QMs - read in the QM csv files (older caves only) QMs - read in the QM csv files (older caves only)
scans - the survey scans in all the wallets (must run before survex) scans - the survey scans in all the wallets (must run before survex)
@@ -492,6 +497,8 @@ if __name__ == "__main__":
jq.enq("logbooks", import_logbook) # default year set in imports.py jq.enq("logbooks", import_logbook) # default year set in imports.py
elif "people" in sys.argv: elif "people" in sys.argv:
jq.enq("people", import_people) jq.enq("people", import_people)
elif "users" in sys.argv:
jq.enq("users", import_users)
elif "QMs" in sys.argv: elif "QMs" in sys.argv:
jq.enq("QMs", import_QMs) jq.enq("QMs", import_QMs)
elif "reset" in sys.argv: elif "reset" in sys.argv:

View File

@@ -10,7 +10,7 @@ lint.ignore = ["E402", "F541"]
[project] [project]
name = "troggle" name = "troggle"
version = "2024.12.1" version = "2025.01.18"
description = "Troggle - cave data management" description = "Troggle - cave data management"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
@@ -18,6 +18,7 @@ dependencies = [
] ]
[dependency-groups] [dependency-groups]
dev = [ dev = [
"cryptography>=44.0.0",
"django>=5", "django>=5",
"beautifulsoup4>=4.12.3", "beautifulsoup4>=4.12.3",
"piexif>=1.1.3", "piexif>=1.1.3",

View File

@@ -181,7 +181,8 @@ def do_ARGE_cave(slug, caveid, areacode, svxid):
caveid may be kataster number or it may be e.g. LA34 caveid may be kataster number or it may be e.g. LA34
""" """
default_note = "This is (probably) an ARGE or VfHO cave where we only have the survex file and no other information" default_note = "This is (probably) an ARGE or VfHO cave where we only have the survex file and no other information."
default_note += "<br />If there is a 'Messteam' or 'Zeichner' listed, then it is probably ARGE."
url = f"{areacode}/{caveid}/{caveid}.html" url = f"{areacode}/{caveid}/{caveid}.html"
urltest = Cave.objects.filter(url=url) urltest = Cave.objects.filter(url=url)
@@ -210,11 +211,17 @@ def do_ARGE_cave(slug, caveid, areacode, svxid):
print(f"{caveid} {rest}") print(f"{caveid} {rest}")
passages = "\n" passages = "\n"
# ; Messteam: Uwe Kirsamer, Uli Nohlen, Aiko Schütz, Torben Schulz,Thomas Holder,Robert Winkler
# ; Zeichner: Aiko Schütz, Robert Winkler
for line in rest: for line in rest:
if line.strip().startswith("*begin"): if line.strip().startswith("*begin"):
passages = f"{passages}{line}" passages = f"{passages}{line}<br />\n"
if line.strip().startswith("; Messteam:") or line.strip().startswith("; Zeichner:"):
passages = f"{passages}{line}<br />\n"
commentary= "ARGE or VfHO cave.<br />3 lines of the survexfile,<br /> then all the *begin lines and any '; Messteam' and '; Zeichner' lines:<br><pre>"
cave = Cave( cave = Cave(
underground_description="ARGE or VfHO cave.<br>3 lines of the survexfile, then all the *begin lines:<br><pre>" + line1 +line2 +line3 +passages +"</pre>", underground_description=commentary + line1 +line2 +line3 +passages +"</pre>",
unofficial_number="ARGE-or-VfHO", unofficial_number="ARGE-or-VfHO",
survex_file= f"{svxid}.svx", survex_file= f"{svxid}.svx",
url=url, url=url,

View File

@@ -26,6 +26,12 @@ def import_people():
with transaction.atomic(): with transaction.atomic():
troggle.parsers.people.load_people_expos() troggle.parsers.people.load_people_expos()
def import_users():
print("-- Importing troggle Users (users.json) to ", end="")
print(django.db.connections.databases["default"]["NAME"])
with transaction.atomic():
troggle.parsers.people.load_users()
def import_surveyscans(): def import_surveyscans():
print("-- Importing Survey Scans and Wallets") print("-- Importing Survey Scans and Wallets")
with transaction.atomic(): with transaction.atomic():

View File

@@ -1,10 +1,16 @@
import base64
import csv import csv
import json
import os import os
import re import re
from cryptography.fernet import Fernet
from html import unescape from html import unescape
from pathlib import Path from pathlib import Path
from django.conf import settings from django.conf import settings
from django.core import serializers
from django.contrib.auth.models import User
from django.db import models
from unidecode import unidecode from unidecode import unidecode
from troggle.core.models.troggle import DataIssue, Expedition, Person, PersonExpedition from troggle.core.models.troggle import DataIssue, Expedition, Person, PersonExpedition
@@ -15,7 +21,6 @@ The standalone script needs to be renedred defucnt, and all the parsing needs to
or they should use the same code by importing a module. or they should use the same code by importing a module.
""" """
def parse_blurb(personline, header, person): def parse_blurb(personline, header, person):
"""create mugshot Photo instance """create mugshot Photo instance
Would be better if all this was done before the Person object was created in the db, then it would not Would be better if all this was done before the Person object was created in the db, then it would not
@@ -86,6 +91,94 @@ def troggle_slugify(longname):
return slug return slug
USERS_FILE = "users_e.json"
ENCRYPTED_DIR = "encrypted"
def load_users():
"""These are the previously registered users of the troggle system.
"""
PARSER_USERS = "_users"
DataIssue.objects.filter(parser=PARSER_USERS).delete()
key = settings.LONGTERM_SECRET_KEY # Django generated
k = base64.urlsafe_b64encode(key.encode("utf8")[:32]) # make Fernet compatible
f = Fernet(k)
print(f)
jsonfile = settings.EXPOWEB / ENCRYPTED_DIR / USERS_FILE
jsonurl = "/" + str(Path(ENCRYPTED_DIR) / USERS_FILE)
if not (jsonfile.is_file()):
message = f" ! Users json file does not exist: '{jsonfile}'"
DataIssue.objects.create(parser=PARSER_USERS, message=message)
print(message)
return None
with open(jsonfile, 'r', encoding='utf-8') as json_f:
try:
registered_users_dict = json.load(json_f)
except FileNotFoundError:
print("File not found!")
except json.JSONDecodeError:
print("Invalid JSON format! - JSONDecodeError")
except Exception as e:
print(f"An exception occurred: {str(e)}")
message = f"! Troggle USERs. Failed to load {jsonfile} JSON file"
print(message)
DataIssue.objects.update_or_create(parser=PARSER_USERS, message=message, url=jsonurl)
return None
users_list = registered_users_dict["registered_users"]
print(f" - {len(users_list)} users read from JSON")
for userdata in users_list:
if userdata["username"]:
if userdata["username"] == "expo":
continue
if userdata["username"] == "expoadmin":
continue
try:
e_email = userdata["email"]
email = f.decrypt(e_email).decode()
print(f" - user: '{userdata["username"]} <{email}>' ")
if existing_user := User.objects.filter(username=userdata["username"]): # WALRUS
# print(f" - deleting existing user '{existing_user[0]}' before importing")
existing_user[0].delete()
user = User.objects.create_user(userdata["username"], email, "secret")
user.set_password = "secret" # stores hash not password
user.is_staff = False
user.is_superuser = False
user.save()
except Exception as e:
print(f"Exception <{e}>\nusers in db: {len(User.objects.all())}\n{User.objects.all()}")
formatted_json = json.dumps(userdata, indent=4)
print(formatted_json)
return None
else:
print(f" - user: BAD username for {userdata} ")
# if userdata["date"] != "" or userdata["date"] != "None":
# message = f"! {str(self.walletname)} Date format not ISO {userdata['date']}. Failed to load from {jsonfile} JSON file"
# from troggle.core.models.troggle import DataIssue
# DataIssue.objects.update_or_create(parser="wallets", message=message, url=wurl)
ru = []
for u in User.objects.all():
if u.username == "expo":
continue
if u.username == "expoadmin":
continue
e_email = f.encrypt(u.email.encode("utf8")).decode()
ru.append({"username":u.username, "email": e_email, "password": u.password})
print(u.username, e_email)
original = f.decrypt(e_email).decode()
print(u.username, original)
jsondict = { "registered_users": ru }
encryptedfile = settings.EXPOWEB / ENCRYPTED_DIR / "encrypt.json"
with open(encryptedfile, 'w', encoding='utf-8') as json_f:
json.dump(jsondict, json_f, indent=1)
return True
def load_people_expos(): def load_people_expos():
"""This is where the folk.csv file is parsed to read people's names. """This is where the folk.csv file is parsed to read people's names.
Which it gets wrong for people like Lydia-Clare Leather and various 'von' and 'de' middle 'names' Which it gets wrong for people like Lydia-Clare Leather and various 'von' and 'de' middle 'names'

View File

@@ -18,6 +18,7 @@ dependencies = [
] ]
[dependency-groups] [dependency-groups]
dev = [ dev = [
"cryptography>=44.0.0",
"django>=5", "django>=5",
"beautifulsoup4>=4.12.3", "beautifulsoup4>=4.12.3",
"piexif>=1.1.3", "piexif>=1.1.3",

View File

@@ -18,6 +18,7 @@ dependencies = [
] ]
[dependency-groups] [dependency-groups]
server = [ server = [
"cryptography>=44.0.0",
"django==3.2.19", "django==3.2.19",
"beautifulsoup4==4.11.2", "beautifulsoup4==4.11.2",
"piexif==1.1.3", "piexif==1.1.3",

View File

@@ -16,7 +16,7 @@ if 'runserver' in sys.argv:
print(">>>>running on dev local runserver<<<<") print(">>>>running on dev local runserver<<<<")
DEVSERVER = True DEVSERVER = True
else: else:
print(">>>>running on expo.survex.com<<<<") # print(">>>>running on expo.survex.com<<<<")
DEVSERVER = False DEVSERVER = False
EPOCH = date.fromisoformat('1970-01-01') EPOCH = date.fromisoformat('1970-01-01')

64
uv.lock generated
View File

@@ -22,6 +22,28 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 },
] ]
[[package]]
name = "cffi"
version = "1.17.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pycparser" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 },
{ url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 },
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 },
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 },
{ url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 },
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
{ url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 },
{ url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 },
]
[[package]] [[package]]
name = "coverage" name = "coverage"
version = "7.6.9" version = "7.6.9"
@@ -50,6 +72,37 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/26/74/b0729f196f328ac55e42b1e22ec2f16d8bcafe4b8158a26ec9f1cdd1d93e/coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", size = 211815 }, { url = "https://files.pythonhosted.org/packages/26/74/b0729f196f328ac55e42b1e22ec2f16d8bcafe4b8158a26ec9f1cdd1d93e/coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", size = 211815 },
] ]
[[package]]
name = "cryptography"
version = "44.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 },
{ url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 },
{ url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 },
{ url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 },
{ url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 },
{ url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 },
{ url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 },
{ url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 },
{ url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 },
{ url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 },
{ url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 },
{ url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 },
{ url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 },
{ url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 },
{ url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 },
{ url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 },
{ url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 },
{ url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 },
{ url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 },
{ url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 },
]
[[package]] [[package]]
name = "django" name = "django"
version = "5.1.4" version = "5.1.4"
@@ -100,6 +153,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 },
] ]
[[package]]
name = "pycparser"
version = "2.22"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 },
]
[[package]] [[package]]
name = "soupsieve" name = "soupsieve"
version = "2.6" version = "2.6"
@@ -127,6 +189,7 @@ source = { virtual = "." }
dev = [ dev = [
{ name = "beautifulsoup4" }, { name = "beautifulsoup4" },
{ name = "coverage" }, { name = "coverage" },
{ name = "cryptography" },
{ name = "django" }, { name = "django" },
{ name = "piexif" }, { name = "piexif" },
{ name = "pillow" }, { name = "pillow" },
@@ -139,6 +202,7 @@ dev = [
dev = [ dev = [
{ name = "beautifulsoup4", specifier = ">=4.12.3" }, { name = "beautifulsoup4", specifier = ">=4.12.3" },
{ name = "coverage", specifier = ">=7.6.9" }, { name = "coverage", specifier = ">=7.6.9" },
{ name = "cryptography" },
{ name = "django", specifier = ">=5" }, { name = "django", specifier = ">=5" },
{ name = "piexif", specifier = ">=1.1.3" }, { name = "piexif", specifier = ">=1.1.3" },
{ name = "pillow", specifier = ">=11.0.0" }, { name = "pillow", specifier = ">=11.0.0" },