Browse Source

some more linting

master
nicolas-arnaud 2 years ago
parent
commit
60fcdcc48d
  1. 88
      back/volume/src/chat/chat.gateway.ts
  2. 8
      back/volume/src/users/users.controller.ts
  3. 181
      back/volume/src/users/users.service.ts
  4. 16
      front/Dockerfile
  5. 14
      front/volume/src/App.svelte
  6. 4
      front/volume/src/Auth.ts
  7. 6
      front/volume/src/components/Leaderboard.svelte
  8. 4
      front/volume/src/components/MatchHistory.svelte

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

@ -1,100 +1,100 @@
import { UnauthorizedException, UseGuards } from "@nestjs/common"; import { UnauthorizedException, UseGuards } from '@nestjs/common'
import { import {
type OnGatewayConnection, type OnGatewayConnection,
type OnGatewayDisconnect, type OnGatewayDisconnect,
MessageBody, MessageBody,
SubscribeMessage, SubscribeMessage,
WebSocketGateway, WebSocketGateway,
WebSocketServer, WebSocketServer
} from "@nestjs/websockets"; } from '@nestjs/websockets'
import { Socket, Server } from "socket.io"; import { Socket, Server } from 'socket.io'
import { ChatService } from "./chat.service"; import { ChatService } from './chat.service'
import { type User } from "src/users/entity/user.entity"; import { type User } from 'src/users/entity/user.entity'
import { UsersService } from "src/users/users.service"; import { UsersService } from 'src/users/users.service'
import { Channel } from "./entity/channel.entity"; import { Channel } from './entity/channel.entity'
import { Message } from "./entity/message.entity"; import { Message } from './entity/message.entity'
import { CreateChannelDto } from "./dto/createChannel.dto"; import { CreateChannelDto } from './dto/createChannel.dto'
@WebSocketGateway({ @WebSocketGateway({
cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ }, cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ }
}) })
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer() @WebSocketServer()
server: Server; server: Server
constructor( constructor (
private readonly userService: UsersService, private readonly userService: UsersService,
private readonly chatService: ChatService private readonly chatService: ChatService
) {} ) {}
async handleConnection(socket: Socket) { async handleConnection (socket: Socket) {
try { try {
const user: User | null = await this.userService.findUser( const user: User | null = await this.userService.findUser(
socket.data.user.ftId socket.data.user.ftId
); )
if (user == null) { if (user == null) {
socket.emit("Error", new UnauthorizedException()); socket.emit('Error', new UnauthorizedException())
// socket.disconnect(); // socket.disconnect();
return; return
} else { } else {
socket.data.user = user; socket.data.user = user
const channels = await this.chatService.getChannelsForUser(user.id); const channels = await this.chatService.getChannelsForUser(user.id)
// Only emit rooms to the specific connected client // Only emit rooms to the specific connected client
return this.server.to(socket.id).emit("channel", channels); return this.server.to(socket.id).emit('channel', channels)
} }
} catch { } catch {
socket.emit("Error", new UnauthorizedException()); socket.emit('Error', new UnauthorizedException())
// socket.disconnect(); // socket.disconnect();
} }
} }
handleDisconnect(socket: Socket) { handleDisconnect (socket: Socket) {
// socket.disconnect() // socket.disconnect()
} }
@SubscribeMessage("createChannel") @SubscribeMessage('createChannel')
async onCreateChannel( async onCreateChannel (
socket: Socket, socket: Socket,
@MessageBody() channeldto: CreateChannelDto @MessageBody() channeldto: CreateChannelDto
): Promise<Channel | null> { ): Promise<Channel | null> {
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 == null) return null; if (owner == null) return null
channel.owners.push(owner); channel.owners.push(owner)
channel.password = channeldto.password; channel.password = channeldto.password
/// .../// /// ...///
return await this.chatService.createChannel(channel, socket.data.user); return await this.chatService.createChannel(channel, socket.data.user)
} }
@SubscribeMessage("joinChannel") @SubscribeMessage('joinChannel')
async onJoinChannel(socket: Socket, channel: Channel) { async onJoinChannel (socket: Socket, channel: Channel) {
// add user to channel // add user to channel
const messages = await this.chatService.findMessagesInChannelForUser( const messages = await this.chatService.findMessagesInChannelForUser(
channel, channel,
socket.data.user socket.data.user
); )
this.server.to(socket.id).emit("messages", messages); this.server.to(socket.id).emit('messages', messages)
} }
@SubscribeMessage("leaveChannel") @SubscribeMessage('leaveChannel')
async onLeaveChannel(socket: Socket) { async onLeaveChannel (socket: Socket) {
await this.chatService.deleteBySocketId(socket.id); await this.chatService.deleteBySocketId(socket.id)
} }
@SubscribeMessage("addMessage") @SubscribeMessage('addMessage')
async onAddMessage(socket: Socket, message: Message) { async onAddMessage (socket: Socket, message: Message) {
const createdMessage: Message = await this.chatService.createMessage({ const createdMessage: Message = await this.chatService.createMessage({
...message, ...message,
author: socket.data.user, author: socket.data.user
}); })
const channel = await this.chatService.getChannel( const channel = await this.chatService.getChannel(
createdMessage.channel.id createdMessage.channel.id
); )
if (channel != null) { 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
} }

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

@ -137,12 +137,12 @@ export class UsersController {
@FtUser() profile: Profile, @FtUser() profile: Profile,
@Param('username') username: string @Param('username') username: string
): Promise<NotFoundException | null | undefined> { ): Promise<NotFoundException | null | undefined> {
const target = (await this.usersService.findUserByName(username))!; const target = (await this.usersService.findUserByName(username))!
if (!target) if (!target) throw new BadRequestException('Target unknown.')
throw new BadRequestException("Target unknown.") if (profile.id === target.ftId) {
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, target.id) return await this.usersService.invit(profile.id, target.id)
} }

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

