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

Commit

Permalink
UI for open groups is MVP; #449
Browse files Browse the repository at this point in the history
Trusted users can answer the question "Who is Gittip?" and we compute a
percentage split for the pot based on those answers. The rest is
details. Or faucets and fixtures. ;-)
  • Loading branch information
chadwhitacre committed Apr 14, 2013
1 parent 6fe538f commit 2c509a8
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 179 deletions.
17 changes: 15 additions & 2 deletions branch.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ BEGIN;

CREATE TYPE participant_type AS ENUM ( 'individual'
, 'group'
, 'open company'
, 'open group'
);

CREATE TABLE log_participant_type
Expand Down Expand Up @@ -40,6 +40,8 @@ BEGIN;
, NEW.type
);

UPDATE participants SET type='open group' WHERE username_lower='gittip';


------------------
-- identifications
Expand All @@ -53,12 +55,23 @@ BEGIN;
ON DELETE RESTRICT ON UPDATE CASCADE
, "group" text NOT NULL REFERENCES participants
ON DELETE RESTRICT ON UPDATE CASCADE
, weight numeric DEFAULT 0.1
, weight int NOT NULL DEFAULT 0
, identified_by text NOT NULL REFERENCES participants
ON DELETE RESTRICT ON UPDATE CASCADE
, CONSTRAINT no_member_of_self CHECK (member != "group")
, CONSTRAINT no_self_nomination CHECK (member != "identified_by")
, CONSTRAINT no_stacking_the_deck CHECK ("group" != "identified_by")
);


CREATE VIEW current_identifications AS
SELECT DISTINCT ON (member, "group", identified_by) *
FROM identifications
JOIN participants p ON p.username = identified_by
WHERE p.is_suspicious IS FALSE
ORDER BY member
, "group"
, identified_by
, mtime DESC;

END;
2 changes: 2 additions & 0 deletions configure-aspen.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import gittip.authentication
import gittip.orm
import gittip.csrf
import gittip.models.participant


gittip.wireup.canonical()
Expand All @@ -13,6 +14,7 @@
gittip.wireup.username_restrictions(website)
gittip.wireup.sentry(website)
gittip.wireup.mixpanel(website)
gittip.wireup.nanswers()


website.bitbucket_consumer_key = os.environ['BITBUCKET_CONSUMER_KEY'].decode('ASCII')
Expand Down
1 change: 1 addition & 0 deletions default_local.env
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ TWITTER_CONSUMER_KEY=QBB9vEhxO4DFiieRF68zTA
TWITTER_CONSUMER_SECRET=mUymh1hVMiQdMQbduQFYRi79EYYVeOZGrhj27H59H78
TWITTER_CALLBACK=http://127.0.0.1:8537/on/twitter/associate
MIXPANEL_TOKEN=cb9dec68ac0ee57071f0be39f164a417
NANSWERS_THRESHOLD=2
1 change: 1 addition & 0 deletions default_tests.env
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ TWITTER_CONSUMER_KEY=QBB9vEhxO4DFiieRF68zTA
TWITTER_CONSUMER_SECRET=mUymh1hVMiQdMQbduQFYRi79EYYVeOZGrhj27H59H78
TWITTER_CALLBACK=http://127.0.0.1:8537/on/twitter/associate
MIXPANEL_TOKEN=cb9dec68ac0ee57071f0be39f164a417
NANSWERS_THRESHOLD=2
48 changes: 45 additions & 3 deletions gittip/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import datetime
import os
from collections import defaultdict
from decimal import Decimal

import pytz
Expand All @@ -23,6 +24,7 @@
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
".,-_;:@ ")
NANSWERS_THRESHOLD = 0 # configured in wireup.py

class Participant(db.Model):
__tablename__ = "participants"
Expand Down Expand Up @@ -51,7 +53,7 @@ class Participant(db.Model):
balanced_account_uri = Column(Text)
last_ach_result = Column(Text)
is_suspicious = Column(Boolean)
type = Column(Enum('individual', 'group', 'open company', nullable=False))
type = Column(Enum('individual', 'group', 'open group', nullable=False))

