Skip to content
This repository was archived by the owner on Apr 6, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
490b47e
feat(republik): expose Membership.cancelReasons
patte Mar 12, 2018
b52fa59
feat(auth): add User.eventLog
patte Mar 13, 2018
9f7af6a
feat(republik): slack notifications for: cancel- and reactivateMember…
patte Mar 13, 2018
ca6be93
fix(republik): cleanup updateUser
patte Mar 13, 2018
4513244
feat(republik): movePledge
patte Mar 13, 2018
7a53d38
Merge branch 'master' into admin
patte Mar 14, 2018
f545ef4
feat(republik): moveMembership
patte Mar 14, 2018
2ad1fad
fix(move-Membership/-Pledge): fix transactions and conditions
patte Mar 15, 2018
682432f
Merge branch 'master' into admin
patte Mar 15, 2018
2cc1ecc
feat(republik): make reactivateMembership activate YEARLYs correctly
patte Mar 15, 2018
b141c18
fix(republik): make updateNewsletterSubscription accept a userId and …
patte Mar 16, 2018
8ffe47f
feat(republik): adminNotes for User, incl. update AdminNotes mutation
patte Mar 19, 2018
c40818b
feat(republik): User.checkMembershipSubscriptions && CHECK_MEMBERSHIP…
patte Mar 19, 2018
0bd4388
feat(republik): generateMembership
patte Mar 19, 2018
42c730c
fix($browser): typo fixed
lukasbuenger Mar 30, 2018
0298cf0
style($auth): removeUserFromRoll to removeUserFromRole
lukasbuenger Mar 30, 2018
e508a81
fix(republik): deny moveMembership and movePledge for MONTHLY
patte Mar 30, 2018
b48226a
Merge branch 'admin' of github.com:orbiting/backends into admin
patte Mar 30, 2018
f29a4bc
style($auth): fix typo
lukasbuenger Mar 30, 2018
2dd9629
feat($auth): mutations addUserToRole and removeUserFromRole
lukasbuenger Mar 30, 2018
396da13
fix(auth): enforce supporter on mergeUser
lukasbuenger Mar 30, 2018
1bdcea9
Merge branch 'master' into admin
patte Apr 2, 2018
6545892
Merge branch 'master' into admin
patte Apr 2, 2018
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
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ DATABASE_URL=postgres://patte@localhost:5432/republik
# - republik for payment redirect urls
FRONTEND_BASE_URL=http://localhost:3010

#url to crowdfunding-admin
# used by
# - slack to send link to profiles to SLACK_CHANNEL_ADMIN
ADMIN_FRONTEND_BASE_URL=http://localhost:3003

# log requsts that take longer than the specified ms
#REQ_TIMEOUT=2000

Expand Down
41 changes: 41 additions & 0 deletions packages/auth/graphql/resolvers/EventLog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

module.exports = {
type (eventLog, args) {
if (
eventLog.action === 'INSERT' &&
eventLog.oldData === null &&
eventLog.newData &&
eventLog.newData.sess.token
) {
return 'TOKEN_REQUEST'
}
if (
eventLog.action === 'UPDATE' &&
eventLog.oldData &&
eventLog.newData &&
eventLog.oldData.sess.cookie.expires !==
eventLog.newData.sess.cookie.expires
) {
return 'ROLL_SESSION'
}
if (
eventLog.action === 'UPDATE' &&
eventLog.oldData &&
eventLog.newData &&
eventLog.oldData.sess.token &&
eventLog.newData.sess.token === null
) {
if (eventLog.newData.sess.passport.user) {
return 'AUTHORIZE_SESSION'
} else {
return 'DENY_SESSION'
}
}
if (
eventLog.action === 'DELETE'
) {
return 'SIGNOUT_TIMEOUT'
}
return 'UNKNOWN'
}
}
29 changes: 29 additions & 0 deletions packages/auth/graphql/resolvers/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,34 @@ module.exports = {
},
updatedAt (user, args, { user: me }) {
return user._raw.updatedAt
},
async eventLog (user, args, { pgdb, user: me }) {
Roles.ensureUserIsMeOrInRoles(user, me, userAccessRoles)
return pgdb.query(`
SELECT
e.*,
to_json(s.*) as "activeSession"
FROM
"eventLog" e
LEFT JOIN
sessions s
ON e."newData" #>> '{sid}' = s.sid
WHERE
e."newData" #>> '{sess,email}' = :email OR
e."oldData" #>> '{sess,email}' = :email OR
e."newData" #>> '{sess,passport,user}' = :userId OR
e."oldData" #>> '{sess,passport,user}' = :userId
ORDER BY
e."createdAt" DESC
`, {
email: user.email,
userId: user.userId
})
.then(result => result
.map(e => ({
...e,
archivedSession: e.newData || e.oldData
}))
)
}
}
24 changes: 24 additions & 0 deletions packages/auth/graphql/resolvers/_mutations/addUserToRole.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const t = require('../../../lib/t')
const {
ensureUserHasRole,
userHasRole,
addUserToRole
} = require('../../../lib/Roles')
const logger = console