@ -2,168 +2,169 @@ import {
BadRequestException, BadRequestException,
Catch, Catch,
Injectable, Injectable,
NotFoundException, NotFoundException
} from "@nestjs/common"; } from '@nestjs/common'
import { InjectRepository } from "@nestjs/typeorm"; import { InjectRepository } from '@nestjs/typeorm'
import { EntityNotFoundError, QueryFailedError, Repository } from "typeorm"; import { EntityNotFoundError, QueryFailedError, Repository } from 'typeorm'
import { User } from "./entity/user.entity"; import { User } from './entity/user.entity'
import { type UserDto } from "./dto/user.dto"; import { type UserDto } from './dto/user.dto'
import { type Channel } from "src/chat/entity/channel.entity"; import { type Channel } from 'src/chat/entity/channel.entity'
import type Result from "src/pong/entity/result.entity"; import type Result from 'src/pong/entity/result.entity'
import { Cron } from "@nestjs/schedule"; 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 getLeaderboard(): 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.getLeaderboard(); 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: 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.friends.findIndex((friend) => friend.ftId === targetFtId) !== -1) if (user.friends.findIndex((friend) => friend.ftId === targetFtId) !== -1) {
return new BadRequestException("You are already friends."); return new BadRequestException('You are already friends.')
}
const target = (await this.usersRepository.findOne({ const target = (await this.usersRepository.findOne({
where: { ftId: targetFtId }, where: { ftId: targetFtId },
relations: { relations: {
followers: true, followers: true,
friends: true, friends: true
}, }
}))!; }))!
const id = user.followers.findIndex( const id = user.followers.findIndex(
(follower) => follower.ftId === targetFtId (follower) => follower.ftId === targetFtId
); )
if (id !== -1) { if (id !== -1) {
user.friends.push(target); user.friends.push(target)
if (user.ftId !== target.ftId) target.friends.push(user); if (user.ftId !== target.ftId) target.friends.push(user)
user.followers.slice(id, 1); user.followers.slice(id, 1)
await this.usersRepository.save(user); await this.usersRepository.save(user)
} else target.followers.push(user); } else target.followers.push(user)
await this.usersRepository.save(target); await this.usersRepository.save(target)
} }
} }

