mirror of
https://github.com/ApfelTeeSaft/Disky.git
synced 2026-08-26 19:23:34 +00:00
Check Desc for details
Added a semi proper Login command, needs a lot of bugfixing tho Auth to Bluesky broke? overall improved messages with ephemeral type
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
DISCORD_TOKEN=token
|
||||
CLIENT_ID=discord_client_id
|
||||
BLUESKY_IDENTIFIER=bot_account_handle # for example apfelteesaft.com or apfelbot.bsky.social
|
||||
BLUESKY_PASSWORD=app_password # the application password, refer to documentation
|
||||
DISCORD_TOKEN=
|
||||
CLIENT_ID=
|
||||
# deprecated, implemented in per user auth
|
||||
# BLUESKY_IDENTIFIER=bot_account_handle # for example apfelteesaft.com or apfelbot.bsky.social
|
||||
# BLUESKY_PASSWORD=app_password # the application password, refer to documentation
|
||||
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
|
||||
APPWRITE_DATABASE_ID=
|
||||
APPWRITE_COLLECTION_ID=
|
||||
APPWRITE_PROJECT_ID=
|
||||
APPWRITE_API_KEY=
|
||||
Generated
+14
@@ -15,6 +15,7 @@
|
||||
"cron": "^3.2.1",
|
||||
"discord.js": "^14.16.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"node-appwrite": "^14.1.0",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7"
|
||||
},
|
||||
@@ -1445,6 +1446,14 @@
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="
|
||||
},
|
||||
"node_modules/node-appwrite": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-14.1.0.tgz",
|
||||
"integrity": "sha512-kuKAZrdaAcGYOMUXtxNb1j+uIy+FIMiiU1dFkgwTXLsMLeLvC6HJ8/FH/kN9JyrWR2a2zcGN7gWfyQgWYoLMTA==",
|
||||
"dependencies": {
|
||||
"node-fetch-native-with-agent": "1.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
@@ -1464,6 +1473,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch-native-with-agent": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
|
||||
"integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g=="
|
||||
},
|
||||
"node_modules/node-gyp": {
|
||||
"version": "8.4.1",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"cron": "^3.2.1",
|
||||
"discord.js": "^14.16.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"node-appwrite": "^14.1.0",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7"
|
||||
},
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js';
|
||||
import { BskyAgent } from '@atproto/api';
|
||||
import { getBlueskyAgent } from '../helpers/bluesky';
|
||||
|
||||
export async function handleAnalyticsCommand(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
handle: string,
|
||||
agent: BskyAgent
|
||||
handle: string
|
||||
) {
|
||||
const startTime = Date.now();
|
||||
await interaction.deferReply();
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const agent = await getBlueskyAgent(interaction.user.id);
|
||||
|
||||
if (!agent) {
|
||||
await interaction.editReply({
|
||||
content: 'You need to log in using `/login` before using this command.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const profile = await agent.getProfile({ actor: handle });
|
||||
@@ -29,7 +37,7 @@ export async function handleAnalyticsCommand(
|
||||
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
await interaction.editReply('Failed to fetch analytics. Please check the handle and try again.');
|
||||
console.error('Error fetching analytics:', error);
|
||||
await interaction.editReply('Failed to fetch analytics. Please check the handle and try again.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ChatInputCommandInteraction } from 'discord.js';
|
||||
import { AppwriteService } from '../services/appwrite';
|
||||
import { BskyAgent } from '@atproto/api';
|
||||
|
||||
export async function handleLoginCommand(interaction: ChatInputCommandInteraction) {
|
||||
const handle = interaction.options.getString('handle', true);
|
||||
const appPassword = interaction.options.getString('app-password', true);
|
||||
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const agent = new BskyAgent({ service: 'https://bsky.social' });
|
||||
|
||||
try {
|
||||
console.log(`Attempting login for handle: ${handle}`);
|
||||
|
||||
const loginPayload = { identifier: handle, password: appPassword };
|
||||
|
||||
await agent.login(loginPayload);
|
||||
|
||||
const bearerToken = agent.session?.accessJwt;
|
||||
if (!bearerToken) {
|
||||
throw new Error('Failed to retrieve bearer token.');
|
||||
}
|
||||
|
||||
const appwriteService = new AppwriteService();
|
||||
await appwriteService.setUserBearer(interaction.user.id, bearerToken, handle, appPassword);
|
||||
|
||||
await interaction.editReply({
|
||||
content: `Successfully logged into Bluesky as **${handle}**!`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error);
|
||||
|
||||
await interaction.editReply({
|
||||
content: `Login failed. Please check your handle or app password and try again.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
+88
-111
@@ -1,171 +1,148 @@
|
||||
import { Client, EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import { Client, EmbedBuilder, TextChannel, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { BskyAgent } from '@atproto/api';
|
||||
import sqlite3 from 'sqlite3';
|
||||
import { open, Database as SqliteDatabase } from 'sqlite';
|
||||
import { AppwriteService } from '../services/appwrite';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const WATCHED_PROFILES_FILE = path.resolve('./watchedProfiles.json');
|
||||
const roleId = '1305987062847242280'; // role id from cutiecord
|
||||
const roleId = '1305987062847242280'; // TODO: implement into watchbluesky command
|
||||
|
||||
let db: SqliteDatabase<sqlite3.Database, sqlite3.Statement>;
|
||||
let watchedProfiles: { [handle: string]: string[] } = {};
|
||||
|
||||
async function initDatabase() {
|
||||
db = await open({
|
||||
filename: './posts.db',
|
||||
driver: sqlite3.Database,
|
||||
});
|
||||
|
||||
await db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS announced_posts (
|
||||
uri TEXT PRIMARY KEY,
|
||||
handle TEXT NOT NULL,
|
||||
createdAt TEXT NOT NULL
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
async function isPostAnnounced(uri: string): Promise<boolean> {
|
||||
const result = await db.get('SELECT 1 FROM announced_posts WHERE uri = ?', uri);
|
||||
return !!result;
|
||||
}
|
||||
|
||||
async function markPostAsAnnounced(uri: string, handle: string, createdAt: string) {
|
||||
await db.run(
|
||||
'INSERT INTO announced_posts (uri, handle, createdAt) VALUES (?, ?, ?)',
|
||||
uri,
|
||||
handle,
|
||||
createdAt
|
||||
);
|
||||
}
|
||||
|
||||
async function getWatchedProfiles(): Promise<Record<string, string[]>> {
|
||||
async function loadWatchedProfiles(): Promise<void> {
|
||||
if (!fs.existsSync(WATCHED_PROFILES_FILE)) {
|
||||
fs.writeFileSync(WATCHED_PROFILES_FILE, JSON.stringify({}));
|
||||
}
|
||||
|
||||
const data = fs.readFileSync(WATCHED_PROFILES_FILE, 'utf-8');
|
||||
return JSON.parse(data);
|
||||
watchedProfiles = JSON.parse(data);
|
||||
}
|
||||
|
||||
async function saveWatchedProfiles(watchedProfiles: Record<string, string[]>) {
|
||||
async function saveWatchedProfiles(): Promise<void> {
|
||||
fs.writeFileSync(WATCHED_PROFILES_FILE, JSON.stringify(watchedProfiles, null, 2));
|
||||
}
|
||||
|
||||
async function processFeedItem(post: any, client: Client, handle: string, channels: string[]) {
|
||||
try {
|
||||
if (!post || !post.record || !post.author || !post.record.text || !post.uri) {
|
||||
console.warn(`Invalid feed item structure for handle: ${handle}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const postUri = post.uri;
|
||||
|
||||
if (await isPostAnnounced(postUri)) {
|
||||
console.log(`Skipping already announced post for handle: ${handle}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const postLink = `https://bsky.app/profile/${post.author.handle}/post/${post.uri.split('/').pop()}`;
|
||||
async function processFeedItem(
|
||||
client: Client,
|
||||
post: any,
|
||||
handle: string,
|
||||
channels: string[]
|
||||
) {
|
||||
if (!post?.record?.text || !post.uri) return;
|
||||
|
||||
const postLink = `https://bsky.app/profile/${handle}/post/${post.uri.split('/').pop()}`;
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({
|
||||
name: post.author.displayName || post.author.handle,
|
||||
iconURL: post.author.avatar || undefined,
|
||||
})
|
||||
.setAuthor({ name: handle })
|
||||
.setDescription(post.record.text)
|
||||
.setTimestamp(new Date(post.record.createdAt))
|
||||
.setFooter({ text: `From ${handle}` })
|
||||
.setColor('#1DA1F2');
|
||||
.setColor('Blue')
|
||||
.setFooter({ text: `New post from ${handle}` })
|
||||
.setTimestamp(new Date(post.record.createdAt));
|
||||
|
||||
for (const channelId of channels) {
|
||||
const channel = client.channels.cache.get(channelId) as TextChannel;
|
||||
if (!channel) {
|
||||
console.warn(`Channel with ID ${channelId} not found.`);
|
||||
continue;
|
||||
}
|
||||
if (channel) {
|
||||
await channel.send({
|
||||
content: `<@&${roleId}> ${postLink}`,
|
||||
embeds: [embed],
|
||||
});
|
||||
}
|
||||
|
||||
await markPostAsAnnounced(postUri, handle, post.record.createdAt);
|
||||
} catch (error) {
|
||||
console.error(`Error processing feed item for handle: ${handle}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkFeeds(client: Client, agent: BskyAgent) {
|
||||
console.log('Running scheduled check for watched profiles...');
|
||||
const watchedProfiles = await getWatchedProfiles();
|
||||
|
||||
for (const handle of Object.keys(watchedProfiles)) {
|
||||
async function checkFeeds(client: Client, appwriteService: AppwriteService) {
|
||||
for (const handle in watchedProfiles) {
|
||||
const channels = watchedProfiles[handle];
|
||||
console.log(`Checking feed for handle: ${handle}`);
|
||||
const agent = new BskyAgent({ service: 'https://bsky.social' });
|
||||
|
||||
const bearer = await appwriteService.getUserBearer(handle);
|
||||
if (!bearer) continue;
|
||||
|
||||
await agent.resumeSession({
|
||||
accessJwt: bearer,
|
||||
refreshJwt: '',
|
||||
handle,
|
||||
did: '',
|
||||
active: true,
|
||||
});
|
||||
|
||||
const response = await agent.getAuthorFeed({ actor: handle });
|
||||
for (const post of response.data.feed || []) {
|
||||
await processFeedItem(client, post, handle, channels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function startWatcher(client: Client) {
|
||||
await loadWatchedProfiles();
|
||||
const appwriteService = new AppwriteService();
|
||||
setInterval(async () => {
|
||||
await checkFeeds(client, appwriteService);
|
||||
}, 120000);
|
||||
}
|
||||
|
||||
export async function handleWatchCommand(interaction: ChatInputCommandInteraction, handle: string) {
|
||||
const channelId = interaction.channelId;
|
||||
const appwriteService = new AppwriteService();
|
||||
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
try {
|
||||
const response = await agent.getAuthorFeed({ actor: handle });
|
||||
let bearer = await appwriteService.getUserBearer(interaction.user.id);
|
||||
|
||||
if (!response.data.feed || response.data.feed.length === 0) {
|
||||
console.log(`No posts found for handle: ${handle}`);
|
||||
continue;
|
||||
if (!bearer) {
|
||||
const userDoc = await appwriteService.getUserDocument(interaction.user.id);
|
||||
|
||||
if (!userDoc) {
|
||||
await interaction.editReply(
|
||||
`You need to log in using \`/login\` before you can watch a profile.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const feedItem of response.data.feed.reverse()) {
|
||||
await processFeedItem(feedItem.post, client, handle, channels);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error fetching feed for handle: ${handle}`, error);
|
||||
}
|
||||
}
|
||||
const { handle: savedHandle, appPassword } = userDoc;
|
||||
|
||||
const agent = new BskyAgent({ service: 'https://bsky.social' });
|
||||
await agent.login({ identifier: savedHandle, password: appPassword });
|
||||
bearer = agent.session?.accessJwt ?? null;
|
||||
|
||||
if (!bearer) {
|
||||
await interaction.editReply(
|
||||
`Failed to authenticate with Bluesky. Please check your credentials and try again using \`/login\`.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
export async function startWatcher(client: Client, agent: BskyAgent) {
|
||||
await initDatabase();
|
||||
console.log('Database initialized.');
|
||||
|
||||
console.log('Running initial check for watched profiles...');
|
||||
await checkFeeds(client, agent);
|
||||
|
||||
setInterval(async () => {
|
||||
await checkFeeds(client, agent);
|
||||
}, 120000); // Check every 2 minutes
|
||||
await appwriteService.setUserBearer(interaction.user.id, bearer, savedHandle, appPassword);
|
||||
}
|
||||
|
||||
export async function handleWatchCommand(interaction: any, handle: string) {
|
||||
const watchedProfiles = await getWatchedProfiles();
|
||||
|
||||
if (!watchedProfiles[handle]) {
|
||||
watchedProfiles[handle] = [];
|
||||
}
|
||||
|
||||
const channelId = interaction.channelId;
|
||||
|
||||
if (!watchedProfiles[handle].includes(channelId)) {
|
||||
watchedProfiles[handle].push(channelId);
|
||||
await saveWatchedProfiles(watchedProfiles);
|
||||
await interaction.reply(`Now watching posts from \`${handle}\` in this channel.`);
|
||||
await saveWatchedProfiles();
|
||||
await interaction.editReply(`Now watching posts from ${handle} in this channel.`);
|
||||
} else {
|
||||
await interaction.reply(`Already watching posts from \`${handle}\` in this channel.`);
|
||||
await interaction.editReply(`Already watching posts from ${handle} in this channel.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error in handleWatchCommand:`, error);
|
||||
await interaction.editReply(`An error occurred while processing your request.`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleUnwatchCommand(interaction: any, handle: string) {
|
||||
const watchedProfiles = await getWatchedProfiles();
|
||||
const channelId = interaction.channelId;
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
if (watchedProfiles[handle]) {
|
||||
const channelId = interaction.channelId;
|
||||
|
||||
watchedProfiles[handle] = watchedProfiles[handle].filter((id) => id !== channelId);
|
||||
|
||||
if (watchedProfiles[handle].length === 0) {
|
||||
delete watchedProfiles[handle];
|
||||
}
|
||||
|
||||
await saveWatchedProfiles(watchedProfiles);
|
||||
await interaction.reply(`Stopped watching posts from \`${handle}\` in this channel.`);
|
||||
await saveWatchedProfiles();
|
||||
await interaction.editReply(`Stopped watching posts from ${handle} in this channel.`);
|
||||
} else {
|
||||
await interaction.reply(`No active watch for \`${handle}\` in this channel.`);
|
||||
await interaction.editReply(`No active watch for ${handle} in this channel.`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { BskyAgent } from '@atproto/api';
|
||||
import { AppwriteService } from '../services/appwrite';
|
||||
|
||||
const appwriteService = new AppwriteService();
|
||||
|
||||
export async function getBlueskyAgent(userId: string): Promise<BskyAgent | null> {
|
||||
const bearer = await appwriteService.getUserBearer(userId);
|
||||
if (!bearer) {
|
||||
console.warn(`Bearer token not found for user ${userId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const agent = new BskyAgent({ service: 'https://bsky.social' });
|
||||
try {
|
||||
await agent.resumeSession({
|
||||
accessJwt: bearer,
|
||||
refreshJwt: '',
|
||||
handle: '',
|
||||
did: '',
|
||||
active: true,
|
||||
});
|
||||
return agent;
|
||||
} catch (error) {
|
||||
console.error(`Bearer validation failed for user ${userId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+31
-41
@@ -1,14 +1,13 @@
|
||||
import { Client, GatewayIntentBits, REST, Routes } from 'discord.js';
|
||||
import dotenv from 'dotenv';
|
||||
import { BskyAgent } from '@atproto/api';
|
||||
import { handleAnalyticsCommand } from './commands/analytics';
|
||||
import { handleWatchCommand, handleUnwatchCommand, startWatcher } from './commands/watcher';
|
||||
import { handleLoginCommand } from './commands/login';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const TOKEN = process.env.DISCORD_TOKEN!;
|
||||
const CLIENT_ID = process.env.CLIENT_ID!;
|
||||
const agent = new BskyAgent({ service: 'https://bsky.social' });
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
@@ -25,6 +24,24 @@ const commands = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'login',
|
||||
description: 'Authenticate with Bluesky',
|
||||
options: [
|
||||
{
|
||||
name: 'handle',
|
||||
type: 3,
|
||||
description: 'Your Bluesky handle',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'app-password',
|
||||
type: 3,
|
||||
description: 'Your Bluesky app password',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'watchbluesky',
|
||||
description: 'Start watching a Bluesky profile for new posts',
|
||||
@@ -53,7 +70,6 @@ const commands = [
|
||||
|
||||
async function registerCommands() {
|
||||
const rest = new REST({ version: '10' }).setToken(TOKEN);
|
||||
|
||||
try {
|
||||
console.log('Registering application commands...');
|
||||
await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands });
|
||||
@@ -63,29 +79,10 @@ async function registerCommands() {
|
||||
}
|
||||
}
|
||||
|
||||
async function authenticateBluesky() {
|
||||
const identifier = process.env.BLUESKY_IDENTIFIER!;
|
||||
const password = process.env.BLUESKY_PASSWORD!;
|
||||
|
||||
if (!identifier || !password) {
|
||||
console.error('Bluesky credentials are not properly configured in the environment variables.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await agent.login({ identifier, password });
|
||||
console.log('Successfully authenticated with Bluesky!');
|
||||
} catch (error) {
|
||||
console.error('Failed to authenticate with Bluesky:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
client.once('ready', async () => {
|
||||
console.log(`Logged in as ${client.user?.tag}!`);
|
||||
await registerCommands();
|
||||
await authenticateBluesky();
|
||||
startWatcher(client, agent);
|
||||
startWatcher(client);
|
||||
});
|
||||
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
@@ -93,29 +90,22 @@ client.on('interactionCreate', async (interaction) => {
|
||||
|
||||
const { commandName, options } = interaction;
|
||||
|
||||
if (commandName === 'analytics') {
|
||||
const handle = options.getString('handle', true);
|
||||
await handleAnalyticsCommand(interaction, handle, agent);
|
||||
}
|
||||
|
||||
if (commandName === 'watchbluesky') {
|
||||
const handle = options.getString('handle', true);
|
||||
try {
|
||||
if (commandName === 'login') {
|
||||
await handleLoginCommand(interaction);
|
||||
} else if (commandName === 'analytics') {
|
||||
const handle = options.getString('handle', true);
|
||||
await handleAnalyticsCommand(interaction, handle);
|
||||
} else if (commandName === 'watchbluesky') {
|
||||
const handle = options.getString('handle', true);
|
||||
await handleWatchCommand(interaction, handle);
|
||||
} catch (error) {
|
||||
console.error('Error handling watchbluesky command:', error);
|
||||
await interaction.reply('Failed to watch Bluesky handle. Please try again later.');
|
||||
}
|
||||
}
|
||||
|
||||
if (commandName === 'unwatchbluesky') {
|
||||
} else if (commandName === 'unwatchbluesky') {
|
||||
const handle = options.getString('handle', true);
|
||||
try {
|
||||
await handleUnwatchCommand(interaction, handle);
|
||||
} catch (error) {
|
||||
console.error('Error handling unwatchbluesky command:', error);
|
||||
await interaction.reply('Failed to unwatch Bluesky handle. Please try again later.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error handling command ${commandName}:`, error);
|
||||
await interaction.reply({ content: 'An error occurred while processing your command.', ephemeral: true });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Client, Databases } from 'node-appwrite';
|
||||
|
||||
export class AppwriteService {
|
||||
private client: Client;
|
||||
private database: Databases;
|
||||
|
||||
constructor() {
|
||||
this.client = new Client();
|
||||
this.database = new Databases(this.client);
|
||||
|
||||
this.client
|
||||
.setEndpoint(process.env.APPWRITE_ENDPOINT!)
|
||||
.setProject(process.env.APPWRITE_PROJECT_ID!)
|
||||
.setKey(process.env.APPWRITE_API_KEY!);
|
||||
}
|
||||
|
||||
async getUserDocument(userId: string): Promise<{ handle: string; appPassword: string } | null> {
|
||||
try {
|
||||
const document = await this.database.getDocument(
|
||||
process.env.APPWRITE_DATABASE_ID!,
|
||||
process.env.APPWRITE_COLLECTION_ID!,
|
||||
userId
|
||||
);
|
||||
|
||||
const handle = document.handle || null;
|
||||
const appPassword = document.appPassword || null;
|
||||
|
||||
if (!handle || !appPassword) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { handle, appPassword };
|
||||
} catch (error) {
|
||||
console.error(`Failed to get user document for ${userId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async setUserBearer(userId: string, bearer: string, handle: string, appPassword: string): Promise<void> {
|
||||
try {
|
||||
await this.database.createDocument(
|
||||
process.env.APPWRITE_DATABASE_ID!,
|
||||
process.env.APPWRITE_COLLECTION_ID!,
|
||||
userId,
|
||||
{ bearer, handle, appPassword }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to set user bearer:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async getUserBearer(userId: string): Promise<string | null> {
|
||||
try {
|
||||
const document = await this.database.getDocument(
|
||||
process.env.APPWRITE_DATABASE_ID!,
|
||||
process.env.APPWRITE_COLLECTION_ID!,
|
||||
userId
|
||||
);
|
||||
return document.bearer;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
Reference in New Issue
Block a user