module.exports = async (_, args, { pgdb, req, signInHooks }) => {
ensureUserHasRole(req.user, 'admin')
const { userId, role } = args
const user = await pgdb.public.users.findOne({id: userId})

if (!user) {
logger.error('user not found', { req: req._log() })
throw new Error(t('api/users/404'))
}

if (userHasRole(user, role)) {
return user
} else {
return addUserToRole(userId, role, pgdb)
}
}
27 changes: 27 additions & 0 deletions packages/auth/graphql/resolvers/_mutations/removeUserFromRole.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const t = require('../../../lib/t')
const {
ensureUserHasRole,
userHasRole,
removeUserFromRole
} = require('../../../lib/Roles')

const logger = console

module.exports = async (_, args, { pgdb, req, signInHooks }) => {
ensureUserHasRole(req.user, 'admin')

const { userId, role } = args

const user = await pgdb.public.users.findOne({id: userId})

if (!user) {
logger.error('user not found', { req: req._log() })
throw new Error(t('api/users/404'))
}

if (!userHasRole(user, role)) {
return user
} else {
return removeUserFromRole(userId, role, pgdb)
}
}
17 changes: 17 additions & 0 deletions packages/auth/graphql/schema-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type User {
createdAt: DateTime!
updatedAt: DateTime!
sessions: [Session!]
eventLog: [EventLog!]!
}

type SignInResponse {
Expand All @@ -38,4 +39,20 @@ type RequestInfo {
countryFlag: String
city: String
}

enum EventLogType {
TOKEN_REQUEST
ROLL_SESSION
AUTHORIZE_SESSION
DENY_SESSION
SIGNOUT_TIMEOUT
UNKNOWN
}

type EventLog {
type: EventLogType
archivedSession: Session
activeSession: Session
createdAt: DateTime!
}
`
6 changes: 6 additions & 0 deletions packages/auth/graphql/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,11 @@ type mutations {
# if userId is null, the logged in user's sessions get cleared
# required role to clear other's session: supporter
clearSessions(userId: ID): Boolean!

# Add a user to a given role
addUserToRole(userId: ID!, role: String!): User!

# Remove a user from a given role
removeUserFromRole(userId: ID!, role: String!): User!
}
`
12 changes: 5 additions & 7 deletions packages/auth/lib/Roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ const ensureUserHasRole = (user, role) => {
}
}


