registration: Collect organization type on sign-up.

This commit is contained in:
Eeshan Garg 2021-06-24 15:35:06 -02:30 committed by Tim Abbott
parent 43f3f9221d
commit faa695e86d
11 changed files with 168 additions and 15 deletions

View File

@ -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;

View File

@ -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') }}

View File

@ -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

View File

@ -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,

View File

@ -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
),
]

View File

@ -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

View File

@ -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(

View File

@ -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)

View File

@ -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,

View File

@ -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"]
),
}, },
) )

View File

@ -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