From cbd08127efe8105576be779ad7f0fa938878a36a Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 14 Jan 2024 12:14:44 +1100 Subject: [PATCH] initial work on fixing user exports with s3 - custom storages - tar.gz within bucket using s3_tar - slightly changes export directory structure - major problems still outstanding re delivering s3 files to end users --- .../migrations/0192_auto_20240114_0055.py | 53 ++ bookwyrm/models/bookwyrm_export_job.py | 460 ++++++++++++------ bookwyrm/models/job.py | 7 +- bookwyrm/settings.py | 1 + bookwyrm/storage_backends.py | 14 + bookwyrm/templatetags/utilities.py | 27 +- exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 | Bin 0 -> 3820 bytes exports/ba15a57f-e29e-4a29-aaf4-306b66960273 | Bin 0 -> 41614 bytes requirements.txt | 1 + 9 files changed, 408 insertions(+), 155 deletions(-) create mode 100644 bookwyrm/migrations/0192_auto_20240114_0055.py create mode 100644 exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 create mode 100644 exports/ba15a57f-e29e-4a29-aaf4-306b66960273 diff --git a/bookwyrm/migrations/0192_auto_20240114_0055.py b/bookwyrm/migrations/0192_auto_20240114_0055.py new file mode 100644 index 000000000..f4d324f7f --- /dev/null +++ b/bookwyrm/migrations/0192_auto_20240114_0055.py @@ -0,0 +1,53 @@ +# Generated by Django 3.2.23 on 2024-01-14 00:55 + +import bookwyrm.storage_backends +import django.core.serializers.json +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0191_merge_20240102_0326'), + ] + + operations = [ + migrations.AddField( + model_name='bookwyrmexportjob', + name='export_json', + field=models.JSONField(encoder=django.core.serializers.json.DjangoJSONEncoder, null=True), + ), + migrations.AddField( + model_name='bookwyrmexportjob', + name='json_completed', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='bookwyrmexportjob', + name='export_data', + field=models.FileField(null=True, storage=bookwyrm.storage_backends.ExportsFileStorage, upload_to=''), + ), + migrations.CreateModel( + name='AddFileToTar', + fields=[ + ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), + ('parent_export_job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='child_edition_export_jobs', to='bookwyrm.bookwyrmexportjob')), + ], + options={ + 'abstract': False, + }, + bases=('bookwyrm.childjob',), + ), + migrations.CreateModel( + name='AddBookToUserExportJob', + fields=[ + ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), + ('edition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.edition')), + ], + options={ + 'abstract': False, + }, + bases=('bookwyrm.childjob',), + ), + ] diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 1f6085e0c..12a9792e2 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -2,94 +2,347 @@ import dataclasses import logging +import boto3 +from s3_tar import S3Tar from uuid import uuid4 -from django.db.models import FileField +from django.db.models import CASCADE, BooleanField, FileField, ForeignKey, JSONField from django.db.models import Q from django.core.serializers.json import DjangoJSONEncoder -from django.core.files.base import ContentFile +from django.core.files.base import ContentFile, File +from django.utils import timezone + +from bookwyrm import settings, storage_backends from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, List, ListItem from bookwyrm.models import Review, Comment, Quotation from bookwyrm.models import Edition from bookwyrm.models import UserFollows, User, UserBlocks -from bookwyrm.models.job import ParentJob, ParentTask +from bookwyrm.models.job import ParentJob, ChildJob, ParentTask, SubTask from bookwyrm.tasks import app, IMPORTS from bookwyrm.utils.tar import BookwyrmTarFile logger = logging.getLogger(__name__) - class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" - export_data = FileField(null=True) + if settings.USE_S3: + storage = storage_backends.ExportsS3Storage + else: + storage = storage_backends.ExportsFileStorage + + export_data = FileField(null=True, storage=storage) # use custom storage backend here + export_json = JSONField(null=True, encoder=DjangoJSONEncoder) + json_completed = BooleanField(default=False) + def start_job(self): """Start the job""" - start_export_task.delay(job_id=self.id, no_children=True) - return self + task = start_export_task.delay(job_id=self.id, no_children=False) + self.task_id = task.id + self.save(update_fields=["task_id"]) + + + def notify_child_job_complete(self): + """let the job know when the items get work done""" + + if self.complete: + return + + self.updated_date = timezone.now() + self.save(update_fields=["updated_date"]) + + if not self.complete and self.has_completed: + if not self.json_completed: + + try: + self.json_completed = True + self.save(update_fields=["json_completed"]) + + # add json file to tarfile + tar_job = AddFileToTar.objects.create( + parent_job=self, + parent_export_job=self + ) + tar_job.start_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("job %s failed with error: %s", self.id, err) + tar_job.set_status("failed") + self.stop_job(reason="failed") + + else: + self.complete_job() + + +class AddBookToUserExportJob(ChildJob): + """append book metadata for each book in an export""" + + edition = ForeignKey(Edition, on_delete=CASCADE) + + def start_job(self): + """Start the job""" + try: + + book = {} + book["work"] = self.edition.parent_work.to_activity() + book["edition"] = self.edition.to_activity() + + if book["edition"].get("cover"): + # change the URL to be relative to the JSON file + filename = book["edition"]["cover"]["url"].rsplit("/", maxsplit=1)[-1] + book["edition"]["cover"]["url"] = f"covers/{filename}" + + # authors + book["authors"] = [] + for author in self.edition.authors.all(): + book["authors"].append(author.to_activity()) + + # Shelves this book is on + # Every ShelfItem is this book so we don't other serializing + book["shelves"] = [] + shelf_books = ( + ShelfBook.objects.select_related("shelf") + .filter(user=self.parent_job.user, book=self.edition) + .distinct() + ) + + for shelfbook in shelf_books: + book["shelves"].append(shelfbook.shelf.to_activity()) + + # Lists and ListItems + # ListItems include "notes" and "approved" so we need them + # even though we know it's this book + book["lists"] = [] + list_items = ListItem.objects.filter(book=self.edition, user=self.parent_job.user).distinct() + + for item in list_items: + list_info = item.book_list.to_activity() + list_info[ + "privacy" + ] = item.book_list.privacy # this isn't serialized so we add it + list_info["list_item"] = item.to_activity() + book["lists"].append(list_info) + + # Statuses + # Can't use select_subclasses here because + # we need to filter on the "book" value, + # which is not available on an ordinary Status + for status in ["comments", "quotations", "reviews"]: + book[status] = [] + + + comments = Comment.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in comments: + obj = status.to_activity() + obj["progress"] = status.progress + obj["progress_mode"] = status.progress_mode + book["comments"].append(obj) + + + quotes = Quotation.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in quotes: + obj = status.to_activity() + obj["position"] = status.position + obj["endposition"] = status.endposition + obj["position_mode"] = status.position_mode + book["quotations"].append(obj) + + + reviews = Review.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in reviews: + obj = status.to_activity() + book["reviews"].append(obj) + + # readthroughs can't be serialized to activity + book_readthroughs = ( + ReadThrough.objects.filter(user=self.parent_job.user, book=self.edition).distinct().values() + ) + book["readthroughs"] = list(book_readthroughs) + + self.parent_job.export_json["books"].append(book) + self.parent_job.save(update_fields=["export_json"]) + self.complete_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("AddBookToUserExportJob %s Failed with error: %s", self.id, err) + self.set_status("failed") + + +class AddFileToTar(ChildJob): + """add files to export""" + + parent_export_job = ForeignKey( + BookwyrmExportJob, on_delete=CASCADE, related_name="child_edition_export_jobs" + ) # TODO: do we actually need this? Does self.parent_job.export_data work? + + + def start_job(self): + """Start the job""" + + # NOTE we are doing this all in one big job, which has the potential to block a thread + # This is because we need to refer to the same s3_job or BookwyrmTarFile whilst writing + # Alternatives using a series of jobs in a loop would be beter + # but Hugh couldn't make that work + + try: + task_id=self.parent_export_job.task_id + export_data = self.parent_export_job.export_data + export_json = self.parent_export_job.export_json + json_data = DjangoJSONEncoder().encode(export_json) + user = self.parent_export_job.user + editions = get_books_for_user(user) + + if settings.USE_S3: + s3_job = S3Tar( + settings.AWS_STORAGE_BUCKET_NAME, + f"exports/{str(self.parent_export_job.task_id)}.tar.gz" + ) + + # TODO: either encrypt the file or we will need to get it to the user + # from this secure part of the bucket + export_data.save("archive.json", ContentFile(json_data.encode("utf-8"))) + + s3_job.add_file( + f"exports/{export_data.name}" + ) + s3_job.add_file( + f"images/{user.avatar.name}", + folder="avatar" + ) + for book in editions: + if getattr(book, "cover", False): + cover_name = f"images/{book.cover.name}" + s3_job.add_file( + cover_name, + folder="covers" + ) + + s3_job.tar() + # delete export json as soon as it's tarred + # there is probably a better way to do this + # Currently this merely makes the file empty + export_data.delete(save=False) + + else: + # TODO: is the export_data file open to the world? + logger.info( "export file URL: %s",export_data.url) + + export_data.open("wb") + with BookwyrmTarFile.open(mode="w:gz", fileobj=export_data) as tar: + + tar.write_bytes(json_data.encode("utf-8")) + + # Add avatar image if present + if getattr(user, "avatar", False): + tar.add_image(user.avatar, filename="avatar", directory=f"avatar/") # TODO: does this work? + + for book in editions: + if getattr(book, "cover", False): + tar.add_image(book.cover) + + export_data.close() + + + self.complete_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("AddFileToTar %s Failed with error: %s", self.id, err) + self.stop_job(reason="failed") + self.parent_job.stop_job(reason="failed") @app.task(queue=IMPORTS, base=ParentTask) def start_export_task(**kwargs): - """trigger the child tasks for each row""" + """trigger the child tasks for user export""" + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) # don't start the job if it was stopped from the UI if job.complete: return try: - # This is where ChildJobs get made + + # prepare the initial file and base json job.export_data = ContentFile(b"", str(uuid4())) - json_data = json_export(job.user) - tar_export(json_data, job.user, job.export_data) - job.save(update_fields=["export_data"]) + job.export_json = job.user.to_activity() + job.save(update_fields=["export_data", "export_json"]) + + # let's go + json_export.delay(job_id=job.id, job_user=job.user.id, no_children=False) + except Exception as err: # pylint: disable=broad-except logger.exception("User Export Job %s Failed with error: %s", job.id, err) job.set_status("failed") - job.set_status("complete") +@app.task(queue=IMPORTS, base=ParentTask) +def export_saved_lists_task(**kwargs): + """add user saved lists to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + saved_lists = List.objects.filter(id__in=job.user.saved_lists.all()).distinct() + job.export_json["saved_lists"] = [l.remote_id for l in saved_lists] + job.save(update_fields=["export_json"]) -def tar_export(json_data: str, user, file): - """wrap the export information in a tar file""" - file.open("wb") - with BookwyrmTarFile.open(mode="w:gz", fileobj=file) as tar: - tar.write_bytes(json_data.encode("utf-8")) +@app.task(queue=IMPORTS, base=ParentTask) +def export_follows_task(**kwargs): + """add user follows to export JSON""" - # Add avatar image if present - if getattr(user, "avatar", False): - tar.add_image(user.avatar, filename="avatar") - - editions = get_books_for_user(user) - for book in editions: - if getattr(book, "cover", False): - tar.add_image(book.cover) - - file.close() + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + follows = UserFollows.objects.filter(user_subject=job.user).distinct() + following = User.objects.filter(userfollows_user_object__in=follows).distinct() + job.export_json["follows"] = [f.remote_id for f in following] + job.save(update_fields=["export_json"]) -def json_export( - user, -): # pylint: disable=too-many-locals, too-many-statements, too-many-branches +@app.task(queue=IMPORTS, base=ParentTask) +def export_blocks_task(**kwargs): + """add user blocks to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + blocks = UserBlocks.objects.filter(user_subject=job.user).distinct() + blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() + job.export_json["blocks"] = [b.remote_id for b in blocking] + job.save(update_fields=["export_json"]) + + +@app.task(queue=IMPORTS, base=ParentTask) +def export_reading_goals_task(**kwargs): + """add user reading goals to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + reading_goals = AnnualGoal.objects.filter(user=job.user).distinct() + job.export_json["goals"] = [] + for goal in reading_goals: + exported_user["goals"].append( + {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} + ) + job.save(update_fields=["export_json"]) + + +@app.task(queue=IMPORTS, base=ParentTask) +def json_export(**kwargs): """Generate an export for a user""" - # User as AP object - exported_user = user.to_activity() + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + job.set_status("active") + job_id = kwargs["job_id"] + # I don't love this but it prevents a JSON encoding error # when there is no user image if isinstance( - exported_user["icon"], + job.export_json["icon"], dataclasses._MISSING_TYPE, # pylint: disable=protected-access ): - exported_user["icon"] = {} + job.export_json["icon"] = {} else: # change the URL to be relative to the JSON file - file_type = exported_user["icon"]["url"].rsplit(".", maxsplit=1)[-1] + file_type = job.export_json["icon"]["url"].rsplit(".", maxsplit=1)[-1] filename = f"avatar.{file_type}" - exported_user["icon"]["url"] = filename + job.export_json["icon"]["url"] = filename # Additional settings - can't be serialized as AP vals = [ @@ -98,120 +351,45 @@ def json_export( "default_post_privacy", "show_suggested_users", ] - exported_user["settings"] = {} + job.export_json["settings"] = {} for k in vals: - exported_user["settings"][k] = getattr(user, k) + job.export_json["settings"][k] = getattr(job.user, k) - # Reading goals - can't be serialized as AP - reading_goals = AnnualGoal.objects.filter(user=user).distinct() - exported_user["goals"] = [] - for goal in reading_goals: - exported_user["goals"].append( - {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} - ) + job.export_json["books"] = [] - # Reading history - can't be serialized as AP - readthroughs = ReadThrough.objects.filter(user=user).distinct().values() - readthroughs = list(readthroughs) + # save settings we just updated + job.save(update_fields=["export_json"]) - # Books - editions = get_books_for_user(user) - exported_user["books"] = [] + # trigger subtasks + export_saved_lists_task.delay(job_id=job_id, no_children=False) + export_follows_task.delay(job_id=job_id, no_children=False) + export_blocks_task.delay(job_id=job_id, no_children=False) + trigger_books_jobs.delay(job_id=job_id, no_children=False) - for edition in editions: - book = {} - book["work"] = edition.parent_work.to_activity() - book["edition"] = edition.to_activity() - if book["edition"].get("cover"): - # change the URL to be relative to the JSON file - filename = book["edition"]["cover"]["url"].rsplit("/", maxsplit=1)[-1] - book["edition"]["cover"]["url"] = f"covers/{filename}" +@app.task(queue=IMPORTS, base=ParentTask) +def trigger_books_jobs(**kwargs): + """trigger tasks to get data for each book""" - # authors - book["authors"] = [] - for author in edition.authors.all(): - book["authors"].append(author.to_activity()) + try: + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + editions = get_books_for_user(job.user) - # Shelves this book is on - # Every ShelfItem is this book so we don't other serializing - book["shelves"] = [] - shelf_books = ( - ShelfBook.objects.select_related("shelf") - .filter(user=user, book=edition) - .distinct() - ) + if len(editions) == 0: + job.notify_child_job_complete() + return - for shelfbook in shelf_books: - book["shelves"].append(shelfbook.shelf.to_activity()) - - # Lists and ListItems - # ListItems include "notes" and "approved" so we need them - # even though we know it's this book - book["lists"] = [] - list_items = ListItem.objects.filter(book=edition, user=user).distinct() - - for item in list_items: - list_info = item.book_list.to_activity() - list_info[ - "privacy" - ] = item.book_list.privacy # this isn't serialized so we add it - list_info["list_item"] = item.to_activity() - book["lists"].append(list_info) - - # Statuses - # Can't use select_subclasses here because - # we need to filter on the "book" value, - # which is not available on an ordinary Status - for status in ["comments", "quotations", "reviews"]: - book[status] = [] - - comments = Comment.objects.filter(user=user, book=edition).all() - for status in comments: - obj = status.to_activity() - obj["progress"] = status.progress - obj["progress_mode"] = status.progress_mode - book["comments"].append(obj) - - quotes = Quotation.objects.filter(user=user, book=edition).all() - for status in quotes: - obj = status.to_activity() - obj["position"] = status.position - obj["endposition"] = status.endposition - obj["position_mode"] = status.position_mode - book["quotations"].append(obj) - - reviews = Review.objects.filter(user=user, book=edition).all() - for status in reviews: - obj = status.to_activity() - book["reviews"].append(obj) - - # readthroughs can't be serialized to activity - book_readthroughs = ( - ReadThrough.objects.filter(user=user, book=edition).distinct().values() - ) - book["readthroughs"] = list(book_readthroughs) - - # append everything - exported_user["books"].append(book) - - # saved book lists - just the remote id - saved_lists = List.objects.filter(id__in=user.saved_lists.all()).distinct() - exported_user["saved_lists"] = [l.remote_id for l in saved_lists] - - # follows - just the remote id - follows = UserFollows.objects.filter(user_subject=user).distinct() - following = User.objects.filter(userfollows_user_object__in=follows).distinct() - exported_user["follows"] = [f.remote_id for f in following] - - # blocks - just the remote id - blocks = UserBlocks.objects.filter(user_subject=user).distinct() - blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() - - exported_user["blocks"] = [b.remote_id for b in blocking] - - return DjangoJSONEncoder().encode(exported_user) + for edition in editions: + try: + edition_job = AddBookToUserExportJob.objects.create(edition=edition, parent_job=job) + edition_job.start_job() + except Exception as err: # pylint: disable=broad-except + logger.exception("AddBookToUserExportJob %s Failed with error: %s", edition_job.id, err) + edition_job.set_status("failed") + except Exception as err: # pylint: disable=broad-except + logger.exception("trigger_books_jobs %s Failed with error: %s", job.id, err) + job.set_status("failed") def get_books_for_user(user): """Get all the books and editions related to a user""" diff --git a/bookwyrm/models/job.py b/bookwyrm/models/job.py index 4f5cb2093..5a2653571 100644 --- a/bookwyrm/models/job.py +++ b/bookwyrm/models/job.py @@ -135,8 +135,7 @@ class ParentJob(Job): ) app.control.revoke(list(tasks)) - for task in self.pending_child_jobs: - task.update(status=self.Status.STOPPED) + self.pending_child_jobs.update(status=self.Status.STOPPED) @property def has_completed(self): @@ -248,7 +247,7 @@ class SubTask(app.Task): """ def before_start( - self, task_id, args, kwargs + self, task_id, *args, **kwargs ): # pylint: disable=no-self-use, unused-argument """Handler called before the task starts. Override. @@ -272,7 +271,7 @@ class SubTask(app.Task): child_job.set_status(ChildJob.Status.ACTIVE) def on_success( - self, retval, task_id, args, kwargs + self, retval, task_id, *args, **kwargs ): # pylint: disable=no-self-use, unused-argument """Run by the worker if the task executes successfully. Override. diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index fcc91857a..7896850e3 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -442,3 +442,4 @@ if HTTP_X_FORWARDED_PROTO: # Do not change this setting unless you already have an existing # user with the same username - in which case you should change it! INSTANCE_ACTOR_USERNAME = "bookwyrm.instance.actor" +DATA_UPLOAD_MAX_MEMORY_SIZE = (1024**2 * 20) # 20MB TEMPORARY FIX WHILST WORKING ON THIS \ No newline at end of file diff --git a/bookwyrm/storage_backends.py b/bookwyrm/storage_backends.py index 6dd9f522c..c97b4e848 100644 --- a/bookwyrm/storage_backends.py +++ b/bookwyrm/storage_backends.py @@ -1,6 +1,7 @@ """Handles backends for storages""" import os from tempfile import SpooledTemporaryFile +from django.core.files.storage import FileSystemStorage from storages.backends.s3boto3 import S3Boto3Storage from storages.backends.azure_storage import AzureStorage @@ -61,3 +62,16 @@ class AzureImagesStorage(AzureStorage): # pylint: disable=abstract-method location = "images" overwrite_files = False + +class ExportsFileStorage(FileSystemStorage): # pylint: disable=abstract-method + """Storage class for exports contents with local files""" + + location = "exports" + overwrite_files = False + +class ExportsS3Storage(S3Boto3Storage): # pylint: disable=abstract-method + """Storage class for exports contents with S3""" + + location = "exports" + default_acl = None + overwrite_files = False \ No newline at end of file diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index fca66688a..754db41dd 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ from django.templatetags.static import static from bookwyrm.models import User -from bookwyrm.settings import INSTANCE_ACTOR_USERNAME +from bookwyrm.settings import INSTANCE_ACTOR_USERNAME, USE_S3 register = template.Library() @@ -133,15 +133,22 @@ def get_file_size(file): """display the size of a file in human readable terms""" try: - raw_size = os.stat(file.path).st_size - if raw_size < 1024: - return f"{raw_size} bytes" - if raw_size < 1024**2: - return f"{raw_size/1024:.2f} KB" - if raw_size < 1024**3: - return f"{raw_size/1024**2:.2f} MB" - return f"{raw_size/1024**3:.2f} GB" - except Exception: # pylint: disable=broad-except + # TODO: this obviously isn't a proper solution + # boto storages do not implement 'path' + if not USE_S3: + raw_size = os.stat(file.path).st_size + if raw_size < 1024: + return f"{raw_size} bytes" + if raw_size < 1024**2: + return f"{raw_size/1024:.2f} KB" + if raw_size < 1024**3: + return f"{raw_size/1024**2:.2f} MB" + return f"{raw_size/1024**3:.2f} GB" + + return "" + + except Exception as e: # pylint: disable=broad-except + print(e) return "" diff --git a/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 b/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 new file mode 100644 index 0000000000000000000000000000000000000000..d7166b70306179d10b652499641665bc4e5a992a GIT binary patch literal 3820 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%0DVkuOb;zskMvxS82VX=ZCV_wM9(l{qFS=Gij?kh% z(NC4*Pd{3;JNe%XT`9i8xx#agzrTC)Q%-@(qEHXpMq|&5m0Z%lue>}_Uv#qUiCy=? zYZK~{!iB7^xT)?B`S<*m(B~g}LYXK2l>N1}wOyUl>DTQQA8PgA$NerW4HCMOpW%>u zs&tKp{^8J70++qc=Xm?s-?w>cAZ2Yh_tu^AEthv$N%$y~$_n?k6uK-97p?vA{98z- z$k$1$n(bAa%)H(&&e^c_%3`08?+cI5G?e#NYtQXCl@*z$I@$I3Sy!>sSDU$ew!C(` zELE29ciq251_4|9FXSoyR&+j4P;T9?Wbb8qInFpJJgi_%{Ld?Yrv=Y1yZmUX2z#Qh zvZ8Q*kQHy$rI-@6%{j}BXOs$W{Qqm=hr@4sO|96j7*a-B_LrlKuk3vBJhi#p)kPm(zWpKD@%QjW)?lfEvrn#TPm3=7>!T^R z&HU}Htj!VYik2sRc`*CPf@JUGn!NvX*Z*35D)>+6o~rf!SFf9z?YlX@cEeRG)`qzi zg&OV!>-YV8Cf9x?)YJaQuJZDVeQ}rNuI5KgncX3Bb=lj}?ZG=uc$ueev@ULZy5=Nyx``2!rvutJ2`Ba$;DpI?3QhRO~fBpUN;Hp*YxY>@l zTzv8PmhJgZMQ=ap^I!Da8W!mF>6V{}r|Xs*!w9b2Ep?2zpUtW`}mSosl+txGh;&1;+U^9~Fv|Ji)xhi%N-?f!T zd`gnoFNo!qeA`!ByHGx%_q@y5R7v5eTiktVKJyL2*nWhb)-z3uyI8ox;rzxb>5Ay= z)syZVI3Zh641NfYS}8$^A`R}?g7?cy|R?FH;Au~V{r_hy3}iX z&gaR0V-&d`PB~s+SHf}Xl^tDq0qN;mD-mTqlWufb1uldAx)pf?)s3W&@S^fMok8}F{ik!Da z?W?RT@3zRF%TDTXvi_d?u0(9*4%?;I=6u~R`Me;1V`sd#)%Sy`%Qs)2`(;m2nfmou zpOf~BnX7&rZ)IzfJ-dW|a;o8(TThcOhHw6@IKNN6c6YUf=yBoF(9{_c3@?}2hGny@ zmT^0m&d#o=Eu8Rmf6qI%_bzWtOpoc6PFN~-|Cso@)cYs8RDNhLv9NS&4Rt%Q&T8E! zyXmEMt_fb>3}a@VJ^t?O`-y+u)zmuQMmD}YX?piCBj+tg@sRS;aR2q0`;}h1T-BcT z((ZGjZ~XmO-O^JZH%`4?_c5waewn6Guc$@*M^mnSNP>)o48io{pESJcZ2vZ?PLCYIzhaXZhiPIcE6GIdYwB7 zcaKQiH`6KZC`i58)c)ei<3$_4hO_!ES{STWyS0klSb%54nC)M)N^#KA+6xmHRjSZtpL;5_k4sUs0H= zeo|obI)kT6SH3*7v~890{9D4pJ6kiq9;oo#zSL6kOLgUs<|K%Ww_SSK^iPpf)D@p*mCkGXt1I4po~85M^Gf+5Yk?J4+@`$y(AWK8|I77ac6&Vc zFUz^E-xu01Hgoq&9?e{-zXk!ath2fH$8;w=^So@i_PeaRiTVF1!vT$~dtT;_!+$jG3iBo6E8d zR>;+UW3}Bi`N>vhy@RIe<^GPl!Ztj=xMf@V3gvFe)1`cKRKBN*%x%3N(LaYLe%|EQ zQ!GPs9$&d&vyk`tiDLq}_Ag7GFlkvw6)>Hx{Wy7FyNvn5?fa`mza*zMD;{4zr{Vss zTW^=E>dqBgX2Se(^VR!P_iQ>K)ylqPesoXvbIWf!*SE<0KVhJ~W2R9^UGw(&8F|)C z&60<&PcMsI`8q+zDv0%o+UW%T^wX<^7wYfr%ekL6Z8p!$mu+W~}G QnEM~|>#Oz23>pj!0F}dHZ2$lO literal 0 HcmV?d00001 diff --git a/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 b/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 new file mode 100644 index 0000000000000000000000000000000000000000..318069303d9f47f3296429b66dc293422a67d8fe GIT binary patch literal 41614 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 6509effc7..31e59e8ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,6 +35,7 @@ opentelemetry-sdk==1.16.0 protobuf==3.20.* pyotp==2.8.0 qrcode==7.3.1 +s3-tar==0.1.13 # Dev pytest-django==4.1.0