Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: return email subscription data in User #951

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PORT=3000
NETWORK=testnet
HUB_DATABASE_URL=mysql://...
SEQ_DATABASE_URL=mysql://
ENVELOP_DATABASE_URL=mysql://
SEQUENCER_URL=https://testnet.seq.snapshot.org
STAMP_URL=https://stamp.fyi
KEYCARD_URL=https://keycard.snapshot.org
Expand Down
34 changes: 33 additions & 1 deletion src/graphql/operations/users.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { capture } from '@snapshot-labs/snapshot-sentry';
import log from '../../helpers/log';
import db from '../../helpers/mysql';
import db, { envelopDB } from '../../helpers/mysql';
import { buildWhereQuery, checkLimits, formatUser } from '../helpers';

export default async function (parent, args) {
Expand Down Expand Up @@ -72,10 +72,42 @@ export default async function (parent, args) {
user.lastVote = count.lastVote;
});
}

const subscribers = await getEmailSubscribers(ids);
users.forEach((user: any) => {
user.emailSubscription = subscribers[user.id] || {
status: 'NOT_SUBSCRIBED',
subscriptions: []
};
});

return users.map(formatUser);
} catch (e: any) {
log.error(`[graphql] users, ${JSON.stringify(e)}`);
capture(e, { args });
return Promise.reject(new Error('request failed'));
}
}

async function getEmailSubscribers(
user_ids: string[]
): Promise<
Record<string, { status: 'VERIFIED' | 'UNVERIFIED'; subscriptions: string[] }>
> {
if (!envelopDB) return {};

const subscribers = await envelopDB.queryAsync(
`SELECT verified, address, subscriptions FROM subscribers WHERE address IN (?)`,
user_ids
);

return Object.fromEntries(
subscribers.map((s: any) => [
s.address,
{
status: s.verified > 0 ? 'VERIFIED' : 'UNVERIFIED',
subscriptions: JSON.parse(s.subscriptions)
}
])
);
}
6 changes: 6 additions & 0 deletions src/graphql/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ type DelegationPortal {
delegationApi: String!
}

type EmailSubscription {
status: String!
subscriptions: [String]
}

type Vote {
id: String!
ipfs: String
Expand Down Expand Up @@ -581,6 +586,7 @@ type User {
votesCount: Int
proposalsCount: Int
lastVote: Int
emailSubscription: EmailSubscription
}

type Statement {
Expand Down
19 changes: 17 additions & 2 deletions src/helpers/mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ hubConfig.connectTimeout = 60e3;
hubConfig.acquireTimeout = 60e3;
hubConfig.timeout = 60e3;
hubConfig.charset = 'utf8mb4';

const hubDB = mysql.createPool(hubConfig);

// @ts-ignore
Expand All @@ -35,6 +34,22 @@ sequencerConfig.timeout = 60e3;
sequencerConfig.charset = 'utf8mb4';
const sequencerDB = mysql.createPool(sequencerConfig);

let envelopDB;
if (process.env.ENVELOP_DATABASE_URL) {
// @ts-ignore
const envelopConfig = parse(process.env.ENVELOP_DATABASE_URL);
envelopConfig.connectionLimit = connectionLimit;
envelopConfig.multipleStatements = true;
envelopConfig.database = envelopConfig.path[0];
envelopConfig.host = envelopConfig.hosts[0].name;
envelopConfig.port = envelopConfig.hosts[0].port;
envelopConfig.connectTimeout = 60e3;
envelopConfig.acquireTimeout = 60e3;
envelopConfig.timeout = 60e3;
envelopConfig.charset = 'utf8mb4';
envelopDB = mysql.createPool(envelopConfig);
}

bluebird.promisifyAll([Pool, Connection]);

export { hubDB as default, sequencerDB };
export { hubDB as default, sequencerDB, envelopDB };
1 change: 1 addition & 0 deletions test/.env.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
HUB_DATABASE_URL=mysql://root:[email protected]:3306/hub_test
SEQ_DATABASE_URL=mysql://root:[email protected]:3306/hub_test
ENVELOP_DATABASE_URL=mysql://root:[email protected]:3306/hub_test
NODE_ENV=test
11 changes: 11 additions & 0 deletions test/schema_envelop.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE subscribers (
email VARCHAR(256) NOT NULL,
address VARCHAR(256) NOT NULL,
subscriptions JSON DEFAULT NULL,
created BIGINT NOT NULL,
verified BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (email, address),
UNIQUE KEY idx_address_email (address, email),
INDEX created (created),
INDEX verified (verified)
);
7 changes: 5 additions & 2 deletions test/setupDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ bluebird.promisifyAll([Pool, Connection]);
const db = mysql.createPool(config);
const dbName = config.path[0];

const schemaFiles = ['./src/helpers/schema.sql', './test/schema_envelop.sql'];

if (!dbName.endsWith(TEST_DATABASE_SUFFIX)) {
console.error(
`Invalid test database name. Must end with ${TEST_DATABASE_SUFFIX}`
Expand All @@ -33,8 +35,9 @@ async function run() {
console.info(`- Creating new database: ${dbName}`);
await db.queryAsync(`CREATE DATABASE ${dbName}`);

const schema = fs
.readFileSync('./src/helpers/schema.sql', 'utf8')
const schema = schemaFiles
.map(file => fs.readFileSync(file, 'utf8'))
.join(' ')
.replaceAll('CREATE TABLE ', `CREATE TABLE ${dbName}.`)
.split(splitToken)
.filter(s => s.trim().length > 0);
Expand Down
Loading