feat: notes wip part tres
All checks were successful
create archive with lfs / tag (push) Successful in 10s

This commit is contained in:
dusk 2024-10-30 16:33:08 +03:00
parent 9f57b193ce
commit 980579b50c
Signed by: dusk
SSH Key Fingerprint: SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw
11 changed files with 1157 additions and 33 deletions

BIN
bun.lockb

Binary file not shown.

3
gazebot/.gitignore vendored
View File

@ -1,2 +1,5 @@
target target
.env .env
Secrets.toml/target
.shuttle*
Secrets*.toml

1082
gazebot/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,3 +9,5 @@ tracing-subscriber = "0.3"
dotenvy = "0.15.7" dotenvy = "0.15.7"
serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
shuttle-serenity = "0.48.0"
shuttle-runtime = "0.48.0"

View File

@ -1,9 +1,11 @@
use std::env; use std::env;
use serenity::all::ActivityData;
use serenity::async_trait; use serenity::async_trait;
use serenity::model::channel::Message; use serenity::model::channel::Message;
use serenity::model::prelude::*; use serenity::model::prelude::*;
use serenity::prelude::*; use serenity::prelude::*;
use shuttle_runtime::SecretStore;
struct Handler; struct Handler;
@ -17,26 +19,44 @@ impl EventHandler for Handler {
} }
} }
async fn ready(&self, _: Context, ready: Ready) { async fn ready(&self, ctx: Context, ready: Ready) {
println!("{} is connected!", ready.user.name); println!("{} is connected!", ready.user.name);
ctx.set_presence(Some(ActivityData::listening("messages to log")), OnlineStatus::Online);
} }
} }
#[tokio::main] // #[tokio::main]
async fn main() { // async fn main() {
let _ = dotenvy::dotenv(); // let _ = dotenvy::dotenv();
tracing_subscriber::fmt::init(); // tracing_subscriber::fmt::init();
let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment"); // let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
let intents = GatewayIntents::GUILD_MESSAGES // let intents = GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client = // let mut client =
Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client"); // Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client");
if let Err(why) = client.start().await { // if let Err(why) = client.start().await {
println!("Client error: {why:?}"); // println!("Client error: {why:?}");
} // }
// }
#[shuttle_runtime::main]
async fn serenity(
#[shuttle_runtime::Secrets] secrets: SecretStore,
) -> shuttle_serenity::ShuttleSerenity {
// Get the discord token set in `Secrets.toml`
let token = secrets.get("DISCORD_TOKEN").unwrap();
// Set gateway intents, which decides what events the bot will be notified about
let intents = GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
let client = Client::builder(&token, intents)
.event_handler(Handler)
.await
.expect("Err creating client");
Ok(client.into())
} }

View File

@ -39,6 +39,7 @@
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@atproto/api": "^0.13.12",
"@std/toml": "npm:@jsr/std__toml", "@std/toml": "npm:@jsr/std__toml",
"base64url": "^3.0.1", "base64url": "^3.0.1",
"nanoid": "^5.0.8", "nanoid": "^5.0.8",

View File

@ -2,6 +2,7 @@ import type { Cookies } from '@sveltejs/kit'
import { env } from '$env/dynamic/private' import { env } from '$env/dynamic/private'
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
import { existsSync, readFileSync } from 'fs' import { existsSync, readFileSync } from 'fs'
import { Agent, CredentialSession } from '@atproto/api'
export const scopeCookies = (cookies: Cookies, path: string) => { export const scopeCookies = (cookies: Cookies, path: string) => {
return { return {
@ -19,3 +20,10 @@ export const scopeCookies = (cookies: Cookies, path: string) => {
export const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount` export const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount`
export const visitCount = writable(parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0')); export const visitCount = writable(parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0'));
const loginToBsky = () => {
const creds = new CredentialSession(new URL("https://bsky.social"))
creds.login({identifier: 'gaze.systems', password: env.BSKY_PASSWORD ?? "" })
return new Agent(creds)
}
export const bskyClient = loginToBsky()

View File

@ -29,9 +29,14 @@ export const writeNote = (id: NoteId, note: Note) => {
// only append to note list if its not in it yet // only append to note list if its not in it yet
let noteList = readNotesList() let noteList = readNotesList()
if (noteList.indexOf(id) === -1) { if (noteList.indexOf(id) === -1) {
writeNotesList(noteList.concat([id])) writeNotesList([id].concat(noteList))
} }
} }
export const createNote = (note: Note) => {
const id = genNoteId()
writeNote(id, note)
return id
}
export const readNotesList = (): NoteId[] => { export const readNotesList = (): NoteId[] => {
return JSON.parse(readFileSync(notesListFile).toString()) return JSON.parse(readFileSync(notesListFile).toString())

View File

@ -25,9 +25,9 @@
" "
> >
<pre class="language-bash"><code class="language-bash"><nobr> <pre class="language-bash"><code class="language-bash"><nobr>
<Token v="[" punct/>gazesystems <Token v="/notes/" keywd/><Token v="]$" punct/> <Token v="source" funct/> note.nu <Token v="[" punct/>gazesystems <Token v="/log/" keywd/><Token v="]$" punct/> <Token v="source" funct/> log.nu
<br> <br>
<Token v="[" punct/>gazesystems <Token v="/notes/" keywd/><Token v="]$" punct/> <Token v="ls" funct/> notes <Token v="|" punct/> <Token v="each" funct/> <Token v="&#123;" punct/><Token v="|" punct/>file<Token v="|" punct/> <Token v="render" funct/> <Token v="(" punct/><Token v="open" funct/> $file.name<Token v=")" punct/><Token v="&#125;" punct/> <Token v="[" punct/>gazesystems <Token v="/log/" keywd/><Token v="]$" punct/> <Token v="ls" funct/> log <Token v="|" punct/> <Token v="each" funct/> <Token v="&#123;" punct/><Token v="|" punct/>file<Token v="|" punct/> <Token v="render" funct/> <Token v="(" punct/><Token v="open" funct/> $file.name<Token v=")" punct/><Token v="&#125;" punct/>
<br> <br>
<br> <br>
{#each data.notes as { noteId, note }, index} {#each data.notes as { noteId, note }, index}

View File

@ -0,0 +1,31 @@
import { env } from '$env/dynamic/private';
import { PUBLIC_BASE_URL } from '$env/static/public';
import { bskyClient } from '$lib';
import { createNote } from '$lib/notes.js';
export const POST = async ({ request }) => {
const token = request.headers.get('authorization')
if (token !== env.GAZEBOT_TOKEN) {
return new Response("rizz failed", { status: 403 })
}
// get note data
const noteData = await request.json()
if (noteData.content ?? null === null) {
return new Response("no rizz :(", { status: 400 })
}
// create note
const published = Date.now()
const noteId = createNote({ content: noteData.content, published })
// bridge to bsky if want to bridge
if (noteData.bskyPosse ?? null !== null) {
await bskyClient.post({text: `${noteData.content} (${PUBLIC_BASE_URL}/log?id=${noteId})`})
}
// send back created note id
return new Response(JSON.stringify({ noteId }), {
headers: {
'content-type': 'application/json',
'cache-control': 'no-store',
}
})
};