API - add export task when data export is requested

This commit is contained in:
Sam
2023-03-01 16:30:44 +01:00
parent e4fc8849be
commit 90c85f921c
6 changed files with 220 additions and 15 deletions

View File

@ -34,6 +34,7 @@ from fittrackee.utils import get_readable_duration
from fittrackee.workouts.models import Sport
from .models import BlacklistedToken, User, UserDataExport, UserSportPreference
from .tasks import export_data
from .utils.controls import check_password, is_valid_email, register_controls
from .utils.token import decode_user_token
@ -1735,9 +1736,10 @@ def request_user_data_export(auth_user: User) -> Union[Dict, HttpResponse]:
if not existing_export_request.completed:
return InvalidPayloadErrorResponse("ongoing request exists")
if (
existing_export_request.created_at
> datetime.datetime.utcnow() - datetime.timedelta(hours=24)
export_expiration = current_app.config["DATA_EXPORT_EXPIRATION"]
if existing_export_request.created_at > (
datetime.datetime.utcnow()
- datetime.timedelta(hours=export_expiration)
):
return InvalidPayloadErrorResponse(
"completed request already exists"
@ -1750,6 +1752,9 @@ def request_user_data_export(auth_user: User) -> Union[Dict, HttpResponse]:
export_request = UserDataExport(user_id=auth_user.id)
db.session.add(export_request)
db.session.commit()
export_data.send(export_request_id=export_request.id)
return {"status": "success", "request": export_request.serialize()}
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
return handle_error_and_return_response(e, db=db)

View File

@ -1,12 +1,13 @@
import json
import os
import secrets
from typing import Dict, List, Optional, Union
from typing import Dict, List, Optional, Tuple, Union
from zipfile import ZipFile
from fittrackee import appLog, db
from fittrackee.files import get_absolute_file_path
from .models import User
from .models import User, UserDataExport
class UserDataExporter:
@ -50,7 +51,7 @@ class UserDataExporter:
export_file.write(json_object)
return file_path
def generate_archive(self) -> Optional[str]:
def generate_archive(self) -> Tuple[Optional[str], Optional[str]]:
try:
user_data_file_name = self.export_data(
self.get_user_info(), "user_data"
@ -81,6 +82,30 @@ class UserDataExporter:
)
file_exists = os.path.exists(zip_path)
return zip_file if file_exists else None
return (zip_path, zip_file) if file_exists else (None, None)
except Exception:
return None
return None, None
def export_user_data(export_request_id: int) -> None:
export_request = UserDataExport.query.filter_by(
id=export_request_id
).first()
if not export_request:
appLog.error(f"No export to process for id '{export_request_id}'")
return
if export_request.completed:
appLog.info(f"Export id '{export_request_id}' already processed")
return
user = User.query.filter_by(id=export_request.user_id).first()
exporter = UserDataExporter(user)
archive_file_path, archive_file_name = exporter.generate_archive()
export_request.completed = True
if archive_file_name and archive_file_path:
export_request.file_name = archive_file_name
export_request.file_size = os.path.getsize(archive_file_path)
db.session.commit()

View File

@ -0,0 +1,7 @@
from fittrackee import dramatiq
from fittrackee.users.export_data import export_user_data
@dramatiq.actor(queue_name='fittrackee_users_exports')
def export_data(export_request_id: int) -> None:
export_user_data(export_request_id)