const userIsInRoles = (user, roles = []) => {
const matches = roles.filter( role =>
const matches = roles.filter(role =>
userHasRole(user, role)
)
return matches.length > 0
Expand All @@ -35,18 +34,17 @@ const ensureUserIsInRoles = (user, roles) => {
console.info('signIn', { stack: new Error().stack })
throw new Error(t('api/signIn'))
}
if(!userIsInRoles(user, roles)) {
if (!userIsInRoles(user, roles)) {
console.info('unauthorized', { stack: new Error().stack })
throw new Error(t.pluralize('api/unauthorized', {
count: roles.length,
role: roles
.map( role => `«${role}»`)
.map(role => `«${role}»`)
.join(', ')
}))
}
}


const addUserToRole = async (userId, role, pgdb) => {
await pgdb.query(`
UPDATE
Expand All @@ -63,7 +61,7 @@ const addUserToRole = async (userId, role, pgdb) => {
return pgdb.public.users.findOne({id: userId})
}

const removeUserFromRoll = async (userId, role, pgdb) => {
const removeUserFromRole = async (userId, role, pgdb) => {
await pgdb.query(`
UPDATE
users
Expand Down Expand Up @@ -108,5 +106,5 @@ module.exports = {
userIsMeOrHasProfile,
ensureUserIsInRoles,
addUserToRole,
removeUserFromRoll
removeUserFromRole
}
8 changes: 4 additions & 4 deletions packages/auth/lib/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
},
{
"key": "api/unauthorized",
"value": "Nicht genehmigt. Sie müssen die Rolle «{role}» besitzen um die gwünschte Aktion auszuführen."
"value": "Nicht genehmigt. Sie müssen die Rolle «{role}» besitzen, um die gewünschte Aktion auszuführen."
},
{
"key": "api/unauthorized/1",
"value": "Nicht genehmigt. Sie müssen die Rolle {role} besitzen um die gwünschte Aktion auszuführen."
"value": "Nicht genehmigt. Sie müssen die Rolle {role} besitzen, um die gewünschte Aktion auszuführen."
},
{
"key": "api/unauthorized/other",
"value": "Nicht genehmigt. Sie müssen mindestens eine der folgenden Rollen {role} besitzen um die gwünschte Aktion auszuführen."
"value": "Nicht genehmigt. Sie müssen mindestens eine der folgenden Rollen {role} besitzen, um die gewünschte Aktion auszuführen."
},
{
"key": "api/email/invalid",
Expand Down Expand Up @@ -59,4 +59,4 @@
"value": "Der User konnte leider nicht gefunden werden."
}
]
}
}
2 changes: 1 addition & 1 deletion packages/auth/script/roleUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PgDb.connect({connectionString: DATABASE_URL}).then(async (pgdb) => {

let newUser
if (process.argv[4]) {
newUser = await Roles.removeUserFromRoll(user.id, role, pgdb)
newUser = await Roles.removeUserFromRole(user.id, role, pgdb)
} else {
newUser = await Roles.addUserToRole(user.id, role, pgdb)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/script/roleUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ PgDb.connect({connectionString: DATABASE_URL}).then(async (pgdb) => {
)
} else {
promises.push(
Roles.removeUserFromRoll(existingUser.id, role, transaction)
Roles.removeUserFromRole(existingUser.id, role, transaction)
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions servers/publikator/lib/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
{
"key": "api/unauthorized",
"value": "Nicht genehmigt. Sie müssen die Rolle «{role}» besitzen um die gwünschte Aktion auszuführen."
"value": "Nicht genehmigt. Sie müssen die Rolle «{role}» besitzen, um die gewünschte Aktion auszuführen."
},
{
"key": "api/email/invalid",
Expand Down Expand Up @@ -59,4 +59,4 @@
"value": "1 weiteres Foto"
}
]
}
}
2 changes: 2 additions & 0 deletions servers/republik/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ MAILCHIMP_INTEREST_MEMBER_BENEFACTOR=
#SLACK_API_TOKEN=
#SLACK_CHANNEL_COMMENTS=
#SLACK_CHANNEL_GREETING=
#SLACK_CHANNEL_ADMIN=
#SLACK_CHANNEL_FINANCE=

# Sheet IDs for gsheets powered pages
#GSHEETS={"someSheetId": "faqs","someSheetId": "updates","someSheetId": "events"}
Expand Down
12 changes: 11 additions & 1 deletion servers/republik/__tests__/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ const Supporter = {
verified: true
}

const Admin = {
id: 'a0000000-0000-0000-0001-000000000004',
firstName: 'willhelm tell',
lastName: 'admin',
email: 'willhelmtell_admin@project-r.construction',
roles: ['admin'],
verified: true
}

const Anonymous = {
firstName: null,
lastName: null,
Expand All @@ -105,6 +114,7 @@ module.exports = {
Supporter,
Unverified,
Anonymous,
Member
Member,
Admin
}
}
60 changes: 60 additions & 0 deletions servers/republik/__tests__/crowdfundings/addUserToRole.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const test = require('tape-async')
const { connectIfNeeded, apolloFetch, pgDatabase } = require('../helpers.js')
const { signIn, signOut, Users } = require('../auth.js')

const ADD_USER_TO_ROLE = `
mutation addUserToRole($userId: ID!, $role: String!) {
user: addUserToRole(userId: $userId, role: $role) {
id
roles
}
}
`

const addUserToRole = async ({ userId, role }) => {
return apolloFetch({
query: ADD_USER_TO_ROLE,
variables: {
userId, role
}
})
}

const prepare = async (options) => {
await connectIfNeeded()
await pgDatabase().public.users.truncate({ cascade: true })
}

test('addUserToRole: Users.Admin adds role to Users.Supporter', async (t) => {
await prepare()
await pgDatabase().public.users.insert(Users.Supporter)
await signIn({ user: Users.Admin })

const result = await addUserToRole({
userId: Users.Supporter.id,
role: 'editor'
})
const user = await pgDatabase().public.users.findOne({ id: Users.Supporter.id })
t.deepEqual(user.roles, ['supporter', 'editor'], 'the db user object has the new role `editor`')
t.deepEqual(result.data.user.roles, ['supporter', 'editor'], 'the graphq result includes the new role `editor`')

await signOut()
t.end()
})

test('addUserToRole: Users.Supporter adds role to Users.Member', async (t) => {
await prepare()
await pgDatabase().public.users.insert(Users.Member)
await signIn({ user: Users.Supporter })

const result = await addUserToRole({
userId: Users.Member.id,
role: 'editor'
})
const user = await pgDatabase().public.users.findOne({ id: Users.Member.id })
t.deepEqual(user.roles, ['member'], 'the db user object is unchanged')
t.ok(result.errors, 'rejects calls from non-admins')

await signOut()
t.end()
})
Loading