Initial commit

This commit is contained in:
2025-04-07 12:59:20 +03:00
commit d47a21fcbf
47 changed files with 12696 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
import { omit } from "radash";
export default defineOAuthStravaEventHandler({
config: {
scope: ["read,activity:read,activity:write"],
},
onSuccess: async (event, auth) => {
const userPayload = {
id: auth.user.id,
name: `${auth.user.firstname} ${auth.user.lastname}`,
city: auth.user.city,
country: auth.user.country,
sex: auth.user.sex,
weight: auth.user.weight,
avatar: auth.user.profile,
};
await setUserSession(event, {
user: userPayload,
});
const db = useDrizzle();
const [user] = await db
.insert(tables.users)
.values(userPayload)
.onConflictDoUpdate({
target: tables.users.id,
set: omit(userPayload, ["id"]),
})
.returning();
const tokenExpiration = new Date(auth.tokens.expires_at * 1000);
await db
.insert(tables.tokens)
.values({
userId: user.id,
refreshToken: auth.tokens.refresh_token,
accessToken: auth.tokens.access_token,
expiresAt: tokenExpiration,
})
.onConflictDoUpdate({
target: tables.tokens.userId,
set: {
refreshToken: auth.tokens.refresh_token,
accessToken: auth.tokens.access_token,
expiresAt: tokenExpiration,
},
});
await db
.insert(tables.preferences)
.values({
userId: user.id,
data: {
enabled: true,
language: "english",
},
})
.onConflictDoNothing();
sendRedirect(event, "/");
},
});

View File

@@ -0,0 +1,58 @@
import { get } from "radash";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const db = useDrizzle();
const ai = hubAI();
const user = await db.query.users.findFirst({
where: (f, o) => o.eq(f.id, body.owner_id),
with: {
preferences: true,
},
});
if (!user?.preferences.data?.enabled) {
return;
}
const strava = await useStrava(body.owner_id);
const activity = await strava!(`/activities/${body.object_id}`);
const aiResponse = await ai.run("@cf/meta/llama-3-8b-instruct", {
response_format: {
type: "json_schema",
json_schema: {
type: "object",
properties: {
title: "string",
description: "string",
},
required: ["title", "description"],
},
},
prompt: `
Generate a title and a short description for my strava activity. Use my preferred language. Make sure to include emojis and make it fun.
My user profile:
Sex: ${user?.sex}
City: ${user?.city}
Country: ${user?.country}
Weight: ${user?.weight}
Language: ${user?.preferences.data.language}
The activity data in json format:
${JSON.stringify(activity)}
`,
});
await strava!(`activities/${body.object_id}`, {
method: "PUT",
body: {
name: get(aiResponse, "response.title"),
description: get(aiResponse, "response.description"),
},
});
});

View File

@@ -0,0 +1,17 @@
import { get, isEmpty } from "radash";
import { eq } from "drizzle-orm";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const db = useDrizzle();
if (get(body, "updates.authorized") !== false) {
return;
}
await db
.delete(tables.users)
.where(eq(tables.users.id, get(body, "object_id")));
sendNoContent(event);
});

View File

@@ -0,0 +1,5 @@
export default defineEventHandler(async (event) => {
const query = getQuery(event);
return { "hub.challenge": query["hub.challenge"] };
});

View File

@@ -0,0 +1,14 @@
import { get } from "radash";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const db = useDrizzle();
const aspectType = get(body, "aspect_type");
const objectType = get(body, "object_type");
await $fetch(`/webhooks/strava/${objectType}-${aspectType}`, {
method: "post",
body,
});
});