16
front/Dockerfile

@ -4,4 +4,18 @@ RUN apk update && apk upgrade && apk add npm
WORKDIR /var/www/html WORKDIR /var/www/html
COPY entrypoint.sh /tmp/entrypoint.sh COPY entrypoint.sh /tmp/entrypoint.sh
ENTRYPOINT ["sh", "/tmp/entrypoint.sh"]
COPY ../.env .env
ENTRYPOINT npm install; \
if [[ $NODE_ENV == "production" ]]; then \
npm run build && npm run preview; \
elif [[ $NODE_ENV == "development" ]]; then \
npm run dev; \
elif [[ $NODE_ENV == "debug" ]]; then \
npm run dev; \
elif [[ $NODE_ENV == "check" ]]; then \
npm run format && npm run check; echo "=== FINISH ===" \
else echo "Nothing to do for that NODE_ENV context."; \
fi;

14
front/volume/src/App.svelte

@ -17,7 +17,7 @@
import type { SpectateType } from "./components/Spectate.svelte"; import type { SpectateType } from "./components/Spectate.svelte";
import type { ChannelsType } from "./components/Channels.svelte"; import type { ChannelsType } from "./components/Channels.svelte";
import { store, getUser, login, logout, API_URL } from "./Auth"; import { store, getUser, login, API_URL } from "./Auth";
import FakeLogin from "./FakeLogin.svelte"; import FakeLogin from "./FakeLogin.svelte";
// PROFILE // PROFILE
@ -27,7 +27,6 @@
setInterval(() => { setInterval(() => {
getUser(); getUser();
}, 15000); }, 15000);
let isProfileOpen = false; let isProfileOpen = false;
function clickProfile() { function clickProfile() {
isProfileOpen = true; isProfileOpen = true;
@ -51,17 +50,17 @@
// HISTORY // HISTORY
let matches: Array<Match>; let matches: Array<Match>;
let isHistoryOpen = false; let isHistoryOpen = false;
function clickHistory() { async function clickHistory() {
isHistoryOpen = true; isHistoryOpen = true;
getHistory(); matches = await getHistory();
} }
export async function getHistory(): Promise<void> { export async function getHistory(): Promise<Array<Match>> {
let response = await fetch(API_URL + "/history/" + $store.ftId, { let response = await fetch(API_URL + "/history/" + $store.ftId, {
credentials: "include", credentials: "include",
mode: "cors", mode: "cors",
}); });
matches = await response.json(); return await response.json();
} }
// FRIENDS // FRIENDS
@ -130,7 +129,8 @@
selectedChannel = channel; selectedChannel = channel;
}; };
let leaderboard: Player[] = []; let leaderboard: Array<Player> = [];
export async function getLeader(): Promise<Player[]> { export async function getLeader(): Promise<Player[]> {
let response = await fetch(API_URL + "/leaderboard", { let response = await fetch(API_URL + "/leaderboard", {
credentials: "include", credentials: "include",

4
front/volume/src/Auth.ts

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

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

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type Player from './Profile.svelte' import type { Player } from "./Profile.svelte";
export let leaderboard: Array<Player> = [];
export let leaderboard: Array<Player>;
</script> </script>
<div class="overlay"> <div class="overlay">

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

@ -1,7 +1,7 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
import type user from "./Profile.svelte"; import type Player from "./Profile.svelte";
export interface Match { export interface Match {
players: Array<user>; players: Array<Player>;
score: Array<number>; score: Array<number>;
date: Date; date: Date;
} }

Loading…
Cancel
Save