Browse Source

some routes change

master
nicolas-arnaud 2 years ago
parent
commit
6d0799ae4d
  1. 32
      back/volume/src/users/users.controller.ts
  2. 202
      back/volume/src/users/users.service.ts
  3. 23
      front/volume/src/App.svelte
  4. 3
      front/volume/src/Auth.ts
  5. 2
      front/volume/src/components/Channels.svelte
  6. 0
      front/volume/src/components/Chat.svelte
  7. 10
      front/volume/src/components/Friends.svelte
  8. 11
      front/volume/src/components/Leaderboard.svelte
  9. 30
      front/volume/src/components/Profile.svelte
  10. 4
      front/volume/src/components/Spectate.svelte

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

@ -62,13 +62,13 @@ export class UsersController {
return await this.usersService.getInvits(profile.id) return await this.usersService.getInvits(profile.id)
} }
@Get('leader') @Get('leaderboard')
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async getLeader (): Promise<User[]> { async getLeaderboard (): Promise<User[]> {
return await this.usersService.getLeader() return await this.usersService.getLeaderboard()
} }
@Get('leader/:id') @Get('rank/:id')
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async getRank (@Param('id', ParseIntPipe) id: number): Promise<number> { async getRank (@Param('id', ParseIntPipe) id: number): Promise<number> {
return await this.usersService.getRank(id) return await this.usersService.getRank(id)
@ -110,7 +110,7 @@ export class UsersController {
description: 'A new avatar for the user', description: 'A new avatar for the user',
type: AvatarUploadDto type: AvatarUploadDto
}) })
async addAvatar ( async changeAvatar (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@UploadedFile() file: Express.Multer.File @UploadedFile() file: Express.Multer.File
): Promise<void> { ): Promise<void> {
@ -131,16 +131,20 @@ export class UsersController {
return await this.usersService.findUserByName(username) return await this.usersService.findUserByName(username)
} }
@Get('invit/:id') @Get('invit/:username')
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async invitUser ( async invitUser (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@Param('id', ParseIntPipe) id: number @Param('username') username: string
): Promise<NotFoundException | null | undefined> { ): Promise<NotFoundException | null | undefined> {
if (profile.id === id) { const target = (await this.usersService.findUserByName(username))!;
if (!target)
throw new BadRequestException("Target unknown.")
if (profile.id === target.ftId)
throw new BadRequestException("You can't invit yourself.") throw new BadRequestException("You can't invit yourself.")
}
return await this.usersService.invit(profile.id, id) return await this.usersService.invit(profile.id, target.id)
} }
@Get('avatar/:id') @Get('avatar/:id')
@ -185,15 +189,11 @@ export class UsersController {
@Post() @Post()
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async create ( async updateUser (
@Body() payload: UserDto, @Body() payload: UserDto,
@FtUser() profile: Profile @FtUser() profile: Profile
): Promise<User | null> { ): Promise<User | null> {
const user = await this.usersService.findUser(profile.id) const user = (await this.usersService.findUser(profile.id))!
if (user != null) {
return await this.usersService.update(user, payload) return await this.usersService.update(user, payload)
} else {
return await this.usersService.create(payload)
}
} }
} }

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

