registration: Allow UI flow to import org from slack.

This commit is contained in:
Aman Agrawal 2024-11-09 13:03:07 +05:30
parent e1a752c0c1
commit 1f1beb1452
12 changed files with 92 additions and 15 deletions

View File

@ -39,13 +39,6 @@
</div>
</form>
</div>
<div class="bottom-text">
{% trans %}
Or import
from <a href="/help/import-from-slack">Slack</a>, <a href="/help/import-from-mattermost">Mattermost</a>,
or <a href="/help/import-from-rocketchat">Rocket.Chat</a>.
{% endtrans %}
</div>
</div>
</div>
</div>

View File

@ -85,4 +85,26 @@
{% endif %}
</div>
</div>
{% if not user_registration_form %}
<div class="input-box">
<div class="inline-block" id="realm-creation-import-from-wrapper">
<select id="import_from" name="import_from">
{% for key, choice in import_from_choices %}
<option value="{{ key }}" {% if key == "none" %}selected{% endif %}>{{ _(choice) }}</option>
{% endfor %}
</select>
<div class="not-editable-realm-field extra-info-realm-creation-import-from">
{% trans %}
You can also import from
<a href="/help/import-from-mattermost">Mattermost</a> or
<a href="/help/import-from-rocketchat">Rocket.Chat</a>.
{% endtrans %}
</div>
</div>
<label for="import_from" class="inline-block">
{{ _('Import chat history?') }}
</label>
</div>
{% endif %}
</div>

View File

@ -14,7 +14,7 @@
</div>
<div class="white-box">
{% if poll_for_import_completion %}
<input type='hidden' name='key' value='{{ key }}' id="auth_key" />
<input type='hidden' name='key' value='{{ key }}' id="auth_key_for_polling" />
<div class="input-box">
<label for="uploaded-file-info">{{ _("Import progress") }}</label>
<div id="slack-import-poll-status" class="not-editable-realm-field">
@ -25,7 +25,7 @@
<form method="post" class="form-inline" action="{{ url('import_realm_from_slack') }}">
{{ csrf_input }}
<div class="input-box no-validation">
<input type='hidden' name='key' value='{{ key }}' />
<input type='hidden' name='key' value='{{ key }}' id="auth_key_for_file_upload"/>
</div>
<div class="input-box slack-import-extra-info">
<div class="not-editable-realm-field">

View File

@ -348,7 +348,7 @@ $(() => {
});
if ($("#slack-import-drag-and-drop").length > 0) {
const key = $<HTMLInputElement>("#auth_key").val();
const key = $<HTMLInputElement>("#auth_key_for_file_upload").val();
const uppy = new Uppy({
debug: true,
autoProceed: true,
@ -370,6 +370,7 @@ $(() => {
"Drag and drop your Slack export file here, or click to browse.",
}),
},
pluralize: () => 0,
},
});
uppy.use(Tus, {endpoint: "/api/v1/tus/", removeFingerprintOnSuccess: true});
@ -384,7 +385,7 @@ $(() => {
}
if ($("#slack-import-poll-status").length > 0) {
const key = $<HTMLInputElement>("#auth_key").val();
const key = $<HTMLInputElement>("#auth_key_for_polling").val();
const pollInterval = 2000; // Poll every 2 seconds
let poll_id: ReturnType<typeof setTimeout> | undefined;

View File

@ -22,7 +22,7 @@ from zerver.lib.realm_icon import get_realm_icon_url
from zerver.lib.request import RequestNotes
from zerver.lib.send_email import FromAddress
from zerver.lib.subdomains import get_subdomain, is_root_domain_available
from zerver.models import Realm, UserProfile
from zerver.models import PreregistrationRealm, Realm, UserProfile
from zerver.models.realms import get_realm
from zproject.backends import (
AUTH_BACKEND_NAME_MAP,
@ -293,5 +293,6 @@ def get_realm_create_form_context() -> dict[str, Any]:
"MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
"root_domain_available": is_root_domain_available(),
"sorted_realm_types": sorted(Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]),
"import_from_choices": PreregistrationRealm.IMPORT_FROM_CHOICES,
}
return context

View File

@ -32,7 +32,7 @@ from zerver.lib.name_restrictions import is_reserved_subdomain
from zerver.lib.rate_limiter import RateLimitedObject, rate_limit_request_by_ip
from zerver.lib.subdomains import get_subdomain, is_root_domain_available
from zerver.lib.users import check_full_name
from zerver.models import Realm, UserProfile
from zerver.models import PreregistrationRealm, Realm, UserProfile
from zerver.models.realm_audit_logs import RealmAuditLog
from zerver.models.realms import (
DisposableEmailError,
@ -325,6 +325,9 @@ class ImportRealmOwnerSelectionForm(forms.Form):
class RealmCreationForm(RealmDetailsForm):
# This form determines whether users can create a new realm.
email = forms.EmailField(validators=[email_not_system_bot, email_is_not_disposable])
import_from = forms.ChoiceField(
choices=PreregistrationRealm.IMPORT_FROM_CHOICES,
)
def __init__(self, *args: Any, **kwargs: Any) -> None:
kwargs["realm_creation"] = True

View File

@ -896,6 +896,7 @@ Output:
"realm_type": realm_type,
"realm_default_language": realm_default_language,
"realm_subdomain": realm_subdomain,
"import_from": "none",
}
if realm_in_root_domain is not None:
payload["realm_in_root_domain"] = realm_in_root_domain

View File

@ -50,6 +50,10 @@ class PreregistrationRealm(models.Model):
UserProfile, null=True, related_name="+", on_delete=models.SET_NULL
)
IMPORT_FROM_CHOICES = [
("none", "Don't import"),
("slack", "Import from Slack"),
]
data_import_metadata = models.JSONField(default=dict, encoder=DjangoJSONEncoder)

