Skip to content

Commit

Permalink
Merge pull request #1 from dylibso/mo/register-command
Browse files Browse the repository at this point in the history
feat: /register now properly registers the user
  • Loading branch information
mhmd-azeez authored Jul 10, 2024
2 parents a6ae6dc + 29f16d5 commit e8e2272
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 56 deletions.
1 change: 1 addition & 0 deletions migrations/0003-discord-credentials.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter type credential_type add value 'discord';
1 change: 1 addition & 0 deletions migrations/0004-discord-credentials-p2.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
create index "credentials_discord_idx" on "credentials" using gin("data") where "deleted_at" is null and "type" = 'discord' and "data" ? 'id';
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"typescript": "^5.5.3"
},
"dependencies": {
"@dylibso/xtp": "0.0.0-rc4",
"@dylibso/xtp": "^0.0.0-rc5",
"@extism/extism": "^1.0.3",
"@fastify/cookie": "^9.3.1",
"@fastify/oauth2": "^7.8.0",
Expand Down
46 changes: 36 additions & 10 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import { Client, CommandInteraction, GatewayIntentBits, REST, Routes } from 'dis
import { DISCORD_BOT_TOKEN, DISCORD_BOT_CLIENT_ID } from './config';
import { findMatchingMessageHandlers } from './domain/message-handlers';
import { getXtp } from './db';
import { getXtpData, registerUser } from './domain/users';

export async function startDiscordClient() {
if (!DISCORD_BOT_TOKEN) {
return;
}

await refreshCommands(DISCORD_BOT_TOKEN);
const rest = new REST({ version: '9' }).setToken(DISCORD_BOT_TOKEN);
await refreshCommands(rest);

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
GatewayIntentBits.MessageContent,
],
});