@ -1,179 +1,169 @@
import { Catch, Injectable, NotFoundException } from '@nestjs/common' import {
import { InjectRepository } from '@nestjs/typeorm' BadRequestException,
import { EntityNotFoundError, QueryFailedError, Repository } from 'typeorm' Catch,
import { User } from './entity/user.entity' Injectable,
import { type UserDto } from './dto/user.dto' NotFoundException,
import { type Channel } from 'src/chat/entity/channel.entity' } from "@nestjs/common";
import type Result from 'src/pong/entity/result.entity' import { InjectRepository } from "@nestjs/typeorm";
import { Cron } from '@nestjs/schedule' import { EntityNotFoundError, QueryFailedError, Repository } from "typeorm";
import { User } from "./entity/user.entity";
import { type UserDto } from "./dto/user.dto";
import { type Channel } from "src/chat/entity/channel.entity";
import type Result from "src/pong/entity/result.entity";
import { Cron } from "@nestjs/schedule";
@Injectable() @Injectable()
@Catch(QueryFailedError, EntityNotFoundError) @Catch(QueryFailedError, EntityNotFoundError)
export class UsersService { export class UsersService {
constructor ( constructor(
@InjectRepository(User) private readonly usersRepository: Repository<User> @InjectRepository(User) private readonly usersRepository: Repository<User>
) {} ) {}
save (user: User) { save(user: User) {
this.usersRepository.save(user) this.usersRepository.save(user);
} }
async findUsers (): Promise<User[]> { async findUsers(): Promise<User[]> {
return await this.usersRepository.find({}) return await this.usersRepository.find({});
} }
async findUserByName (username: string): Promise<User | null> { async findUserByName(username: string): Promise<User | null> {
const user = await this.usersRepository.findOne({ const user = await this.usersRepository.findOne({
where: { username }, where: { username },
relations: { results: true } relations: { results: true },
}) });
return user return user;
} }
@Cron('0 * * * * *') @Cron("0 * * * * *")
async updateStatus () { async updateStatus() {
const users = await this.usersRepository.find({}) const users = await this.usersRepository.find({});
users.forEach((usr) => { users.forEach((usr) => {
if (Date.now() - usr.lastAccess > 60000) { if (Date.now() - usr.lastAccess > 60000) {
usr.status = 'offline' usr.status = "offline";
this.usersRepository.save(usr) this.usersRepository.save(usr);
} }
}) });
} }
async findUser (ftId: number): Promise<User | null> { async findUser(ftId: number): Promise<User | null> {
const user = await this.usersRepository.findOneBy({ ftId }) const user = await this.usersRepository.findOneBy({ ftId });
if (user == null) return null if (user == null) return null;
user.lastAccess = Date.now() user.lastAccess = Date.now();
user.status = 'online' user.status = "online";
this.usersRepository.save(user) this.usersRepository.save(user);
return user return user;
} }
async findOnlineUsers (): Promise<User[]> { async findOnlineUsers(): Promise<User[]> {
return await this.usersRepository.find({ where: { status: 'online' } }) return await this.usersRepository.find({ where: { status: "online" } });
} }
async create (userData: UserDto) { async create(userData: UserDto) {
try { try {
const newUser = this.usersRepository.create(userData) const newUser = this.usersRepository.create(userData);
return await this.usersRepository.save(newUser) return await this.usersRepository.save(newUser);
} catch (err) { } catch (err) {
throw new Error(`Error creating user ${err}`) throw new Error(`Error creating user ${err}`);
} }
} }
async findOnlineInChannel (channel: Channel): Promise<User[]> { async findOnlineInChannel(channel: Channel): Promise<User[]> {
return await this.usersRepository return await this.usersRepository
.createQueryBuilder('user') .createQueryBuilder("user")
.where('user.channel = :chan', { chan: channel }) .where("user.channel = :chan", { chan: channel })
.andWhere('user.status := status)', { status: 'online' }) .andWhere("user.status := status)", { status: "online" })
.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( return await this.usersRepository.update(
{ ftId }, { 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 != null) return user.friends if (user != null) return user.friends;
return [] return [];
} }
async getInvits (ftId: number): Promise<User[]> { async getInvits(ftId: number): Promise<User[]> {
const user = await this.usersRepository.findOne({ const user = await this.usersRepository.findOne({
where: { ftId }, where: { ftId },
relations: { relations: {
followers: true followers: true,
} },
}) });
if (user != null) return user.followers if (user != null) return user.followers;
return [] return [];
} }
async getResults (ftId: number): Promise<Result[]> { async getResults(ftId: number): Promise<Result[]> {
const user = await this.usersRepository.findOne({ const user = await this.usersRepository.findOne({
where: { ftId }, where: { ftId },
relations: { relations: {
results: { results: {
players: true players: true,
} },
} },
}) });
if (user != null) return user.results if (user != null) return user.results;
return [] return [];
} }
async getLeader (): Promise<User[]> { async getLeaderboard(): Promise<User[]> {
return await this.usersRepository.find({ return await this.usersRepository.find({
order: { order: {
winrate: 'DESC' winrate: "DESC",
} },
}) });
} }
async getRank (ftId: number): Promise<number> { async getRank(ftId: number): Promise<number> {
const leader = await this.getLeader() const leader = await this.getLeaderboard();
return leader.findIndex((user) => user.ftId === ftId) return leader.findIndex((user) => user.ftId === ftId);
} }
async invit (ftId: number, targetFtId: number): Promise<any> { async invit(ftId: number, targetFtId: number): Promise<any> {
const user = await this.usersRepository.findOne({ const user: User = (await this.usersRepository.findOne({
where: { ftId }, where: { ftId },
relations: { relations: {
followers: true, followers: true,
friends: true friends: true,
} },
}) }))!;
if (user == null) { if (user.friends.findIndex((friend) => friend.ftId === targetFtId) !== -1)
return new NotFoundException(`Error: user id ${ftId} isn't in our db.`) return new BadRequestException("You are already friends.");
} const target = (await this.usersRepository.findOne({
if (user.friends.findIndex((friend) => friend.ftId === targetFtId) !== -1) {
return null
}
const target = await this.usersRepository.findOne({
where: { ftId: targetFtId }, where: { ftId: targetFtId },
relations: { relations: {
followers: true, followers: true,
friends: true friends: true,
} },
}) }))!;
if (target == null) {
return new NotFoundException(
`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) {
console.log( user.friends.push(target);
`Friend relation complete between ${user.username} and ${target.username}` if (user.ftId !== target.ftId) target.friends.push(user);
) user.followers.slice(id, 1);
user.friends.push(target) await this.usersRepository.save(user);
if (user.ftId !== target.ftId) target.friends.push(user) } else target.followers.push(user);
user.followers.slice(id, 1) await this.usersRepository.save(target);
await this.usersRepository.save(user)
} else {
console.log(`You asked ${target.username} to be your friend.`)
target.followers.push(user)
}
await this.usersRepository.save(target)
} }
} }

23
front/volume/src/App.svelte

@ -1,19 +1,22 @@
<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";
import type { Match } from "./components/MatchHistory.svelte";
import Friends, { addFriend } from "./components/Friends.svelte"; import Friends, { addFriend } from "./components/Friends.svelte";
import type { Friend } from "./components/Friends.svelte";
import Spectate from "./components/Spectate.svelte"; import Spectate from "./components/Spectate.svelte";
import type { SpectateType } from "./components/Spectate.svelte"; import Chat from "./components/Chat.svelte";
import Pong from "./components/Pong/Pong.svelte";
import Chat2 from "./components/Chat2.svelte";
import Channels from "./components/Channels.svelte"; import Channels from "./components/Channels.svelte";
import type { ChannelsType } from "./components/Channels.svelte";
import Leaderboard from "./components/Leaderboard.svelte"; import Leaderboard from "./components/Leaderboard.svelte";
import type { Player } from "./components/Leaderboard.svelte";
import Pong from "./components/Pong/Pong.svelte";
import type { Player } from "./components/Profile.svelte";
import type { Match } from "./components/MatchHistory.svelte";
import type { Friend } from "./components/Friends.svelte";
import type { SpectateType } from "./components/Spectate.svelte";
import type { ChannelsType } from "./components/Channels.svelte";
import { store, getUser, login, logout, API_URL } from "./Auth"; import { store, getUser, login, logout, API_URL } from "./Auth";
import FakeLogin from "./FakeLogin.svelte"; import FakeLogin from "./FakeLogin.svelte";
@ -30,7 +33,7 @@
isProfileOpen = true; isProfileOpen = true;
} }
let userProfile; let userProfile: Player;
let isIdProfileOpen = false; let isIdProfileOpen = false;
async function openIdProfile(event: CustomEvent<string>) { async function openIdProfile(event: CustomEvent<string>) {
console.log("Opening profile: " + event.detail); console.log("Opening profile: " + event.detail);
@ -129,7 +132,7 @@
let leaderboard: Player[] = []; let leaderboard: Player[] = [];
export async function getLeader(): Promise<Player[]> { export async function getLeader(): Promise<Player[]> {
let response = await fetch(API_URL + "/leader", { let response = await fetch(API_URL + "/leaderboard", {
credentials: "include", credentials: "include",
mode: "cors", mode: "cors",
}); });
@ -181,7 +184,7 @@
on:click={() => (selectedChannel = undefined)} on:click={() => (selectedChannel = undefined)}
on:keydown={() => (selectedChannel = undefined)} on:keydown={() => (selectedChannel = undefined)}
> >
<Chat2 <Chat
chatMessages={selectedChannel.messages} chatMessages={selectedChannel.messages}
on:view-profile={openIdProfile} on:view-profile={openIdProfile}
on:add-friend={addFriend} on:add-friend={addFriend}

3
front/volume/src/Auth.ts

@ -7,8 +7,7 @@ store.subscribe((value) => {
else localStorage.removeItem("user"); else localStorage.removeItem("user");
}); });
export const API_URL = export const API_URL = `http://${import.meta.env.VITE_HOST}:${import.meta.env.VITE_BACK_PORT}`
"http://" + import.meta.env.VITE_HOST + ":" + 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, {

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

@ -1,5 +1,5 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
import type { chatMessagesType } from "./Chat2.svelte"; import type { chatMessagesType } from "./Chat.svelte";
export interface ChannelsType { export interface ChannelsType {
id: string; id: string;
name: string; name: string;

0
front/volume/src/components/Chat2.svelte → front/volume/src/components/Chat.svelte

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

@ -12,20 +12,14 @@
? event.target.querySelector('input[type="text"]').value ? event.target.querySelector('input[type="text"]').value
: event.detail; : event.detail;
let response = await fetch(API_URL + "/user/" + username, { const response = await fetch(API_URL + "/invit/" + username, {
credentials: "include",
mode: "cors",
});
let target = await response.json();
response = await fetch(API_URL + "/invit/" + target.ftId, {
credentials: "include", credentials: "include",
mode: "cors", mode: "cors",
}); });
if (response.ok) { if (response.ok) {
alert("Invitation send."); alert("Invitation send.");
} else { } else {
alert("Invitation refused."); alert("Invitation failed.");
} }
} }
</script> </script>

11
front/volume/src/components/Leaderboard.svelte

@ -1,15 +1,6 @@
<script lang="ts" context="module">
export interface Player {
username: string;
wins: number;
looses: number;
matchs: number;
winrate: number;
rank: number;
}
</script>
<script lang="ts"> <script lang="ts">
import type Player from './Profile.svelte'
export let leaderboard: Array<Player> = []; export let leaderboard: Array<Player> = [];
</script> </script>

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

@ -1,15 +1,20 @@
<script lang="ts" context="module">
export interface Player {
username: string;
wins: number;
looses: number;
matchs: number;
winrate: number;
rank: number;
is2faEnabled: boolean;
}
</script>
<script lang="ts"> <script lang="ts">
import { API_URL, store, logout } from "../Auth"; import { API_URL, store, logout } from "../Auth";
export let edit = 0; export let edit: number;
export let user = { export let user: any;
username: "",
wins: 0,
looses: 0,
winrate: 0,
rank: -1,
is2faEnabled: false,
};
async function handleSubmit() { async function handleSubmit() {
let response = await fetch(API_URL, { let response = await fetch(API_URL, {
@ -45,7 +50,7 @@
<img src={API_URL + "/avatar"} alt="avatar" class="profile-img" /> <img src={API_URL + "/avatar"} alt="avatar" class="profile-img" />
{:else} {:else}
<form <form
action={API_URL + "/avatar"} action={`${API_URL}/avatar/${user.id}`}
method="post" method="post"
enctype="multipart/form-data" enctype="multipart/form-data"
id="upload_avatar" id="upload_avatar"
@ -136,15 +141,12 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.profile-body > p { .profile-body > p {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.profile-body > img {
display: flex;
justify-content: center;
}
.username { .username {
text-align: center; text-align: center;
} }

4
front/volume/src/components/Spectate.svelte

@ -8,7 +8,9 @@
<script lang="ts"> <script lang="ts">
export let spectate: Array<SpectateType> = []; export let spectate: Array<SpectateType> = [];
export let watch = (id: string) => {}; export let watch = (id: string) => {
console.log(id);
};
</script> </script>
<div class="overlay"> <div class="overlay">

Loading…
Cancel
Save