mirror of https://github.com/zulip/zulip.git
Add new organization type field to Realm objects.
Adds a new field org_type to Realm. Defaults for restricted_to_domain and invite_required are now controlled by org_type at time of realm creation (see zerver.lib.actions.do_create_realm), rather than at the database level. Note that the backend defaults are all org_type=corporate, since that matches the current assumptions in the codebase, whereas the frontend default is org_type=community, since if a user isn't sure they probably want community. Since we will likely in the future enable/disable various administrative features based on whether an organization is corporate or community, we discuss those issues in the realm creation form. Before we actually implement any such features, we'll want to make sure users understand what type of organization they are a member of. Choice of org_type (via radio button) has been added to the realm creation flow and the realm creation management command, and the open-realm option removed. The database defaults have not been changed, which allows our testing code to work unchanged. [includes some HTML/CSS work by Brock Whittaker to make it look nice]
This commit is contained in:
parent
dbeab6aa6f
commit
777fcaa6a0
|
@ -141,12 +141,16 @@ administrator for your new Zulip organization. After getting
|
|||
oriented, we recommend visiting the special "Administration" tab
|
||||
linked to from the upper-right gear menu in the Zulip app to configure
|
||||
important policy settings like how users can join your new
|
||||
organization. By default, your organization will be configured as
|
||||
follows ([screenshot here](_images/zulip-admin-settings.png)):
|
||||
organization. By default, your organization will be configured as
|
||||
follows depending on what type of organization you selected:
|
||||
|
||||
* `restricted_to_domain=True`: Only people with emails with the same ending as yours can join.
|
||||
* `invite_required=False`: An invitation is not required to join the realm.
|
||||
* `invite_by_admin_only=False`: You don't need to be an admin user to invite other users.
|
||||
Community Organization:
|
||||
* `restricted_to_domain=False`: No restriction on user email addresses.
|
||||
* `invite_required=True`: A user must be invited to join.
|
||||
|
||||
Corporate Organization:
|
||||
* `restricted_to_domain=True`: New users must have an email address in the same domain (e.g. @acme.com) as yours.
|
||||
* `invite_required=False`: No invitation is required to join.
|
||||
|
||||
Next, you'll likely want to do one of the following:
|
||||
|
||||
|
|
|
@ -47,9 +47,11 @@ casper.then(function () {
|
|||
this.test.assertSelectorContains('.pitch', "You're almost there.");
|
||||
});
|
||||
|
||||
this.test.assertEvalEquals(function () {
|
||||
return $('.controls.fakecontrol input[type=text]').attr('placeholder');
|
||||
}, email);
|
||||
this.waitForSelector('#id_email', function () {
|
||||
this.test.assertEvalEquals(function () {
|
||||
return $('#id_email').attr('placeholder');
|
||||
}, email);
|
||||
});
|
||||
|
||||
this.waitForSelector('label[for=id_team_name]', function () {
|
||||
this.test.assertSelectorHasText('label[for=id_team_name]', 'Organization name');
|
||||
|
@ -87,9 +89,12 @@ casper.then(function () {
|
|||
this.test.assertSelectorHasText('.app-main.portico-page-container', "You're the first one here!");
|
||||
});
|
||||
|
||||
this.waitForSelector('.invite_row', function () {
|
||||
this.test.assertSelectorHasText('.invite_row', domain);
|
||||
});
|
||||
// Getting rid of the invite page in the onboarding flow, so getting rid
|
||||
// of this currently failing test. The test is implicitly expecting a
|
||||
// realm created with restricted_to_domain=True, but we changed the
|
||||
// default when introducting org_type
|
||||
// this.waitForSelector('.invite_row', function () {
|
||||
// this.test.assertSelectorHasText('.invite_row', domain); });
|
||||
|
||||
this.waitForSelector('#submit_invitation', function () {
|
||||
this.click('#submit_invitation');
|
||||
|
|
|
@ -79,6 +79,36 @@ li {
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.help-box {
|
||||
width: 500px;
|
||||
|
||||
padding: 10px;
|
||||
margin: 10px 0px;
|
||||
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
|
||||
color: #444;
|
||||
|
||||
border-width: order: 1px solid #CCC;
|
||||
border-radius: 4px;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.help-box .blob {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.help-inline {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#company-email {
|
||||
display: none;
|
||||
}
|
||||
|
@ -904,6 +934,10 @@ a.bottom-signup-button {
|
|||
width: auto;
|
||||
}
|
||||
|
||||
.input-group.margin {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.password-reset .input-group {
|
||||
margin: 15px 0px;
|
||||
}
|
||||
|
@ -936,7 +970,7 @@ a.bottom-signup-button {
|
|||
|
||||
.center-container {
|
||||
height: calc(100vh - 94px);
|
||||
min-height: 500px;
|
||||
min-height: 700px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
-wekbit-box-align: center;
|
||||
|
@ -1148,3 +1182,101 @@ a.bottom-signup-button {
|
|||
width: 25px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
/* --- new settings styling --- */
|
||||
.input-group input[type=radio],
|
||||
.input-group input[type=checkbox] {
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.input-group input[type=radio] {
|
||||
position: relative;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
margin: 0;
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
.m-v-20 {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
|
||||
.input-group.radio {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.input-group.grid label.inline-block {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.input-group.grid {
|
||||
padding: 10px 0px;
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
||||
label.label-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.input-group label.inline-block {
|
||||
/* eyeballing off-centered aesth. */
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.button-new {
|
||||
padding: 8px 15px;
|
||||
margin: 0;
|
||||
min-width: 130px;
|
||||
|
||||
font-weight: 400;
|
||||
|
||||
background-color: #478fca;
|
||||
color: #FFF;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* -- button states -- */
|
||||
.button-new:hover {
|
||||
-webkit-filter: brightness(1.1);
|
||||
-moz-filter: brightness(1.1);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
.button-new:active {
|
||||
-webkit-filter: brightness(0.9);
|
||||
-moz-filter: brightness(0.9);
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
|
||||
.button-new.sea-green {
|
||||
background-color: #24cac2;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
|
|
@ -19,52 +19,46 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
|||
<h1>You're almost there.</h1>
|
||||
<p>
|
||||
We just need you to do one last thing.
|
||||
<br />
|
||||
Tell us a bit about yourself.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post" class="form-horizontal" id="registration" action="{{ url('zerver.views.accounts_register') }}">
|
||||
{{ csrf_input }}
|
||||
<div class="control-group">
|
||||
<label for="id_email" class="control-label">{{ _('Email') }}</label>
|
||||
<div class="controls fakecontrol">
|
||||
<input type='hidden' name='key' value='{{ key }}' />
|
||||
<input type='text' disabled="true" placeholder="{{ email }}" />
|
||||
</div>
|
||||
<div class="input-group grid">
|
||||
<label for="id_email" class="inline-block label-title">{{ _('Email') }}</label>
|
||||
<input type='hidden' name='key' value='{{ key }}' />
|
||||
<input id="id_email" type='text' disabled="true" placeholder="{{ email }}" />
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label for="id_full_name" class="control-label">{{ _('Full name') }}</label>
|
||||
<div class="controls">
|
||||
{% if lock_name %}
|
||||
<p class="fakecontrol">{{ full_name }}</p>
|
||||
{% else %}
|
||||
<input id="id_full_name" class="required" type="text" name="full_name"
|
||||
value="{% if full_name %}{{ full_name }}{% elif form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
|
||||
maxlength="100" />
|
||||
{% if form.full_name.errors %}
|
||||
{% for error in form.full_name.errors %}
|
||||
<div class="alert alert-error">{{ error }}</div>
|
||||
<div class="input-group grid">
|
||||
<label for="id_full_name" class="inline-block label-title">{{ _('Full name') }}</label>
|
||||
{% if lock_name %}
|
||||
<p class="fakecontrol">{{ full_name }}</p>
|
||||
{% else %}
|
||||
<input id="id_full_name" class="required" type="text" name="full_name" placeholder='{{ "John Doe" }}'
|
||||
value="{% if full_name %}{{ full_name }}{% elif form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
|
||||
maxlength="100" />
|
||||
{% if form.full_name.errors %}
|
||||
{% for error in form.full_name.errors %}
|
||||
<div class="alert alert-error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if creating_new_team %}
|
||||
<div class="input-group grid">
|
||||
<label for="id_team_name" class="inline-block label-title">{{ _('Organization name') }}</label>
|
||||
<input id="id_team_name" class="required" type="text"
|
||||
placeholder="{{ _("E.g. Acme") }}"
|
||||
name="realm_name" maxlength="100" />
|
||||
{% if form.realm_name.errors %}
|
||||
{% for error in form.realm_name.errors %}
|
||||
<div class="alert alert-error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if creating_new_team %}
|
||||
<div class="control-group">
|
||||
<label for="id_team_name" class="control-label">{{ _('Organization name') }}</label>
|
||||
<div class="controls">
|
||||
<input id="id_team_name" class="required" type="text"
|
||||
placeholder="{{ _("E.g. Acme") }}"
|
||||
name="realm_name" maxlength="100" />
|
||||
{% if form.realm_name.errors %}
|
||||
{% for error in form.realm_name.errors %}
|
||||
<div class="alert alert-error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<br /><span class="small">{{ _('You can change this later on the admin page.') }}</span>
|
||||
<div class="help-box">
|
||||
This can be changed later on the settings page.
|
||||
</div>
|
||||
</div>
|
||||
{% if realms_have_subdomains %}
|
||||
|
@ -84,11 +78,48 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
<div class="m-v-20">
|
||||
<label for="id_org_type" class="label-title">{{ _('Organization Type') }}</label>
|
||||
|
||||
{% for org_type_value, org_type_text in form.realm_org_type.field.choices %}
|
||||
<div class="input-group radio">
|
||||
<input id="id_radio_{{ org_type_value }}" class="required inline-block" type="radio"
|
||||
name="realm_org_type" value="{{ org_type_value }}"
|
||||
{% if org_type_value == form.realm_org_type.value() %} checked {% endif %} />
|
||||
<label for="id_radio_{{ org_type_value }}" class="inline-block">{{ org_type_text }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="m-v-20">
|
||||
<div class="help-box">
|
||||
<div id="org_type_blob_1" class="blob display-none">
|
||||
Create a corporate organization if your users will
|
||||
be members of the same company, where the privacy
|
||||
expectation is that the company's organization
|
||||
administrators may need to have access to your
|
||||
users' private message history. Zulip features that
|
||||
allow organization administrators to take control of
|
||||
accounts or access private message history for other
|
||||
users are only available to corporate organizations.
|
||||
</div>
|
||||
<div id="org_type_blob_2" class="blob">
|
||||
Create a community organization for an open source
|
||||
project, social group, or other community where the
|
||||
privacy expectation is that you and other
|
||||
organization administrators won't have access to
|
||||
your users' private message history. Zulip features
|
||||
that allow organization administrators to take
|
||||
control of accounts or access private message
|
||||
history for other users are disabled in community
|
||||
organizations.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if password_auth_enabled %}
|
||||
<div class="control-group">
|
||||
<label for="id_password" class="control-label">{{ _('Password') }}</label>
|
||||
<div class="input-group">
|
||||
<label for="id_password" class="inline-block">{{ _('Password') }}</label>
|
||||
<div class="controls">
|
||||
<input id="id_password" class="required" type="password" name="password"
|
||||
value="{% if form.password.value() %}{{ form.password.value() }}{% endif %}"
|
||||
|
@ -103,31 +134,29 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Password strength') }}</label>
|
||||
<div class="controls">
|
||||
<div class="progress" id="pw_strength">
|
||||
<div class="bar bar-danger" style="width: 10%;"></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label class="inline-block">{{ _('Password strength') }}</label>
|
||||
<div class="progress" id="pw_strength">
|
||||
<div class="bar bar-danger" style="width: 10%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if terms_of_service %}
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
{#
|
||||
This is somewhat subtle.
|
||||
Checkboxes have a name and value, and when the checkbox is ticked, the form posts
|
||||
with name=value. If the checkbox is unticked, the field just isn't present at all.
|
||||
<div class="input-group margin">
|
||||
{% if terms_of_service %}
|
||||
<div class="float-left">
|
||||
{#
|
||||
This is somewhat subtle.
|
||||
Checkboxes have a name and value, and when the checkbox is ticked, the form posts
|
||||
with name=value. If the checkbox is unticked, the field just isn't present at all.
|
||||
|
||||
This is distinct from 'checked', which determines whether the checkbox appears
|
||||
at all. (So, it's not symmetric to the code above.)
|
||||
#}
|
||||
<input id="id_terms" class="required" type="checkbox" name="terms"
|
||||
{% if form.terms.value() %}checked="checked"{% endif %} />
|
||||
This is distinct from 'checked', which determines whether the checkbox appears
|
||||
at all. (So, it's not symmetric to the code above.)
|
||||
#}
|
||||
<input id="id_terms" class="required" type="checkbox" name="terms"
|
||||
{% if form.terms.value() %}checked="checked"{% endif %} />
|
||||
<label for="id_terms" class="inline-block">
|
||||
{{ _('I agree to the') }} <a href="{{ server_uri }}/terms" target="_blank">{{ _('Terms of Service') }}</a>.
|
||||
</label>
|
||||
{% if form.terms.errors %}
|
||||
|
@ -136,11 +165,9 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="submit-button-box">
|
||||
<div class="controls">
|
||||
<input type="submit" class="button btn btn-large btn-primary" value="Register" /><br />
|
||||
{% endif %}
|
||||
<div class="submit-button-box float-right">
|
||||
<input type="submit" class="button-new sea-green" value="Register" /><br />
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -154,6 +181,11 @@ if ($('#id_email:visible').length) {
|
|||
} else if ($('#id_full_name:visible').length) {
|
||||
autofocus('#id_full_name');
|
||||
}
|
||||
|
||||
$("[name=realm_org_type]").on("change", function () {
|
||||
$(".blob").hide();
|
||||
$("#org_type_blob_" + this.value).show();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -84,6 +84,10 @@ class RegistrationForm(forms.Form):
|
|||
required=False)
|
||||
realm_name = forms.CharField(max_length=100, required=False)
|
||||
realm_subdomain = forms.CharField(max_length=40, required=False)
|
||||
realm_org_type = forms.ChoiceField(((Realm.COMMUNITY, 'Community'),
|
||||
(Realm.CORPORATE, 'Corporate')), \
|
||||
initial=Realm.COMMUNITY, required=False)
|
||||
|
||||
if settings.TERMS_OF_SERVICE:
|
||||
terms = forms.BooleanField(required=True)
|
||||
|
||||
|
|
|
@ -1942,13 +1942,35 @@ def do_change_stream_description(realm, stream_name, new_description):
|
|||
value=new_description)
|
||||
send_event(event, stream_user_ids(stream))
|
||||
|
||||
def do_create_realm(domain, name, restricted_to_domain=True, subdomain=None):
|
||||
# type: (text_type, text_type, bool, Optional[text_type]) -> Tuple[Realm, bool]
|
||||
def get_realm_creation_defaults(org_type=None, restricted_to_domain=None, invite_required=None):
|
||||
# type: (Optional[int], Optional[bool], Optional[bool]) -> Dict[text_type, Any]
|
||||
if org_type is None:
|
||||
org_type = Realm.CORPORATE
|
||||
# not totally clear what the defaults should be if exactly one of
|
||||
# restricted_to_domain or invite_required are set. Just doing the
|
||||
# least complicated thing that works when both are unset.
|
||||
if restricted_to_domain is None:
|
||||
restricted_to_domain = (org_type == Realm.CORPORATE)
|
||||
if invite_required is None:
|
||||
invite_required = not (org_type == Realm.CORPORATE)
|
||||
return {'org_type': org_type,
|
||||
'restricted_to_domain': restricted_to_domain,
|
||||
'invite_required': invite_required}
|
||||
|
||||
def do_create_realm(domain, name, subdomain=None, restricted_to_domain=None,
|
||||
invite_required=None, org_type=None):
|
||||
# type: (text_type, text_type, Optional[text_type], Optional[bool], Optional[bool], Optional[int]) -> Tuple[Realm, bool]
|
||||
realm = get_realm(domain)
|
||||
created = not realm
|
||||
if created:
|
||||
realm = Realm(domain=domain, name=name, subdomain=subdomain,
|
||||
restricted_to_domain=restricted_to_domain)
|
||||
realm_params = get_realm_creation_defaults(org_type=org_type,
|
||||
restricted_to_domain=restricted_to_domain,
|
||||
invite_required=invite_required)
|
||||
org_type = realm_params['org_type']
|
||||
restricted_to_domain = realm_params['restricted_to_domain']
|
||||
invite_required = realm_params['invite_required']
|
||||
realm = Realm(domain=domain, name=name, org_type=org_type, subdomain=subdomain,
|
||||
restricted_to_domain=restricted_to_domain, invite_required=invite_required)
|
||||
realm.save()
|
||||
|
||||
# Create stream once Realm object has been saved
|
||||
|
@ -1970,7 +1992,9 @@ system-generated notifications.""" % (product_name, notifications_stream.name,)
|
|||
# Log the event
|
||||
log_event({"type": "realm_created",
|
||||
"domain": domain,
|
||||
"restricted_to_domain": restricted_to_domain})
|
||||
"restricted_to_domain": restricted_to_domain,
|
||||
"invite_required": invite_required,
|
||||
"org_type": org_type})
|
||||
|
||||
if settings.NEW_USER_BOT is not None:
|
||||
signup_message = "Signups enabled"
|
||||
|
|
|
@ -385,8 +385,9 @@ class ZulipTestCase(TestCase):
|
|||
return self.submit_reg_form_for_user(username, password, domain=domain)
|
||||
|
||||
def submit_reg_form_for_user(self, username, password, domain="zulip.com",
|
||||
realm_name=None, realm_subdomain=None, **kwargs):
|
||||
# type: (text_type, text_type, text_type, Optional[text_type], Optional[text_type], **Any) -> HttpResponse
|
||||
realm_name=None, realm_subdomain=None,
|
||||
realm_org_type=Realm.COMMUNITY, **kwargs):
|
||||
# type: (text_type, text_type, text_type, Optional[text_type], Optional[text_type], int, **Any) -> HttpResponse
|
||||
"""
|
||||
Stage two of the two-step registration process.
|
||||
|
||||
|
@ -400,6 +401,7 @@ class ZulipTestCase(TestCase):
|
|||
'realm_name': realm_name,
|
||||
'realm_subdomain': realm_subdomain,
|
||||
'key': find_key_by_email(username + '@' + domain),
|
||||
'realm_org_type': realm_org_type,
|
||||
'terms': True},
|
||||
**kwargs)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from typing import Any
|
|||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from zerver.lib.actions import do_create_realm, set_default_streams
|
||||
from zerver.lib.actions import Realm, do_create_realm, set_default_streams, get_realm_creation_defaults
|
||||
from zerver.models import RealmAlias
|
||||
|
||||
if settings.ZILENCER_ENABLED:
|
||||
|
@ -21,11 +21,6 @@ class Command(BaseCommand):
|
|||
Usage: python manage.py create_realm --domain=foo.com --name='Foo, Inc.'"""
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('-o', '--open-realm',
|
||||
dest='open_realm',
|
||||
action="store_true",
|
||||
default=False,
|
||||
help='Make this an open realm.'),
|
||||
make_option('-d', '--domain',
|
||||
dest='domain',
|
||||
type='str',
|
||||
|
@ -34,6 +29,17 @@ Usage: python manage.py create_realm --domain=foo.com --name='Foo, Inc.'"""
|
|||
dest='name',
|
||||
type='str',
|
||||
help='The user-visible name for the realm.'),
|
||||
make_option('--corporate',
|
||||
dest='org_type',
|
||||
action="store_const",
|
||||
const=Realm.CORPORATE,
|
||||
help='Is a corporate org_type'),
|
||||
make_option('--community',
|
||||
dest='org_type',
|
||||
action="store_const",
|
||||
const=Realm.COMMUNITY,
|
||||
default=None,
|
||||
help='Is a community org_type. Is the default.'),
|
||||
make_option('--deployment',
|
||||
dest='deployment_id',
|
||||
type='int',
|
||||
|
@ -60,26 +66,21 @@ Usage: python manage.py create_realm --domain=foo.com --name='Foo, Inc.'"""
|
|||
|
||||
def handle(self, *args, **options):
|
||||
# type: (*Any, **Any) -> None
|
||||
if options["domain"] is None or options["name"] is None:
|
||||
domain = options["domain"]
|
||||
name = options["name"]
|
||||
|
||||
if domain is None or name is None:
|
||||
print("\033[1;31mPlease provide both a domain and name.\033[0m\n", file=sys.stderr)
|
||||
self.print_help("python manage.py", "create_realm")
|
||||
exit(1)
|
||||
|
||||
if options["open_realm"] and options["deployment_id"] is not None:
|
||||
print("\033[1;31mExternal deployments cannot be open realms.\033[0m\n", file=sys.stderr)
|
||||
self.print_help("python manage.py", "create_realm")
|
||||
exit(1)
|
||||
if options["deployment_id"] is not None and not settings.ZILENCER_ENABLED:
|
||||
print("\033[1;31mExternal deployments are not supported on voyager deployments.\033[0m\n", file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
domain = options["domain"]
|
||||
name = options["name"]
|
||||
|
||||
self.validate_domain(domain)
|
||||
|
||||
realm, created = do_create_realm(
|
||||
domain, name, restricted_to_domain=not options["open_realm"])
|
||||
realm, created = do_create_realm(domain, name, org_type=options["org_type"])
|
||||
if created:
|
||||
print(domain, "created.")
|
||||
if options["deployment_id"] is not None:
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0029_realm_subdomain'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='realm',
|
||||
name='org_type',
|
||||
field=models.PositiveSmallIntegerField(default=1),
|
||||
),
|
||||
]
|
|
@ -145,6 +145,11 @@ class Realm(ModelReprMixin, models.Model):
|
|||
DEFAULT_MESSAGE_CONTENT_EDIT_LIMIT_SECONDS = 600 # if changed, also change in admin.js
|
||||
message_content_edit_limit_seconds = models.IntegerField(default=DEFAULT_MESSAGE_CONTENT_EDIT_LIMIT_SECONDS) # type: int
|
||||
|
||||
# Valid org_types are {CORPORATE, COMMUNITY}
|
||||
CORPORATE = 1
|
||||
COMMUNITY = 2
|
||||
org_type = models.PositiveSmallIntegerField(default=CORPORATE) # type: int
|
||||
|
||||
date_created = models.DateTimeField(default=timezone.now) # type: datetime.datetime
|
||||
notifications_stream = models.ForeignKey('Stream', related_name='+', null=True, blank=True) # type: Optional[Stream]
|
||||
deactivated = models.BooleanField(default=False) # type: bool
|
||||
|
|
|
@ -668,10 +668,11 @@ class RealmCreationTest(ZulipTestCase):
|
|||
username = "user1"
|
||||
password = "test"
|
||||
domain = "test.com"
|
||||
org_type = Realm.COMMUNITY
|
||||
email = "user1@test.com"
|
||||
|
||||
# Make sure the realm does not exist
|
||||
self.assertIsNone(get_realm("test.com"))
|
||||
self.assertIsNone(get_realm(domain))
|
||||
|
||||
with self.settings(OPEN_REALM_CREATION=True):
|
||||
# Create new realm with the email
|
||||
|
@ -687,21 +688,49 @@ class RealmCreationTest(ZulipTestCase):
|
|||
result = self.client_get(confirmation_url)
|
||||
self.assertEquals(result.status_code, 200)
|
||||
|
||||
result = self.submit_reg_form_for_user(username, password, domain)
|
||||
result = self.submit_reg_form_for_user(username, password, domain=domain, realm_org_type=org_type)
|
||||
self.assertEquals(result.status_code, 302)
|
||||
|
||||
# Make sure the realm is created
|
||||
realm = get_realm("test.com")
|
||||
|
||||
realm = get_realm(domain)
|
||||
self.assertIsNotNone(realm)
|
||||
self.assertEqual(realm.domain, domain)
|
||||
self.assertEqual(get_user_profile_by_email(email).realm, realm)
|
||||
|
||||
# Check defaults
|
||||
self.assertEquals(realm.org_type, Realm.COMMUNITY)
|
||||
self.assertEquals(realm.restricted_to_domain, False)
|
||||
self.assertEquals(realm.invite_required, True)
|
||||
|
||||
self.assertTrue(result["Location"].endswith("/invite/"))
|
||||
|
||||
result = self.client_get(result["Location"])
|
||||
self.assert_in_response("You're the first one here!", result)
|
||||
|
||||
def test_realm_corporate_defaults(self):
|
||||
# type: () -> None
|
||||
username = "user1"
|
||||
password = "test"
|
||||
domain = "test.com"
|
||||
org_type = Realm.CORPORATE
|
||||
email = "user1@test.com"
|
||||
|
||||
# Make sure the realm does not exist
|
||||
self.assertIsNone(get_realm(domain))
|
||||
|
||||
# Create new realm with the email
|
||||
with self.settings(OPEN_REALM_CREATION=True):
|
||||
self.client_post('/create_realm/', {'email': email})
|
||||
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
||||
self.client_get(confirmation_url)
|
||||
self.submit_reg_form_for_user(username, password, domain=domain, realm_org_type=org_type)
|
||||
|
||||
# Check corporate defaults were set correctly
|
||||
realm = get_realm(domain)
|
||||
self.assertEquals(realm.org_type, Realm.CORPORATE)
|
||||
self.assertEquals(realm.restricted_to_domain, True)
|
||||
self.assertEquals(realm.invite_required, False)
|
||||
|
||||
class UserSignUpTest(ZulipTestCase):
|
||||
|
||||
def test_user_default_language(self):
|
||||
|
|
|
@ -198,11 +198,13 @@ def accounts_register(request):
|
|||
|
||||
if realm_creation:
|
||||
domain = split_email_to_domain(email)
|
||||
realm_name = form.cleaned_data['realm_name']
|
||||
org_type = int(form.cleaned_data['realm_org_type'])
|
||||
if settings.REALMS_HAVE_SUBDOMAINS:
|
||||
realm = do_create_realm(domain, form.cleaned_data['realm_name'],
|
||||
realm = do_create_realm(domain, realm_name, org_type=org_type,
|
||||
subdomain=form.cleaned_data['realm_subdomain'])[0]
|
||||
else:
|
||||
realm = do_create_realm(domain, form.cleaned_data['realm_name'])[0]
|
||||
realm = do_create_realm(domain, realm_name, org_type=org_type)[0]
|
||||
|
||||
set_default_streams(realm, settings.DEFAULT_NEW_REALM_STREAMS)
|
||||
|
||||
|
|
Loading…
Reference in New Issue