Initial commit
This commit is contained in:
65
server/routes/auth/strava.ts
Normal file
65
server/routes/auth/strava.ts
Normal 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, "/");
|
||||
},
|
||||
});
|
||||
58
server/routes/webhooks/strava/activity-create.post.ts
Normal file
58
server/routes/webhooks/strava/activity-create.post.ts
Normal 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"),
|
||||
},
|
||||
});
|
||||
});
|
||||
17
server/routes/webhooks/strava/athelete-update.post.ts
Normal file
17
server/routes/webhooks/strava/athelete-update.post.ts
Normal 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);
|
||||
});
|
||||
5
server/routes/webhooks/strava/index.get.ts
Normal file
5
server/routes/webhooks/strava/index.get.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = getQuery(event);
|
||||
|
||||
return { "hub.challenge": query["hub.challenge"] };
|
||||
});
|
||||
14
server/routes/webhooks/strava/index.post.ts
Normal file
14
server/routes/webhooks/strava/index.post.ts
Normal 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,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user