View File

@ -306,6 +306,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
"realm_type": Realm.ORG_TYPES["business"]["id"],
"realm_default_language": "en",
"realm_subdomain": "custom-test",
"import_from": "none",
},
)
self.assertEqual(result.status_code, 302)
@ -334,6 +335,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
"realm_type": Realm.ORG_TYPES["business"]["id"],
"realm_default_language": "en",
"realm_subdomain": string_id,
"import_from": "none",
},
)
self.assertEqual(result.status_code, 302)

View File

@ -145,6 +145,7 @@ def create_preregistration_realm(
string_id: str,
org_type: int,
default_language: str,
import_from: str | None = None,
) -> PreregistrationRealm:
return PreregistrationRealm.objects.create(
email=email,
@ -152,6 +153,7 @@ def create_preregistration_realm(
string_id=string_id,
org_type=org_type,
default_language=default_language,
data_import_metadata={"import_from": import_from},
)

View File

@ -157,6 +157,10 @@ def get_prereg_key_and_redirect(
registration_url = reverse("accounts_register")
if realm_creation:
assert isinstance(prereg_object, PreregistrationRealm)
if prereg_object.data_import_metadata.get("import_from") == "slack":
registration_url = reverse("import_realm_from_slack")
else:
registration_url = reverse("realm_register")
return render(
@ -235,6 +239,11 @@ def accounts_register(*args: Any, **kwargs: Any) -> HttpResponse:
return registration_helper(*args, **kwargs)
@require_post
def import_realm_from_slack(*args: Any, **kwargs: Any) -> HttpResponse:
return registration_helper(*args, **kwargs)
@typed_endpoint
def registration_helper(
request: HttpRequest,
@ -298,6 +307,35 @@ def registration_helper(
"key": key,
},
)
elif prereg_realm.data_import_metadata.get("import_from") == "slack":
context: dict[str, Any] = {
"key": key,
}
saved_slack_access_token = prereg_realm.data_import_metadata.get("slack_access_token")
if saved_slack_access_token or slack_access_token:
if slack_access_token and slack_access_token != saved_slack_access_token:
# Verify slack token access.
from zerver.data_import.slack import check_token_access
check_token_access(slack_access_token)
saved_slack_access_token = slack_access_token
prereg_realm.data_import_metadata["slack_access_token"] = slack_access_token
prereg_realm.save(update_fields=["data_import_metadata"])
context["slack_access_token"] = saved_slack_access_token
context["uploaded_import_file_name"] = prereg_realm.data_import_metadata.get(
"uploaded_import_file_name"
)
return TemplateResponse(
request,
"zerver/slack_import.html",
context,
)
password_required = True
role = UserProfile.ROLE_REALM_OWNER
else:
@ -874,9 +912,15 @@ def prepare_realm_activation_url(
string_id: str,
org_type: int,
default_language: str,
import_form: str,
) -> str:
prereg_realm = create_preregistration_realm(
email, realm_name, string_id, org_type, default_language
email,
realm_name,
string_id,
org_type,
default_language,
import_form,
)
activation_url = create_confirmation_link(
prereg_realm, Confirmation.REALM_CREATION, no_associated_realm_object=True
@ -1092,6 +1136,7 @@ def create_realm(request: HttpRequest, creation_key: str | None = None) -> HttpR
realm_type = form.cleaned_data["realm_type"]
realm_default_language = form.cleaned_data["realm_default_language"]
realm_subdomain = form.cleaned_data["realm_subdomain"]
import_from = form.cleaned_data["import_from"]
activation_url = prepare_realm_activation_url(
email,
request.session,
@ -1099,6 +1144,7 @@ def create_realm(request: HttpRequest, creation_key: str | None = None) -> HttpR
realm_subdomain,
realm_type,
realm_default_language,
import_from,
)
if key_record is not None and key_record.presume_email_valid:
# The user has a token created from the server command line;

View File

@ -142,6 +142,7 @@ from zerver.views.registration import (
create_realm,
find_account,
get_prereg_key_and_redirect,
import_realm_from_slack,
new_realm_send_confirm,
realm_import_post_process,
realm_import_status,
@ -604,6 +605,7 @@ i18n_urls = [
realm_import_post_process,
name="realm_import_post_process",
),
path("new/import/slack/", import_realm_from_slack, name="import_realm_from_slack"),
path(
"accounts/do_confirm/<confirmation_key>",
get_prereg_key_and_redirect,