Skip to content

Commit

Permalink
Merge pull request #50 from maailma/member-types
Browse files Browse the repository at this point in the history
Configurable member types
  • Loading branch information
eemeli authored Aug 31, 2018
2 parents ee63feb + dfc5dfa commit f25e487
Show file tree
Hide file tree
Showing 24 changed files with 525 additions and 427 deletions.
6 changes: 0 additions & 6 deletions config/database/21-member-types.sql

This file was deleted.

7 changes: 2 additions & 5 deletions config/database/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ If you end up making changes later to values or tables that are defined in your
## Required Config
Some of the configuration is required, and run at specific points during the initialisation:

### `21-member-types.sql`
Defines the types of memberships that are supported. The order of values matters for upgrades, so use something like this if adding member types:
```sql
ALTER TYPE kansa.MembershipStatus ADD VALUE 'KidInTow' BEFORE 'Child';
```
### `member-types.sql`
Defines the types of memberships that are supported, and their attributes.

### `31-hugo-categories.sql`
Defines the Hugo Awards categories. The order of values defines their listing order, so use something like this if adding categories:
Expand Down
28 changes: 14 additions & 14 deletions config/database/dev-people.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ INSERT INTO admin.Admins (email, member_admin, member_list, siteselection, hugo_

SET ROLE kansa;

INSERT INTO People (legal_name, email, membership, member_number, hugo_nominator, hugo_voter)
VALUES ('Admin', '[email protected]', 'NonMember', NULL, false, false),
('Member Admin', '[email protected]', 'NonMember', NULL, false, false),
('Site Selection', '[email protected]', 'NonMember', NULL, false, false),
('Hugo Admin', '[email protected]', 'NonMember', NULL, false, false),
('First Member', '[email protected]', 'FirstWorldcon', 2, true, true),
('Fan Parent', '[email protected]', 'Adult', 3, true, true),
('Fan Child', '[email protected]', 'Child', 4, false, false),
('Fan Youth', '[email protected]', 'Youth', 5, true, true),
('Fan Supporter', '[email protected]', 'Supporter', 6, true, true),
('Dupe Supporter', '[email protected]', 'Supporter', 7, false, false),
('Fan Trader', '[email protected]', 'Exhibitor', 8, false, false),
('Fan Helper', '[email protected]', 'Helper', 9, false, false),
('Fan Nominator', '[email protected]', 'NonMember', NULL, true, false);
INSERT INTO People (legal_name, email, membership, member_number)
VALUES ('Admin', '[email protected]', 'NonMember', NULL),
('Member Admin', '[email protected]', 'NonMember', NULL),
('Site Selection', '[email protected]', 'NonMember', NULL),
('Hugo Admin', '[email protected]', 'NonMember', NULL),
('First Member', '[email protected]', 'FirstWorldcon', 2),
('Fan Parent', '[email protected]', 'Adult', 3),
('Fan Child', '[email protected]', 'Child', 4),
('Fan Youth', '[email protected]', 'Youth', 5),
('Fan Supporter', '[email protected]', 'Supporter', 6),
('Dupe Supporter', '[email protected]', 'Supporter', 7),
('Fan Trader', '[email protected]', 'Exhibitor', 8),
('Fan Helper', '[email protected]', 'Helper', 9),
('Fan Nominator', '[email protected]', 'HugoNominator', NULL);

INSERT INTO Keys
VALUES ('[email protected]', 'key'),
Expand Down
4 changes: 4 additions & 0 deletions config/database/fake-people.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ SET row_security = off;
-- Data for Name: people; Type: TABLE DATA; Schema: kansa; Owner: kansa
--

ALTER TABLE kansa.people ADD COLUMN hugo_nominator bool;
ALTER TABLE kansa.people ADD COLUMN hugo_voter bool;
COPY kansa.people (id, last_modified, membership, member_number, legal_name, public_first_name, public_last_name, email, city, state, country, badge_name, badge_subtitle, hugo_nominator, hugo_voter, paper_pubs) FROM stdin;
15 2018-07-29 18:14:07.698028+00 FirstWorldcon 43 Factual Blob Fake (Factual) Blob fblog@fblobsblog.com Fact City Data Central Blobitania \N \N \N \N \N
14 2018-07-29 18:14:07.701524+00 Supporter 42 Samuel Vimes \N \N s.vimes@gmial.ocm Ankh-Morpork \N The Disc \N \N \N \N {"name": "Samuel Vimes", "address": "11, Broadstreet\\r\\nAnkh-Morpork", "country": "Ankh-Morpork"}
Expand Down Expand Up @@ -669,6 +671,8 @@ COPY kansa.people (id, last_modified, membership, member_number, legal_name, pub
660 2018-07-29 18:14:40.950855+00 KidInTow 688 Falkrunn Ungart Falkrunn Ungart [email protected] Waren Kein Denmark \N \N \N \N \N
\.
ALTER TABLE kansa.people DROP COLUMN hugo_nominator;
ALTER TABLE kansa.people DROP COLUMN hugo_voter;
--
-- Data for Name: log; Type: TABLE DATA; Schema: kansa; Owner: kansa
Expand Down
14 changes: 14 additions & 0 deletions config/database/membership-types.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
SET ROLE kansa;

INSERT INTO membership_types (
membership, allow_lookup, badge, daypass_available, hugo_nominator, member, wsfs_member) VALUES
('NonMember', true, false, false, false, false, false),
('HugoNominator', true, false, false, true, false, false),
('Exhibitor', true, true, false, false, true, false),
('Helper', true, true, false, false, true, false),
('Supporter', true, false, false, true, true, true),
('KidInTow', false, true, false, false, true, false),
('Child', false, true, true, false, true, false),
('Youth', true, true, true, true, true, true),
('FirstWorldcon', true, true, false, true, true, true),
('Adult', true, true, true, true, true, true);
2 changes: 1 addition & 1 deletion config/docker-compose.base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ services:
- pgdata:/pgdata
- ../postgres/init/10-admin-init.sql:/docker-entrypoint-initdb.d/10-admin-init.sql:ro
- ../postgres/init/20-kansa-init.sql:/docker-entrypoint-initdb.d/20-kansa-init.sql:ro
- ../config/database/21-member-types.sql:/docker-entrypoint-initdb.d/21-member-types.sql:ro
- ../postgres/init/22-kansa-tables.sql:/docker-entrypoint-initdb.d/22-kansa-tables.sql:ro
- ../postgres/init/25-day-passes.sql:/docker-entrypoint-initdb.d/25-day-passes.sql:ro
- ../postgres/init/25-payments.sql:/docker-entrypoint-initdb.d/25-payments.sql:ro
- ../postgres/init/25-public-data.sql:/docker-entrypoint-initdb.d/25-public-data.sql:ro
- ../postgres/init/28-siteselection.sql:/docker-entrypoint-initdb.d/28-siteselection.sql:ro
- ../config/database/membership-types.sql:/docker-entrypoint-initdb.d/29-membership-types.sql:ro
- ../postgres/init/30-hugo-init.sql:/docker-entrypoint-initdb.d/30-hugo-init.sql:ro
- ../config/database/31-hugo-categories.sql:/docker-entrypoint-initdb.d/31-hugo-categories.sql:ro
- ../postgres/init/32-hugo-tables.sql:/docker-entrypoint-initdb.d/32-hugo-tables.sql:ro
Expand Down
12 changes: 10 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,16 @@ The configuration used by this instance.
{
id: 'w75',
name: 'Worldcon 75',
paid_paper_pubs: true
paid_paper_pubs: true,
membershipTypes: {
Adult: {
badge: true,
hugo_nominator: true,
member: true,
wsfs_member: true
},
...
}
}
```

Expand Down Expand Up @@ -240,7 +249,6 @@ data, `member_admin` or `member_list` authority is required.
{
id, last_modified, member_number, membership, legal_name, email,
public_first_name, public_last_name, city, state, country,
hugo_nominator, hugo_voter,
paper_pubs: { name, address, country },
preferred_name, daypass, daypass_days
}
Expand Down
22 changes: 10 additions & 12 deletions hugo/lib/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,16 @@ class Admin {
}

_classifyWithObject(category, nomination, getInsertQuery) {
return this.db.tx(tx => tx.sequence((i, data) => { switch (i) {
case 0:
return tx.one(`
INSERT INTO Canon (category, nomination)
VALUES ($(category), $(nomination)::jsonb)
ON CONFLICT (category, nomination)
DO UPDATE SET category = EXCLUDED.category
RETURNING id
`, { category, nomination }); // DO UPDATE required for non-empty RETURNING id
case 1:
return tx.none(getInsertQuery(data.id));
}}))
return this.db.tx(tx =>
tx.one(`
INSERT INTO Canon (category, nomination)
VALUES ($(category), $(nomination)::jsonb)
ON CONFLICT (category, nomination)
DO UPDATE SET category = EXCLUDED.category
RETURNING id`, { category, nomination } // DO UPDATE required for non-empty RETURNING id
)
.then(({ id }) => tx.none(getInsertQuery(id)))
)
}

classify(req, res, next) {
Expand Down
9 changes: 7 additions & 2 deletions hugo/lib/nominate.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ function access(req) {
const id = parseInt(req.params.id);
if (isNaN(id) || id < 0) return Promise.reject(new InputError('Bad id number'));
if (!req.session || !req.session.user || !req.session.user.email) return Promise.reject(new AuthError());
return req.app.locals.db.oneOrNone('SELECT email, hugo_nominator, hugo_voter FROM kansa.People WHERE id = $1', id)
return req.app.locals.db.oneOrNone(`
SELECT p.email, m.hugo_nominator, m.wsfs_member
FROM kansa.people p
LEFT JOIN kansa.membership_types m USING (membership)
WHERE id = $1`, id
)
.then(data => {
if (!data || !req.session.user.hugo_admin && req.session.user.email !== data.email) throw new AuthError();
return {
id,
nominator: !!data.hugo_nominator,
voter: !!data.hugo_voter
voter: !!data.wsfs_member
};
});
}
Expand Down
9 changes: 5 additions & 4 deletions hugo/lib/vote.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ class Vote {
if (isNaN(id) || id < 0) return Promise.reject(new InputError('Bad id number'));
if (!req.session || !req.session.user || !req.session.user.email) return Promise.reject(new AuthError());
return this.db.oneOrNone(`
SELECT email, hugo_voter
FROM kansa.People
WHERE id = $1`, id
SELECT p.email, m.wsfs_member
FROM kansa.People p
LEFT JOIN kansa.membership_types m USING (membership)
WHERE id = $1`, id
)
.then(data => {
if (!data || !req.session.user.hugo_admin && req.session.user.email !== data.email) throw new AuthError();
return {
id,
voter: !!data.hugo_voter
voter: !!data.wsfs_member
};
});
}
Expand Down
2 changes: 1 addition & 1 deletion kansa/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ const peopleStream = new PeopleStream(db);
router.get('/public/people', cors({ origin: '*' }), publicData.getPublicPeople);
router.get('/public/stats', cors({ origin: '*' }), publicData.getPublicStats);
router.get('/public/daypass-stats', cors({ origin: '*' }), publicData.getDaypassStats);
router.get('/config', publicData.getConfig);