### Relations ###
accounts_elsewhere = relationship( "Elsewhere"
Expand Down Expand Up @@ -273,10 +275,50 @@ def get_age_in_seconds(self):
out = (now - self.claimed_time).total_seconds()
return out

def allowed_to_answer(self):
return self.is_suspicious is False \
and len(self.exchanges) > 1

def compute_split(self):
if self.type != 'open company':
if self.type != 'open group':
return [{"username": self.username, "weight": "1.0"}]
pass

nanswers = gittip.db.fetchone("""
SELECT count(*)
FROM ( SELECT identified_by
FROM current_identifications
WHERE "group"=%s
AND weight > 0
GROUP BY identified_by
) AS anon
""", (self.username,))['count']

split = []
if nanswers >= NANSWERS_THRESHOLD:
rows = gittip.db.fetchall("""
SELECT *
FROM current_identifications
WHERE "group"=%s
AND weight > 0
""", (self.username,))

splitmap = defaultdict(int)
total = 0
for row in rows:
splitmap[row['member']] += row['weight']
total += row['weight']

total = float(total)
for username, weight in splitmap.items():
split.append({"username": username, "weight": weight / total})

split.sort(key=lambda r: r['weight'], reverse=True)

return (nanswers, NANSWERS_THRESHOLD, split)


# TODO: Move these queries into this class.
Expand Down
4 changes: 4 additions & 0 deletions gittip/wireup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ def tell_sentry(request):
def mixpanel(website):
website.mixpanel_token = os.environ['MIXPANEL_TOKEN']
gittip.mixpanel.MIXPANEL_TOKEN = os.environ['MIXPANEL_TOKEN']

def nanswers():
from gittip.models import participant
participant.NANSWERS_THRESHOLD = int(os.environ['NANSWERS_THRESHOLD'])
33 changes: 7 additions & 26 deletions templates/gittip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -969,41 +969,18 @@ button.selected:hover {
}
}

#openco {
#open_group {

.fine {
font: normal 10px $Helvetica;
text-transform: uppercase;
}

#weeks {
margin-top: 10px;

#this-week {
width: 220px;
float: left;
text-align: left;
.amount {
font: bold 56px $Helvetica;
}
}

#last-week {
width: 220px;
float: right;
text-align: right;

.account {
padding: 5px 0;
}
}
}

TD {
padding-right: 0.5em;
}

#my-identifications {
#identifications {
width: 250px;
float: right;
position: relative;
Expand Down Expand Up @@ -1063,9 +1040,13 @@ button.selected:hover {
}
}

#crowd {
#split {
width: 180px;
float: left;

.percentage {
text-align: right;
}
}

}
Expand Down
80 changes: 0 additions & 80 deletions templates/identifications.html

This file was deleted.

92 changes: 92 additions & 0 deletions templates/open-group-members.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script src="/assets/{{ __version__ }}/open_group.js"></script>

<div id="open_group" ng-app="Gittip.open_group">

<div class="group" ng-controller="Gittip.open_group.IdentificationsCtrl">
<div id="split">
<h2>Where it Goes.</h2>

{% if user.allowed_to_answer() %}
<p class="fine" ui-if="nanswers_needed == 0">This info is
<b>public</b>.</p>
{% end %}

<p class="fine" ui-if="nanswers_needed == 0">Money given to
{{ participant.username }} is split as follows, based on everyone's
answer to, &ldquo;Who is {{ participant.username }}?&rdquo;</p>

<p class="fine" ui-if="nanswers_needed > 0">We need

<ng-pluralize
count="nanswers_needed"
when="{ 'one': 'one more person'
, 'other': '{} more people'
}"></ng-pluralize>

to answer <b>&ldquo;Who is {{ participant.username }}?&rdquo;</b>
before we'll start distributing money collected for
{{ participant.username }}.</p>

<table>
<tr ng-repeat="participant in split">
<td>&#123;{ participant.username }}</td>
<td class="percentage">&#123;{ participant.weight * 100 | currency:"" }}%</td>
</tr>
</table>
</div>

<div id="identifications">
<h2>Who is {{ participant.username }}?</h2>

{% if user.allowed_to_answer() %}
<p class="fine">Your answer is <b>private</b>.</p>

<p class="fine">Whom do you associate with
{{ participant.username }}, and how strongly?</p>

<table>
<tr ng-repeat="participant in identifications">
<td>&#123;{ participant.username }}</td>
<td>
<input type="radio"
name="weight-&#123;{ participant.username }}"
value="&#123;{ weight }}"
title="weight = &#123;{ weight }}"
ng-repeat="weight in weights"
ng-model="participant.weight"
ng-change="change(participant, weight)"
/>
</td>
</tr>
<tr>
<td colspan="2" id="lookup-container">
<br />
<form ng-submit="doAdd()">
<input tabindex="1" id="query"
autocomplete="off"
placeholder="Enter a Gittip username"
ng-model="query"
ng-change="doLookup()"
/>&nbsp;&nbsp;<button type="submit"
tabindex="2">Add</button>
</form>
<ul id="lookup-results">
<li ng-repeat="participant in lookup">
<span>&#123;{ participant.username }}</span>
</li>
</ul>
</tr>
</table>
{% else %}

<p class="fine">Once you have successfully moved money into or out
of Gittip, you will be able to give your own answer to &ldquo;Who
is {{ participant.username }}?&rdquo;</p>

{% end %}
</div>
</div>

</div>
4 changes: 2 additions & 2 deletions www/%username/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ <h2>Statement</h2>
<div class="col0">
{% end %}

{% if participant.type == 'open company' %}
{% include "templates/identifications.html %}
{% if participant.type == 'open group' %}
{% include "templates/open-group-members.html %}
{% end %}

<h2>Funding Goal</h2>
Expand Down
Loading

0 comments on commit 2c509a8

Please sign in to comment.