mirror of https://github.com/zulip/zulip.git
Delete the old zulip.com "referrals" system.
This system hasn't been in active use for several years, and had some problems with it's design. So it makes sense to just remove it to declutter the codebase. Fixes #5655.
This commit is contained in:
parent
fcd944447e
commit
d5517bae36
|
@ -95,7 +95,6 @@
|
||||||
"realm_icon": false,
|
"realm_icon": false,
|
||||||
"feature_flags": false,
|
"feature_flags": false,
|
||||||
"search_suggestion": false,
|
"search_suggestion": false,
|
||||||
"referral": false,
|
|
||||||
"notifications": false,
|
"notifications": false,
|
||||||
"message_flags": false,
|
"message_flags": false,
|
||||||
"bot_data": false,
|
"bot_data": false,
|
||||||
|
|
|
@ -278,14 +278,6 @@ var event_fixtures = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
referral: {
|
|
||||||
type: 'referral',
|
|
||||||
referrals: {
|
|
||||||
granted: 10,
|
|
||||||
used: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
restart: {
|
restart: {
|
||||||
type: 'restart',
|
type: 'restart',
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
@ -659,18 +651,6 @@ with_overrides(function (override) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
with_overrides(function (override) {
|
|
||||||
// referral
|
|
||||||
var event = event_fixtures.referral;
|
|
||||||
global.with_stub(function (stub) {
|
|
||||||
override('referral.update_state', stub.f);
|
|
||||||
dispatch(event);
|
|
||||||
var args = stub.get_args('granted', 'used');
|
|
||||||
assert_same(args.granted, event.referrals.granted);
|
|
||||||
assert_same(args.used, event.referrals.used);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
with_overrides(function (override) {
|
with_overrides(function (override) {
|
||||||
// restart
|
// restart
|
||||||
var event = event_fixtures.restart;
|
var event = event_fixtures.restart;
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
var referral = (function () {
|
|
||||||
|
|
||||||
var exports = {};
|
|
||||||
|
|
||||||
var placeholder_invitees = ['nikola.tesla@example.com',
|
|
||||||
'sam.morse@example.com',
|
|
||||||
'c.shannon@example.com',
|
|
||||||
'hedy.lamarr@example.com',
|
|
||||||
'grace.hopper@example.com',
|
|
||||||
'ada.lovelace@example.com'];
|
|
||||||
|
|
||||||
var last_granted;
|
|
||||||
var last_used;
|
|
||||||
var ever_had_invites = false;
|
|
||||||
exports.update_state = function (granted, used) {
|
|
||||||
if (last_granted === granted && last_used === used) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_granted = granted;
|
|
||||||
last_used = used;
|
|
||||||
|
|
||||||
if (granted <= 0 || !page_params.share_the_love) {
|
|
||||||
$("#share-the-love").hide();
|
|
||||||
} else {
|
|
||||||
$("#referral-form input").attr('placeholder', _.shuffle(placeholder_invitees).pop());
|
|
||||||
$("#invite-hearts").empty();
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < used; i += 1) {
|
|
||||||
$("#invite-hearts").append($('<i class="icon-vector-heart"> </i>'));
|
|
||||||
}
|
|
||||||
|
|
||||||
var invites_left = Math.max(0, granted - used);
|
|
||||||
for (i = 0; i < invites_left; i += 1) {
|
|
||||||
$("#invite-hearts").append($('<i class="icon-vector-heart-empty"> </i>'));
|
|
||||||
}
|
|
||||||
|
|
||||||
var invites_left_text = i18n.t('__count__ invite remaining', {count: invites_left});
|
|
||||||
$(".invite-count").text(invites_left_text);
|
|
||||||
|
|
||||||
if (invites_left > 0) {
|
|
||||||
ever_had_invites = true;
|
|
||||||
$(".still-have-invites").show();
|
|
||||||
$(".no-more-invites").hide();
|
|
||||||
} else {
|
|
||||||
$(".still-have-invites").hide();
|
|
||||||
$("#referral-form input").blur();
|
|
||||||
if (ever_had_invites) {
|
|
||||||
$(".no-more-invites").show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used > 0) {
|
|
||||||
$("#encouraging-invite-message").hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#share-the-love").show();
|
|
||||||
}
|
|
||||||
|
|
||||||
resize.resize_page_components();
|
|
||||||
};
|
|
||||||
|
|
||||||
function show_and_fade_elem(elem) {
|
|
||||||
elem.stop();
|
|
||||||
elem.css({opacity: 100});
|
|
||||||
elem.show().delay(4000).fadeOut(1000, ui.resize_page_components);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(function () {
|
|
||||||
var validator = $("#referral-form").validate({
|
|
||||||
errorClass: 'text-error',
|
|
||||||
submitHandler: function () {
|
|
||||||
channel.post({
|
|
||||||
url: "/json/refer_friend",
|
|
||||||
data: { email: $("#referral-form input").val() },
|
|
||||||
error: function () {
|
|
||||||
// We ignore errors from the server because
|
|
||||||
// they're unlikely and we'll get an email either
|
|
||||||
// way
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
show_and_fade_elem($("#tell-a-friend-success"));
|
|
||||||
$("#referral-form input").val('');
|
|
||||||
exports.update_state(last_granted, last_used + 1);
|
|
||||||
},
|
|
||||||
success: function () {
|
|
||||||
resize.resize_page_components();
|
|
||||||
},
|
|
||||||
showErrors: function () {
|
|
||||||
this.defaultShowErrors();
|
|
||||||
resize.resize_page_components();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#referral-form input").on('blur', function () {
|
|
||||||
if ($("#referral-form input").val() === '') {
|
|
||||||
validator.resetForm();
|
|
||||||
resize.resize_page_components();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#referral-form").on("click", function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#share-the-love-expand-collapse").click(function (e) {
|
|
||||||
$("#share-the-love-contents").toggle();
|
|
||||||
$("#share-the-love-expand-collapse .toggle").toggleClass('icon-vector-caret-right icon-vector-caret-down');
|
|
||||||
resize.resize_page_components();
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
exports.update_state(page_params.referrals.granted, page_params.referrals.used);
|
|
||||||
});
|
|
||||||
|
|
||||||
return exports;
|
|
||||||
}());
|
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
|
||||||
module.exports = referral;
|
|
||||||
}
|
|
|
@ -66,12 +66,6 @@ function get_new_heights() {
|
||||||
- $("#streams_header").outerHeight(true)
|
- $("#streams_header").outerHeight(true)
|
||||||
- 10; // stream_filters margin-bottom
|
- 10; // stream_filters margin-bottom
|
||||||
|
|
||||||
if ($("#share-the-love").is(":visible")) {
|
|
||||||
res.stream_filters_max_height -=
|
|
||||||
$("#share-the-love").outerHeight(true)
|
|
||||||
+ 20; // share-the-love margins + 10px of ??
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't let us crush the stream sidebar completely out of view
|
// Don't let us crush the stream sidebar completely out of view
|
||||||
res.stream_filters_max_height = Math.max(80, res.stream_filters_max_height);
|
res.stream_filters_max_height = Math.max(80, res.stream_filters_max_height);
|
||||||
|
|
||||||
|
@ -239,7 +233,6 @@ exports.resize_page_components = function () {
|
||||||
sidebar = $(".bottom_sidebar").expectOne();
|
sidebar = $(".bottom_sidebar").expectOne();
|
||||||
sidebar.append($("#user-list").expectOne());
|
sidebar.append($("#user-list").expectOne());
|
||||||
sidebar.append($("#group-pm-list").expectOne());
|
sidebar.append($("#group-pm-list").expectOne());
|
||||||
sidebar.append($("#share-the-love").expectOne());
|
|
||||||
$("#user_presences").css("margin", "0px");
|
$("#user_presences").css("margin", "0px");
|
||||||
$("#group-pms").css("margin", "0px");
|
$("#group-pms").css("margin", "0px");
|
||||||
$("#userlist-toggle").css("display", "none");
|
$("#userlist-toggle").css("display", "none");
|
||||||
|
|
|
@ -169,10 +169,6 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'referral':
|
|
||||||
referral.update_state(event.referrals.granted, event.referrals.used);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'stream':
|
case 'stream':
|
||||||
if (event.op === 'update') {
|
if (event.op === 'update') {
|
||||||
// Legacy: Stream properties are still managed by subs.js on the client side.
|
// Legacy: Stream properties are still managed by subs.js on the client side.
|
||||||
|
|
|
@ -410,8 +410,7 @@ li.expanded_private_message a {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#topics_header,
|
#topics_header {
|
||||||
#sharethelove-header {
|
|
||||||
border-top: 1px solid hsl(0, 0%, 88%);
|
border-top: 1px solid hsl(0, 0%, 88%);
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
@ -430,76 +429,6 @@ li.expanded_private_message a {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#share-the-love {
|
|
||||||
margin-left: 0px;
|
|
||||||
margin-right: 0px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
line-height: 18px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love-contents {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love-expand-collapse {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love-expand-collapse h4 {
|
|
||||||
padding-left: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love-expand-collapse .toggle {
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love input,
|
|
||||||
#share-the-love p {
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#referral-form label {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love .icon-vector-heart {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love .still-have-invites {
|
|
||||||
clear: both;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love .no-more-invites {
|
|
||||||
clear: both;
|
|
||||||
display: none;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love .invite-count-area {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-the-love .alert {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#referral-form {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tell-a-friend-success {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.show-more-topics a {
|
li.show-more-topics a {
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,8 +478,6 @@ paths:
|
||||||
|
|
||||||
* `realm_waiting_period_threshold`:
|
* `realm_waiting_period_threshold`:
|
||||||
|
|
||||||
* `referrals`:
|
|
||||||
|
|
||||||
* `streams`:
|
* `streams`:
|
||||||
|
|
||||||
* `twenty_four_hour_time`:
|
* `twenty_four_hour_time`:
|
||||||
|
@ -1015,8 +1013,6 @@ definitions:
|
||||||
realm_waiting_period_threshold:
|
realm_waiting_period_threshold:
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
referrals:
|
|
||||||
type: string
|
|
||||||
streams:
|
streams:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -1089,7 +1085,6 @@ definitions:
|
||||||
#realm_domains
|
#realm_domains
|
||||||
#realm_emoji
|
#realm_emoji
|
||||||
#realm_filters
|
#realm_filters
|
||||||
#referrals
|
|
||||||
#subscriptions
|
#subscriptions
|
||||||
#unsubscribed
|
#unsubscribed
|
||||||
|
|
||||||
|
|
|
@ -73,43 +73,5 @@
|
||||||
<ul id="stream_filters" class="filters"></ul>
|
<ul id="stream_filters" class="filters"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="share-the-love">
|
|
||||||
<div id="share-the-love-expand-collapse">
|
|
||||||
<i class="toggle icon-vector-caret-right"></i><div id="sharethelove-header"><h4 class="sidebar-title">{{ _('SHARE THE LOVE') }}<span class="still-have-invites"> (<span class="invite-count">0</span>)</span></h4></div>
|
|
||||||
</div>
|
|
||||||
<div id="share-the-love-contents">
|
|
||||||
<div id="tell-a-friend-success" class="alert alert-success">
|
|
||||||
{% trans %}<strong>Thanks!</strong> A hand-crafted, artisanal invite is on the way.{% endtrans %}
|
|
||||||
</div>
|
|
||||||
<div class="still-have-invites" id="encouraging-invite-message">
|
|
||||||
<p>
|
|
||||||
{{ _("Know someone who would love Zulip for their company or group? Invite 'em!") }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="no-more-invites">
|
|
||||||
<p>
|
|
||||||
{% trans %}
|
|
||||||
We'll have more invites for
|
|
||||||
you soon, but for now, enjoy
|
|
||||||
this <a target="_blank"
|
|
||||||
href="http://www.youtube.com/watch?v=PW71En5Pa5s#t=2m01s">song
|
|
||||||
that expresses how we feel when you're
|
|
||||||
logged out</a>.
|
|
||||||
{% endtrans %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="still-have-invites">
|
|
||||||
{# Many of these values are set by the initialization code in referral.js #}
|
|
||||||
<form id="referral-form">
|
|
||||||
<input class="input-block-level required" type="email" name="email" />
|
|
||||||
<label for="email" generated="true" class="text-error"></label>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="invite-count-area">
|
|
||||||
<span id="invite-hearts"></span>
|
|
||||||
<small class="pull-right"><span class="invite-count">0 {{ _('invites remaining') }}</span></small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -127,7 +127,6 @@ def find_edges_to_remove(graph, methods):
|
||||||
('pm_list', 'resize'),
|
('pm_list', 'resize'),
|
||||||
('notifications', 'navigate'),
|
('notifications', 'navigate'),
|
||||||
('compose', 'socket'),
|
('compose', 'socket'),
|
||||||
('referral', 'resize'),
|
|
||||||
('stream_muting', 'message_util'),
|
('stream_muting', 'message_util'),
|
||||||
('subs', 'stream_list'),
|
('subs', 'stream_list'),
|
||||||
('ui', 'message_fetch'),
|
('ui', 'message_fetch'),
|
||||||
|
|
|
@ -34,7 +34,7 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
|
||||||
RealmDomain, \
|
RealmDomain, \
|
||||||
Subscription, Recipient, Message, Attachment, UserMessage, RealmAuditLog, \
|
Subscription, Recipient, Message, Attachment, UserMessage, RealmAuditLog, \
|
||||||
UserHotspot, \
|
UserHotspot, \
|
||||||
Client, DefaultStream, UserPresence, Referral, PushDeviceToken, \
|
Client, DefaultStream, UserPresence, PushDeviceToken, \
|
||||||
MAX_SUBJECT_LENGTH, \
|
MAX_SUBJECT_LENGTH, \
|
||||||
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
|
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
|
||||||
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
|
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
|
||||||
|
@ -3155,33 +3155,6 @@ def do_invite_users(user_profile, invitee_emails, streams, body=None):
|
||||||
|
|
||||||
return ret_error, ret_error_data
|
return ret_error, ret_error_data
|
||||||
|
|
||||||
def send_referral_event(user_profile):
|
|
||||||
# type: (UserProfile) -> None
|
|
||||||
event = dict(type="referral",
|
|
||||||
referrals=dict(granted=user_profile.invites_granted,
|
|
||||||
used=user_profile.invites_used))
|
|
||||||
send_event(event, [user_profile.id])
|
|
||||||
|
|
||||||
def do_refer_friend(user_profile, email):
|
|
||||||
# type: (UserProfile, Text) -> None
|
|
||||||
content = ('Referrer: "%s" <%s>\n'
|
|
||||||
'Realm: %s\n'
|
|
||||||
'Referred: %s') % (user_profile.full_name, user_profile.email,
|
|
||||||
user_profile.realm.string_id, email)
|
|
||||||
subject = "Zulip referral: %s" % (email,)
|
|
||||||
from_email = '"%s" <%s>' % (user_profile.full_name, 'referrals@zulip.com')
|
|
||||||
to_email = '"Zulip Referrals" <zulip+referrals@zulip.com>'
|
|
||||||
headers = {'Reply-To': '"%s" <%s>' % (user_profile.full_name, user_profile.email,)}
|
|
||||||
msg = EmailMessage(subject, content, from_email, [to_email], headers=headers)
|
|
||||||
msg.send()
|
|
||||||
|
|
||||||
referral = Referral(user_profile=user_profile, email=email)
|
|
||||||
referral.save()
|
|
||||||
user_profile.invites_used += 1
|
|
||||||
user_profile.save(update_fields=['invites_used'])
|
|
||||||
|
|
||||||
send_referral_event(user_profile)
|
|
||||||
|
|
||||||
def notify_realm_emoji(realm):
|
def notify_realm_emoji(realm):
|
||||||
# type: (Realm) -> None
|
# type: (Realm) -> None
|
||||||
event = dict(type="realm_emoji", op="update",
|
event = dict(type="realm_emoji", op="update",
|
||||||
|
|
|
@ -144,10 +144,6 @@ def fetch_initial_state_data(user_profile, event_types, queue_id,
|
||||||
if want('realm_bot'):
|
if want('realm_bot'):
|
||||||
state['realm_bots'] = get_owned_bot_dicts(user_profile)
|
state['realm_bots'] = get_owned_bot_dicts(user_profile)
|
||||||
|
|
||||||
if want('referral'):
|
|
||||||
state['referrals'] = {'granted': user_profile.invites_granted,
|
|
||||||
'used': user_profile.invites_used}
|
|
||||||
|
|
||||||
if want('subscription'):
|
if want('subscription'):
|
||||||
subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper(
|
subscriptions, unsubscribed, never_subscribed = gather_subscriptions_helper(
|
||||||
user_profile, include_subscribers=include_subscribers)
|
user_profile, include_subscribers=include_subscribers)
|
||||||
|
@ -415,8 +411,6 @@ def apply_event(state, event, user_profile, include_subscribers):
|
||||||
elif event['type'] == "reaction":
|
elif event['type'] == "reaction":
|
||||||
# The client will get the message with the reactions directly
|
# The client will get the message with the reactions directly
|
||||||
pass
|
pass
|
||||||
elif event['type'] == "referral":
|
|
||||||
state['referrals'] = event['referrals']
|
|
||||||
elif event['type'] == 'typing':
|
elif event['type'] == 'typing':
|
||||||
# Typing notification events are transient and thus ignored
|
# Typing notification events are transient and thus ignored
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -77,7 +77,6 @@ ALL_ZERVER_TABLES = [
|
||||||
'zerver_realmemoji',
|
'zerver_realmemoji',
|
||||||
'zerver_realmfilter',
|
'zerver_realmfilter',
|
||||||
'zerver_recipient',
|
'zerver_recipient',
|
||||||
'zerver_referral',
|
|
||||||
'zerver_scheduledjob',
|
'zerver_scheduledjob',
|
||||||
'zerver_stream',
|
'zerver_stream',
|
||||||
'zerver_subscription',
|
'zerver_subscription',
|
||||||
|
@ -97,7 +96,6 @@ NON_EXPORTED_TABLES = [
|
||||||
'zerver_preregistrationuser',
|
'zerver_preregistrationuser',
|
||||||
'zerver_preregistrationuser_streams',
|
'zerver_preregistrationuser_streams',
|
||||||
'zerver_pushdevicetoken',
|
'zerver_pushdevicetoken',
|
||||||
'zerver_referral',
|
|
||||||
'zerver_scheduledjob',
|
'zerver_scheduledjob',
|
||||||
'zerver_userprofile_groups',
|
'zerver_userprofile_groups',
|
||||||
'zerver_userprofile_user_permissions',
|
'zerver_userprofile_user_permissions',
|
||||||
|
|
|
@ -36,7 +36,6 @@ class Command(BaseCommand):
|
||||||
* Users' passwords and API keys (users will need to use SSO or reset password)
|
* Users' passwords and API keys (users will need to use SSO or reset password)
|
||||||
* Mobile tokens for APNS/GCM (users will need to reconnect their mobile devices)
|
* Mobile tokens for APNS/GCM (users will need to reconnect their mobile devices)
|
||||||
* ScheduledJob (Not relevant on a new server)
|
* ScheduledJob (Not relevant on a new server)
|
||||||
* Referral (Unused)
|
|
||||||
* Deployment (Unused)
|
* Deployment (Unused)
|
||||||
* third_party_api_results cache (this means rerending all old
|
* third_party_api_results cache (this means rerending all old
|
||||||
messages could be expensive)
|
messages could be expensive)
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.2 on 2017-07-07 08:34
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('zerver', '0087_remove_old_scheduled_jobs'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='referral',
|
||||||
|
name='user_profile',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='invites_granted',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='invites_used',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Referral',
|
||||||
|
),
|
||||||
|
]
|
|
@ -647,9 +647,6 @@ class UserProfile(ModelReprMixin, AbstractBaseUser, PermissionsMixin):
|
||||||
# completed.
|
# completed.
|
||||||
onboarding_steps = models.TextField(default=u'[]') # type: Text
|
onboarding_steps = models.TextField(default=u'[]') # type: Text
|
||||||
|
|
||||||
invites_granted = models.IntegerField(default=0) # type: int
|
|
||||||
invites_used = models.IntegerField(default=0) # type: int
|
|
||||||
|
|
||||||
alert_words = models.TextField(default=u'[]') # type: Text # json-serialized list of strings
|
alert_words = models.TextField(default=u'[]') # type: Text # json-serialized list of strings
|
||||||
|
|
||||||
# Contains serialized JSON of the form:
|
# Contains serialized JSON of the form:
|
||||||
|
@ -1677,11 +1674,6 @@ class DefaultStream(models.Model):
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
unique_together = ("realm", "stream")
|
unique_together = ("realm", "stream")
|
||||||
|
|
||||||
class Referral(models.Model):
|
|
||||||
user_profile = models.ForeignKey(UserProfile, on_delete=CASCADE) # type: UserProfile
|
|
||||||
email = models.EmailField(blank=False, null=False) # type: Text
|
|
||||||
timestamp = models.DateTimeField(auto_now_add=True, null=False) # type: datetime.datetime
|
|
||||||
|
|
||||||
class ScheduledJob(models.Model):
|
class ScheduledJob(models.Model):
|
||||||
scheduled_timestamp = models.DateTimeField(auto_now_add=False, null=False) # type: datetime.datetime
|
scheduled_timestamp = models.DateTimeField(auto_now_add=False, null=False) # type: datetime.datetime
|
||||||
type = models.PositiveSmallIntegerField() # type: int
|
type = models.PositiveSmallIntegerField() # type: int
|
||||||
|
|
|
@ -46,7 +46,6 @@ from zerver.lib.actions import (
|
||||||
do_delete_message,
|
do_delete_message,
|
||||||
do_mark_hotspot_as_read,
|
do_mark_hotspot_as_read,
|
||||||
do_reactivate_user,
|
do_reactivate_user,
|
||||||
do_refer_friend,
|
|
||||||
do_regenerate_api_key,
|
do_regenerate_api_key,
|
||||||
do_remove_alert_words,
|
do_remove_alert_words,
|
||||||
do_remove_default_stream,
|
do_remove_default_stream,
|
||||||
|
@ -723,19 +722,6 @@ class EventsRegisterTest(ZulipTestCase):
|
||||||
error = schema_checker('events[0]', events[0])
|
error = schema_checker('events[0]', events[0])
|
||||||
self.assert_on_error(error)
|
self.assert_on_error(error)
|
||||||
|
|
||||||
def test_referral_events(self):
|
|
||||||
# type: () -> None
|
|
||||||
schema_checker = self.check_events_dict([
|
|
||||||
('type', equals('referral')),
|
|
||||||
('referrals', check_dict_only([
|
|
||||||
('granted', check_int),
|
|
||||||
('used', check_int),
|
|
||||||
])),
|
|
||||||
])
|
|
||||||
events = self.do_test(lambda: do_refer_friend(self.user_profile, "friend@example.com"))
|
|
||||||
error = schema_checker('events[0]', events[0])
|
|
||||||
self.assert_on_error(error)
|
|
||||||
|
|
||||||
def test_register_events(self):
|
def test_register_events(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
realm_user_add_checker = self.check_events_dict([
|
realm_user_add_checker = self.check_events_dict([
|
||||||
|
|
|
@ -31,7 +31,6 @@ class HomeTest(ZulipTestCase):
|
||||||
'Manage streams',
|
'Manage streams',
|
||||||
'Narrow by topic',
|
'Narrow by topic',
|
||||||
'Next message',
|
'Next message',
|
||||||
'SHARE THE LOVE',
|
|
||||||
'Search streams',
|
'Search streams',
|
||||||
'Welcome to Zulip',
|
'Welcome to Zulip',
|
||||||
'pygments.css',
|
'pygments.css',
|
||||||
|
@ -130,13 +129,11 @@ class HomeTest(ZulipTestCase):
|
||||||
"realm_uri",
|
"realm_uri",
|
||||||
"realm_users",
|
"realm_users",
|
||||||
"realm_waiting_period_threshold",
|
"realm_waiting_period_threshold",
|
||||||
"referrals",
|
|
||||||
"save_stacktraces",
|
"save_stacktraces",
|
||||||
"server_generation",
|
"server_generation",
|
||||||
"server_inline_image_preview",
|
"server_inline_image_preview",
|
||||||
"server_inline_url_embed_preview",
|
"server_inline_url_embed_preview",
|
||||||
"server_uri",
|
"server_uri",
|
||||||
"share_the_love",
|
|
||||||
"subscriptions",
|
"subscriptions",
|
||||||
"test_suite",
|
"test_suite",
|
||||||
"timezone",
|
"timezone",
|
||||||
|
|
|
@ -27,7 +27,7 @@ from zerver.models import (
|
||||||
get_unique_open_realm, get_unique_non_system_realm,
|
get_unique_open_realm, get_unique_non_system_realm,
|
||||||
completely_open, get_recipient,
|
completely_open, get_recipient,
|
||||||
PreregistrationUser, Realm, RealmDomain, Recipient, Message,
|
PreregistrationUser, Realm, RealmDomain, Recipient, Message,
|
||||||
Referral, ScheduledJob, UserProfile, UserMessage,
|
ScheduledJob, UserProfile, UserMessage,
|
||||||
Stream, Subscription, ScheduledJob, flush_per_request_caches
|
Stream, Subscription, ScheduledJob, flush_per_request_caches
|
||||||
)
|
)
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
|
@ -675,55 +675,6 @@ so we didn't send them an invitation. We did send invitations to everyone else!"
|
||||||
|
|
||||||
self.assert_json_success(self.invite(invitee, [stream_name]))
|
self.assert_json_success(self.invite(invitee, [stream_name]))
|
||||||
|
|
||||||
def test_refer_friend(self):
|
|
||||||
# type: () -> None
|
|
||||||
self.login(self.example_email("hamlet"))
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
user.invites_granted = 1
|
|
||||||
user.invites_used = 0
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
invitee = "alice-test@zulip.com"
|
|
||||||
result = self.client_post('/json/refer_friend', dict(email=invitee))
|
|
||||||
self.assert_json_success(result)
|
|
||||||
|
|
||||||
# verify this works
|
|
||||||
Referral.objects.get(user_profile=user, email=invitee)
|
|
||||||
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
self.assertEqual(user.invites_used, 1)
|
|
||||||
|
|
||||||
def test_refer_friend_no_email(self):
|
|
||||||
# type: () -> None
|
|
||||||
self.login(self.example_email("hamlet"))
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
user.invites_granted = 1
|
|
||||||
user.invites_used = 0
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
self.assert_json_error(
|
|
||||||
self.client_post('/json/refer_friend', dict(email='')),
|
|
||||||
"No email address specified")
|
|
||||||
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
self.assertEqual(user.invites_used, 0)
|
|
||||||
|
|
||||||
def test_refer_friend_no_invites(self):
|
|
||||||
# type: () -> None
|
|
||||||
self.login(self.example_email("hamlet"))
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
user.invites_granted = 1
|
|
||||||
user.invites_used = 1
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
invitee = "alice-test@zulip.com"
|
|
||||||
self.assert_json_error(
|
|
||||||
self.client_post('/json/refer_friend', dict(email=invitee)),
|
|
||||||
"Insufficient invites")
|
|
||||||
|
|
||||||
user = self.example_user('hamlet')
|
|
||||||
self.assertEqual(user.invites_used, 1)
|
|
||||||
|
|
||||||
def test_invitation_reminder_email(self):
|
def test_invitation_reminder_email(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
from django.core.mail import outbox
|
from django.core.mail import outbox
|
||||||
|
|
|
@ -184,7 +184,6 @@ def home_real(request):
|
||||||
# These end up in a global JavaScript Object named 'page_params'.
|
# These end up in a global JavaScript Object named 'page_params'.
|
||||||
page_params = dict(
|
page_params = dict(
|
||||||
# Server settings.
|
# Server settings.
|
||||||
share_the_love = settings.SHARE_THE_LOVE,
|
|
||||||
development_environment = settings.DEVELOPMENT,
|
development_environment = settings.DEVELOPMENT,
|
||||||
debug_mode = settings.DEBUG,
|
debug_mode = settings.DEBUG,
|
||||||
test_suite = settings.TEST_SUITE,
|
test_suite = settings.TEST_SUITE,
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
|
||||||
from typing import List, Optional, Set, Text
|
from typing import List, Optional, Set, Text
|
||||||
|
|
||||||
from zerver.decorator import authenticated_json_post_view
|
from zerver.decorator import authenticated_json_post_view
|
||||||
from zerver.lib.actions import do_invite_users, do_refer_friend, \
|
from zerver.lib.actions import do_invite_users, \
|
||||||
get_default_subs, internal_send_message
|
get_default_subs, internal_send_message
|
||||||
from zerver.lib.request import REQ, has_request_variables, JsonableError
|
from zerver.lib.request import REQ, has_request_variables, JsonableError
|
||||||
from zerver.lib.response import json_success, json_error
|
from zerver.lib.response import json_success, json_error
|
||||||
|
@ -67,16 +67,3 @@ def get_invitee_emails_set(invitee_emails_raw):
|
||||||
email = is_email_with_name.group('email')
|
email = is_email_with_name.group('email')
|
||||||
invitee_emails.add(email.strip())
|
invitee_emails.add(email.strip())
|
||||||
return invitee_emails
|
return invitee_emails
|
||||||
|
|
||||||
@authenticated_json_post_view
|
|
||||||
@has_request_variables
|
|
||||||
def json_refer_friend(request, user_profile, email=REQ()):
|
|
||||||
# type: (HttpRequest, UserProfile, str) -> HttpResponse
|
|
||||||
if not email:
|
|
||||||
return json_error(_("No email address specified"))
|
|
||||||
if user_profile.invites_granted - user_profile.invites_used <= 0:
|
|
||||||
return json_error(_("Insufficient invites"))
|
|
||||||
|
|
||||||
do_refer_friend(user_profile, email)
|
|
||||||
|
|
||||||
return json_success()
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
|
|
||||||
from zerver.lib.actions import send_referral_event
|
|
||||||
from zerver.models import get_user_profile_by_email
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = """Grants a user invites and resets the number of invites they've used."""
|
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
|
||||||
# type: (ArgumentParser) -> None
|
|
||||||
parser.add_argument('email', metavar='<email>', type=str,
|
|
||||||
help="user to grant invites to")
|
|
||||||
parser.add_argument('num_invites', metavar='<num invites>', type=int,
|
|
||||||
help="number of invites to grant")
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
# type: (*Any, **Any) -> None
|
|
||||||
email = options['email']
|
|
||||||
num_invites = options['num_invites']
|
|
||||||
|
|
||||||
user_profile = get_user_profile_by_email(email)
|
|
||||||
user_profile.invites_granted = num_invites
|
|
||||||
user_profile.invites_used = 0
|
|
||||||
|
|
||||||
user_profile.save(update_fields=['invites_granted', 'invites_used'])
|
|
||||||
send_referral_event(user_profile)
|
|
|
@ -15,7 +15,6 @@ import zerver.views.muting
|
||||||
legacy_urls = [
|
legacy_urls = [
|
||||||
# These are json format views used by the web client. They require a logged in browser.
|
# These are json format views used by the web client. They require a logged in browser.
|
||||||
url(r'^json/invite_users$', zerver.views.invite.json_invite_users),
|
url(r'^json/invite_users$', zerver.views.invite.json_invite_users),
|
||||||
url(r'^json/refer_friend$', zerver.views.invite.json_refer_friend),
|
|
||||||
url(r'^json/settings/change$', zerver.views.user_settings.json_change_settings),
|
url(r'^json/settings/change$', zerver.views.user_settings.json_change_settings),
|
||||||
|
|
||||||
# We should remove this endpoint and all code related to it.
|
# We should remove this endpoint and all code related to it.
|
||||||
|
|
|
@ -29,7 +29,6 @@ if not ZULIP_COM:
|
||||||
raise Exception("You should create your own local settings from prod_settings_template.")
|
raise Exception("You should create your own local settings from prod_settings_template.")
|
||||||
|
|
||||||
ZULIP_FRIENDS_LIST_ID = '84b2f3da6b'
|
ZULIP_FRIENDS_LIST_ID = '84b2f3da6b'
|
||||||
SHARE_THE_LOVE = True
|
|
||||||
SHOW_OSS_ANNOUNCEMENT = True
|
SHOW_OSS_ANNOUNCEMENT = True
|
||||||
REGISTER_LINK_DISABLED = True
|
REGISTER_LINK_DISABLED = True
|
||||||
CUSTOM_LOGO_URL = "/static/images/logo/zulip-dropbox.png"
|
CUSTOM_LOGO_URL = "/static/images/logo/zulip-dropbox.png"
|
||||||
|
|
|
@ -153,7 +153,6 @@ DEFAULT_SETTINGS = {'TWITTER_CONSUMER_KEY': '',
|
||||||
'FEEDBACK_BOT': 'feedback@zulip.com',
|
'FEEDBACK_BOT': 'feedback@zulip.com',
|
||||||
'FEEDBACK_BOT_NAME': 'Zulip Feedback Bot',
|
'FEEDBACK_BOT_NAME': 'Zulip Feedback Bot',
|
||||||
'ADMINS': '',
|
'ADMINS': '',
|
||||||
'SHARE_THE_LOVE': False,
|
|
||||||
'INLINE_IMAGE_PREVIEW': True,
|
'INLINE_IMAGE_PREVIEW': True,
|
||||||
'INLINE_URL_EMBED_PREVIEW': False,
|
'INLINE_URL_EMBED_PREVIEW': False,
|
||||||
'CAMO_URI': '',
|
'CAMO_URI': '',
|
||||||
|
@ -949,7 +948,6 @@ JS_SPECS = {
|
||||||
'js/admin.js',
|
'js/admin.js',
|
||||||
'js/tab_bar.js',
|
'js/tab_bar.js',
|
||||||
'js/emoji.js',
|
'js/emoji.js',
|
||||||
'js/referral.js',
|
|
||||||
'js/custom_markdown.js',
|
'js/custom_markdown.js',
|
||||||
'js/bot_data.js',
|
'js/bot_data.js',
|
||||||
'js/reactions.js',
|
'js/reactions.js',
|
||||||
|
|
Loading…
Reference in New Issue