mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	tusd: Allow user to upload files during preregistration.
Allow user to upload files during preregistration. This will be used to upload import data. Co-authored-by: Alex Vandiver <alexmv@zulip.com>
This commit is contained in:
		@@ -3,17 +3,20 @@ import os
 | 
				
			|||||||
import orjson
 | 
					import orjson
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.test import override_settings
 | 
					from django.test import override_settings
 | 
				
			||||||
 | 
					from typing_extensions import ParamSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zerver.lib.cache import cache_delete, get_realm_used_upload_space_cache_key
 | 
					from zerver.lib.cache import cache_delete, get_realm_used_upload_space_cache_key
 | 
				
			||||||
from zerver.lib.test_classes import ZulipTestCase
 | 
					from zerver.lib.test_classes import ZulipTestCase
 | 
				
			||||||
from zerver.lib.test_helpers import create_s3_buckets, use_s3_backend
 | 
					from zerver.lib.test_helpers import create_s3_buckets, find_key_by_email, use_s3_backend
 | 
				
			||||||
from zerver.lib.upload import sanitize_name, upload_backend, upload_message_attachment
 | 
					from zerver.lib.upload import sanitize_name, upload_backend, upload_message_attachment
 | 
				
			||||||
from zerver.lib.upload.s3 import S3UploadBackend
 | 
					from zerver.lib.upload.s3 import S3UploadBackend
 | 
				
			||||||
from zerver.lib.utils import assert_is_not_none
 | 
					from zerver.lib.utils import assert_is_not_none
 | 
				
			||||||
from zerver.models import Attachment, Realm
 | 
					from zerver.models import Attachment, PreregistrationRealm, Realm
 | 
				
			||||||
from zerver.models.realms import get_realm
 | 
					from zerver.models.realms import get_realm
 | 
				
			||||||
from zerver.views.tusd import TusEvent, TusHook, TusHTTPRequest, TusUpload
 | 
					from zerver.views.tusd import TusEvent, TusHook, TusHTTPRequest, TusUpload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ParamT = ParamSpec("ParamT")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TusdHooksTest(ZulipTestCase):
 | 
					class TusdHooksTest(ZulipTestCase):
 | 
				
			||||||
    def test_non_localhost(self) -> None:
 | 
					    def test_non_localhost(self) -> None:
 | 
				
			||||||
