3box profiles (#9)

* Fix auth

* Added 3box profile info

* Added player names in list

* Added hasura action to fetch verified accounts on 3Box

* Added usernames

* fix router
This commit is contained in:
Pacien Boisson
2020-05-13 10:02:21 +02:00
committed by GitHub
parent 7747ff69d0
commit 214f3f65c2
37 changed files with 9547 additions and 331 deletions

1
packages/backend/@types/3box.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module '3box';

View File

@@ -13,6 +13,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"3box": "^1.18.1",
"body-parser": "^1.19.0",
"ethers": "^4.0.46",
"express": "^4.17.1",

View File

@@ -0,0 +1,11 @@
import express from 'express';
import { asyncHandlerWrapper } from '../../lib/apiHelpers';
import updateBoxProfileHandler from './updateBoxProfile/handler';
const router = express.Router();
router.post('/updateBoxProfile', asyncHandlerWrapper(updateBoxProfileHandler));
export default router;

View File

@@ -0,0 +1,107 @@
import { Request, Response } from 'express';
import {hasuraQuery} from "../../../lib/hasuraHelpers";
import {getPlayerETHAddress} from "../../../lib/playerHelpers";
import Box from '3box';
const getPlayerQuery = `
query GetPlayer ($playerId: uuid!) {
Player(
where: {
id: { _eq: $playerId }
}
) {
id
Accounts {
identifier
type
}
}
}
`;
const upsertAccount = `
mutation upsert_Account($objects: [Account_insert_input!]!) {
insert_Account (
objects: $objects,
on_conflict: {
constraint: Account_identifier_type_player_key,
update_columns: [identifier]
}
) {
affected_rows
}
}
`;
const handler = async (req: Request, res: Response) => {
const { session_variables } = req.body;
const role = session_variables['x-hasura-role'];
const playerId = session_variables['x-hasura-user-id'];
if(role !== 'player') {
throw new Error('expected role player');
}
const result = await hasuraQuery(getPlayerQuery, {
playerId,
});
const player = result.Player[0];
if(!player) {
throw new Error('unknown-player');
}
const ethAddress = getPlayerETHAddress(player);
const boxProfile = await Box.getProfile(ethAddress);
const verifiedProfile = await Box.getVerifiedAccounts(boxProfile);
const updatedProfiles = await updateVerifiedProfiles(playerId, verifiedProfile);
res.json({
success: true,
updatedProfiles,
});
};
async function updateVerifiedProfiles(playerId: string, verifiedProfiles: any) {
const updatedProfiles: string[] = [];
if(verifiedProfiles.github) {
const result = await hasuraQuery(upsertAccount, {
objects: [
{
player_id: playerId,
type: 'GITHUB',
identifier: verifiedProfiles.github.username,
linkToProof: verifiedProfiles.github.proof,
}
],
});
if(result.affected_rows === 0) {
throw new Error('Error while upserting github profile');
}
updatedProfiles.push('github');
}
if(verifiedProfiles.twitter) {
const result = await hasuraQuery(upsertAccount, {
objects: [
{
player_id: playerId,
type: 'TWITTER',
identifier: verifiedProfiles.twitter.username,
linkToProof: verifiedProfiles.twitter.proof,
}
],
});
if(result.affected_rows === 0) {
throw new Error('Error while upserting github profile');
}
updatedProfiles.push('twitter');
}
return updatedProfiles;
}
export default handler;

View File

@@ -1,6 +1,4 @@
import fetch from 'node-fetch';
import config from '../../config';
import { hasuraQuery } from '../../lib/hasuraHelpers';
const getPlayerQuery = `
query GetPlayerFromETH ($eth_address: String) {
@@ -18,40 +16,27 @@ query GetPlayerFromETH ($eth_address: String) {
`;
const createProfileMutation = `
mutation CreateAccountFromETH ($eth_address: String) {
mutation CreateAccountFromETH ($eth_address: String!, $username: String!) {
insert_Account(
objects: {
type: "ETHEREUM",
identifier: $eth_address
Player: {
data: {}
data: {
username: $username
}
}
}) {
returning {
identifier
}
affected_rows
returning {
identifier
Player {
id
}
}
}
}
`;
async function hasuraQuery(query: string, qv: any = {}) {
const result = await fetch(config.graphqlURL, {
method: 'POST',
body: JSON.stringify({ query: query, variables: qv }),
headers: {
'Content-Type': 'application/json',
'x-hasura-access-key': config.adminKey,
},
});
const { errors, data } = await result.json();
if(errors) {
throw new Error(JSON.stringify(errors));
}
return data;
}
interface IPlayer {
id: string
}
@@ -59,7 +44,11 @@ interface IPlayer {
export async function createPlayer(ethAddress: string): Promise<IPlayer> {
const resProfile = await hasuraQuery(createProfileMutation, {
eth_address: ethAddress,
username: ethAddress,
});
if(resProfile.insert_Account.affected_rows !== 2) {
throw new Error('error while creating profile');
}
return resProfile.insert_Account.returning[0].Player;
}

View File

@@ -2,6 +2,8 @@ import express from 'express';
import { asyncHandlerWrapper } from '../lib/apiHelpers';
import actionsRoutes from './actions/routes';
import authHandler from './auth-webhook/handler';
const router = express.Router();
@@ -11,5 +13,6 @@ router.get('/', function (req, res) {
});
router.get('/auth-webhook', asyncHandlerWrapper(authHandler));
router.use('/actions', actionsRoutes);
export default router;

View File

@@ -0,0 +1,20 @@
import fetch from 'node-fetch';
import config from '../config';
export async function hasuraQuery(query: string, qv: any = {}) {
const result = await fetch(config.graphqlURL, {
method: 'POST',
body: JSON.stringify({ query: query, variables: qv }),
headers: {
'Content-Type': 'application/json',
'x-hasura-access-key': config.adminKey,
},
});
const { errors, data } = await result.json();
if(errors) {
throw new Error(JSON.stringify(errors));
}
return data;
}

View File

@@ -0,0 +1,3 @@
export function getPlayerETHAddress(player: any) {
return player.Accounts.find((a: any) => a.type === "ETHEREUM").identifier;
}

View File

@@ -6,6 +6,11 @@
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
"esModuleInterop": true,
"typeRoots": ["./@types"]
},
"include": [
"src",
"./@types"
]
}