client.on('ready', () => {
Expand All @@ -28,13 +30,13 @@ export async function startDiscordClient() {
return;
}

const guild = message.guild || {name: "", id: ""};
const guild = message.guild || { name: "", id: "" };

console.log(`Incoming message in ${guild.name} (${guild.id}): `, message.content);
const xtp = await getXtp();
const handlers = await findMatchingMessageHandlers(guild.id, message.content);

for (let i = 0; i < handlers.length; i++){
for (let i = 0; i < handlers.length; i++) {
const handler = handlers[i];
console.log("Found matching handler: ", handler.id, "regex=" + handler.regex);
try {
Expand All @@ -45,7 +47,7 @@ export async function startDiscordClient() {
default: ""
});

if (result !== null && result!.length > 0){
if (result !== null && result!.length > 0) {
await message.reply(result!);
}
} catch (err) {
Expand All @@ -71,21 +73,45 @@ export async function startDiscordClient() {
break;

case 'register':
await command.reply('Please register your account at https://www.youtube.com/watch?v=EE-xtCF3T94');
const discordUser = command.user;

const dbUser = await registerUser({
username: discordUser.tag,
discord: {
id: discordUser.id,
discriminator: discordUser.discriminator,
username: discordUser.username,
avatar: discordUser.avatar,
hexAccentColor: discordUser.accentColor || undefined,
}
})

const xtp = getXtpData(dbUser);

await command.reply({
content: `To get started, please activate your new XTP Host by clicking the link below.
${xtp.inviteLink}
Once your account is active, you can dive right in and start building your first plugin.
XTP Product docs can be found here: https://docs.xtp.dylibso.com/
TODO: Add more helpful information here.`,
ephemeral: true,
});

break;
}
})

client.login(DISCORD_BOT_TOKEN);
}

async function refreshCommands(token: string) {
async function refreshCommands(rest: REST) {
if (!DISCORD_BOT_CLIENT_ID) {
return;
}

const rest = new REST({ version: '9' }).setToken(token);

const commands = [
{
name: 'ping',
Expand Down
153 changes: 113 additions & 40 deletions src/domain/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,30 @@ export interface User {
data: Record<string, any>,
created_at: Date,
updated_at: Date,
deleted_at?: Date | null
deleted_at?: Date | null,
}

export interface XtpData {
inviteLink?: string
}

export function getXtpData(user: User) {
return user.data.xtp as XtpData
}

function patchXtpData(user: User, data: Partial<XtpData>) {
user.data.xtp = { ...getXtpData(user), ...data }
}

export interface OAuthGitHubCredentials {
oauth: { access_token: string, scope: string, token_type: string },
user: { login: string, avatar_url: string, name: string, [k: string]: any },
}

export interface DiscordCredentials {
id: string, username: string, discriminator: string, avatar?: string | null, hexAccentColor?: number, [k: string]: any
}

export interface EmailPassword {
email: string,
password: string
Expand All @@ -23,6 +39,7 @@ export interface RegisterUser {
username: string,
github?: OAuthGitHubCredentials
emailPassword?: EmailPassword
discord?: DiscordCredentials
}

export async function findUserByGithubLogin(githubLogin: string) {
Expand All @@ -44,51 +61,107 @@ export async function findUserByGithubLogin(githubLogin: string) {
return user
}

export async function findUserByUsername(username: string) {
const db = await getDatabaseConnection()

const { rows: [user = null] } = await db.query(`
SELECT
"users".*
FROM "users"
WHERE
"users"."username" = $1
LIMIT 1
`, [username])

return user
}

export async function updateUser(db: any, user: User) {
const { rows: [updatedUser] } = await db.query(`
UPDATE "users"
SET
username = $2,
data = $3
WHERE
id = $1
RETURNING *;
`, [user.id, user.username, user.data])

return updatedUser
}

export async function registerUser(registration: RegisterUser): Promise<User> {
const db = await getDatabaseConnection()
const xtp = await getXtp()

return await db.transaction(async (db: any) => {
console.log('running create user row', registration)
const result = await db.query(`
INSERT INTO "users" (
username
) VALUES (
$1
) RETURNING *;
`, [registration.username])

const { rows: [user] } = result

if (registration.github) {
console.log('running create credential row')
await db.query(`
INSERT INTO "credentials" (
user_id,
"type",
data
try {
return await db.transaction(async (db: any) => {
console.log('running create user row', registration)
const result = await db.query(`
INSERT INTO "users" (
username
) VALUES (
$1,
'oauth-github',
$2::jsonb
);
`, [user.id, JSON.stringify(registration.github.user)])

console.log('sending guest invite')
await xtp.inviteGuest({
name: registration.github.user.name,
email: registration.github.user.email,
guestKey: user.id
}).catch(err => {
console.error(err)
})
}
$1
) RETURNING *;
`, [registration.username])

if (registration.emailPassword) {
// TODO
}
const { rows: [user] } = result

if (registration.github) {
console.log('running create credential row')
await db.query(`
INSERT INTO "credentials" (
user_id,
"type",
data
) VALUES (
$1,
'oauth-github',
$2::jsonb
);
`, [user.id, JSON.stringify(registration.github.user)])

console.log('sending guest invite')
await xtp.inviteGuest({
name: registration.github.user.name,
email: registration.github.user.email,
guestKey: user.id,
deliveryMethod: 'email'
}).catch(err => {
console.error(err)
})
} else if (registration.discord) {
console.log('running create credential row')
await db.query(`
INSERT INTO "credentials" (
user_id,
"type",
data
) VALUES (
$1,
'discord',
$2::jsonb
);
`, [user.id, JSON.stringify(registration.discord)])

const response = await xtp.inviteGuest({ guestKey: user.id, deliveryMethod: 'link' });
patchXtpData(user, { inviteLink: response.link.link })

await updateUser(db, user)
}

if (registration.emailPassword) {
// TODO
}


return user
})
} catch (e: any) {
if (e.code === '23505' && e.constraint === 'users_username_idx') {
return await findUserByUsername(registration.username)
}

return user
})
throw e
}
}

0 comments on commit e8e2272

Please sign in to comment.