@@ -98,7 +101,7 @@ class TusdHooksTest(ZulipTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TusdPreCreateTest(ZulipTestCase):
 | 
					class TusdPreCreateTest(ZulipTestCase):
 | 
				
			||||||
    def request(self) -> TusHook:
 | 
					    def request(self, key: str = "") -> TusHook:
 | 
				
			||||||
        return TusHook(
 | 
					        return TusHook(
 | 
				
			||||||
            type="pre-create",
 | 
					            type="pre-create",
 | 
				
			||||||
            event=TusEvent(
 | 
					            event=TusEvent(
 | 
				
			||||||
@@ -114,6 +117,7 @@ class TusdPreCreateTest(ZulipTestCase):
 | 
				
			|||||||
                        "filetype": "text/plain",
 | 
					                        "filetype": "text/plain",
 | 
				
			||||||
                        "name": "zulip.txt",
 | 
					                        "name": "zulip.txt",
 | 
				
			||||||
                        "type": "text/plain",
 | 
					                        "type": "text/plain",
 | 
				
			||||||
 | 
					                        "key": key,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    offset=0,
 | 
					                    offset=0,
 | 
				
			||||||
                    partial_uploads=None,
 | 
					                    partial_uploads=None,
 | 
				
			||||||
@@ -295,6 +299,162 @@ class TusdPreCreateTest(ZulipTestCase):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertEqual(result_json["RejectUpload"], True)
 | 
					        self.assertEqual(result_json["RejectUpload"], True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_realm_import_data_upload(self) -> None:
 | 
				
			||||||
 | 
					        # Choose import from slack
 | 
				
			||||||
 | 
					        email = "ete-slack-import@zulip.com"
 | 
				
			||||||
 | 
					        self.submit_realm_creation_form(
 | 
				
			||||||
 | 
					            email,
 | 
				
			||||||
 | 
					            realm_subdomain="ete-slack-import",
 | 
				
			||||||
 | 
					            realm_name="Slack import end to end",
 | 
				
			||||||
 | 
					            # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					            # import_from="slack",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        prereg_realm = PreregistrationRealm.objects.get(email=email)
 | 
				
			||||||
 | 
					        # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					        # self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
 | 
				
			||||||
 | 
					        prereg_realm.data_import_metadata["import_from"] = "slack"
 | 
				
			||||||
 | 
					        prereg_realm.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        confirmation_key = find_key_by_email(email)
 | 
				
			||||||
 | 
					        assert confirmation_key is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertLogs(level="WARNING") as warn_log:
 | 
				
			||||||
 | 
					            result = self.client_post(
 | 
				
			||||||
 | 
					                "/api/internal/tusd",
 | 
				
			||||||
 | 
					                self.request(key=confirmation_key).model_dump(),
 | 
				
			||||||
 | 
					                content_type="application/json",
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        self.assertEqual(result.status_code, 200)
 | 
				
			||||||
 | 
					        # Verify if we tried to remove any existing upload.
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            warn_log.output,
 | 
				
			||||||
 | 
					            ["WARNING:root:slack.zip does not exist. Its entry in the database will be removed."],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        result_json = result.json()
 | 
				
			||||||
 | 
					        self.assertEqual(result_json.get("HttpResponse", None), None)
 | 
				
			||||||
 | 
					        self.assertEqual(result_json.get("RejectUpload", False), False)
 | 
				
			||||||
 | 
					        self.assertEqual(list(result_json["ChangeFileInfo"].keys()), ["ID"])
 | 
				
			||||||
 | 
					        filename = f"import/{prereg_realm.id}/slack.zip"
 | 
				
			||||||
 | 
					        self.assertTrue(result_json["ChangeFileInfo"]["ID"].endswith(filename))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info = TusUpload(
 | 
				
			||||||
 | 
					            id=filename,
 | 
				
			||||||
 | 
					            size=len("zulip!"),
 | 
				
			||||||
 | 
					            offset=0,
 | 
				
			||||||
 | 
					            size_is_deferred=False,
 | 
				
			||||||
 | 
					            meta_data={
 | 
				
			||||||
 | 
					                "filename": filename,
 | 
				
			||||||
 | 
					                "filetype": "text/plain",
 | 
				
			||||||
 | 
					                "name": "zulip.zip",
 | 
				
			||||||
 | 
					                "type": "text/plain",
 | 
				
			||||||
 | 
					                "key": confirmation_key,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            is_final=False,
 | 
				
			||||||
 | 
					            is_partial=False,
 | 
				
			||||||
 | 
					            partial_uploads=None,
 | 
				
			||||||
 | 
					            storage=None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        request = TusHook(
 | 
				
			||||||
 | 
					            type="pre-finish",
 | 
				
			||||||
 | 
					            event=TusEvent(
 | 
				
			||||||
 | 
					                upload=info,
 | 
				
			||||||
 | 
					                http_request=TusHTTPRequest(
 | 
				
			||||||
 | 
					                    method="PATCH",
 | 
				
			||||||
 | 
					                    uri=f"/api/v1/tus/{info.id}",
 | 
				
			||||||
 | 
					                    remote_addr="12.34.56.78",
 | 
				
			||||||
 | 
					                    header={},
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Post the hook saying the file is in place
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/api/internal/tusd",
 | 
				
			||||||
 | 
					            request.model_dump(),
 | 
				
			||||||
 | 
					            content_type="application/json",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(result.status_code, 200)
 | 
				
			||||||
 | 
					        prereg_realm.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            prereg_realm.data_import_metadata["uploaded_import_file_name"].endswith(filename)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_realm_import_data_upload_size_is_deferred(self) -> None:
 | 
				
			||||||
 | 
					        # Choose import from slack
 | 
				
			||||||
 | 
					        email = "ete-slack-import@zulip.com"
 | 
				
			||||||
 | 
					        self.submit_realm_creation_form(
 | 
				
			||||||
 | 
					            email,
 | 
				
			||||||
 | 
					            realm_subdomain="ete-slack-import",
 | 
				
			||||||
 | 
					            realm_name="Slack import end to end",
 | 
				
			||||||
 | 
					            # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					            # import_from="slack",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        prereg_realm = PreregistrationRealm.objects.get(email=email)
 | 
				
			||||||
 | 
					        # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					        # self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
 | 
				
			||||||
 | 
					        prereg_realm.data_import_metadata["import_from"] = "slack"
 | 
				
			||||||
 | 
					        prereg_realm.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        confirmation_key = find_key_by_email(email)
 | 
				
			||||||
 | 
					        assert confirmation_key is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        request = self.request(key=confirmation_key)
 | 
				
			||||||
 | 
					        request.event.upload.size = None
 | 
				
			||||||
 | 
					        request.event.upload.size_is_deferred = True
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/api/internal/tusd",
 | 
				
			||||||
 | 
					            request.model_dump(),
 | 
				
			||||||
 | 
					            content_type="application/json",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(result.status_code, 200)
 | 
				
			||||||
 | 
					        result_json = result.json()
 | 
				
			||||||
 | 
					        self.assertEqual(result_json["HttpResponse"]["StatusCode"], 411)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            orjson.loads(result_json["HttpResponse"]["Body"]),
 | 
				
			||||||
 | 
					            {"message": "SizeIsDeferred is not supported"},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(result_json["RejectUpload"], True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_realm_import_data_upload_size_limit_exceeded(self) -> None:
 | 
				
			||||||
 | 
					        # Choose import from slack
 | 
				
			||||||
 | 
					        email = "ete-slack-import@zulip.com"
 | 
				
			||||||
 | 
					        self.submit_realm_creation_form(
 | 
				
			||||||
 | 
					            email,
 | 
				
			||||||
 | 
					            realm_subdomain="ete-slack-import",
 | 
				
			||||||
 | 
					            realm_name="Slack import end to end",
 | 
				
			||||||
 | 
					            # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					            # import_from="slack",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        prereg_realm = PreregistrationRealm.objects.get(email=email)
 | 
				
			||||||
 | 
					        # TODO: Uncomment after adding support to form.
 | 
				
			||||||
 | 
					        # self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
 | 
				
			||||||
 | 
					        prereg_realm.data_import_metadata["import_from"] = "slack"
 | 
				
			||||||
 | 
					        prereg_realm.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        confirmation_key = find_key_by_email(email)
 | 
				
			||||||
 | 
					        assert confirmation_key is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        request = self.request(key=confirmation_key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        max_upload_size = settings.MAX_WEB_DATA_IMPORT_SIZE_MB * 1024 * 1024
 | 
				
			||||||
 | 
					        request.event.upload.size = max_upload_size + 1
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/api/internal/tusd",
 | 
				
			||||||
 | 
					            request.model_dump(),
 | 
				
			||||||
 | 
					            content_type="application/json",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(result.status_code, 200)
 | 
				
			||||||
 | 
					        result_json = result.json()
 | 
				
			||||||
 | 
					        self.assertEqual(result_json["HttpResponse"]["StatusCode"], 413)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            orjson.loads(result_json["HttpResponse"]["Body"]),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "message": f"Uploaded file is larger than the allowed limit of {settings.MAX_WEB_DATA_IMPORT_SIZE_MB} MiB"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(result_json["RejectUpload"], True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TusdPreFinishTest(ZulipTestCase):
 | 
					class TusdPreFinishTest(ZulipTestCase):
 | 
				
			||||||
    def request(self, info: TusUpload) -> TusHook:
 | 
					    def request(self, info: TusUpload) -> TusHook:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ from django.views.decorators.csrf import csrf_exempt
 | 
				
			|||||||
from pydantic import BaseModel, ConfigDict, Field
 | 
					from pydantic import BaseModel, ConfigDict, Field
 | 
				
			||||||
from pydantic.alias_generators import to_pascal
 | 
					from pydantic.alias_generators import to_pascal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from confirmation.models import Confirmation, ConfirmationKeyError, get_object_from_key
 | 
				
			||||||
from zerver.decorator import get_basic_credentials, validate_api_key
 | 
					from zerver.decorator import get_basic_credentials, validate_api_key
 | 
				
			||||||
from zerver.lib.exceptions import AccessDeniedError, JsonableError
 | 
					from zerver.lib.exceptions import AccessDeniedError, JsonableError
 | 
				
			||||||
from zerver.lib.mime_types import guess_type
 | 
					from zerver.lib.mime_types import guess_type
 | 
				
			||||||
@@ -21,11 +22,12 @@ from zerver.lib.upload import (
 | 
				
			|||||||
    attachment_vips_source,
 | 
					    attachment_vips_source,
 | 
				
			||||||
    check_upload_within_quota,
 | 
					    check_upload_within_quota,
 | 
				
			||||||
    create_attachment,
 | 
					    create_attachment,
 | 
				
			||||||
 | 
					    delete_message_attachment,
 | 
				
			||||||
    sanitize_name,
 | 
					    sanitize_name,
 | 
				
			||||||
    upload_backend,
 | 
					    upload_backend,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from zerver.lib.upload.base import INLINE_MIME_TYPES
 | 
					from zerver.lib.upload.base import INLINE_MIME_TYPES
 | 
				
			||||||
from zerver.models import Realm, UserProfile
 | 
					from zerver.models import PreregistrationRealm, Realm, UserProfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# See https://tus.github.io/tusd/advanced-topics/hooks/ for the spec
 | 
					# See https://tus.github.io/tusd/advanced-topics/hooks/ for the spec
 | 
				
			||||||
@@ -237,6 +239,40 @@ def authenticate_user(request: HttpRequest) -> UserProfile | AnonymousUser:
 | 
				
			|||||||
    return request.user
 | 
					    return request.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def handle_preregistration_pre_create_hook(
 | 
				
			||||||
 | 
					    request: HttpRequest, preregistration_realm: PreregistrationRealm, data: TusUpload
 | 
				
			||||||
 | 
					) -> HttpResponse:
 | 
				
			||||||
 | 
					    max_upload_size = settings.MAX_WEB_DATA_IMPORT_SIZE_MB * 1024 * 1024  # 1G
 | 
				
			||||||
 | 
					    if data.size_is_deferred or data.size is None:
 | 
				
			||||||
 | 
					        return reject_upload("SizeIsDeferred is not supported", 411)
 | 
				
			||||||
 | 
					    if data.size > max_upload_size:
 | 
				
			||||||
 | 
					        return reject_upload(
 | 
				
			||||||
 | 
					            _("Uploaded file is larger than the allowed limit of {max_file_size} MiB").format(
 | 
				
			||||||
 | 
					                max_file_size=settings.MAX_WEB_DATA_IMPORT_SIZE_MB
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            413,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename = f"import/{preregistration_realm.id}/slack.zip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Delete any existing upload, so tusd doesn't declare that there's nothing
 | 
				
			||||||
 | 
					    # to do. This also has the nice benefit of deleting the previous upload.
 | 
				
			||||||
 | 
					    delete_message_attachment(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return tusd_json_response({"ChangeFileInfo": {"ID": filename}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def handle_preregistration_pre_finish_hook(
 | 
				
			||||||
 | 
					    request: HttpRequest, preregistration_realm: PreregistrationRealm, data: TusUpload
 | 
				
			||||||
 | 
					) -> HttpResponse:
 | 
				
			||||||
 | 
					    # Save the filename to display the uploaded file to user. We need to store it in
 | 
				
			||||||
 | 
					    # the database so that is available even after a refresh.
 | 
				
			||||||
 | 
					    filename = data.meta_data["filename"]
 | 
				
			||||||
 | 
					    preregistration_realm.data_import_metadata["uploaded_import_file_name"] = filename
 | 
				
			||||||
 | 
					    preregistration_realm.save(update_fields=["data_import_metadata"])
 | 
				
			||||||
 | 
					    return tusd_json_response({})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@csrf_exempt
 | 
					@csrf_exempt
 | 
				
			||||||
@typed_endpoint
 | 
					@typed_endpoint
 | 
				
			||||||
def handle_tusd_hook(
 | 
					def handle_tusd_hook(
 | 
				
			||||||
@@ -248,14 +284,34 @@ def handle_tusd_hook(
 | 
				
			|||||||
    if not is_local_addr(request.META["REMOTE_ADDR"]):
 | 
					    if not is_local_addr(request.META["REMOTE_ADDR"]):
 | 
				
			||||||
        raise AccessDeniedError
 | 
					        raise AccessDeniedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    maybe_user = authenticate_user(request)
 | 
					 | 
				
			||||||
    if isinstance(maybe_user, AnonymousUser):
 | 
					 | 
				
			||||||
        return reject_upload("Unauthenticated upload", 401)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    hook_name = payload.type
 | 
					    hook_name = payload.type
 | 
				
			||||||
 | 
					    maybe_user = authenticate_user(request)
 | 
				
			||||||
 | 
					    if maybe_user.is_authenticated:
 | 
				
			||||||
 | 
					        # Authenticated requests are file upload requests
 | 
				
			||||||
        if hook_name == "pre-create":
 | 
					        if hook_name == "pre-create":
 | 
				
			||||||
            return handle_upload_pre_create_hook(request, maybe_user, payload.event.upload)
 | 
					            return handle_upload_pre_create_hook(request, maybe_user, payload.event.upload)
 | 
				
			||||||
        elif hook_name == "pre-finish":
 | 
					        elif hook_name == "pre-finish":
 | 
				
			||||||
            return handle_upload_pre_finish_hook(request, maybe_user, payload.event.upload)
 | 
					            return handle_upload_pre_finish_hook(request, maybe_user, payload.event.upload)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return HttpResponseNotFound()
 | 
					            return HttpResponseNotFound()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Check if unauthenticated requests are for realm creation
 | 
				
			||||||
 | 
					    key = payload.event.upload.meta_data.get("key")
 | 
				
			||||||
 | 
					    if key is None:
 | 
				
			||||||
 | 
					        return reject_upload("Unauthenticated upload", 401)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        prereg_object = get_object_from_key(
 | 
				
			||||||
 | 
					            key, [Confirmation.REALM_CREATION], mark_object_used=False
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    except ConfirmationKeyError:
 | 
				
			||||||
 | 
					        return reject_upload("Unauthenticated upload", 401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert isinstance(prereg_object, PreregistrationRealm)
 | 
				
			||||||
 | 
					    assert prereg_object.created_realm is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if hook_name == "pre-create":
 | 
				
			||||||
 | 
					        return handle_preregistration_pre_create_hook(request, prereg_object, payload.event.upload)
 | 
				
			||||||
 | 
					    elif hook_name == "pre-finish":
 | 
				
			||||||
 | 
					        return handle_preregistration_pre_finish_hook(request, prereg_object, payload.event.upload)
 | 
				
			||||||
 | 
					    else:  # nocoverage
 | 
				
			||||||
 | 
					        return HttpResponseNotFound()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -674,3 +674,7 @@ CUSTOM_AUTHENTICATION_WRAPPER_FUNCTION: Callable[..., Any] | None = None
 | 
				
			|||||||
# notification to a stream and also delete the previous counter
 | 
					# notification to a stream and also delete the previous counter
 | 
				
			||||||
# notification.
 | 
					# notification.
 | 
				
			||||||
RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS = 60
 | 
					RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS = 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# For realm imports during registration, maximum size of file
 | 
				
			||||||
 | 
					# that can be uploaded.
 | 
				
			||||||
 | 
					MAX_WEB_DATA_IMPORT_SIZE_MB = 1024
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user