+
-
-
-
-
- {{ message.creator.username }}
-
-
{{ message.body }}
-
-
-
-
-
+ v-for="(message, i) in server.messages"
+ class="relative">
+
+
@@ -135,26 +119,25 @@
\ No newline at end of file
diff --git a/pages/channel/@me/index.vue b/pages/channel/@me/index.vue
index ce10c29..8151e25 100644
--- a/pages/channel/@me/index.vue
+++ b/pages/channel/@me/index.vue
@@ -20,7 +20,7 @@ export default {
}
},
mounted() {
- useGlobalStore().setActive('dms', '@me')
+ useGlobalStore().setActiveServer('dms', '@me')
},
methods: {
async startDM() {
diff --git a/pages/channel/[id].vue b/pages/channel/[id].vue
index 012f18d..4528076 100644
--- a/pages/channel/[id].vue
+++ b/pages/channel/[id].vue
@@ -3,6 +3,7 @@
\ No newline at end of file
diff --git a/pages/signup.vue b/pages/signup.vue
index daf4fb2..dca4be4 100644
--- a/pages/signup.vue
+++ b/pages/signup.vue
@@ -63,15 +63,19 @@ export default {
const token = useCookie('sessionToken')
token.value = user.token
- const headers = { Cookie: `sessionToken=${token.value}`}
- const { servers, dms } = await $fetch('/api/user/getServers', { headers })
+ setTimeout(async () => {
+ const headers = { Cookie: `sessionToken=${token.value}` }
+ const { servers, dms } = await $fetch('/api/user/getServers', { headers })
- globalStore.setServers(servers)
- globalStore.setDms(dms)
+ if (!servers || !dms) return;
- useGlobalStore().setUser(user.user)
+ globalStore.setServers(servers)
+ globalStore.setDms(dms)
- navigateTo('/channel/@me')
+ globalStore.setUser(user.user)
+
+ navigateTo('/channel/@me')
+ })
}
}
}
diff --git a/prisma/dev.db b/prisma/dev.db
deleted file mode 100644
index e69de29..0000000
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 14edb61..7857486 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -17,6 +17,9 @@ model User {
session Session[]
channels Channel[]
roles Role[]
+ createdAt DateTime @default(now())
+ Reaction Reaction? @relation(fields: [reactionId], references: [id])
+ reactionId String?
}
model Server {
@@ -26,6 +29,7 @@ model Server {
channels Channel[]
roles Role[]
InviteCode InviteCode[]
+ createdAt DateTime @default(now())
}
model Role {
@@ -56,6 +60,9 @@ model Message {
userId String
channelId String
invites InviteCode[]
+ reactions Reaction[]
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
}
model InviteCode {
@@ -80,3 +87,12 @@ model ExpiredSession {
id String @id @default(cuid())
token String
}
+
+model Reaction {
+ id String @id @default(cuid())
+ emoji Json
+ count Int
+ users User[]
+ Message Message? @relation(fields: [messageId], references: [id])
+ messageId String?
+}
diff --git a/server/api/channels/[id]/index.get.ts b/server/api/channels/[id]/index.get.ts
index e766317..c8637d3 100644
--- a/server/api/channels/[id]/index.get.ts
+++ b/server/api/channels/[id]/index.get.ts
@@ -33,7 +33,55 @@ export default defineEventHandler(async (event) => {
id: true,
username: true
}
- }
+ },
+ channels: {
+ select: {
+ id: true,
+ DM: true,
+ name: true,
+ messages: {
+ select: {
+ id: true,
+ body: true,
+ creator: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ invites: {
+ select: {
+ id: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true
+ }
+ }
+ }
+ }
+ }
+ },
+ reactions: {
+ select: {
+ id: true,
+ emoji: true,
+ count: true,
+ users: {
+ select: {
+ id: true,
+ username: true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
}
},
messages: {
@@ -61,6 +109,19 @@ export default defineEventHandler(async (event) => {
}
}
}
+ },
+ reactions: {
+ select: {
+ id: true,
+ emoji: true,
+ count: true,
+ users: {
+ select: {
+ id: true,
+ username: true
+ }
+ }
+ }
}
}
},
@@ -93,6 +154,8 @@ export default defineEventHandler(async (event) => {
}
}) as IServer | null;
+ if (!server) return;
+
const userInServer: Array
| undefined = server?.participants.filter((e: SafeUser) => e.id === event.context.user.id)
if (!userInServer) {
diff --git a/server/api/channels/[id]/messages/[messageId]/reactions/[name].post.ts b/server/api/channels/[id]/messages/[messageId]/reactions/[name].post.ts
new file mode 100644
index 0000000..80c15cd
--- /dev/null
+++ b/server/api/channels/[id]/messages/[messageId]/reactions/[name].post.ts
@@ -0,0 +1,173 @@
+import { IChannel, IServer, SafeUser } from '~/types'
+import { PrismaClient } from '@prisma/client'
+import { node } from 'unenv'
+const prisma = new PrismaClient()
+
+export default defineEventHandler(async (event) => {
+ if (!event.context.user.authenticated) {
+ event.node.res.statusCode = 401;
+ return {
+ message: 'You must be logged in to send a message.'
+ }
+ }
+
+ const emoji = decodeURIComponent(event.context.params.name)
+
+ if (emoji.length !== 2) {
+ event.node.res.statusCode = 400;
+ return {
+ message: 'reaction is not an emoji or more than one emoji.'
+ }
+ }
+
+ const first = emoji.charCodeAt(0);
+ const second = emoji.charCodeAt(1);
+
+ if (!((first >= 0xD800 && first <= 0xDBFF) && (second >= 0xDC00 && second <= 0xDFFF))) {
+ event.node.res.statusCode = 400;
+ return {
+ message: 'reaction is not an emoji or more than one emoji.'
+ }
+ }
+
+ const messageSelect = {
+ id: true,
+ body: true,
+ creator: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ invites: {
+ select: {
+ id: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true
+ }
+ }
+ }
+ }
+ }
+ },
+ reactions: {
+ select: {
+ id: true,
+ emoji: true,
+ count: true,
+ users: {
+ select: {
+ id: true,
+ username: true
+ }
+ }
+ }
+ }
+ }
+
+ const message = await prisma.message.findFirst({
+ where: {
+ id: event.context.params.messageId
+ },
+ select: messageSelect
+ })
+
+ if (!message.id) {
+ event.node.res.statusCode = 404;
+ return {
+ message: `message with id "${event.context.params.messageId}" not found.`
+ }
+ }
+
+ const reactionInMessage = message.reactions.find((e) => e.emoji.name === emoji)
+
+ let count;
+
+ if (reactionInMessage?.count) {
+ count = reactionInMessage.count + 1;
+ } else {
+ count = 1;
+ }
+
+ if (reactionInMessage && reactionInMessage.users.find((e) => e.id === event.context.user.id)) {
+ // remove reaction
+ await prisma.reaction.update({
+ where: {
+ id: reactionInMessage.id
+ },
+ data: {
+ count: reactionInMessage.count - 1,
+ users: {
+ disconnect: [{ id: event.context.user.id }]
+ }
+ }
+ })
+
+ const updatedMessage = await prisma.message.findFirst({
+ where: {
+ id: event.context.params.messageId
+ },
+ select: messageSelect
+ })
+
+ global.io.emit(`message-${event.context.params.id}`, { message: updatedMessage });
+
+ return { message: updatedMessage }
+ }
+
+ let reaction;
+ if (reactionInMessage) {
+ // reaction already exists, so up the count by one and add the user to the users who have reacted
+ reaction = await prisma.reaction.update({
+ where: {
+ id: reactionInMessage.id
+ },
+ data: {
+ count,
+ users: {
+ connect: [{
+ id: event.context.user.id,
+ }]
+ },
+ }
+ })
+ } else {
+ reaction = await prisma.reaction.create({
+ data: {
+ emoji: {
+ name: emoji,
+ id: null
+ },
+ count: count,
+ users: {
+ connect: [{
+ id: event.context.user.id,
+ }]
+ },
+ Message: {
+ connect: {
+ id: message.id,
+ }
+ }
+ }
+ })
+ }
+
+ if (!reaction.messageId) return;
+
+ const updatedMessage = await prisma.message.findFirst({
+ where: {
+ id: reaction.messageId,
+ },
+ select: messageSelect
+ })
+
+ global.io.emit(`message-${event.context.params.id}`, { message: updatedMessage });
+
+ return { message: updatedMessage }
+})
\ No newline at end of file
diff --git a/server/api/guilds/[id]/addChannel.post.ts b/server/api/guilds/[id]/addChannel.post.ts
index 52a8b74..55de722 100644
--- a/server/api/guilds/[id]/addChannel.post.ts
+++ b/server/api/guilds/[id]/addChannel.post.ts
@@ -61,8 +61,69 @@ export default defineEventHandler(async (event) => {
id: server.id
}
}
+ },
+ select: {
+ id: true,
+ name: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ channels: {
+ select: {
+ id: true,
+ DM: true,
+ name: true
+ }
+ },
+ }
+ },
+ messages: {
+ select: {
+ id: true,
+ body: true,
+ creator: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ invites: {
+ select: {
+ id: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ DM: true,
+ dmParticipants: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ serverId: true,
}
}) as IChannel
+ global.io.emit(`addChannel-${server.id}`, channel)
+
return channel
})
\ No newline at end of file
diff --git a/server/api/guilds/[id]/index.get.ts b/server/api/guilds/[id]/index.get.ts
index ed13d5a..ae00597 100644
--- a/server/api/guilds/[id]/index.get.ts
+++ b/server/api/guilds/[id]/index.get.ts
@@ -21,10 +21,63 @@ export default defineEventHandler(async (event) => {
where: {
id: event.context.params.id
},
- include: {
- participants: true,
- channels: true,
- roles: true
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ channels: {
+ select: {
+ id: true,
+ DM: true,
+ name: true,
+ messages: {
+ select: {
+ id: true,
+ body: true,
+ creator: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ invites: {
+ select: {
+ id: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true
+ }
+ }
+ }
+ }
+ }
+ },
+ reactions: {
+ select: {
+ id: true,
+ emoji: true,
+ count: true,
+ users: {
+ select: {
+ id: true,
+ username: true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
}
}) as IServer | null;
diff --git a/server/api/login.post.ts b/server/api/login.post.ts
index ea3805e..abb95cd 100644
--- a/server/api/login.post.ts
+++ b/server/api/login.post.ts
@@ -14,8 +14,6 @@ export default defineEventHandler(async (event) => {
}
}
-
-
let user = await prisma.user.findFirst({
where: {
username: body.username
diff --git a/server/api/signup.post.ts b/server/api/signup.post.ts
index 178b121..c3f57a6 100644
--- a/server/api/signup.post.ts
+++ b/server/api/signup.post.ts
@@ -45,6 +45,21 @@ export default defineEventHandler(async (event) => {
select: {
id: true,
username: true,
+ servers: {
+ participants: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ channels: {
+ select: {
+ id: true,
+ DM: true,
+ name: true,
+ }
+ },
+ }
},
}) as unknown as IUser
diff --git a/server/api/user/getServers.get.ts b/server/api/user/getServers.get.ts
index ca9b914..364c425 100644
--- a/server/api/user/getServers.get.ts
+++ b/server/api/user/getServers.get.ts
@@ -25,8 +25,68 @@ export default defineEventHandler(async (event) => {
select: {
id: true,
DM: true,
- name: true
- }
+ name: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ channels: {
+ select: {
+ id: true,
+ DM: true,
+ name: true,
+ messages: {
+ select: {
+ id: true,
+ body: true,
+ creator: {
+ select: {
+ id: true,
+ username: true
+ }
+ },
+ invites: {
+ select: {
+ id: true,
+ server: {
+ select: {
+ id: true,
+ name: true,
+ participants: {
+ select: {
+ id: true
+ }
+ }
+ }
+ }
+ }
+ },
+ reactions: {
+ select: {
+ id: true,
+ emoji: true,
+ count: true,
+ users: {
+ select: {
+ id: true,
+ username: true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ },
+ },
},
participants: {
select: {
diff --git a/server/middleware/socket.ts b/server/middleware/socket.ts
index c353e5d..36a30b8 100644
--- a/server/middleware/socket.ts
+++ b/server/middleware/socket.ts
@@ -17,7 +17,6 @@ export default defineEventHandler(({ node }) => {
return;
}
- console.time()
const { user } = await prisma.session.findFirst({
where: {
token
@@ -87,7 +86,6 @@ export default defineEventHandler(({ node }) => {
}
}
}) as { user: IUser } | null;
- console.timeEnd();
if (!user) {
return;
diff --git a/stores/store.ts b/stores/store.ts
index 9f30082..c8745d4 100644
--- a/stores/store.ts
+++ b/stores/store.ts
@@ -1,8 +1,11 @@
+import { channel } from "diagnostics_channel";
+import { serve } from "esbuild";
import { Socket } from "socket.io-client";
-import { SafeUser, IServer, IChannel } from "../types";
+import { SafeUser, IServer, IChannel, IMessage } from "../types";
export const useGlobalStore = defineStore('global', {
state: () => ({
+ activeChannel: {} as IChannel,
activeServer: {} as IServer | IChannel,
activeServerType: '' as "dms" | "servers" | undefined,
user: {} as SafeUser,
@@ -11,27 +14,7 @@ export const useGlobalStore = defineStore('global', {
socket: null as unknown
}),
actions: {
- setUser(user: SafeUser) {
- this.user = user;
- },
- addServer(server: IServer) {
- if (!this.servers || this.servers.find((e) => e.id === server.id)) return;
- this.servers.push(server)
- },
- addDM(dmChannel: IChannel) {
- if (!this.dms || this.dms.find((e) => e.id === dmChannel.id)) return;
- this.dms.push(dmChannel)
- },
- setServers(servers: Array) {
- this.servers = servers
- },
- setDms(dms: Array) {
- this.dms = dms
- },
- setSocket(socket: Socket) {
- this.socket = socket
- },
- setActive(type: "servers" | "dms", channelId: string) {
+ setActiveServer(type: "servers" | "dms", channelId: string) {
if (channelId === '@me') {
this.activeServer = {} as IServer | IChannel
this.activeServerType = 'dms'
@@ -42,24 +25,71 @@ export const useGlobalStore = defineStore('global', {
const searchableArray: IChannel[] | IServer[] | undefined = this[type]
if (!searchableArray) return;
- let activeServerIndex: number;
+ let activeServer: number;
if (type === 'servers') {
- activeServerIndex = searchableArray.findIndex((e) => {
+ activeServer = searchableArray.find((e) => {
return e.channels.some((channel: IChannel) => channel.id === channelId)
})
} else {
- activeServerIndex = searchableArray.findIndex((e) => {
+ activeServer = searchableArray.find((e) => {
return e.id === channelId
})
}
- this.activeServer = this.servers[activeServerIndex]
+ this.activeServer = activeServer
+ },
+ setActiveChannel(channel: IChannel) {
+ this.activeChannel = channel;
+ },
+ updateServer(channelId: string, server: IServer) {
+ const serverIndex = this.servers.findIndex(s => s.channels.some((c) => c.id === channelId))
+ this.servers[serverIndex] = server
+ },
+ setServers(servers: Array) {
+ this.servers = servers
+ },
+ addChannel(serverId: string, channel: IChannel) {
+ const serverIndex = this.servers.findIndex(s => s.id === serverId)
+ const server = this.servers[serverIndex]
+ if (serverIndex < 0 || !server) return;
+ if (server.channels.find((c) => c.id === channel.id)) return;
+ server.channels.push(channel)
+ },
+ addDM(dmChannel: IChannel) {
+ if (this.dms.find((e) => e.id === dmChannel.id)) {
+ const index = this.dms.findIndex((e) => e.id === dmChannel.id)
+ this.dms[index] = dmChannel
+ return;
+ }
+ this.dms.push(dmChannel)
+ },
+ addServer(server: IServer) {
+ if (this.servers.find((e) => e.id === server.id)) {
+ const index = this.servers.findIndex((e) => e.id === server.id)
+ this.servers[index] = server
+ return;
+ }
+ this.servers.push(server)
+ },
+ setDms(dms: Array) {
+ this.dms = dms
+ },
+ setSocket(socket: Socket) {
+ this.socket = socket
+ },
+ setUser(user: SafeUser) {
+ this.user = user;
+ },
+ updateMessage(messageId: string, message: IMessage) {
+ const messageIndex = this.activeChannel.messages.findIndex((e) => e.id === messageId)
+ if (messageIndex < 0) return;
+ this.activeChannel.messages[messageIndex] = message
},
logout() {
this.dms = []
this.servers = []
this.socket = null
- this.activeServer = {} as IServer | IChannel
+ this.activeServer = {} as IChannel
}
},
})
diff --git a/tsconfig.json b/tsconfig.json
index 1211d5a..91700dc 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,3 +1,26 @@
{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": [
+ "ESNext",
+ "ESNext.AsyncIterable",
+ "DOM"
+ ],
+ "sourceMap": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "incremental": true,
+ "jsx": "preserve",
+ "noUncheckedIndexedAccess": true,
+ "noImplicitAny": true,
+ "allowJs": true
+ },
"extends": "./.nuxt/tsconfig.json"
}
\ No newline at end of file
diff --git a/types/index.ts b/types/index.ts
index 613d817..9c8eddf 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -6,6 +6,7 @@ export interface IUser {
servers?: Array;
channels?: Array;
roles?: Array;
+ createdAt: Date;
}
export type SafeUser = Omit, 'email'>
@@ -23,7 +24,7 @@ export interface IChannel {
id: string;
name: string;
server: IServer;
- messages?: Array
+ messages: Array
DM: boolean;
dmParticipants?: Array;
serverId: string;
@@ -37,6 +38,9 @@ export interface IMessage {
userId: string;
channelId: string;
invites?: IInviteCode[];
+ reactions?: IReaction[];
+ createdAt: Date;
+ updatedAt: Date;
}
export interface IInviteCode {
@@ -58,4 +62,17 @@ export interface IRole {
users: IUser[];
server?: IServer;
serverId?: string;
+}
+
+export interface IReaction {
+ id: string;
+ emoji: {
+ name: string;
+ id?: string;
+ };
+ count: number;
+ previousCount?: number;
+ users: IUser[];
+ Message: IMessage;
+ messageId: string;
}
\ No newline at end of file