Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Implement option to hide total receiving from others (issue #1683) #1847

Merged
merged 11 commits into from
Jan 10, 2014
8 changes: 8 additions & 0 deletions branch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-------------------------------------------------------------------------------
-- https://github.com/gittip/www.gittip.com/issues/1683

BEGIN;
ALTER TABLE participants RENAME COLUMN anonymous TO anonymous_giving;
ALTER TABLE participants ADD COLUMN anonymous_receiving bool NOT NULL DEFAULT FALSE;
ALTER TABLE homepage_top_receivers ADD COLUMN anonymous boolean;
END;
4 changes: 2 additions & 2 deletions gittip/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,9 +674,9 @@ def get_og_title(self):
out = self.username
receiving = self.get_dollars_receiving()
giving = self.get_dollars_giving()
if (giving > receiving) and not self.anonymous:
if (giving > receiving) and not self.anonymous_giving:
out += " gives $%.2f/wk" % giving
elif receiving > 0:
elif receiving > 0 and not self.anonymous_receiving:
out += " receives $%.2f/wk" % receiving
else:
out += " is"
Expand Down
4 changes: 4 additions & 0 deletions gittip/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,12 @@ def make_participant(self, username, **kw):

participant = Participant.with_random_username()
participant.change_username(username)
return self.update_participant(participant, **kw)


def update_participant(self, participant, **kw):
if 'elsewhere' in kw or 'claimed_time' in kw:
username = participant.username
platform = kw.pop('elsewhere', 'github')
user_info = dict(login=username)
self.seq += 1
Expand Down
12 changes: 6 additions & 6 deletions gittip/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ def update_homepage_queries_once(db):
cursor.execute("DELETE FROM homepage_top_givers")
cursor.execute("""

INSERT INTO homepage_top_givers
SELECT tipper AS username, anonymous, sum(amount) AS amount
INSERT INTO homepage_top_givers (username, anonymous, amount)
SELECT tipper, anonymous_giving, sum(amount) AS amount
FROM ( SELECT DISTINCT ON (tipper, tippee)
amount
, tipper
Expand All @@ -382,7 +382,7 @@ def update_homepage_queries_once(db):
) AS foo
JOIN participants p ON p.username = tipper
WHERE is_suspicious IS NOT true
GROUP BY tipper, anonymous
GROUP BY tipper, anonymous_giving
ORDER BY amount DESC;

""".strip())
Expand All @@ -408,8 +408,8 @@ def update_homepage_queries_once(db):
cursor.execute("DELETE FROM homepage_top_receivers")
cursor.execute("""

INSERT INTO homepage_top_receivers
SELECT tippee AS username, claimed_time, sum(amount) AS amount
INSERT INTO homepage_top_receivers (username, anonymous, amount, claimed_time)
SELECT tippee, anonymous_receiving, sum(amount) AS amount, claimed_time
FROM ( SELECT DISTINCT ON (tipper, tippee)
amount
, tippee
Expand All @@ -424,7 +424,7 @@ def update_homepage_queries_once(db):
) AS foo
JOIN participants p ON p.username = tippee
WHERE is_suspicious IS NOT true
GROUP BY tippee, claimed_time
GROUP BY tippee, anonymous_receiving, claimed_time
ORDER BY amount DESC;

""".strip())
Expand Down
5 changes: 3 additions & 2 deletions gittip/utils/fake_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def fake_sentence(start=1, stop=100):
return faker.sentence(random.randrange(start,stop))


def fake_participant(db, number="singular", is_admin=False, anonymous=False):
def fake_participant(db, number="singular", is_admin=False):
"""Create a fake User.
"""
username = faker.first_name() + fake_text_id(3)
Expand All @@ -70,7 +70,8 @@ def fake_participant(db, number="singular", is_admin=False, anonymous=False):
, ctime=faker.date_time_this_year()
, is_admin=is_admin
, balance=fake_balance()
, anonymous=anonymous
, anonymous_giving=(random.randrange(5) == 0)
, anonymous_receiving=(random.randrange(5) == 0)
, goal=fake_balance()
, balanced_account_uri=faker.uri()
, last_ach_result=''
Expand Down
25 changes: 23 additions & 2 deletions js/gittip/profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,34 @@ Gittip.profile.init = function() {
// Wire up aggregate giving knob.
// ==============================

$('.anonymous input').click(function() {
$('.anonymous-giving input').click(function() {
jQuery.ajax(
{ url: 'anonymous.json'
, type: 'POST'
, data: {toggle: 'giving'}
, dataType: 'json'
, success: function(data) {
$('.anonymous input').attr('checked', data.anonymous);
$('.anonymous-giving input').attr('checked', data.giving);
}
, error: function() {
alert("Failed to change your anonymity preference. Please try again.");
}
}
);
});


// Wire up aggregate receiving knob.
// ==============================

$('.anonymous-receiving input').click(function() {
jQuery.ajax(
{ url: 'anonymous.json'
, type: 'POST'
, data: {toggle: 'receiving'}
, dataType: 'json'
, success: function(data) {
$('.anonymous-receiving input').attr('checked', data.receiving);
}
, error: function() {
alert("Failed to change your anonymity preference. Please try again.");
Expand Down
4 changes: 2 additions & 2 deletions js/gittip/tips.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ Gittip.tips.init = function() {
$myTip.change();

// update display
$('.total-giving').text(data.total_giving);
$('.my-total-giving').text('$'+data.total_giving);
$('.total-receiving').text(
// check and see if we are on our giving page or not
new RegExp('/' + tippee + '/').test(window.location.href) ?
data.total_receiving_tippee : data.total_receiving);
'$'+data.total_receiving_tippee : '$'+data.total_receiving);

// Increment an elsewhere receiver's "people ready to give"
if(!oldAmount)
Expand Down
5 changes: 4 additions & 1 deletion templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ <h1>
<a href="/{{ user.participant.username }}/">{{ user.participant.username }}</a> &ndash;
<a id="sign-out" href="/sign-out.html">sign out</a>
<div class="quick-stats">
Giving: <a href="/{{ user.participant.username }}/giving/">${{ user.participant.get_dollars_giving() }}/wk</a><br />
Giving: <a href="/{{ user.participant.username }}/giving/">
<span class="my-total-giving">${{ user.participant.get_dollars_giving() }}<span>/wk
</a>
<br />
Receiving: <b>${{ user.participant.get_dollars_receiving() }}/wk</b>
</div>
</div>
Expand Down
48 changes: 23 additions & 25 deletions templates/participant.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,45 @@

{% block box %}

{% set prefix = user.participant == participant and "my-" or "" %}
{% set anon_giving = participant.anonymous_giving %}
{% set g = participant.get_dollars_giving() %}
{% set giving = anon_giving and "anonymously" or "$"+str(g) %}
{% set anon_receiving = participant.anonymous_receiving %}
{% set r = participant.get_dollars_receiving() %}
{% set receiving = anon_receiving and "anonymously" or "$"+str(r) %}

<table class="on-profile{% if participant.is_suspicious %} is-suspicious{% endif %}">
<tr>
<td class="picture">
<a href="/{{ participant.username }}/"><img src="{{ participant.get_img_src(128) }}" /></a>
</td>
<td class="giving-receiving">
{% set giving = participant.get_dollars_giving() %}
{% set receiving = participant.get_dollars_receiving() %}

{% if giving > receiving and not participant.anonymous %}
{% if anon_giving and anon_receiving %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This replaces our "USERNAME JOINED RECENTLY" text with "USERNAME gives and receives anonymously", shouldn't we only show that if the user is giving/receiving something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would leak the information that the giving and receiving amounts are zero. Anonymous users might not expect or want that.

<h2 class="pad-sign">{{ participant.username }}</h2>
<div class="unit pad-sign">gives and receives anonymously</div>
{% elif not anon_giving and g > 0 and (g > r or anon_receiving) %}
<h2 class="pad-sign">{{ participant.username }} gives</h2>
<div class="number">
{% if user.participant == participant %}
$<span class="total-giving">{{ giving }}</span>
{% else %}
${{ giving }}
{% endif %}
<span class="{{prefix}}total-giving">{{ giving }}</span>
</div>
<div class="unit pad-sign">per
week{% if receiving > 0 %}, and receives $<span class="total-receiving">{{ receiving }}</span>{% endif %}
<div class="unit pad-sign">
per week{% if r > 0 %}, and receives {{ receiving }}{% endif %}
</div>
{% elif receiving > 0 %}
{% elif not anon_receiving and r > 0 and (r >= g or anon_giving) %}
<h2 class="pad-sign">{{ participant.username }} receives</h2>
<div class="number">$<span class="total-receiving">{{ receiving }}</span></div>
<div class="unit pad-sign">per
week{% if giving > 0 %}, and gives
{% if participant.anonymous %}
anonymously
{% elif user.participant == participant %}
$<span class="total-giving">{{ giving }}</span>
{% else %}
${{ giving }}
{% endif %}
<div class="number">
<span class="total-receiving">{{ receiving }}</span>
</div>
<div class="unit pad-sign">
per week{% if g > 0 %}, and gives
<span class="{{prefix}}total-giving">{{ giving }}</span>
{% endif %}
</div>
{% else %}
{% set age = participant.get_age_in_seconds() %}
<h2>{{ participant.username }}
{% if giving > 0 %}
gives anonymously
{% elif age < 60 %}
{% if age < 60 %}
just joined Gittip! :D
{% elif age < (60 * 60 * 24 * 7) %}
joined recently
Expand Down
10 changes: 8 additions & 2 deletions templates/profile-edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ <h2 class="warning">Have you linked to your Gittip profile from other

</form>
<p>
<label tabindex="104" class="anonymous">
<label tabindex="104" class="anonymous-giving">
<input type="checkbox"
{% if participant.anonymous %}checked="true"{% endif %} />
{% if participant.anonymous_giving %}checked="true"{% endif %} />
Hide total giving from others.
</label>
<br />
<label tabindex="105" class="anonymous-receiving">
<input type="checkbox"
{% if participant.anonymous_receiving %}checked="true"{% endif %} />
Hide total receiving from others.
</label>
</p>


Expand Down
37 changes: 24 additions & 13 deletions tests/test_anonymous_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,36 @@ def setUp(self):
Harness.setUp(self)
self.make_participant('alice')

def hit_anonymous(self, method='GET', expected_code=200):
response = self.client.hit(method, "/alice/anonymous.json", auth_as='alice')
def hit_anonymous(self, method='GET', expected_code=200, **kw):
response = self.client.hit(method, "/alice/anonymous.json", auth_as='alice', **kw)
if response.code != expected_code:
print(response.body)
return response


def test_participant_can_get_their_anonymity_setting(self):
def test_participant_can_get_their_anonymity_settings(self):
response = self.hit_anonymous('GET')
actual = json.loads(response.body)['anonymous']
actual = json.loads(response.body)
assert actual == {'giving': False, 'receiving': False}

def test_participant_can_toggle_anonymous_giving(self):
response = self.hit_anonymous('POST', data={'toggle': 'giving'})
actual = json.loads(response.body)
assert actual['giving'] is True

def test_participant_can_toggle_anonymous_receiving(self):
response = self.hit_anonymous('POST', data={'toggle': 'receiving'})
actual = json.loads(response.body)
assert actual['receiving'] is True

def test_participant_can_toggle_anonymous_giving_back(self):
response = self.hit_anonymous('POST', data={'toggle': 'giving'})
response = self.hit_anonymous('POST', data={'toggle': 'giving'})
actual = json.loads(response.body)['giving']
assert actual is False

def test_participant_can_toggle_their_anonymity_setting(self):
response = self.hit_anonymous('POST')
actual = json.loads(response.body)['anonymous']
assert actual is True

def test_participant_can_toggle_their_anonymity_setting_back(self):
response = self.hit_anonymous('POST')
response = self.hit_anonymous('POST')
actual = json.loads(response.body)['anonymous']
def test_participant_can_toggle_anonymous_receiving_back(self):
response = self.hit_anonymous('POST', data={'toggle': 'receiving'})
response = self.hit_anonymous('POST', data={'toggle': 'receiving'})
actual = json.loads(response.body)['receiving']
assert actual is False
13 changes: 12 additions & 1 deletion tests/test_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@ def test_homepage(self):

def test_homepage_with_anonymous_giver(self):
TwitterAccount(self.db, "bob", {}).opt_in("bob")
alice = self.make_participant('alice', anonymous=True, last_bill_result='')
alice = self.make_participant('alice', anonymous_giving=True, last_bill_result='')
alice.set_tip_to('bob', 1)
update_homepage_queries_once(self.db)

actual = self.client.GET('/').body
expected = "Anonymous"
assert expected in actual

def test_homepage_with_anonymous_receiver(self):
bob, _ = TwitterAccount(self.db, "bob", {}).opt_in("bob")
self.update_participant(bob.participant, anonymous_receiving=True, last_bill_result='')
alice = self.make_participant('alice', last_bill_result='', claimed_time='now')
alice.set_tip_to('bob', 1)
update_homepage_queries_once(self.db)

Expand Down
15 changes: 13 additions & 2 deletions tests/test_public_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,25 @@ def test_anonymous_gets_giving(self):
def test_anonymous_gets_null_giving_if_user_anonymous(self):
alice = self.make_participant( 'alice'
, last_bill_result=''
, anonymous=True
)
, anonymous_giving=True
)
self.make_participant('bob')
alice.set_tip_to('bob', '1.00')
data = json.loads(self.client.GET('/alice/public.json').body)

assert data['giving'] == None

def test_anonymous_gets_null_receiving_if_user_anonymous(self):
alice = self.make_participant( 'alice'
, last_bill_result=''
, anonymous_receiving=True
)
self.make_participant('bob')
alice.set_tip_to('bob', '1.00')
data = json.loads(self.client.GET('/alice/public.json').body)

assert data['receiving'] == None

def test_anonymous_does_not_get_goal_if_user_regifts(self):
self.make_participant('alice', last_bill_result='', goal=0)
data = json.loads(self.client.GET('/alice/public.json').body)
Expand Down
20 changes: 13 additions & 7 deletions www/%username/anonymous.json.spt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@ if user.ANON:
raise Response(404)
request.allow("GET", "POST")
if POST:
field = body.get("toggle", "giving")
if field not in ["giving", "receiving"]:
raise Response(400)
rec = website.db.one("""

UPDATE participants
SET anonymous=not anonymous
SET anonymous_{0}=not anonymous_{0}
WHERE username=%s
RETURNING anonymous
RETURNING anonymous_{0}

""", (user.participant.username,))
""".format(field), (user.participant.username,))
assert rec is not None
response.body = {field: rec}
else:
rec = website.db.one("""

SELECT anonymous FROM participants WHERE username=%s
SELECT anonymous_giving AS giving, anonymous_receiving AS receiving
FROM participants WHERE username=%s

""", (user.participant.username,))
assert rec is not None
response.body = {"anonymous": rec}
""", (user.participant.username,), back_as=dict)
assert rec is not None
response.body = rec
4 changes: 2 additions & 2 deletions www/%username/giving/index.html.spt
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ first_time = qs.get('first_time') == '1'
</ol>

{% endif %}
{% if participant == user %}
<h2>You give $<span class="total-giving">{{ total }}</span> per
{% if participant == user.participant %}
<h2>You give <span class="my-total-giving">${{ total }}</span> per
week</h2>
{% else %}
<h2>{{ participant.username }} gives ${{ total }} per week</h2>
Expand Down
Loading