-
Notifications
You must be signed in to change notification settings - Fork 141
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
Discord Bot #417
base: master
Are you sure you want to change the base?
Discord Bot #417
Conversation
server/cleanup.ts
Outdated
|
||
try { | ||
// get all known users who have been assigned a sub role | ||
const result = await postgres?.query('SELECT * FROM discord'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with this being one-way (e.g. we don't remove roles for former subscribers).
server/server.ts
Outdated
return res.status(400).json({ error: 'invalid user token' }); | ||
} | ||
const customer = await getCustomerByEmail(decoded.email as string); | ||
const isSubscriber = Boolean( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a helper function for this logic?
server/server.ts
Outdated
const isSubscriber = Boolean( | ||
customer?.subscriptions?.data?.find((sub) => sub?.status === 'active') | ||
); | ||
if (!isSubscriber) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I think it would be okay to let all users link a Discord, but then have the background process do the sub checking/role assigning
server/server.ts
Outdated
true | ||
); | ||
if (user) { | ||
await postgres?.query('DELETE FROM discord WHERE "customerId" = $1', [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could just store email + discord id + sub state? And we could update the sub state in the same code that already syncs subs to postgres
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But do we have to save anything if we never remove the sub roles like you suggested above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume users might want to delete/edit their discord linked account
server/server.ts
Outdated
} | ||
return res.status(200).json({}); | ||
}) | ||
.get('/discordRole', async (req, res) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we return this in the metadata call maybe?
}); | ||
}; | ||
|
||
setDiscordUsername(value: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than making the user enter a name and risk errors (or entering someone else's name), could we integrate with Discord OAuth to automatically fetch the user's info?
In the generated authentication URL the |
We don't do any security checks and right now someone could theoretically link someone else's Discord account but I don't believe this is something to be concerned about because no damage could be caused. |
server/server.ts
Outdated
try { | ||
// users should only have one account max. with a sub role per email, | ||
// set email to null to tell background process to clean it up. | ||
await postgres?.query('UPDATE discord SET email = null WHERE email = $1', [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonder if it's better to have one links table that can support linking different types of accounts in the future by adding more columns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean a table which has a column for each service's user ID? I think with a table like that we would not have to be matching the email address anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we would still be matching the email to find the row, but that row could support multiple services.
server/syncSubs.ts
Outdated
const members = await guild?.members.fetch(); | ||
|
||
// from discord API get username and discriminator of all users on discord server without a sub role | ||
const membersWithoutRole = members |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we just joined the subscriber and discord links table and applied the role to all those users? Since the discord has thousands of members, might be more efficient? As mentioned before I don't think cleanup is essential and we can add a separate process for that later if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we could do that. But we will have to add a hasRole
column to the discord table so we don't keep trying to assign a role to users who already have one over and over again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this may be moot if we just do the role add on link
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but to answer the question, can we check-then-assign for each user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we can check role status for each user with an individual discord API call, if this is what you're asking.
|
||
deleteDiscord = async () => { | ||
const token = await this.props.user.getIdToken(); | ||
await window.fetch(serverPath + '/discord/auth', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems confusing to have the same POST call do delete. Maybe make a separate DELETE verb call to the same endpoint?
The important settings are
|
return res.sendStatus(500); | ||
} | ||
try { | ||
const result = await postgres?.query( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think you can delete and return the deleted content?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it returns the deleted rows. The rows array is always empty. Are you sure it does? Maybe I'm missing a query method argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to add RETURNING to your query
server/server.ts
Outdated
@@ -278,6 +384,19 @@ app.delete('/deleteAccount', async (req, res) => { | |||
} | |||
if (postgres) { | |||
await postgres?.query('DELETE FROM room WHERE owner = $1', [decoded.uid]); | |||
const result = await postgres?.query( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can just delete here and not change role?
server/server.ts
Outdated
[decoded.email] | ||
); | ||
if (result.rowCount) { | ||
await discordBot.assignRole( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the link action? we don't need to remove any roles?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you pass the argument undo=true to assignRole it removes the role. Maybe this is a bit confusing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah i'm asking why we need to remove the role here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. Ok we will leave out all role removing stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To answer the question: We remove the role here because we want to limit the linked discord accounts per email to max 1 . if we dont remove the role here someone could theoretically assign a sub role to an unlimited number of accounts.
Would that be fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we defer this cleanup to later, right?
sql/schema.sql
Outdated
@@ -25,6 +25,13 @@ CREATE TABLE subscriber( | |||
PRIMARY KEY(uid) | |||
); | |||
|
|||
CREATE TABLE discord( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any more thoughts on making this a generic link table that can support linking other accounts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds finde to me. Do you have any naming suggestion for the table?
@@ -109,11 +116,16 @@ class WatchParty extends React.Component { | |||
); | |||
}} | |||
/> | |||
<Route path="/discord/auth" exact> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this a modal on the app rather than its own route? or is a new path required for the discord auth?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user will redirected to the URL you choose when generating the OAuth2 URL. In our case the user will be redirected to watchparty.me/discord/auth . So I think we need this new path.
Alright, I believe I've addressed everything. |
I tried doing this in a modal instead of a new window but Discord is blocking iframes and I don't know if there is another method. |
onClick={this.authDiscord} | ||
> | ||
<Icon name="discord" /> | ||
Link Discord Account |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's say "Link Discord Account/Get Subscriber Role"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looked a little awkward because it's too long. I've added a popup instead.
@@ -57,6 +59,23 @@ if (config.DATABASE_URL) { | |||
postgres.connect(); | |||
} | |||
|
|||
let discordBot: DiscordBot; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably run in a separate service
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, that might make the endpoint logic more complicated. But we may need to scale to multiple instances of the server soon, and I'm not sure if that will work if multiple processes are logging into the same Discord bot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think would be the best way to do the communication between the server processes and the discord process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could just use a redis queue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that might not be necessary because as far as I can tell it is possible to access the same bot through multiple different client instances using the same token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preferred solution is usually to set up an HTTP server on the bot and have the web instances call it. But if you think it might be OK to scale out, then we can try that first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it out by starting the dev server multiple times. Which I guess comes close to having multiple instances of the same server.
All roles that have previously been set manually will be removed. Users who are still subscribers must assign them again themselves.
closes #63