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

Profile statements i18n #3010

Merged
merged 22 commits into from
Dec 26, 2014
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions branch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
BEGIN;

CREATE TABLE statements
( participant bigint NOT NULL REFERENCES participants(id)
, lang text NOT NULL
, content text NOT NULL CHECK (content <> '')
, UNIQUE (participant, lang)
);

INSERT INTO statements
SELECT id, 'en', concat('I am making the world better by ', statement)
FROM participants
WHERE statement <> ''
AND number = 'singular';

INSERT INTO statements
SELECT id, 'en', concat('We are making the world better by ', statement)
FROM participants
WHERE statement <> ''
AND number = 'plural';

CREATE FUNCTION enumerate(anyarray) RETURNS TABLE (rank bigint, value anyelement) AS $$
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice.

SELECT row_number() over() as rank, value FROM unnest($1) value;
$$ LANGUAGE sql STABLE;

END;
47 changes: 41 additions & 6 deletions gratipay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,44 @@ def update_number(self, number):
# Statement
# =========

def update_statement(self, statement):
self.db.run("UPDATE participants SET statement=%s WHERE id=%s", (statement, self.id))
self.set_attributes(statement=statement)
def get_statement(self, langs):
"""Get the participant's statement in the language that best matches
the list provided.
"""
return self.db.one("""
SELECT content, lang
FROM statements
JOIN enumerate(%(langs)s) langs ON langs.value = statements.lang
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes me really nervous. We have some assurance that self.id won't contain a SQL injection. What assurance do we give ourselves that langs won't contain a SQL injection?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't matter what langs contains, psycopg handles the escaping.

WHERE participant=%(id)s
ORDER BY langs.rank
LIMIT 1
""", dict(id=self.id, langs=langs), default=(None, None))

def get_statement_langs(self):
return self.db.all("SELECT lang FROM statements WHERE participant=%s",
(self.id,))

def upsert_statement(self, lang, statement):
if not statement:
self.db.run("DELETE FROM statements WHERE participant=%s AND lang=%s",
(self.id, lang))
return
r = self.db.one("""
UPDATE statements
SET content=%s
WHERE participant=%s
AND lang=%s
RETURNING true
""", (statement, self.id, lang))
if not r:
try:
self.db.run("""
INSERT INTO statements
(lang, content, participant)
VALUES (%s, %s, %s)
""", (lang, statement, self.id))
except IntegrityError:
return self.upsert_statement(lang, statement)


# Pricing
Expand Down Expand Up @@ -418,7 +453,7 @@ def clear_takes(self, cursor):


def clear_personal_information(self, cursor):
"""Clear personal information such as statement and goal.
"""Clear personal information such as statements and goal.
"""
if self.IS_PLURAL:
self.remove_all_members(cursor)
Expand All @@ -433,10 +468,10 @@ def clear_personal_information(self, cursor):
);

DELETE FROM emails WHERE participant = %(username)s;
DELETE FROM statements WHERE participant=%(participant_id)s;

UPDATE participants
SET statement=''
, goal=NULL
SET goal=NULL
, anonymous_giving=False
, anonymous_receiving=False
, number='singular'
Expand Down
Loading