router.post('/key', key.setKey);
router.all('/login', user.login);

router.get('/config', (req, res) => res.json(config));
router.get('/barcode/:key/:id.:fmt', badge.getBarcode);
router.get('/blank-badge', badge.getBadge);

Expand Down
21 changes: 14 additions & 7 deletions kansa/lib/badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ const splitNameInTwain = (name) => {
function getBadge(req, res, next) {
const id = parseInt(req.params.id || '0')
req.app.locals.db.oneOrNone(`
SELECT member_number, membership, get_badge_name(p) AS name, get_badge_subtitle(p) AS subtitle
FROM people p WHERE id = $1 AND membership != 'Supporter'`, id
SELECT
p.member_number, membership,
get_badge_name(p) AS name, get_badge_subtitle(p) AS subtitle
FROM people p
LEFT JOIN membership_types m USING (membership)
WHERE id = $1 AND m.badge = true`, id
)
.then(data => {
const { member_number, membership, name, subtitle } = data || {}
Expand Down Expand Up @@ -75,12 +79,15 @@ function getBarcode(req, res, next) {
const format = req.params.fmt === 'pdf' ? 'pdf' : 'png'
req.app.locals.db.one(`
SELECT member_number, membership,
get_badge_name(p) AS name, get_badge_subtitle(p) AS subtitle,
d.status AS daypass, daypass_days(d) AS days
FROM people p
get_badge_name(p) AS name, get_badge_subtitle(p) AS subtitle,
d.status AS daypass, daypass_days(d) AS days
FROM people p
JOIN keys k USING (email)
LEFT JOIN daypasses d ON (p.id = d.person_id)
WHERE p.id=$(id) ${key ? 'AND key=$(key)' : ''} AND membership != 'Supporter'`, { id, key }
LEFT JOIN membership_types m USING (membership)
LEFT JOIN daypasses d ON (p.id = d.person_id)
WHERE p.id=$(id) AND
(m.badge = true OR d.status IS NOT NULL)
${key ? 'AND key=$(key)' : ''}`, { id, key }
)
.then(data => {
const { daypass, days, member_number, membership, name, subtitle } = data
Expand Down
28 changes: 11 additions & 17 deletions kansa/lib/mail.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ function mailTask(type, data, delay) {
}

const mailRecipient = (email, res) => {
const mt = [ 'NonMember', 'KidInTow', 'Exhibitor', 'Helper', 'Child', 'Supporter', 'Youth', 'FirstWorldcon', 'Adult' ]
// inlined as types/person.js has Supporter < Child
const mi = res.reduce((max, r) => Math.max(max, mt.indexOf(r.membership)), -1)
let name = res[0].name
switch (res.length) {
case 0: return { email, delete: true }
Expand All @@ -32,32 +29,29 @@ const mailRecipient = (email, res) => {
name = names.join(', ')
}
const attending = res
.filter(r => {
switch (r.membership) {
case 'Supporter': return false
case 'NonMember': return !!r.daypass
default: return true
}
})
.filter(r => r.badge || r.daypass)
.map(({ id, name }) => ({ id, name }))
const hugo_members = res
.filter(r => r.hugo_nominator || r.hugo_voter)
.filter(r => r.hugo_nominator || r.wsfs_member)
.map(({ id, name }) => ({ id, name }))
return {
attending,
email: res[0].email,
hugo_members,
key: res[0].key,
membership: mt[mi],
membership: res[0].membership, // FIXME: see https://github.com/maailma/kansa/issues/49
name
}
}
mailRecipient.selector = `
SELECT email, key, p.id, membership, preferred_name(p) as name,
hugo_nominator, hugo_voter, d.status AS daypass
FROM people p
LEFT JOIN keys USING (email)
LEFT JOIN daypasses d ON (p.id = d.person_id)`
SELECT
email, key, p.id, membership, preferred_name(p) as name,
m.badge, m.hugo_nominator, m.wsfs_member,
d.status AS daypass
FROM people p
LEFT JOIN keys USING (email)
LEFT JOIN membership_type m USING (membership)
LEFT JOIN daypasses d ON (p.id = d.person_id)`

function rxUpdateTask(recipients) {
return fetch('http://kyyhky/update-recipients', {
Expand Down
Loading

0 comments on commit f25e487

Please sign in to comment.