Skip to content

Commit 8c60baf

Browse files
committed
looks good to me
[skip netlify]
1 parent 311c8fd commit 8c60baf

File tree

6 files changed

+108
-15
lines changed

6 files changed

+108
-15
lines changed

.github/workflows/lint.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ on:
66
push:
77
branches: [main]
88

9-
permissions:
10-
contents: read
11-
129
env:
1310
SUPABASE_DATABASE_URL: ${{ secrets.SUPABASE_DATABASE_URL }}
1411

@@ -30,4 +27,7 @@ jobs:
3027
- uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944 # v1.3.1
3128
if: always()
3229
with:
33-
commit-message: 'style: autofix'
30+
commit-message: |
31+
style: autofix
32+
33+
[skip netlify]

app/layouts/default.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const links: [NavigationMenuItem[], NavigationMenuItem[] ] = [[{
1111
}], [{
1212
label: 'New Topic',
1313
icon: 'i-lucide-plus',
14+
onSelect: async () => navigateTo(`/topic/${await createTopic()}`),
1415
}/* , { label: 'Feedback', icon: 'i-lucide-message-circle', to: 'https://github.com/nuxt-ui-pro/dashboard', target: '_blank',} */]];
1516
1617
const groups = computed(() => [{

app/utils/topics.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { SupabaseClient } from "@supabase/supabase-js"
2+
3+
export async function createTopic(supa: SupabaseClient) {
4+
const { data } = await supa
5+
.from('topics')
6+
.insert({
7+
title: 'New Topic',
8+
description: '',
9+
})
10+
.select('id')
11+
.single()
12+
.throwOnError()
13+
14+
return data.id;
15+
}

server/api/request-tasks.post.ts

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,49 @@ import { serverSupabaseClient, serverSupabaseUser } from '#supabase/server';
22
import { z } from 'zod';
33

44
const Body = z.object({
5-
id: z.string(),
5+
id: z.string().uuid(),
66
});
77

88
export default defineEventHandler(async (ev) => {
99
const body = await readValidatedBody(ev, Body.parse);
10-
// const user = await serverSupabaseUser(ev);
10+
const user = requiresLogin(await serverSupabaseUser(ev));
1111
const supa = await serverSupabaseClient(ev);
1212

13-
const taskOwner = await supa
14-
.from('tasks')
15-
.select('*')
13+
// Verify ownership
14+
const owner = await supa
15+
.from('topics')
16+
.select('owner')
1617
.eq('id', body.id)
17-
.single();
18+
.limit(1)
19+
.throwOnError();
20+
if (owner.data[0]?.owner !== user.id)
21+
throw createError({ status: 404, message: 'Task not found' });
1822

19-
if (taskOwner.error) {
20-
console.error('Error querying task owner:', taskOwner.error);
21-
throw createError({ status: 500, message: 'Failed to query task owner' });
23+
// Query timeline_nodes for the given topic
24+
const timelineResponse = await supa
25+
.from('timeline_nodes')
26+
.select('*')
27+
.eq('topic_id', body.id);
28+
if (timelineResponse.error) {
29+
console.error('Error querying timeline_nodes:', timelineResponse.error);
30+
throw createError({ status: 500, message: 'Failed to query timeline_nodes' });
2231
}
23-
24-
// todo
32+
33+
// Query tasks for the given topic
34+
const tasksResponse = await supa
35+
.from('tasks')
36+
.select('*')
37+
.eq('topic_id', body.id)
38+
.throwOnError();
39+
40+
// Concatenate timeline_nodes and tasks info
41+
const timelineText = timelineResponse.data
42+
.map((node: any) => `${node.title}: ${node.description}`)
43+
.join('\n');
44+
const tasksText = tasksResponse.data
45+
.map((task: any) => `${task.title}: ${task.description} (Status: ${task.status})`)
46+
.join('\n');
47+
const contentForDeepseek = timelineText + '\n' + tasksText;
48+
49+
return contentForDeepseek;
2550
});

server/utils/auth.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { User } from '@supabase/supabase-js';
2+
3+
export function requiresLogin(user: User | null) {
4+
if (!user) {
5+
throw createError({
6+
statusCode: 401,
7+
statusMessage: 'Unauthorized',
8+
message: 'You must be logged in to access this resource.',
9+
});
10+
}
11+
return user;
12+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
ALTER TABLE public.topics
2+
ALTER COLUMN owner SET DEFAULT auth.uid();
3+
4+
DROP POLICY allow_owner ON public.topics;
5+
CREATE POLICY allow_owner ON public.topics
6+
FOR ALL
7+
USING (owner = auth.uid())
8+
WITH CHECK (owner = auth.uid());
9+
10+
DROP POLICY allow_owner ON public.timeline_nodes;
11+
CREATE POLICY allow_owner ON public.timeline_nodes
12+
FOR ALL
13+
USING (EXISTS (
14+
SELECT 1
15+
FROM public.topics
16+
WHERE public.topics.id = public.timeline_nodes.topic_id
17+
AND public.topics.owner = auth.uid()
18+
))
19+
WITH CHECK (EXISTS (
20+
SELECT 1
21+
FROM public.topics
22+
WHERE public.topics.id = public.timeline_nodes.topic_id
23+
AND public.topics.owner = auth.uid()
24+
));
25+
26+
DROP POLICY allow_owner ON public.tasks;
27+
CREATE POLICY allow_owner ON public.tasks
28+
FOR ALL
29+
USING (EXISTS (
30+
SELECT 1
31+
FROM public.topics
32+
WHERE public.topics.id = public.tasks.topic_id
33+
AND public.topics.owner = auth.uid()
34+
))
35+
WITH CHECK (EXISTS (
36+
SELECT 1
37+
FROM public.topics
38+
WHERE public.topics.id = public.tasks.topic_id
39+
AND public.topics.owner = auth.uid()
40+
));

0 commit comments

Comments
 (0)