fix bug that breaks subscriptions in channels, leaving servers, fix

subscrptions part 6
This commit is contained in:
Soph :3 2026-01-17 10:52:36 +02:00
parent d0509788ff
commit 5a85d72a51
5 changed files with 198 additions and 66 deletions

View file

@ -24,6 +24,8 @@
import { overview_data } from '$lib/state.svelte';
let dialogType: 'create_channel' | 'leave_server' | '' = $state('');
let {
currentPage = $bindable<string | null>(),
subPage = $bindable<string | null>(),
@ -505,11 +507,23 @@
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item>
<Dialog.Trigger>Create channel</Dialog.Trigger>
<Dialog.Trigger
onclick={() => {
dialogType = 'create_channel';
}}>Create channel</Dialog.Trigger
>
</ContextMenu.Item>
<ContextMenu.Item class="text-red-500 underline">
<Dialog.Trigger
onclick={() => {
dialogType = 'leave_server';
}}>Leave server</Dialog.Trigger
>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Root>
{#if dialogType == 'create_channel'}
<Dialog.Content>
<form
method="POST"
@ -534,7 +548,9 @@
>
<Dialog.Header>
<Dialog.Title>Create a channel</Dialog.Title>
<Dialog.Description>Add a new channel to this server.</Dialog.Description>
<Dialog.Description
>Add a new channel to this server.</Dialog.Description
>
</Dialog.Header>
<div class="space-y-1">
@ -551,13 +567,55 @@
</div>
<Dialog.Footer>
<Dialog.Close class={buttonVariants({ variant: 'outline' })}
>Cancel</Dialog.Close
<Dialog.Close
type="button"
class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close
>
<Button type="submit">Create</Button>
</Dialog.Footer>
</form>
</Dialog.Content>
{:else if dialogType == 'leave_server'}
<Dialog.Content>
<form
method="POST"
action="?/leaveServer"
use:enhance={() => {
return async ({ result }) => {
if (result.type == 'success') {
toast.success('Left server successfully');
}
if (result.type == 'error' || result.type == 'failure') {
toast.error(
'Could not leave server: ' +
(result.type === 'error' ? result.error : result.data?.error)
);
}
await invalidateAll();
await fill_overview_data(psd);
};
}}
>
<input type="hidden" name="serverId" value={server.id} />
<Dialog.Header>
<Dialog.Title>Leave this server</Dialog.Title>
<Dialog.Description
>Would you like to leave this server?</Dialog.Description
>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close class={buttonVariants({ variant: 'outline' })}
>No</Dialog.Close
>
<Button variant="destructive" type="submit">Yes</Button>
</Dialog.Footer>
</form>
</Dialog.Content>
{/if}
</Dialog.Root>
{#each server.channels as channel (channel.id)}
<Dialog.Root>

View file

@ -43,7 +43,9 @@ export async function GET({ locals, request }) {
const userId = locals.user.id;
//@TODO add more to subscribed eventually, server members, et cetera
const subscribed = locals.user.friends.map((f) => f.id);
const subscribed = locals.user.friends
.map((f) => f.id) // friends
.concat(locals.user.servers.map((z) => z.id)); // server changes like nameschanges and etc
subscribed.push(userId); // shit such as friend requests
const overwrite = locals.user.statusOverwrite;

View file

@ -122,7 +122,7 @@
});
}
previousSubscription = currentPageID;
previousSubscription = subscribe;
}
getMessages();

View file

