mirror of https://github.com/zulip/zulip.git
registration: Collect organization type on sign-up.
This commit is contained in:
parent
43f3f9221d
commit
faa695e86d
|
@ -400,7 +400,8 @@ html {
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="password"] {
|
input[type="password"],
|
||||||
|
select {
|
||||||
padding: 10px 32px 10px 12px;
|
padding: 10px 32px 10px 12px;
|
||||||
margin: 25px 0 5px;
|
margin: 25px 0 5px;
|
||||||
|
|
||||||
|
@ -458,9 +459,11 @@ html {
|
||||||
input[type="text"]:focus + label,
|
input[type="text"]:focus + label,
|
||||||
input[type="email"]:focus + label,
|
input[type="email"]:focus + label,
|
||||||
input[type="password"]:focus + label,
|
input[type="password"]:focus + label,
|
||||||
|
select:focus + label,
|
||||||
input[type="text"]:valid + label,
|
input[type="text"]:valid + label,
|
||||||
input[type="email"]:valid + label,
|
input[type="email"]:valid + label,
|
||||||
input[type="password"]:valid + label {
|
input[type="password"]:valid + label,
|
||||||
|
select:valid + label {
|
||||||
left: 0;
|
left: 0;
|
||||||
transform: translateY(0) translateX(0);
|
transform: translateY(0) translateX(0);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
@ -470,6 +473,12 @@ html {
|
||||||
color: hsl(0, 0%, 27%);
|
color: hsl(0, 0%, 27%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The width of the "Organization name" text box
|
||||||
|
right above this one is also 326px. */
|
||||||
|
select {
|
||||||
|
width: 326px;
|
||||||
|
}
|
||||||
|
|
||||||
p.text-error {
|
p.text-error {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -47,6 +47,20 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="input-box">
|
||||||
|
<div class="inline-block relative">
|
||||||
|
<select name="realm_type" id="realm_type">
|
||||||
|
{% for realm_type in sorted_realm_types %}
|
||||||
|
{% if not realm_type.hidden %}
|
||||||
|
<option value="{{ realm_type.id }}">{{ _(realm_type.name) }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<label class="static org-url">
|
<label class="static org-url">
|
||||||
{{ _('Organization URL') }}
|
{{ _('Organization URL') }}
|
||||||
|
|
|
@ -114,6 +114,7 @@ class RegistrationForm(forms.Form):
|
||||||
# actually required for a realm
|
# actually required for a realm
|
||||||
password = forms.CharField(widget=forms.PasswordInput, max_length=MAX_PASSWORD_LENGTH)
|
password = forms.CharField(widget=forms.PasswordInput, max_length=MAX_PASSWORD_LENGTH)
|
||||||
realm_subdomain = forms.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH, required=False)
|
realm_subdomain = forms.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH, required=False)
|
||||||
|
realm_type = forms.IntegerField(required=False)
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
# Since the superclass doesn't except random extra kwargs, we
|
# Since the superclass doesn't except random extra kwargs, we
|
||||||
|
|
|
@ -627,6 +627,7 @@ Output:
|
||||||
default_stream_groups: Sequence[str] = [],
|
default_stream_groups: Sequence[str] = [],
|
||||||
source_realm_id: str = "",
|
source_realm_id: str = "",
|
||||||
key: Optional[str] = None,
|
key: Optional[str] = None,
|
||||||
|
realm_type: Optional[int] = Realm.ORG_TYPES["business"]["id"],
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
"""
|
"""
|
||||||
|
@ -643,6 +644,7 @@ Output:
|
||||||
"full_name": full_name,
|
"full_name": full_name,
|
||||||
"realm_name": realm_name,
|
"realm_name": realm_name,
|
||||||
"realm_subdomain": realm_subdomain,
|
"realm_subdomain": realm_subdomain,
|
||||||
|
"realm_type": realm_type,
|
||||||
"key": key if key is not None else find_key_by_email(email),
|
"key": key if key is not None else find_key_by_email(email),
|
||||||
"timezone": timezone,
|
"timezone": timezone,
|
||||||
"terms": True,
|
"terms": True,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Generated by Django 3.2.4 on 2021-07-06 20:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
|
||||||
|
|
||||||
|
def reset_realm_org_type(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||||
|
UNSPECIFIED = 0
|
||||||
|
Realm = apps.get_model("zerver", "Realm")
|
||||||
|
Realm.objects.all().update(org_type=UNSPECIFIED)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0332_realmuserdefault"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="realm",
|
||||||
|
name="org_type",
|
||||||
|
field=models.PositiveSmallIntegerField(
|
||||||
|
choices=[
|
||||||
|
(0, "Unspecified"),
|
||||||
|
(10, "Business"),
|
||||||
|
(20, "Open-source project"),
|
||||||
|
(30, "Education"),
|
||||||
|
(40, "Research"),
|
||||||
|
(50, "Event or conference"),
|
||||||
|
(60, "Non-profit (registered)"),
|
||||||
|
(70, "Government"),
|
||||||
|
(80, "Political group"),
|
||||||
|
(90, "Community"),
|
||||||
|
(100, "Personal"),
|
||||||
|
(1000, "Other"),
|
||||||
|
],
|
||||||
|
default=0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
reset_realm_org_type, reverse_code=migrations.RunPython.noop, elidable=True
|
||||||
|
),
|
||||||
|
]
|
|
@ -404,10 +404,86 @@ class Realm(models.Model):
|
||||||
# Messages older than this message ID in the organization are inaccessible.
|
# Messages older than this message ID in the organization are inaccessible.
|
||||||
first_visible_message_id: int = models.IntegerField(default=0)
|
first_visible_message_id: int = models.IntegerField(default=0)
|
||||||
|
|
||||||
# Valid org_types are {CORPORATE, COMMUNITY}
|
# Valid org types
|
||||||
CORPORATE = 1
|
ORG_TYPES: Dict[str, Dict[str, Any]] = {
|
||||||
COMMUNITY = 2
|
"unspecified": {
|
||||||
org_type: int = models.PositiveSmallIntegerField(default=CORPORATE)
|
"name": "Unspecified",
|
||||||
|
"id": 0,
|
||||||
|
"hidden": True,
|
||||||
|
"display_order": 0,
|
||||||
|
},
|
||||||
|
"business": {
|
||||||
|
"name": "Business",
|
||||||
|
"id": 10,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 1,
|
||||||
|
},
|
||||||
|
"opensource": {
|
||||||
|
"name": "Open-source project",
|
||||||
|
"id": 20,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 2,
|
||||||
|
},
|
||||||
|
"education": {
|
||||||
|
"name": "Education",
|
||||||
|
"id": 30,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 3,
|
||||||
|
},
|
||||||
|
"research": {
|
||||||
|
"name": "Research",
|
||||||
|
"id": 40,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 4,
|
||||||
|
},
|
||||||
|
"event": {
|
||||||
|
"name": "Event or conference",
|
||||||
|
"id": 50,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 5,
|
||||||
|
},
|
||||||
|
"nonprofit": {
|
||||||
|
"name": "Non-profit (registered)",
|
||||||
|
"id": 60,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 6,
|
||||||
|
},
|
||||||
|
"government": {
|
||||||
|
"name": "Government",
|
||||||
|
"id": 70,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 7,
|
||||||
|
},
|
||||||
|
"political_group": {
|
||||||
|
"name": "Political group",
|
||||||
|
"id": 80,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 8,
|
||||||
|
},
|
||||||
|
"community": {
|
||||||
|
"name": "Community",
|
||||||
|
"id": 90,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 9,
|
||||||
|
},
|
||||||
|
"personal": {
|
||||||
|
"name": "Personal",
|
||||||
|
"id": 100,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 100,
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"name": "Other",
|
||||||
|
"id": 1000,
|
||||||
|
"hidden": False,
|
||||||
|
"display_order": 1000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
org_type: int = models.PositiveSmallIntegerField(
|
||||||
|
default=ORG_TYPES["unspecified"]["id"],
|
||||||
|
choices=[(t["id"], t["name"]) for t in ORG_TYPES.values()],
|
||||||
|
)
|
||||||
|
|
||||||
UPGRADE_TEXT_STANDARD = gettext_lazy("Available on Zulip Standard. Upgrade to access.")
|
UPGRADE_TEXT_STANDARD = gettext_lazy("Available on Zulip Standard. Upgrade to access.")
|
||||||
# plan_type controls various features around resource/feature
|
# plan_type controls various features around resource/feature
|
||||||
|
|
|
@ -660,7 +660,7 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(realm.description, "")
|
self.assertEqual(realm.description, "")
|
||||||
self.assertTrue(realm.invite_required)
|
self.assertTrue(realm.invite_required)
|
||||||
self.assertEqual(realm.plan_type, Realm.LIMITED)
|
self.assertEqual(realm.plan_type, Realm.LIMITED)
|
||||||
self.assertEqual(realm.org_type, Realm.CORPORATE)
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["unspecified"]["id"])
|
||||||
self.assertEqual(type(realm.date_created), datetime.datetime)
|
self.assertEqual(type(realm.date_created), datetime.datetime)
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
|
@ -690,7 +690,7 @@ class RealmTest(ZulipTestCase):
|
||||||
description="realm description",
|
description="realm description",
|
||||||
invite_required=False,
|
invite_required=False,
|
||||||
plan_type=Realm.STANDARD_FREE,
|
plan_type=Realm.STANDARD_FREE,
|
||||||
org_type=Realm.COMMUNITY,
|
org_type=Realm.ORG_TYPES["community"]["id"],
|
||||||
)
|
)
|
||||||
self.assertEqual(realm.string_id, "realm_string_id")
|
self.assertEqual(realm.string_id, "realm_string_id")
|
||||||
self.assertEqual(realm.name, "realm name")
|
self.assertEqual(realm.name, "realm name")
|
||||||
|
@ -699,7 +699,7 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(realm.description, "realm description")
|
self.assertEqual(realm.description, "realm description")
|
||||||
self.assertFalse(realm.invite_required)
|
self.assertFalse(realm.invite_required)
|
||||||
self.assertEqual(realm.plan_type, Realm.STANDARD_FREE)
|
self.assertEqual(realm.plan_type, Realm.STANDARD_FREE)
|
||||||
self.assertEqual(realm.org_type, Realm.COMMUNITY)
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["community"]["id"])
|
||||||
self.assertEqual(realm.date_created, date_created)
|
self.assertEqual(realm.date_created, date_created)
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
|
|
|
@ -2869,7 +2869,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(user.role, UserProfile.ROLE_REALM_OWNER)
|
self.assertEqual(user.role, UserProfile.ROLE_REALM_OWNER)
|
||||||
|
|
||||||
# Check defaults
|
# Check defaults
|
||||||
self.assertEqual(realm.org_type, Realm.CORPORATE)
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
||||||
self.assertEqual(realm.emails_restricted_to_domains, False)
|
self.assertEqual(realm.emails_restricted_to_domains, False)
|
||||||
self.assertEqual(realm.invite_required, True)
|
self.assertEqual(realm.invite_required, True)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||||
from confirmation.models import Confirmation, create_confirmation_link
|
from confirmation.models import Confirmation, create_confirmation_link
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
from zerver.lib.subdomains import get_subdomain
|
from zerver.lib.subdomains import get_subdomain
|
||||||
from zerver.models import UserProfile
|
from zerver.models import Realm, UserProfile
|
||||||
from zerver.views.auth import create_preregistration_user
|
from zerver.views.auth import create_preregistration_user
|
||||||
from zerver.views.registration import accounts_register
|
from zerver.views.registration import accounts_register
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ def register_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
name = f"user-{count}"
|
name = f"user-{count}"
|
||||||
email = f"{name}@zulip.com"
|
email = f"{name}@zulip.com"
|
||||||
realm_name = f"realm-{count}"
|
realm_name = f"realm-{count}"
|
||||||
|
realm_type = Realm.ORG_TYPES["business"]["id"]
|
||||||
prereg = create_preregistration_user(
|
prereg = create_preregistration_user(
|
||||||
email, request, realm_creation=True, password_required=False
|
email, request, realm_creation=True, password_required=False
|
||||||
)
|
)
|
||||||
|
@ -58,6 +59,7 @@ def register_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
request,
|
request,
|
||||||
key=key,
|
key=key,
|
||||||
realm_name=realm_name,
|
realm_name=realm_name,
|
||||||
|
realm_type=realm_type,
|
||||||
full_name=name,
|
full_name=name,
|
||||||
password="test",
|
password="test",
|
||||||
realm_subdomain=realm_name,
|
realm_subdomain=realm_name,
|
||||||
|
|
|
@ -308,7 +308,8 @@ def accounts_register(request: HttpRequest) -> HttpResponse:
|
||||||
if realm_creation:
|
if realm_creation:
|
||||||
string_id = form.cleaned_data["realm_subdomain"]
|
string_id = form.cleaned_data["realm_subdomain"]
|
||||||
realm_name = form.cleaned_data["realm_name"]
|
realm_name = form.cleaned_data["realm_name"]
|
||||||
realm = do_create_realm(string_id, realm_name)
|
realm_type = form.cleaned_data["realm_type"]
|
||||||
|
realm = do_create_realm(string_id, realm_name, org_type=realm_type)
|
||||||
setup_realm_internal_bots(realm)
|
setup_realm_internal_bots(realm)
|
||||||
assert realm is not None
|
assert realm is not None
|
||||||
|
|
||||||
|
@ -484,6 +485,9 @@ def accounts_register(request: HttpRequest) -> HttpResponse:
|
||||||
"MAX_NAME_LENGTH": str(UserProfile.MAX_NAME_LENGTH),
|
"MAX_NAME_LENGTH": str(UserProfile.MAX_NAME_LENGTH),
|
||||||
"MAX_PASSWORD_LENGTH": str(form.MAX_PASSWORD_LENGTH),
|
"MAX_PASSWORD_LENGTH": str(form.MAX_PASSWORD_LENGTH),
|
||||||
"MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
|
"MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
|
||||||
|
"sorted_realm_types": sorted(
|
||||||
|
Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]
|
||||||
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ class Command(BaseCommand):
|
||||||
" It's great for testing!",
|
" It's great for testing!",
|
||||||
invite_required=False,
|
invite_required=False,
|
||||||
plan_type=Realm.SELF_HOSTED,
|
plan_type=Realm.SELF_HOSTED,
|
||||||
org_type=Realm.CORPORATE,
|
org_type=Realm.ORG_TYPES["business"]["id"],
|
||||||
)
|
)
|
||||||
RealmDomain.objects.create(realm=zulip_realm, domain="zulip.com")
|
RealmDomain.objects.create(realm=zulip_realm, domain="zulip.com")
|
||||||
assert zulip_realm.notifications_stream is not None
|
assert zulip_realm.notifications_stream is not None
|
||||||
|
@ -327,7 +327,7 @@ class Command(BaseCommand):
|
||||||
emails_restricted_to_domains=True,
|
emails_restricted_to_domains=True,
|
||||||
invite_required=False,
|
invite_required=False,
|
||||||
plan_type=Realm.SELF_HOSTED,
|
plan_type=Realm.SELF_HOSTED,
|
||||||
org_type=Realm.CORPORATE,
|
org_type=Realm.ORG_TYPES["business"]["id"],
|
||||||
)
|
)
|
||||||
RealmDomain.objects.create(realm=mit_realm, domain="mit.edu")
|
RealmDomain.objects.create(realm=mit_realm, domain="mit.edu")
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ class Command(BaseCommand):
|
||||||
emails_restricted_to_domains=False,
|
emails_restricted_to_domains=False,
|
||||||
invite_required=False,
|
invite_required=False,
|
||||||
plan_type=Realm.SELF_HOSTED,
|
plan_type=Realm.SELF_HOSTED,
|
||||||
org_type=Realm.CORPORATE,
|
org_type=Realm.ORG_TYPES["business"]["id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Default to allowing all members to send mentions in
|
# Default to allowing all members to send mentions in
|
||||||
|
|
Loading…
Reference in New Issue