Browse Source

connected friends part to back

master
nicolas-arnaud 2 years ago
parent
commit
7c4bd5e879
  1. 2
      back/volume/src/auth/42.strategy.ts
  2. 11
      back/volume/src/chat/chat.gateway.ts
  3. 2
      back/volume/src/main.ts
  4. 20
      back/volume/src/users/users.controller.ts
  5. 20
      back/volume/src/users/users.service.ts
  6. 152
      front/volume/package-lock.json
  7. 1
      front/volume/package.json
  8. 51
      front/volume/src/App.svelte
  9. 29
      front/volume/src/Auth.ts
  10. 10
      front/volume/src/components/Channels.svelte
  11. 10
      front/volume/src/components/Chat2.svelte
  12. 44
      front/volume/src/components/Friends.svelte
  13. 8
      front/volume/src/components/NavBar.svelte
  14. 49
      front/volume/src/components/Profile.svelte

2
back/volume/src/auth/42.strategy.ts

@ -36,7 +36,7 @@ export class FtStrategy extends PassportStrategy(Strategy, '42') {
if ((await this.usersService.findUser(ftId)) === null) { if ((await this.usersService.findUser(ftId)) === null) {
const newUser = new User() const newUser = new User()
newUser.ftId = profile.id as number newUser.ftId = profile.id as number
newUser.username = profile.displayName as string newUser.username = profile.username as string
newUser.avatar = ftId + '.jpg' newUser.avatar = ftId + '.jpg'
this.usersService.create(newUser) this.usersService.create(newUser)
const file = createWriteStream('avatars/' + ftId + '.jpg') const file = createWriteStream('avatars/' + ftId + '.jpg')

11
back/volume/src/chat/chat.gateway.ts

@ -37,8 +37,10 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
async handleConnection (socket: Socket) { async handleConnection (socket: Socket) {
try { try {
const user: User | null = await this.userService.findUser(socket.data.user.ftId) const user: User | null = await this.userService.findUser(
if (!user) { socket.data.user.ftId
)
if (user == null) {
socket.emit('Error', new UnauthorizedException()) socket.emit('Error', new UnauthorizedException())
// socket.disconnect(); // socket.disconnect();
return return
@ -66,8 +68,7 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
const channel = new Channel() const channel = new Channel()
channel.name = channeldto.name channel.name = channeldto.name
const owner = await this.userService.findUser(channeldto.owner) const owner = await this.userService.findUser(channeldto.owner)
if (!owner) if (owner == null) return null
return null;
channel.owners.push(owner) channel.owners.push(owner)
channel.password = channeldto.password channel.password = channeldto.password
/// .../// /// ...///
@ -98,7 +99,7 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
const channel = await this.chatService.getChannel( const channel = await this.chatService.getChannel(
createdMessage.channel.id createdMessage.channel.id
) )
if (channel) { if (channel != null) {
const users = await this.userService.findOnlineInChannel(channel) const users = await this.userService.findOnlineInChannel(channel)
} }
/// TODO: Send message to users /// TODO: Send message to users

2
back/volume/src/main.ts

@ -7,7 +7,7 @@ import * as session from 'express-session'
import * as passport from 'passport' import * as passport from 'passport'
import { type NestExpressApplication } from '@nestjs/platform-express' import { type NestExpressApplication } from '@nestjs/platform-express'
import * as cookieParser from 'cookie-parser' import * as cookieParser from 'cookie-parser'
import { Response } from 'express'; import { Response } from 'express'
async function bootstrap () { async function bootstrap () {
const logger = new Logger() const logger = new Logger()

20
back/volume/src/users/users.controller.ts

@ -88,18 +88,16 @@ export class UsersController {
async getAvatar ( async getAvatar (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@Res({ passthrough: true }) response: Response @Res({ passthrough: true }) response: Response
){ ) {
return await this.getAvatarById(profile.id, response); return await this.getAvatarById(profile.id, response)
} }
@Get('user/:name') @Get('user/:name')
async getUserByName( async getUserByName (@Param('name') username: string): Promise<User | null> {
@Param('name') username: string return await this.usersService.findUserByName(username)
): Promise<User | null> {
return await this.usersService.findUserByName(username);
} }
@Post('invit/:id') @Get('invit/:id')
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async invitUser ( async invitUser (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@ -114,7 +112,7 @@ export class UsersController {
@Res({ passthrough: true }) response: Response @Res({ passthrough: true }) response: Response
) { ) {
const user = await this.usersService.findUser(ftId) const user = await this.usersService.findUser(ftId)
if (!user) return if (user == null) return
const filename = user.avatar const filename = user.avatar
const stream = createReadStream(join(process.cwd(), 'avatars/' + filename)) const stream = createReadStream(join(process.cwd(), 'avatars/' + filename))
response.set({ response.set({
@ -125,7 +123,9 @@ export class UsersController {
} }
@Get(':id') @Get(':id')
async getUserById (@Param('id', ParseIntPipe) ftId: number): Promise<User | null> { async getUserById (
@Param('id', ParseIntPipe) ftId: number
): Promise<User | null> {
return await this.usersService.findUser(ftId) return await this.usersService.findUser(ftId)
} }
@ -139,7 +139,7 @@ export class UsersController {
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async create (@Body() payload: UserDto, @FtUser() profile: Profile) { async create (@Body() payload: UserDto, @FtUser() profile: Profile) {
const user = await this.usersService.findUser(profile.id) const user = await this.usersService.findUser(profile.id)
if (user) { if (user != null) {
return await this.usersService.update(user, payload) return await this.usersService.update(user, payload)
} else { } else {
return await this.usersService.create(payload) return await this.usersService.create(payload)

20
back/volume/src/users/users.service.ts

@ -44,25 +44,28 @@ export class UsersService {
.getMany() .getMany()
} }
async update (user: User, changes: UserDto):Promise < User | null> { async update (user: User, changes: UserDto): Promise<User | null> {
this.usersRepository.merge(user, changes) this.usersRepository.merge(user, changes)
return await this.usersRepository.save(user) return await this.usersRepository.save(user)
} }
async addAvatar (ftId: number, filename: string) { async addAvatar (ftId: number, filename: string) {
return await this.usersRepository.update({ftId}, { return await this.usersRepository.update(
{ ftId },
{
avatar: filename avatar: filename
}) }
)
} }
async getFriends (ftId: number): Promise< User[] >{ async getFriends (ftId: number): Promise<User[]> {
const user = await this.usersRepository.findOne({ const user = await this.usersRepository.findOne({
where: { ftId }, where: { ftId },
relations: { relations: {
friends: true friends: true
} }
}) })
if (!user) return [] if (user == null) return []
return user.friends return user.friends
} }
@ -73,19 +76,20 @@ export class UsersService {
followers: true followers: true
} }
}) })
if (!user) return null if (user == null) return null
return user.followers return user.followers
} }
async invit (ftId: number, targetFtId: number) { async invit (ftId: number, targetFtId: number) {
const user = await this.findUser(ftId) const user = await this.findUser(ftId)
if (!user) return null if (user == null) return null
const target = await this.findUser(targetFtId) const target = await this.findUser(targetFtId)
if (target == null) { if (target == null) {
return new NotFoundException( return new NotFoundException(
`Error: user id ${targetFtId} isn't in our db.` `Error: user id ${targetFtId} isn't in our db.`
) )
} const id = user.followers.findIndex( }
const id = user.followers.findIndex(
(follower) => follower.ftId === targetFtId (follower) => follower.ftId === targetFtId
) )
if (id != -1) { if (id != -1) {

152
front/volume/package-lock.json

@ -10,7 +10,6 @@
"dependencies": { "dependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.2", "@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0", "@tsconfig/svelte": "^3.0.0",
"axios": "^1.3.4",
"svelte": "^3.55.1", "svelte": "^3.55.1",
"vite": "^4.1.0" "vite": "^4.1.0"
}, },
@ -470,21 +469,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -567,17 +551,6 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -608,14 +581,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/detect-indent": { "node_modules/detect-indent": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
@ -704,38 +669,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -935,25 +868,6 @@
"node": ">=8.6" "node": ">=8.6"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/min-indent": { "node_modules/min-indent": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -1130,11 +1044,6 @@
"svelte": "^3.2.0" "svelte": "^3.2.0"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -1773,21 +1682,6 @@
"picomatch": "^2.0.4" "picomatch": "^2.0.4"
} }
}, },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"balanced-match": { "balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1847,14 +1741,6 @@
"readdirp": "~3.6.0" "readdirp": "~3.6.0"
} }
}, },
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -1874,11 +1760,6 @@
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
"integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==" "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og=="
}, },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"detect-indent": { "detect-indent": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
@ -1951,21 +1832,6 @@
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
} }
}, },
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2113,19 +1979,6 @@
"picomatch": "^2.3.1" "picomatch": "^2.3.1"
} }
}, },
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"min-indent": { "min-indent": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -2241,11 +2094,6 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"queue-microtask": { "queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

1
front/volume/package.json

@ -20,7 +20,6 @@
"dependencies": { "dependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.2", "@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0", "@tsconfig/svelte": "^3.0.0",
"axios": "^1.3.4",
"svelte": "^3.55.1", "svelte": "^3.55.1",
"vite": "^4.1.0" "vite": "^4.1.0"
} }

51
front/volume/src/App.svelte

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte' import { onMount } from "svelte";
import Navbar from "./components/NavBar.svelte"; import Navbar from "./components/NavBar.svelte";
import Profile from "./components/Profile.svelte"; import Profile from "./components/Profile.svelte";
import MatchHistory from "./components/MatchHistory.svelte"; import MatchHistory from "./components/MatchHistory.svelte";
@ -15,14 +15,13 @@
import Channels from "./components/Channels.svelte"; import Channels from "./components/Channels.svelte";
import type { ChannelsType } from "./components/Channels.svelte"; import type { ChannelsType } from "./components/Channels.svelte";
import { store, getUser, login, logout } from "./Auth"; import { store, getUser, login, logout, API_URL } from "./Auth";
// PROFILE // PROFILE
onMount(() => { onMount(() => {
getUser() getUser();
}) });
let isProfileOpen = false; let isProfileOpen = false;
function clickProfile() { function clickProfile() {
@ -46,18 +45,26 @@
// FRIENDS // FRIENDS
let friends: Friend[] = [];
let invits: Friend[] = [];
export async function getFriends(): Promise<Friend[]> {
let response = await fetch(API_URL + "/friends", {
credentials: "include",
});
return await response.json();
}
export async function getInvits(): Promise<Friend[]> {
let response = await fetch(API_URL + "/invits", { credentials: "include" });
return await response.json();
}
let isFriendOpen = false; let isFriendOpen = false;
function clickFriends() { async function clickFriends() {
isFriendOpen = true; isFriendOpen = true;
friends = await getFriends();
invits = await getInvits();
} }
let friends: Array<Friend> = [
{ username: "Alice", status: "online" },
{ username: "Bob", status: "online" },
{ username: "Charlie", status: "offline" },
{ username: "Dave", status: "offline" },
{ username: "Eve", status: "in a game" },
{ username: "Frank", status: "online" },
];
// SPECTATE // SPECTATE
let isSpectateOpen = false; let isSpectateOpen = false;
@ -79,9 +86,15 @@
isChannelsOpen = true; isChannelsOpen = true;
} }
let channels: Array<ChannelsType> = [ let channels: Array<ChannelsType> = [
{ id: "1", name: "General", messages: [] }, { id: "1", name: "General", messages: [], privacy: "public", password: "" },
{ id: "2", name: "Lobby", messages: [] }, {
{ id: "3", name: "Game", messages: [] }, id: "2",
name: "Lobby",
messages: [],
privacy: "private",
password: "test",
},
{ id: "3", name: "Game", messages: [], privacy: "private", password: "" },
]; ];
let selectedChannel: ChannelsType; let selectedChannel: ChannelsType;
const handleSelectChannel = (channel: ChannelsType) => { const handleSelectChannel = (channel: ChannelsType) => {
@ -133,7 +146,7 @@
on:click={() => (isFriendOpen = false)} on:click={() => (isFriendOpen = false)}
on:keydown={() => (isFriendOpen = false)} on:keydown={() => (isFriendOpen = false)}
> >
<Friends {friends} /> <Friends {friends} {invits} />
</div> </div>
{/if} {/if}
{#if isHistoryOpen} {#if isHistoryOpen}
@ -150,7 +163,7 @@
on:keydown={() => (isProfileOpen = false)} on:keydown={() => (isProfileOpen = false)}
> >
<Profile <Profile
username="Alice" username={$store.username}
wins={10} wins={10}
losses={5} losses={5}
elo={256} elo={256}

29
front/volume/src/Auth.ts

@ -1,37 +1,36 @@
import { writable } from 'svelte/store'; import { writable } from "svelte/store";
let _user = localStorage.getItem('user'); let _user = localStorage.getItem("user");
export const store = writable(_user ? JSON.parse(_user) : null); export const store = writable(_user ? JSON.parse(_user) : null);
store.subscribe((value) => { store.subscribe((value) => {
if (value) localStorage.setItem('user', JSON.stringify(value)); if (value) localStorage.setItem("user", JSON.stringify(value));
else localStorage.removeItem('user'); else localStorage.removeItem("user");
}); });
export const API_URL = export const API_URL =
"http://" + import.meta.env.VITE_HOST + "http://" + import.meta.env.VITE_HOST + ":" + import.meta.env.VITE_BACK_PORT;
":" + import.meta.env.VITE_BACK_PORT;
export async function getUser() { export async function getUser() {
const res = await fetch(API_URL, { const res = await fetch(API_URL, {
method: "get", method: "get",
mode: 'cors', mode: "cors",
cache: "no-cache", cache: "no-cache",
credentials: 'include', credentials: "include",
redirect: "follow", redirect: "follow",
referrerPolicy: "no-referrer", referrerPolicy: "no-referrer",
}) });
let user = await res.json() let user = await res.json();
if (user.username) { if (user.username) {
console.log(user) console.log(user);
store.set(user) store.set(user);
} }
} }
export function login() { export function login() {
window.location.replace(API_URL + "/log/in") window.location.replace(API_URL + "/log/in");
} }
export function logout() { export function logout() {
window.location.replace(API_URL + "/log/out") window.location.replace(API_URL + "/log/out");
store.set(null) store.set(null);
} }

10
front/volume/src/components/Channels.svelte

@ -13,15 +13,17 @@
export let channels: Array<ChannelsType> = []; export let channels: Array<ChannelsType> = [];
export let onSelectChannel: (channel: ChannelsType) => void; export let onSelectChannel: (channel: ChannelsType) => void;
const selectChat = (id: string) => { const selectChat = (id: string) => {
const channel = channels.find(c => c.id === id); const channel = channels.find((c) => c.id === id);
if (channel) { if (channel) {
onSelectChannel(channel); onSelectChannel(channel);
} }
} };
const createChannel = () => { const createChannel = () => {
const name = prompt("Enter a name for the new channel:"); const name = prompt("Enter a name for the new channel:");
if (name) { if (name) {
const privacy = prompt("Enter a privacy setting for the new channel (public/private):"); const privacy = prompt(
"Enter a privacy setting for the new channel (public/private):"
);
if (privacy !== "public" && privacy !== "private") { if (privacy !== "public" && privacy !== "private") {
alert("Invalid privacy setting"); alert("Invalid privacy setting");
} }
@ -38,7 +40,7 @@
name, name,
privacy, privacy,
password, password,
messages: [] messages: [],
}; };
channels = [newChannel, ...channels]; channels = [newChannel, ...channels];
} }

10
front/volume/src/components/Chat2.svelte

@ -6,7 +6,6 @@
} }
</script> </script>
<script lang="ts"> <script lang="ts">
const sendMessage = () => { const sendMessage = () => {
if (newText !== "") { if (newText !== "") {
@ -41,7 +40,7 @@
<li>View comments</li> <li>View comments</li>
</ul> </ul>
`; `;
document.querySelector('.overlay')?.appendChild(optionsModal); document.querySelector(".overlay")?.appendChild(optionsModal);
optionsModal.addEventListener("click", () => { optionsModal.addEventListener("click", () => {
document.body.removeChild(optionsModal); document.body.removeChild(optionsModal);
}); });
@ -54,7 +53,12 @@
<div class="messages"> <div class="messages">
{#each chatMessages as message} {#each chatMessages as message}
<p class="message"> <p class="message">
<span class="message-name" on:click={openProfile(message.id)} on:keydown={openProfile(message.id)} style="cursor: pointer;"> <span
class="message-name"
on:click={openProfile(message.id)}
on:keydown={openProfile(message.id)}
style="cursor: pointer;"
>
{message.name} {message.name}
</span>: {message.text} </span>: {message.text}
</p> </p>

44
front/volume/src/components/Friends.svelte

@ -2,13 +2,16 @@
export interface Friend { export interface Friend {
username: string; username: string;
status: "online" | "offline" | "in a game"; status: "online" | "offline" | "in a game";
ftId: number;
} }
</script> </script>
<script lang="ts"> <script lang="ts">
let api = "http://" + import.meta.env.VITE_HOST + ":" + import.meta.env.VITE_BACK_PORT import { API_URL } from "../Auth";
export let friends: Array<Friend>
fetch(api + "/friends").then((response) => response.json()).then((ret) => {friends = ret}); export let friends: Friend[];
export let invits: Friend[];
async function addFriend(event: any) { async function addFriend(event: any) {
console.log(typeof event); console.log(typeof event);
@ -17,24 +20,23 @@
console.log(usernameInput); console.log(usernameInput);
const username = usernameInput.value; const username = usernameInput.value;
let ftId: number
fetch(api + "/user/" + username).then((response) => response.json()).then((ret) => {ftId = ret.ftID});
fetch(api + "/friends").then((response) => response.json()).then((ret) => {friends = JSON.parse(ret)}); let response = await fetch(API_URL + "/user/" + username, {
const response = await fetch(api + "/invit/" + ftId, { credentials: "include",
method: 'POST', mode: "cors",
headers: { });
'Content-Type': 'application/json' let target = await response.json();
},
body: JSON.stringify({ username }) response = await fetch(API_URL + "/invit/" + target.ftId, {
credentials: "include",
}); });
if (response.ok) { if (response.ok) {
console.log('Invitation send.'); console.log("Invitation send.");
} else { } else {
console.log('Unknown user.'); console.log("Unknown user.");
} }
usernameInput.value = ''; usernameInput.value = "";
alert("Trying to add friend" + username); alert("Trying to add friend: " + username);
} }
</script> </script>
@ -51,6 +53,16 @@
{:else} {:else}
<p>No friends to display</p> <p>No friends to display</p>
{/if} {/if}
{#if invits.length > 0}
<h2>Monkey invits</h2>
{#each invits.slice(0, 10) as invit}
<li>
<span>{invit.username} invited you to be friend.</span>
</li>
{/each}
{:else}
<p>No invitations to display</p>
{/if}
<div> <div>
<h3>Add a friend</h3> <h3>Add a friend</h3>
<form on:submit={addFriend}> <form on:submit={addFriend}>

8
front/volume/src/components/NavBar.svelte

@ -1,5 +1,9 @@
<script lang="ts"> <script lang="ts">
let api = "http://" + import.meta.env.VITE_HOST + ":" + import.meta.env.VITE_BACK_PORT; let api =
"http://" +
import.meta.env.VITE_HOST +
":" +
import.meta.env.VITE_BACK_PORT;
export let links = [ export let links = [
{ text: "Home", url: "img/pong.png" }, { text: "Home", url: "img/pong.png" },
{ text: "Spectate" }, { text: "Spectate" },
@ -42,7 +46,7 @@
{#if link.text === "Profile"} {#if link.text === "Profile"}
<li> <li>
<button on:click={clickProfile}> <button on:click={clickProfile}>
<img src={api + '/avatar'} alt="avatar" /> <img src={api + "/avatar"} alt="avatar" />
</button> </button>
</li> </li>
{/if} {/if}

49
front/volume/src/components/Profile.svelte

@ -1,38 +1,27 @@
<script lang="ts" context="module">
export interface User {
username: string;
}
</script>
<script lang="ts"> <script lang="ts">
import { API_URL, store } from "../Auth";
export const API_URL = "http://" + import.meta.env.VITE_HOST + ":" + import.meta.env.VITE_BACK_PORT export let username = $store.userame;
export const AUTH_SERVER_URL = API_URL + "/log/in"
export let avatar = API_URL + "/avatar"
export let username = "";
export let realname = ""; export let realname = "";
export let wins = 0; export let wins = 0;
export let losses = 0; export let losses = 0;
export let elo = 0; export let elo = 0;
export let rank = -1; export let rank = -1;
export let is2faEnabled = false; export let is2faEnabled = false;
const handleSubmit = () => {
const user: User = { username : username}; async function handleSubmit() {
fetch("http://localhost:3001/", { let response = await fetch(API_URL, {
headers: {"content-type": "application/json"}, headers: { "content-type": "application/json" },
method: "POST", method: "POST",
body: JSON.stringify(user), body: JSON.stringify({ username: username }),
credentials: 'include' credentials: "include",
})
.then((res) => res.json())
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err);
}); });
if (response.ok) {
alert("Succefully changed username.");
$store.username = username;
} }
}
async function handle2fa(event: Event) { async function handle2fa(event: Event) {
event.preventDefault(); event.preventDefault();
alert("Trying to " + (is2faEnabled ? "disable" : "enable") + " 2FA"); alert("Trying to " + (is2faEnabled ? "disable" : "enable") + " 2FA");
@ -42,14 +31,14 @@
<div class="overlay"> <div class="overlay">
<div class="profile" on:click|stopPropagation on:keydown|stopPropagation> <div class="profile" on:click|stopPropagation on:keydown|stopPropagation>
<div class="profile-header"> <div class="profile-header">
<img class="profile-img" src={avatar} alt="avatar" /> <img class="profile-img" src={API_URL + "/avatar"} alt="avatar" />
<h3>{realname}</h3> <h3>{realname}</h3>
<form action={avatar} <form
action={API_URL + "/avatar"}
method="post" method="post"
enctype="multipart/form-data"> enctype="multipart/form-data"
<label for="mavatar-input">Select a file:</label> >
<input type="file" id="avatar-input" name="avatar" /> <input type="file" id="avatar-input" name="avatar" />
<br /><br />
<input type="submit" /> <input type="submit" />
</form> </form>
</div> </div>
@ -58,8 +47,8 @@
<div class="username"> <div class="username">
<label for="username">Username</label> <label for="username">Username</label>
<input type="text" id="username" bind:value={username} /> <input type="text" id="username" bind:value={username} />
</div>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</div>
</form> </form>
<p>Wins: {wins}</p> <p>Wins: {wins}</p>
<p>Losses: {losses}</p> <p>Losses: {losses}</p>

Loading…
Cancel
Save