@ -241,23 +241,26 @@
<Tabs.Content value="general" class="space-y-6 p-4">
<div class="space-y-2">
<h2 class="text-lg font-medium">Server Settings</h2>
<div class="flex items-center gap-4">
<Input
placeholder="New server name"
class="max-w-xs"
value={server?.name}
oninput={(e) => {
server.name = e.currentTarget.value;
<form
method="POST"
action="?/changeServerName"
use:enhance={() => {
return async ({ result }) => {
if (result.type === 'success') {
toast.success('Server name updated successfully');
await invalidateAll();
await fill_overview_data(psd);
} else if (result.type === 'failure') {
toast.error('Failed to update server name: ' + result.data?.error);
}
};
}}
/>
<Button
variant="outline"
onclick={() => toast.info('Server name change would be saved (no backend yet)')}
class="flex items-center gap-4"
>
Save Name
</Button>
</div>
<p class="text-xs text-muted-foreground">Changes are local only (no backend yet)</p>
<input type="hidden" name="serverId" value={currentPage} />
<Input name="name" placeholder="New server name" class="max-w-xs" value={server?.name} />
<Button type="submit" variant="outline">Save Name</Button>
</form>
</div>
<div class="space-y-2">

View file

@ -3,7 +3,7 @@ import { db } from '$lib/server/db';
import * as table from '$lib/server/db/schema';
import { ChannelID, InviteID, ServerID } from '$lib';
import { eq } from 'drizzle-orm';
import { _sendToUser } from '../../api/updates/+server';
import { _sendToSubscribers } from '../../api/updates/+server';
import type { Actions } from '../$types';
export default {
@ -83,6 +83,7 @@ export default {
.where(eq(table.server.id, server[0].id));
});
}
_sendToSubscribers(server[0].id, { type: 'server', status: 'new-member' });
return { success: true };
},
@ -189,7 +190,31 @@ export default {
.set({ servers: locals.user!.servers.map((z) => z.id).concat([serverId]) })
.where(eq(table.user.id, locals.user!.id));
_sendToUser(locals.user!.id, { type: 'server', status: 'server-created' });
return { success: true };
},
changeServerName: async ({ request, locals }) => {
const data = await request.formData();
const name = data.get('name');
const serverId = data.get('serverId');
if (typeof name !== 'string' || name.length < 3) {
return fail(400, { error: 'Server name too short' });
}
if (typeof serverId !== 'string') {
return fail(400, { error: 'Server ID incorrect' });
}
const server = await db.select().from(table.server).where(eq(table.server.id, serverId));
if (!server || server.length == 0) {
return fail(400, { error: 'Server ID invalid' });
}
// @TODO check permissions here (only owner or users with manageServer permission should be able to change server name)
await db.update(table.server).set({ name }).where(eq(table.server.id, serverId));
_sendToSubscribers(serverId, { type: 'server', status: 'server-updated' });
return { success: true };
},
createChannel: async ({ request, locals }) => {
@ -228,6 +253,7 @@ export default {
})
.where(eq(table.server.id, serverId));
});
_sendToSubscribers(serverId, { type: 'server', status: 'channel-created' });
return { success: true };
},
@ -263,6 +289,7 @@ export default {
.where(eq(table.server.id, serverId));
});
_sendToSubscribers(serverId, { type: 'server', status: 'channel-deleted' });
return { success: true };
},
deleteServer: async ({ request, locals }) => {
@ -304,7 +331,49 @@ export default {
await tx.delete(table.server).where(eq(table.server.id, serverId));
});
_sendToUser(locals.user!.id, { type: 'server', status: 'server-deleted' });
_sendToSubscribers(serverId, { type: 'server', status: 'server-deleted' });
return { success: true };
},
leaveServer: async ({ request, locals }) => {
const data = await request.formData();
const serverId = data.get('serverId');
if (typeof serverId !== 'string') {
return fail(400, { error: 'Server ID incorrect' });
}
const server = await db.select().from(table.server).where(eq(table.server.id, serverId));
if (!server || server.length == 0) {
return fail(400, { error: 'Server ID invalid' });
}
if (server[0].owner === locals.user!.id) {
return fail(400, { error: 'Owners cannot leave their own server' });
}
if (!locals.user!.servers.some((z) => z.id == serverId)) {
return fail(400, { error: 'Not in this server' });
}
await db.transaction(async (tx) => {
// Remove server from user's server list
await tx
.update(table.user)
.set({
servers: locals.user!.servers.map((z) => z.id).filter((id) => id !== serverId)
})
.where(eq(table.user.id, locals.user!.id));
// Remove user from server's member list
await tx
.update(table.server)
.set({
members: (server[0].members as string[]).filter((id) => id !== locals.user!.id)
})
.where(eq(table.server.id, serverId));
});
_sendToSubscribers(serverId, { type: 'server', status: 'server-left' });
return { success: true };
}
} satisfies Actions;