mirror of https://github.com/zulip/zulip.git
parent
bf53c70dd9
commit
395cafcf46
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 4.2.6 on 2023-11-11 14:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("corporate", "0018_customer_cloud_xor_self_hosted"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="zulipsponsorshiprequest",
|
||||||
|
name="expected_total_users",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="zulipsponsorshiprequest",
|
||||||
|
name="paid_users_count",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="zulipsponsorshiprequest",
|
||||||
|
name="paid_users_description",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
),
|
||||||
|
]
|
|
@ -360,3 +360,6 @@ class ZulipSponsorshipRequest(models.Model):
|
||||||
org_website = models.URLField(max_length=MAX_ORG_URL_LENGTH, blank=True, null=True)
|
org_website = models.URLField(max_length=MAX_ORG_URL_LENGTH, blank=True, null=True)
|
||||||
|
|
||||||
org_description = models.TextField(default="")
|
org_description = models.TextField(default="")
|
||||||
|
expected_total_users = models.TextField(default="")
|
||||||
|
paid_users_count = models.TextField(default="")
|
||||||
|
paid_users_description = models.TextField(default="")
|
||||||
|
|
|
@ -2159,6 +2159,9 @@ class StripeTest(StripeTestCase):
|
||||||
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
||||||
"website": "invalid-url",
|
"website": "invalid-url",
|
||||||
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
||||||
|
"expected_total_users": "10 users",
|
||||||
|
"paid_users_count": "1 user",
|
||||||
|
"paid_users_description": "We have 1 paid user.",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client_post("/json/billing/sponsorship", data)
|
response = self.client_post("/json/billing/sponsorship", data)
|
||||||
|
@ -2172,6 +2175,9 @@ class StripeTest(StripeTestCase):
|
||||||
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
||||||
"website": "",
|
"website": "",
|
||||||
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
||||||
|
"expected_total_users": "10 users",
|
||||||
|
"paid_users_count": "1 user",
|
||||||
|
"paid_users_description": "We have 1 paid user.",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client_post("/json/billing/sponsorship", data)
|
response = self.client_post("/json/billing/sponsorship", data)
|
||||||
|
@ -2223,6 +2229,9 @@ class StripeTest(StripeTestCase):
|
||||||
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
"organization-type": Realm.ORG_TYPES["opensource"]["id"],
|
||||||
"website": "https://infinispan.org/",
|
"website": "https://infinispan.org/",
|
||||||
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
"description": "Infinispan is a distributed in-memory key/value data store with optional schema.",
|
||||||
|
"expected_total_users": "10 users",
|
||||||
|
"paid_users_count": "1 user",
|
||||||
|
"paid_users_description": "We have 1 paid user.",
|
||||||
}
|
}
|
||||||
response = self.client_post("/json/billing/sponsorship", data)
|
response = self.client_post("/json/billing/sponsorship", data)
|
||||||
self.assert_json_success(response)
|
self.assert_json_success(response)
|
||||||
|
|
|
@ -233,6 +233,9 @@ class SponsorshipRequestForm(forms.Form):
|
||||||
website = forms.URLField(max_length=ZulipSponsorshipRequest.MAX_ORG_URL_LENGTH, required=False)
|
website = forms.URLField(max_length=ZulipSponsorshipRequest.MAX_ORG_URL_LENGTH, required=False)
|
||||||
organization_type = forms.IntegerField()
|
organization_type = forms.IntegerField()
|
||||||
description = forms.CharField(widget=forms.Textarea)
|
description = forms.CharField(widget=forms.Textarea)
|
||||||
|
expected_total_users = forms.CharField(widget=forms.Textarea)
|
||||||
|
paid_users_count = forms.CharField(widget=forms.Textarea)
|
||||||
|
paid_users_description = forms.CharField(widget=forms.Textarea, required=False)
|
||||||
|
|
||||||
|
|
||||||
@require_organization_member
|
@require_organization_member
|
||||||
|
@ -243,6 +246,9 @@ def sponsorship(
|
||||||
organization_type: str = REQ("organization-type"),
|
organization_type: str = REQ("organization-type"),
|
||||||
website: str = REQ(),
|
website: str = REQ(),
|
||||||
description: str = REQ(),
|
description: str = REQ(),
|
||||||
|
expected_total_users: str = REQ(),
|
||||||
|
paid_users_count: str = REQ(),
|
||||||
|
paid_users_description: str = REQ(),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
realm = user.realm
|
realm = user.realm
|
||||||
billing_session = RealmBillingSession(user)
|
billing_session = RealmBillingSession(user)
|
||||||
|
@ -266,6 +272,9 @@ def sponsorship(
|
||||||
org_website=form.cleaned_data["website"],
|
org_website=form.cleaned_data["website"],
|
||||||
org_description=form.cleaned_data["description"],
|
org_description=form.cleaned_data["description"],
|
||||||
org_type=form.cleaned_data["organization_type"],
|
org_type=form.cleaned_data["organization_type"],
|
||||||
|
expected_total_users=form.cleaned_data["expected_total_users"],
|
||||||
|
paid_users_count=form.cleaned_data["paid_users_count"],
|
||||||
|
paid_users_description=form.cleaned_data["paid_users_description"],
|
||||||
)
|
)
|
||||||
sponsorship_request.save()
|
sponsorship_request.save()
|
||||||
|
|
||||||
|
@ -287,6 +296,9 @@ def sponsorship(
|
||||||
"organization_type": org_type_display_name,
|
"organization_type": org_type_display_name,
|
||||||
"website": website,
|
"website": website,
|
||||||
"description": description,
|
"description": description,
|
||||||
|
"expected_total_users": expected_total_users,
|
||||||
|
"paid_users_count": paid_users_count,
|
||||||
|
"paid_users_description": paid_users_description,
|
||||||
}
|
}
|
||||||
send_email(
|
send_email(
|
||||||
"zerver/emails/sponsorship_request",
|
"zerver/emails/sponsorship_request",
|
||||||
|
|
|
@ -66,17 +66,35 @@
|
||||||
</div>
|
</div>
|
||||||
<label for="organization-type" class="inline-block label-title">Organization type</label>
|
<label for="organization-type" class="inline-block label-title">Organization type</label>
|
||||||
</div>
|
</div>
|
||||||
|
<p id="sponsorship-discount-details"></p>
|
||||||
<div class="input-box sponsorship-form-field no-validation">
|
<div class="input-box sponsorship-form-field no-validation">
|
||||||
<label for="org-website" class="inline-block label-title">Organization website</label>
|
<label for="org-website" class="inline-block
|
||||||
<input id="org-website" name="website" type="text" placeholder="Leave blank if this organization does not have a website."/>
|
label-title">Organization website (if any)</label>
|
||||||
|
<input id="org-website" name="website" type="text"/>
|
||||||
<div id="sponsorship-org-website-error" class="alert alert-danger sponsorship-field-error"></div>
|
<div id="sponsorship-org-website-error" class="alert alert-danger sponsorship-field-error"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box sponsorship-form-field">
|
<div class="input-box sponsorship-form-field">
|
||||||
<label for="description" class="inline-block label-title">Describe this organization</label>
|
<label for="description" class="inline-block
|
||||||
|
label-title">Description of your organization</label>
|
||||||
<textarea id="description" name="description" cols="100" rows="5"></textarea>
|
<textarea id="description" name="description" cols="100" rows="5"></textarea>
|
||||||
<div id="sponsorship-description-error" class="alert alert-danger sponsorship-field-error"></div>
|
<div id="sponsorship-description-error" class="alert alert-danger sponsorship-field-error"></div>
|
||||||
</div>
|
</div>
|
||||||
<p id="sponsorship-discount-details"></p>
|
<div class="input-box sponsorship-form-field">
|
||||||
|
<label for="expected-total-users" class="inline-block label-title">Expected number of users (approximate range)</label>
|
||||||
|
<input id="expected-total-users" name="expected_total_users" type="text" />
|
||||||
|
<div id="sponsorship-expected-total-users-error" class="alert alert-danger sponsorship-field-error"></div>
|
||||||
|
</div>
|
||||||
|
<div class="input-box sponsorship-form-field no-validation">
|
||||||
|
<label for="paid-users-count" class="inline-block label-title">How many paid staff does your organization have?</label>
|
||||||
|
<input id="paid-users-count" name="paid_users_count" type="text"/>
|
||||||
|
<div id="sponsorship-paid-users-count-error" class="alert alert-danger sponsorship-field-error"></div>
|
||||||
|
</div>
|
||||||
|
<div class="input-box sponsorship-form-field">
|
||||||
|
<label for="paid-users-description" class="inline-block
|
||||||
|
label-title">Description of paid staff (if any)</label>
|
||||||
|
<textarea id="paid-users-description" name="paid_users_description" cols="100" rows="2"></textarea>
|
||||||
|
<div id="sponsorship-paid-users-description-error" class="alert alert-danger sponsorship-field-error"></div>
|
||||||
|
</div>
|
||||||
<!-- Disabled buttons do not fire any events, so we need a container div that isn't disabled for tippyjs to work -->
|
<!-- Disabled buttons do not fire any events, so we need a container div that isn't disabled for tippyjs to work -->
|
||||||
<div class="upgrade-button-container" {% if is_demo_organization %}data-tippy-content="Convert demo organization before upgrading."{% endif %}>
|
<div class="upgrade-button-container" {% if is_demo_organization %}data-tippy-content="Convert demo organization before upgrading."{% endif %}>
|
||||||
<button type="submit" id="sponsorship-button" class="stripe-button-el invoice-button" {% if is_demo_organization %}disabled{% endif %}>
|
<button type="submit" id="sponsorship-button" class="stripe-button-el invoice-button" {% if is_demo_organization %}disabled{% endif %}>
|
||||||
|
|
|
@ -14,6 +14,30 @@ function hide_submit_loading_indicator(): void {
|
||||||
$("#sponsorship-button .sponsorship-button-text").show();
|
$("#sponsorship-button .sponsorship-button-text").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validate_data(data: helpers.FormDataObject): boolean {
|
||||||
|
let found_error = false;
|
||||||
|
if (data.description.trim() === "") {
|
||||||
|
$("#sponsorship-description-error").text("Organization description cannot be blank.");
|
||||||
|
hide_submit_loading_indicator();
|
||||||
|
found_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.paid_users_count.trim() === "") {
|
||||||
|
$("#sponsorship-paid-users-count-error").text("Number of paid staff cannot be blank.");
|
||||||
|
hide_submit_loading_indicator();
|
||||||
|
found_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.expected_total_users.trim() === "") {
|
||||||
|
$("#sponsorship-expected-total-users-error").text(
|
||||||
|
"Expected number of users cannot be blank.",
|
||||||
|
);
|
||||||
|
hide_submit_loading_indicator();
|
||||||
|
found_error = true;
|
||||||
|
}
|
||||||
|
return !found_error;
|
||||||
|
}
|
||||||
|
|
||||||
function create_ajax_request(): void {
|
function create_ajax_request(): void {
|
||||||
show_submit_loading_indicator();
|
show_submit_loading_indicator();
|
||||||
const $form = $("#sponsorship-form");
|
const $form = $("#sponsorship-form");
|
||||||
|
@ -25,10 +49,7 @@ function create_ajax_request(): void {
|
||||||
|
|
||||||
// Clear any previous error messages.
|
// Clear any previous error messages.
|
||||||
$(".sponsorship-field-error").text("");
|
$(".sponsorship-field-error").text("");
|
||||||
|
if (!validate_data(data)) {
|
||||||
if (data.description.trim() === "") {
|
|
||||||
$("#sponsorship-description-error").text("Organization description cannot be blank.");
|
|
||||||
hide_submit_loading_indicator();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +83,10 @@ export function initialize(): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
function update_discount_details(): void {
|
function update_discount_details(): void {
|
||||||
const selected_org_type = $<HTMLSelectElement>("#organization-type").find(":selected").attr("data-string-value") ?? "";
|
const selected_org_type =
|
||||||
|
$<HTMLSelectElement>("#organization-type")
|
||||||
|
.find(":selected")
|
||||||
|
.attr("data-string-value") ?? "";
|
||||||
helpers.update_discount_details(selected_org_type);
|
helpers.update_discount_details(selected_org_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -372,7 +372,7 @@ input[name="licenses"] {
|
||||||
#sponsorship-discount-details {
|
#sponsorship-discount-details {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
padding-top: 25px;
|
padding-top: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
width: 450px;
|
width: 450px;
|
||||||
|
|
Loading…
Reference in New Issue