Skip to content

Commit

Permalink
Merge pull request #23 from Nexite/master
Browse files Browse the repository at this point in the history
add discord user fetching
  • Loading branch information
Nexite authored Nov 15, 2021
2 parents 2ae468f + ffb5dea commit 67a805f
Show file tree
Hide file tree
Showing 5 changed files with 656 additions and 13 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"apollo-server-express": "^2.4.8",
"apollo-upload-client": "^14.1.3",
"auth0": "^2.27.1",
"auth0-get-all-users": "^1.1.0",
"babel-loader": "^8.0.5",
"body-parser": "^1.18.3",
"cross-fetch": "^3.0.6",
Expand Down
27 changes: 27 additions & 0 deletions src/remotes/auth0/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export default function createAuth0Schema(domain, clientId, clientSecret) {
findUsers,
findUsersUncached,
getRolesForUser,
getAllUsers,
findUsersByRole,
findRoles,
updateUser,
Expand All @@ -147,7 +148,17 @@ export default function createAuth0Schema(domain, clientId, clientSecret) {
return (await fn(where, ctx))[0] || null
} catch (ex) { return null; }
},
// VERY SLOW can take from 2-30 seconds
getDiscordUsers: async (_, __, ctx) => {
requireScope(ctx, scopes.readUsers)
const users = (await getAllUsers(ctx)).filter((user) => user?.discordId != null)
return users
},
searchUsers: async (_, { where }, ctx) => findUsers(where, ctx),
userRoles: async (_, { id }, ctx) => {
requireAnyOfScopes(ctx, [scopes.readUserRoles, ctx.user ? `read:user:${ctx.user}` : null])
return await getRolesForUser(id)
},
roleUsers: async (_, { roleId }, ctx) => findUsersByRole(roleId, ctx),
roles: async (_, __, ctx) => findRoles({}, ctx),
};
Expand Down Expand Up @@ -449,6 +460,22 @@ export default function createAuth0Schema(domain, clientId, clientSecret) {
},
};

resolvers.DiscordUser = {
badges: async ({ badges }, { displayed }, ctx) => {
if (badges) {
if (displayed) {
let displayedBadges = badges.filter((b) => b.displayed === true).slice(0, MAX_DISPLAYED_BADGES)
if (displayedBadges.length < 1) {
displayedBadges = badges.slice(0, MAX_DISPLAYED_BADGES)
displayedBadges.map((badge, index) => { badge.displayed = true; badge.order = index })
}
return displayedBadges
}
return badges
}
}
}

resolvers.Subscription = {
userUpdate: {
resolve: async (payload, args, context, info) => ({
Expand Down
29 changes: 29 additions & 0 deletions src/remotes/auth0/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
objectCamelToSnake, objectSnakeToCamel, filterNullOrUndefinedKeys, filterKeysKeep, filterKeysRemove, chunk,
} from '../../utils';
import { scopes, hasAnyOfScopes, requireAnyOfScopes } from '../../auth';
import getAllUsers from 'auth0-get-all-users'

const userPublicFields = ['user_id', 'username', 'name', 'picture', 'pronoun', 'title', 'bio', 'badges', 'discord_id'];
const userPrivateFields = [
Expand All @@ -29,6 +30,33 @@ const cacheOutput = (lru, fn) => (args, context, ...rest) => {
return lru.get(key);
};

const getAllUsersFactory = (auth0) => async (ctx) => {
let users = []
try {
users = await getAllUsers(auth0).asArray({
fields: [
...userPublicFields.map((field) => ({ name: field })),
...(hasAnyOfScopes(ctx, [scopes.readUsers, ctx.user ? `read:user:${ctx.user}` : null]) ? userPrivateFields : []).map((field) => ({ name: field })),
{ name: 'user_metadata' },
],
}, { checkRetries: 100 })
} catch (e) {
if (e.message.startsWith("Giving up waiting for job")) {
throw new Error("Timed out. Please try again!")
}
}

const newUsers = users
.map((user) => ({ ...filterKeysRemove(user, ['user_metadata']), ...user.user_metadata }))
.map((user) => filterKeysKeep(user, [
...userPublicFields,
...(hasAnyOfScopes(ctx, [scopes.readUsers, scopes.writeUsers, ctx.user ? `read:user:${ctx.user}` : null, ctx.user ? `write:user:${ctx.user}` : null]) ? userPrivateFields : []),
]))
.map((user) => ({ ...objectSnakeToCamel(filterKeysRemove(user, ['user_id'])), id: user.user_id }));

return newUsers
}

const findUsersFactory = (auth0) => async (query, ctx, perPage = 10, page = 0, escape = true) => {
if (ctx.user) {
query = { id: ctx.user }
Expand Down Expand Up @@ -173,6 +201,7 @@ export default function getResolvers(domain, clientId, clientSecret) {
findUsers: cacheOutput(lru, findUsersFactory(auth0)),
findUsersUncached: findUsersFactory(auth0),
findUsersByRole: cacheOutput(lru, findUsersByRoleFactory(auth0)),
getAllUsers: getAllUsersFactory(auth0),
getRolesForUser: getRolesForUserFactory(auth0),
updateUser: updateUserFactory(auth0),
addRole: addRoleToUserFactory(auth0),
Expand Down
19 changes: 19 additions & 0 deletions src/remotes/auth0/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ type User {
discordInformation: DiscordInformation
}

type DiscordUser {
id: ID!
name: String
username: String
bio: String
discordId: String
pronoun: String
badges(displayed: Boolean): [DiscordUserBadge]
}

type DiscordUserBadge {
id: ID!
displayed: Boolean
order: Int
expiresUtc: String
}

input UpdateUserInput {
username: String
blocked: Boolean
Expand Down Expand Up @@ -118,7 +135,9 @@ type SubscriptionBadge {

type Query {
getUser(where: UserSingleInput!, fresh: Boolean): User
getDiscordUsers: [DiscordUser]!
searchUsers(where: UserSearch!): [User]!
userRoles(id: ID!): [Role]
roleUsers(roleId: String!): [User]!
roles: [Role]!
}
Expand Down
Loading

0 comments on commit 67a805f

Please sign in to comment.