stream day 2
This commit is contained in:
30
App.vue
Normal file
30
App.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<NuxtLayout>
|
||||
<div class="flex h-screen max-h-screen">
|
||||
<Nav />
|
||||
<Sidebar />
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</NuxtLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useUserStore } from '~/stores/user'
|
||||
|
||||
export default {
|
||||
async setup() {
|
||||
const userStore = useUserStore()
|
||||
const sessionToken = useCookie('sessionToken')
|
||||
console.log(sessionToken.value)
|
||||
if (userStore.user.id === undefined && sessionToken.value) {
|
||||
const user = await $fetch('/api/getCurrentUser')
|
||||
|
||||
if (!user) return;
|
||||
|
||||
userStore.setUser(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
116
components/Nav.vue
Normal file
116
components/Nav.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<nav class="p-4 bg-zinc-800 grid grid-cols-1 grid-rows-[56px_1fr_56px] h-screen text-white relative">
|
||||
<div>
|
||||
<div
|
||||
@click="openServer('@me')"
|
||||
class="bg-zinc-600/80 p-3 rounded-full transition-all hover:rounded-2xl ease-in-out hover:bg-zinc-500/60 duration-300">
|
||||
<svg width="32"
|
||||
height="32"
|
||||
viewBox="0 0 24 24">
|
||||
<path fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 12c2-2.96 0-7-1-8c0 3.038-1.773 4.741-3 6c-1.226 1.26-2 3.24-2 5a6 6 0 1 0 12 0c0-1.532-1.056-3.94-2-5c-1.786 3-2.791 3-4 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-scroll my-2 flex gap-2">
|
||||
<div v-for="server in servers"
|
||||
:key="server.id"
|
||||
@click="openServer(server.id)"
|
||||
class="bg-zinc-600/80 p-3 rounded-full transition-all hover:rounded-2xl ease-in-out hover:bg-zinc-500/60 duration-300 h-[56px] w-[56px]">
|
||||
<svg width="32"
|
||||
height="32"
|
||||
viewBox="0 0 256 154">
|
||||
<defs>
|
||||
<linearGradient id="svgIDa"
|
||||
x1="-2.778%"
|
||||
x2="100%"
|
||||
y1="32%"
|
||||
y2="67.556%">
|
||||
<stop offset="0%"
|
||||
stop-color="#2298BD" />
|
||||
<stop offset="100%"
|
||||
stop-color="#0ED7B5" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#svgIDa)"
|
||||
d="M128 0C93.867 0 72.533 17.067 64 51.2C76.8 34.133 91.733 27.733 108.8 32c9.737 2.434 16.697 9.499 24.401 17.318C145.751 62.057 160.275 76.8 192 76.8c34.133 0 55.467-17.067 64-51.2c-12.8 17.067-27.733 23.467-44.8 19.2c-9.737-2.434-16.697-9.499-24.401-17.318C174.249 14.743 159.725 0 128 0ZM64 76.8C29.867 76.8 8.533 93.867 0 128c12.8-17.067 27.733-23.467 44.8-19.2c9.737 2.434 16.697 9.499 24.401 17.318C81.751 138.857 96.275 153.6 128 153.6c34.133 0 55.467-17.067 64-51.2c-12.8 17.067-27.733 23.467-44.8 19.2c-9.737-2.434-16.697-9.499-24.401-17.318C110.249 91.543 95.725 76.8 64 76.8Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div @click="createServerModelOpen = true"
|
||||
class="bg-zinc-600/80 p-3 rounded-full transition-all hover:rounded-2xl ease-in-out hover:bg-zinc-500/60 duration-300">
|
||||
<svg width="32"
|
||||
height="32"
|
||||
viewBox="0 0 24 24">
|
||||
<path fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 5v14m-7-7h14" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div v-if="createServerModelOpen"
|
||||
class="absolute z-10 top-0 bottom-0 left-0 right-0">
|
||||
<div class="bg-zinc-900/80 w-screen h-screen"
|
||||
@click="createServerModelOpen = false">
|
||||
</div>
|
||||
<div
|
||||
class="p-4 z-20 absolute bg-zinc-800 shadow-md rounded-md -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2 text-white">
|
||||
<h2 class="font-semibold text-xl">
|
||||
Create a server:
|
||||
</h2>
|
||||
<div>
|
||||
<form @submit.prevent="createServer"
|
||||
class="w-3/5">
|
||||
<input v-model="serverName"
|
||||
type="text"
|
||||
class="py-2 px-3 rounded-md mb-2 bg-zinc-700 shadow-md border border-zinc-700/80"
|
||||
placeholder="Server name" />
|
||||
<input type="submit"
|
||||
class="py-2 px-3 rounded-md bg-zinc-700 shadow-md border border-zinc-700/80" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useServerStore } from '~/stores/servers'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
servers: useServerStore().servers,
|
||||
createServerModelOpen: false,
|
||||
serverName: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createServer() {
|
||||
const serverStore = useServerStore();
|
||||
const { server } = await $fetch('/api/channel/create', { method: 'post', body: { serverName: this.serverName } })
|
||||
this.createServerModelOpen = false;
|
||||
this.serverName = '';
|
||||
serverStore.addServer(server)
|
||||
},
|
||||
openServer(id: string): void {
|
||||
const router = useRouter();
|
||||
useServerStore().servers.find((e: unknown, i: number) => {
|
||||
if (e.id === id) {
|
||||
useServerStore().activeServer = i
|
||||
}
|
||||
})
|
||||
router.push({ path: `/channel/${id}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
64
components/Sidebar.vue
Normal file
64
components/Sidebar.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="flex bg-zinc-700 w-60 h-screen shadow-sm text-white select-none">
|
||||
<div class="w-full"
|
||||
v-if="server">
|
||||
<div class="flex p-4 border-b border-zinc-600/80">
|
||||
<h4 class="text-lg font-semibold w-fit ">
|
||||
{{ server.name }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="flex gap-y-1.5 px-1.5 mt-2 flex-col">
|
||||
<div class="flex text-center hover:bg-zinc-600/70 px-2 py-1.5 w-full transition-colors rounded drop-shadow-sm"
|
||||
v-for="channel in server.channels"
|
||||
:key="channel.id">
|
||||
<svg width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24">
|
||||
<path fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16" />
|
||||
</svg> {{ channel.name }}
|
||||
</div>
|
||||
<div class="flex text-center hover:bg-zinc-600/70 px-2 py-1.5 w-full transition-colors rounded drop-shadow-sm"
|
||||
v-for="channel in server.channels"
|
||||
:key="channel.id">
|
||||
<svg width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24">
|
||||
<path fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16" />
|
||||
</svg> {{ channel.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useUserStore } from '~/stores/user'
|
||||
import { useServerStore } from '~/stores/servers'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
user: useUserStore().user,
|
||||
server: useServerStore().servers[useServerStore().activeServer]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const route = useRoute()
|
||||
|
||||
if (route.path.includes('@me')) {
|
||||
this.server = useServerStore().dms[useServerStore().activeServer]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="hover:scale-105 cursor-pointer duration-500 flex flex-col justify-center items-center text-center rounded shadow-xl border-2 border-gray-500 h-full w-full p-6">
|
||||
<h2 class="text-lg text-gray-700">{{name}}</h2>
|
||||
<p class="text-sm text-gray-600">{{description}}</p>
|
||||
<a
|
||||
class="text-sm text-violet-500 underline decoration-dotted underline-offset-2 cursor-pointer mt-3"
|
||||
href={{documentation}}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: ['name', 'description', 'documentation']
|
||||
}
|
||||
</script>
|
||||
@@ -20,4 +20,18 @@ export default {
|
||||
autoprefixer: {},
|
||||
},
|
||||
},
|
||||
|
||||
modules: [
|
||||
[
|
||||
'@pinia/nuxt',
|
||||
{
|
||||
autoImports: [
|
||||
// automatically imports `defineStore`
|
||||
'defineStore', // import { defineStore } from 'pinia'
|
||||
// automatically imports `defineStore` as `definePiniaStore`
|
||||
['defineStore', 'definePiniaStore'], // import { defineStore as definePiniaStore } from 'pinia'
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
90
package-lock.json
generated
90
package-lock.json
generated
@@ -5,9 +5,11 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.4.6",
|
||||
"@prisma/client": "^4.8.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"nuxt": "^3.0.0",
|
||||
"pinia": "^2.0.28",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -831,6 +833,18 @@
|
||||
"vue": "^3.2.45"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinia/nuxt": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.4.6.tgz",
|
||||
"integrity": "sha512-HjrYEfLdFpmsjhicPJgL36jVhzHWukIQPFFHGTSF84Cplu+f2nY2XHKqe9ToHzE9rLee2RjLOwAzOnXa/I/u6A==",
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^3.0.0",
|
||||
"pinia": ">=2.0.27"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/client": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.8.0.tgz",
|
||||
@@ -5065,6 +5079,56 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "2.0.28",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.28.tgz",
|
||||
"integrity": "sha512-YClq9DkqCblq9rlyUual7ezMu/iICWdBtfJrDt4oWU9Zxpijyz7xB2xTwx57DaBQ96UGvvTMORzALr+iO5PVMw==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.4.5",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.4.0",
|
||||
"typescript": ">=4.4.4",
|
||||
"vue": "^2.6.14 || ^3.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pinia/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-types": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz",
|
||||
@@ -8037,6 +8101,15 @@
|
||||
"vue-bundle-renderer": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@pinia/nuxt": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.4.6.tgz",
|
||||
"integrity": "sha512-HjrYEfLdFpmsjhicPJgL36jVhzHWukIQPFFHGTSF84Cplu+f2nY2XHKqe9ToHzE9rLee2RjLOwAzOnXa/I/u6A==",
|
||||
"requires": {
|
||||
"@nuxt/kit": "^3.0.0",
|
||||
"pinia": ">=2.0.27"
|
||||
}
|
||||
},
|
||||
"@prisma/client": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.8.0.tgz",
|
||||
@@ -11029,6 +11102,23 @@
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
|
||||
},
|
||||
"pinia": {
|
||||
"version": "2.0.28",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.28.tgz",
|
||||
"integrity": "sha512-YClq9DkqCblq9rlyUual7ezMu/iICWdBtfJrDt4oWU9Zxpijyz7xB2xTwx57DaBQ96UGvvTMORzALr+iO5PVMw==",
|
||||
"requires": {
|
||||
"@vue/devtools-api": "^6.4.5",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pkg-types": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz",
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
"prepare": "nuxi prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.4.6",
|
||||
"@prisma/client": "^4.8.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"nuxt": "^3.0.0",
|
||||
"pinia": "^2.0.28",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
16
pages/channel/@me/[dmId].vue
Normal file
16
pages/channel/@me/[dmId].vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
hello world
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useServerStore } from '~/stores/servers'
|
||||
|
||||
export default {
|
||||
async setup() {
|
||||
const route = useRoute()
|
||||
|
||||
const { server } = await $fetch(`/api/channel/${route.params.dmId}`)
|
||||
if (!useServerStore().dms.includes(server)) useServerStore().addDM(server);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
26
pages/channel/@me/index.vue
Normal file
26
pages/channel/@me/index.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<form @submit.prevent="startDM">
|
||||
<input v-model="userId" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useServerStore } from '~/stores/servers'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
userId: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async startDM() {
|
||||
const { server } = await $fetch('/api/channel/createDM', { method: 'post', body: { partnerId: this.userId } })
|
||||
|
||||
useServerStore().addDM(server)
|
||||
useRouter().push({ path: '/channel/@me/' + server.id })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -2,6 +2,11 @@
|
||||
hello world
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
$fetch('/api/getChannelById', { params: { test: 123 } })
|
||||
<script setup async>
|
||||
import { useServerStore } from '~/stores/servers'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { server } = await $fetch(`/api/channel/${route.params.id}`)
|
||||
if (!useServerStore().servers.includes(server)) useServerStore().addServer(server);
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
Hello there
|
||||
Hello there traveler
|
||||
<nuxt-link to="/login">Login</nuxt-link>
|
||||
<nuxt-link to="/signup">Signup</nuxt-link>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useUserStore } from '~/stores/user'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -36,6 +38,8 @@ export default {
|
||||
userId.value = user.userId
|
||||
const token = useCookie('sessionToken')
|
||||
token.value = user.token
|
||||
|
||||
useUserStore().setUser(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useUserStore } from '~/stores/user'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -42,6 +44,8 @@ export default {
|
||||
userId.value = user.userId
|
||||
const token = useCookie('sessionToken')
|
||||
token.value = user.token
|
||||
|
||||
useUserStore().setUser(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,27 @@ model User {
|
||||
}
|
||||
|
||||
model Server {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
participants User[]
|
||||
channels Channel[]
|
||||
}
|
||||
|
||||
model Room {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
model Channel {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
Server Server? @relation(fields: [serverId], references: [id])
|
||||
serverId String?
|
||||
Message Message[]
|
||||
}
|
||||
|
||||
model Message {
|
||||
id String @id @default(cuid())
|
||||
body String
|
||||
creator User @relation(fields: [userId], references: [id])
|
||||
userId String
|
||||
id String @id @default(cuid())
|
||||
body String
|
||||
channel Channel @relation(fields: [channelId], references: [id])
|
||||
creator User @relation(fields: [userId], references: [id])
|
||||
userId String
|
||||
channelId String
|
||||
}
|
||||
|
||||
model Session {
|
||||
|
||||
@@ -2,11 +2,11 @@ import { PrismaClient } from '@prisma/client'
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
if (!event.context.authenticated) return {
|
||||
if (!event.context.user.authenticated) return {
|
||||
message: 'You must be logged in to view a channel.'
|
||||
}
|
||||
|
||||
if (!event.context.params.channelId) {
|
||||
if (!event.context.params.id) {
|
||||
event.node.res.statusCode = 400;
|
||||
return {
|
||||
message: 'A channelId is required'
|
||||
@@ -15,10 +15,21 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
const server = await prisma.server.findFirst({
|
||||
where: {
|
||||
id: event.context.params.channelId
|
||||
id: event.context.params.id
|
||||
},
|
||||
include: {
|
||||
participants: true,
|
||||
channels: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!server) {
|
||||
event.node.res.statusCode = 404;
|
||||
return {
|
||||
message: `Channel with id "${event.context.params.id}" not found`
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
server
|
||||
}
|
||||
55
server/api/channel/create.post.ts
Normal file
55
server/api/channel/create.post.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
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 view a channel.'
|
||||
}
|
||||
}
|
||||
|
||||
const { serverName } = await readBody(event)
|
||||
|
||||
if (!serverName) {
|
||||
event.node.res.statusCode = 400;
|
||||
return {
|
||||
message: 'channel name is required to create a channel.'
|
||||
}
|
||||
}
|
||||
|
||||
const preExistingServer = await prisma.server.findFirst({
|
||||
where: {
|
||||
name: serverName
|
||||
}
|
||||
})
|
||||
|
||||
if (preExistingServer) {
|
||||
event.node.res.statusCode = 409;
|
||||
return {
|
||||
message: `Server with name ${serverName} already exists.`
|
||||
}
|
||||
}
|
||||
|
||||
const server = await prisma.server.create({
|
||||
data: {
|
||||
name: serverName,
|
||||
participants: { connect: [{ id: event.context.user.id }] },
|
||||
channels: {
|
||||
create: [
|
||||
{
|
||||
name: 'general',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
include: {
|
||||
channels: true,
|
||||
participants: true
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
server
|
||||
}
|
||||
})
|
||||
67
server/api/channel/createDM.post.ts
Normal file
67
server/api/channel/createDM.post.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
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 view a channel.'
|
||||
}
|
||||
}
|
||||
|
||||
const { partnerId } = await readBody(event)
|
||||
|
||||
if (!partnerId) {
|
||||
event.node.res.statusCode = 400;
|
||||
return {
|
||||
message: 'A friend is required to create a DM.'
|
||||
}
|
||||
}
|
||||
|
||||
const partner = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: partnerId
|
||||
}
|
||||
})
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: event.context.user.id
|
||||
}
|
||||
})
|
||||
|
||||
const preExistingServer = await prisma.server.findFirst({
|
||||
where: {
|
||||
name: `${user.username} and ${partner.username}`
|
||||
}
|
||||
})
|
||||
|
||||
if (preExistingServer) {
|
||||
event.node.res.statusCode = 409;
|
||||
return {
|
||||
message: `DM already exists.`
|
||||
}
|
||||
}
|
||||
|
||||
const server = await prisma.server.create({
|
||||
data: {
|
||||
name: `${user.username} and ${partner.username}`,
|
||||
participants: { connect: [{ id: event.context.user.id }, { id: partner.id }] },
|
||||
channels: {
|
||||
create: [
|
||||
{
|
||||
name: 'default',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
include: {
|
||||
channels: true,
|
||||
participants: true
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
server
|
||||
}
|
||||
})
|
||||
21
server/api/getCurrentUser.get.ts
Normal file
21
server/api/getCurrentUser.get.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
if (event.context.user === undefined || event.context.user.id === undefined) {
|
||||
// event.node.res.statusCode = 401;
|
||||
return {
|
||||
message: "Unauthenticated"
|
||||
}
|
||||
}
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: event.context.user.id
|
||||
}
|
||||
})
|
||||
|
||||
user.passwordhash = undefined;
|
||||
|
||||
return user
|
||||
})
|
||||
@@ -13,6 +13,26 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
}
|
||||
|
||||
const preExistingUser = await prisma.user.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
username: body.username
|
||||
},
|
||||
{
|
||||
email: body.email
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
if (preExistingUser) {
|
||||
event.node.res.statusCode = 409;
|
||||
return {
|
||||
message: `User with username ${body.username} or email ${body.email} already exists`
|
||||
}
|
||||
}
|
||||
|
||||
const passwordhash = await bcryptjs.hash(body.password, 10)
|
||||
|
||||
const user = await prisma.user.create({
|
||||
|
||||
@@ -4,7 +4,12 @@ const prisma = new PrismaClient()
|
||||
export default defineEventHandler(async (event) => {
|
||||
const cookies = parseCookies(event)
|
||||
|
||||
if (!cookies.sessionToken) return;
|
||||
console.log(cookies.sessionToken)
|
||||
|
||||
if (!cookies.sessionToken) {
|
||||
event.context.user = { authenticated: false }
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await prisma.session.findFirst({
|
||||
where: {
|
||||
@@ -12,7 +17,10 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
})
|
||||
|
||||
if (!session) return;
|
||||
if (!session) {
|
||||
event.context.user = { authenticated: false }
|
||||
return;
|
||||
}
|
||||
|
||||
event.context.authenticated = true;
|
||||
event.context.user = { authenticated: true, id: session.userId };
|
||||
})
|
||||
15
stores/servers.ts
Normal file
15
stores/servers.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export const useServerStore = defineStore('server', {
|
||||
state: () => ({
|
||||
servers: [],
|
||||
dms: [],
|
||||
activeServer: undefined
|
||||
}),
|
||||
actions: {
|
||||
addServer(server) {
|
||||
this.servers.push(server)
|
||||
},
|
||||
addDM(server) {
|
||||
this.dms.push(server)
|
||||
}
|
||||
},
|
||||
})
|
||||
10
stores/user.ts
Normal file
10
stores/user.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const useUserStore = defineStore('user', {
|
||||
state: () => ({
|
||||
user: {}
|
||||
}),
|
||||
actions: {
|
||||
setUser(user) {
|
||||
this.user = user;
|
||||
}
|
||||
},
|
||||
})
|
||||
4
types/index.ts
Normal file
4
types/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface IUser {
|
||||
id: string;
|
||||
username: string;
|
||||
}
|
||||
Reference in New Issue
Block a user