feat: Implement core Discord clone functionality including Convex backend, Electron frontend, and UI components for chat, voice, and settings.
This commit is contained in:
85
convex/invites.ts
Normal file
85
convex/invites.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { query, mutation } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
// Create invite with encrypted payload
|
||||
export const create = mutation({
|
||||
args: {
|
||||
code: v.string(),
|
||||
encryptedPayload: v.string(),
|
||||
createdBy: v.id("userProfiles"),
|
||||
maxUses: v.optional(v.number()),
|
||||
expiresAt: v.optional(v.number()),
|
||||
keyVersion: v.number(),
|
||||
},
|
||||
returns: v.object({ success: v.boolean() }),
|
||||
handler: async (ctx, args) => {
|
||||
await ctx.db.insert("invites", {
|
||||
code: args.code,
|
||||
encryptedPayload: args.encryptedPayload,
|
||||
createdBy: args.createdBy,
|
||||
maxUses: args.maxUses,
|
||||
uses: 0,
|
||||
expiresAt: args.expiresAt,
|
||||
keyVersion: args.keyVersion,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
|
||||
// Fetch and validate invite (returns encrypted payload)
|
||||
export const use = query({
|
||||
args: { code: v.string() },
|
||||
returns: v.union(
|
||||
v.object({
|
||||
encryptedPayload: v.string(),
|
||||
keyVersion: v.number(),
|
||||
}),
|
||||
v.object({ error: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
const invite = await ctx.db
|
||||
.query("invites")
|
||||
.withIndex("by_code", (q) => q.eq("code", args.code))
|
||||
.unique();
|
||||
|
||||
if (!invite) {
|
||||
return { error: "Invite not found" };
|
||||
}
|
||||
|
||||
if (invite.expiresAt && Date.now() > invite.expiresAt) {
|
||||
return { error: "Invite expired" };
|
||||
}
|
||||
|
||||
if (
|
||||
invite.maxUses !== undefined &&
|
||||
invite.maxUses !== null &&
|
||||
invite.uses >= invite.maxUses
|
||||
) {
|
||||
return { error: "Invite max uses reached" };
|
||||
}
|
||||
|
||||
return {
|
||||
encryptedPayload: invite.encryptedPayload,
|
||||
keyVersion: invite.keyVersion,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Revoke invite
|
||||
export const revoke = mutation({
|
||||
args: { code: v.string() },
|
||||
returns: v.object({ success: v.boolean() }),
|
||||
handler: async (ctx, args) => {
|
||||
const invite = await ctx.db
|
||||
.query("invites")
|
||||
.withIndex("by_code", (q) => q.eq("code", args.code))
|
||||
.unique();
|
||||
|
||||
if (invite) {
|
||||
await ctx.db.delete(invite._id);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user