diff --git a/.travis.yml b/.travis.yml index d5781c9..ef3cabd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,6 @@ cache: - env/bin - env/lib/python2.7/site-packages script: make test -j2 -branches: - only: - - master deploy: provider: heroku # Required for some reason (default anvil strategy doesn't work) @@ -26,9 +23,7 @@ deploy: secure: o0IjJoL7Ee5y7BiZF5VkAYan+8SigY23+2aG8UsNHkrVcqbd1RIVbhoTjJPyYrwolpSUl20pXZaVwSINQSew7YaCqBJBA6HKjFiA7cDY/t2IhWcIb6cyanFkH//+/WrFMNF6HJHc2n/DzpevYmO4ZAqJmoDToszCRj13dmIdJ2s= app: master: inside-gratipay-com - on: - repo: gratipay/inside.gratipay.com - branch: master + operating-agreement: gratipay-operating-agreement notifications: email: false irc: diff --git a/Makefile b/Makefile index 57d68b2..192abcf 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ clean: find . -name \*.pyc -delete run: env - ./$(env_bin)/honcho -e defaults.env,local.env run ./env/bin/python \ + ./$(env_bin)/honcho run -e defaults.env,local.env ./env/bin/python \ ./startapp.py --port=8536 test: diff --git a/defaults.env b/defaults.env index 1deba36..c19b342 100644 --- a/defaults.env +++ b/defaults.env @@ -1,3 +1,2 @@ PORT=8536 ASPEN_CHANGES_RELOAD=true -WWW_GRATIPAY_COM=../gratipay.com/ diff --git a/inside_gratipay/canonizer.py b/inside_gratipay/canonizer.py deleted file mode 100644 index e74106a..0000000 --- a/inside_gratipay/canonizer.py +++ /dev/null @@ -1,40 +0,0 @@ -# Hostname canonicalization -# ========================= -# Upstreaming: https://github.com/gratipay/aspen-python/pull/382 - -def _extract_scheme(request): - return request.headers.get('X-Forwarded-Proto', 'http') # Heroku - -def _extract_host(request): - return request.headers['Host'] # will 400 if missing - -def Canonizer(expected, permanent_redirect=False, extract_scheme=_extract_scheme, - extract_host=_extract_host): - """Takes a netloc such as http://localhost:8080 (no path part). - """ - - def noop(request): - pass - - def canonize(request): - """Enforce a certain network location. - """ - - scheme = extract_scheme(request) - host = extract_host(request) - - actual = scheme + "://" + host - - if actual != expected: - uri = expected - if request.line.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): - # Redirect to a particular path for idempotent methods. - uri += request.line.uri.path.raw - if request.line.uri.querystring: - uri += '?' + request.line.uri.querystring.raw - else: - # For non-idempotent methods, redirect to homepage. - uri += '/' - request.redirect(uri, permanent=permanent_redirect) - - return expected and canonize or noop diff --git a/inside_gratipay/main.py b/inside_gratipay/main.py index 583033b..c2b72ce 100644 --- a/inside_gratipay/main.py +++ b/inside_gratipay/main.py @@ -6,7 +6,7 @@ from aspen import Response from aspen.website import Website -from . import canonizer, gfm +from . import gfm from .nav import NavItem @@ -51,13 +51,6 @@ def only_allow_certain_methods(request): website.algorithm.insert_after('add_nav_current_to_context', add_nav_next_to_context) -# Hostname canonicalization -# ========================= - -canonize = canonizer.Canonizer(os.environ.get('CANONICAL_LOCATION', '')) -website.algorithm.insert_after('parse_environ_into_request', canonize) - - # Set website.version. # ==================== # Yeesh, what a hack. At Heroku we don't have a git repo once deployed, so diff --git a/requirements.txt b/requirements.txt index 8736790..3432dd0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,6 @@ mistune_contrib==0.1 honcho==0.5.0 six==1.10.0 -libsass==0.3.0 +libsass==0.12.3 --editable . diff --git a/scss/variables.scss b/scss/variables.scss index 4347d4f..7d55084 100644 --- a/scss/variables.scss +++ b/scss/variables.scss @@ -4,8 +4,8 @@ /* */ /*****************************************************************************/ -$ideal: 'Ideal Sans SSm A', 'Ideal Sans SSm B'; -$chronicle: 'Chronicle SSm A', 'Chronicle SSm B'; +$ideal: 'Ideal Sans SSm A', 'Ideal Sans SSm B', 'Ideal Sans SSm', Helvetica, sans-serif; +$chronicle: 'Chronicle SSm A', 'Chronicle SSm B', 'Chronicle SSm', Georgia, serif; $mono: Monaco, "Lucida Mono", monospace; // Colors diff --git a/vendor/libsass-0.12.3.tar.gz b/vendor/libsass-0.12.3.tar.gz new file mode 100644 index 0000000..8c6d88c Binary files /dev/null and b/vendor/libsass-0.12.3.tar.gz differ diff --git a/vendor/libsass-0.3.0.tar.gz b/vendor/libsass-0.3.0.tar.gz deleted file mode 100644 index e8601ea..0000000 Binary files a/vendor/libsass-0.3.0.tar.gz and /dev/null differ diff --git a/www/big-picture/index.spt b/www/big-picture/index.spt index f06e0a0..69065f3 100644 --- a/www/big-picture/index.spt +++ b/www/big-picture/index.spt @@ -1,6 +1,6 @@ nav_title = 'The Big Picture' -nav_children = ['welcome', 'mission', 'values', 'brand', 'strategy', 'customers', 'org-chart', - 'roadmap'] +nav_children = ['welcome', 'operating-agreement', 'mission', 'values', 'brand', 'strategy', + 'customers', 'org-chart', 'roadmap'] [---] [---] text/html diff --git a/www/big-picture/operating-agreement.spt b/www/big-picture/operating-agreement.spt new file mode 100644 index 0000000..68fcfc8 --- /dev/null +++ b/www/big-picture/operating-agreement.spt @@ -0,0 +1,180 @@ +nav_title = "Operating Agreement" +nav_children = [] +[---] +[---] text/html via markdown + +Gratipay, LLC is a worker-owned cooperative, organized under and subject to the +laws of the Commonwealth of Pennsylvania in the United States of America. In +this document, “Gratipay,” “the company,” and +“the cooperative” refer to Gratipay, LLC. This is the operating +agreement that defines how the members of Gratipay govern the cooperative, and +it constitutes the entire agreement between Gratipay and its members. + + +## Basic Definitions + +A cooperative is a democratically governed, for-profit company. Non-cooperative +companies weight power by equity, one vote per share. Cooperatives distribute +power according to the fundamental equality of all natural persons (also called +“individuals” in this document), “one member, one +vote.” Gratipay subscribes to the [principles and values of the +cooperative movement](./values), and intends for this operating agreement to be +consistent with those values. + +An LLC is a Limited Liability Company, a flexible legal structure that protects +its owners from legal liability, while avoiding the double-taxation that comes +with other corporate structures. + +Not all LLCs are cooperatives, and not all cooperatives are LLCs, but an LLC +can be a good choice for structuring a cooperative. An LLC is an especially +compelling choice for Gratipay because of the diverse international composition +of our expected membership (which is easier handled with an LLC than with other +structures), and because Gratipay was already structured as a single-member LLC +before it evolved into a cooperative. + + +## Membership + +Gratipay members are individuals. They share in both the work of the +cooperative and its profits and loses (they are “active” members), +as opposed to only sharing in the profits and losses without sharing in the +work (they are not “passive” members). Gratipay is member-managed, +not manager-managed. Gratipay members are owners, not employees. Members may +bind the company. + +Gratipay decides to invite new members through a vote of the existing +membership. In general, the way to earn an invitation is to [collaborate in our +work](./welcome) for a long time. Once invited, the individual must provide an +[SSN or +ITIN](https://www.irs.gov/individuals/international-taxpayers/taxpayer-identification-numbers-tin) +and consent to this operating agreement in order to become a member of +Gratipay. Gratipay does not require members to make a capital contribution. + +Members may remove themselves from Gratipay for any reason at any time. +Gratipay may remove a member against their will for any reason at any time, by +a vote of the remaining membership. Gratipay automatically and immediately +removes a member (no vote required) if they: + +- abstain from seven votes in a row, +- access a system without permission, +- spend beyond their allowance, or +- violate the [code of conduct](../howto/behave-well). + +Gratipay may reinvite any individual at any time, but a proposal to reinvite +someone must clearly indicate the circumstances of any and all previous +removals. + +Members may not sell or transfer their membership. + +Gratipay maintains membership records [on +Gratipay.com](https://gratipay.com/Gratipay/distributing/). + + +## Governance + +Gratipay makes decisions in online [channels](../appendices/channels), +primarily GitHub. Most decisions are by general consent. That is, a member +announces an intention and waits for an amount of time proportional to the +importance of the decision. If no-one objects then the matter is decided. If +another member objects then the members involved work out a consensus. If they +can't work it out then Gratipay votes. + +Gratipay calls votes by general consent. By default, votes are open for 72 +hours and require a majority to pass. The quorum is: + +- a majority if there are fewer than seven members, +- seven if there are at least 14 but fewer than 35 members, and +- 20% (rounded down) if there are 35 or more members. + +Members cast votes using comments and/or reactions on GitHub issues. Any member +may count the vote and publish their count. Those members who publish a count +within 24 hours after voting closes decide together on the final count. + +The following decisions require a vote with a seven day voting period and a +majority in favor to pass: + +- removing a member against their will, +- changing [the big picture](./), which includes this document, and +- accepting outside financing, which includes loans from members. + +The following decisions require a vote with a 14-day voting period and at least +75% in favor to pass: + +- adding a member, and +- selling or dissolving Gratipay. + +In the case of a vote to decide whether to call a vote, the period is 24 hours +and a majority decides it. + +Gratipay software is open source. In the case of irreconcilable conflict, +members in the minority have the option to fork. + +Gratipay maintains a record of it decisions in [GitHub +issues](https://github.com/search?q=user%3Agratipay&type=Issues). + + +## Access + +Gratipay restricts access in various ways to its various systems (e.g.: web +hosting infrastructure, databases, and upstream payment processor dashboards +and APIs). For each system, Gratipay invites members to have access to the +system by a vote of 100% of the subset of members who already have access to +the system. The usual quorum rules apply, scoped to this subset. + +Any member with control over access to a subsystem may withdraw access from any +other member at any time for any reason. + +Gratipay maintains a record of each member's access in their [onboarding +ticket](https://github.com/gratipay/inside.gratipay.com/issues?q=label%3AOnboarding). + + +## Money + +Gratipay makes guaranteed payments to its members using a +“take-what-you-want” (“twyw”) system integrated into +the Gratipay.com website. Gratipay does not distribute profits apart from +guaranteed payments. + +Gratipay does not accept capital contributions from members. If any member +wants to let Gratipay use their money, they may loan it to Gratipay on mutually +agreeable terms. + +Gratipay's fiscal year is January 1 through December 31. + +Gratipay allocates profits and losses at the end of the year based on the +amount of money each member otherwise takes in guaranteed payments during the +year. For example, if there are two members, and during the year one takes +$150,000 in guaranteed payments and the other $75,000, then if there is $36,000 +in undistributed profit at the end of the year, Gratipay allocates $24,000 to +the first and $8,000 to the second. + +The United States' Internal Revenue Service (IRS) taxes Gratipay as a +partnership. Each year, between January 1 and March 15, Gratipay files a [Form +1065](https://www.irs.gov/pub/irs-pdf/f1065.pdf) with the IRS, and sends a +[Schedule K-1](https://www.irs.gov/pub/irs-pdf/f1065sk1.pdf) to each member +showing their income through Gratipay for the year. Members are responsible for +paying all taxes on their income through Gratipay, including any quarterly +taxes. Member income through Gratipay includes both the distributions of +guaranteed payments that members take for themselves, and the year-end +profit/loss allocations that stay within Gratipay and are not distributed to +members. For example, if a member takes $75,000 in guaranteed payments during +the year, and is allocated $8,000 in profit at the end of the year, then their +taxable income through Gratipay for the year is $83,000. + +Members are entitled to a spending allowance of an equal share of the money in +Gratipay's primary operating account, computed for each month based on the +account balance and the number of members at the end of the previous month. +Members have no allowance in their first month. For example, if at the end of +April the account balance is $10,000 and the number of members is eight, then +each member is authorized to spend up to $1,250 in May. Members are entitled to +a debit card linked to Gratipay's primary operating account. + +All expenses are authorized by one or more members, and authorized expenses go +against each member's monthly allowance. By default, the member who makes the +payment authorizes the expense. Even when a single member pays an expense, +multiple members may co-authorize the expense, with the expense counting +against each member's total monthly allowance in equal proportion by default. +So, for example, if payment of an invoice for $150 is authorized by three +members, the remaining monthly allowance for each decreases by $50. + +Gratipay maintains financial records [on GitHub](/appendices/finances).