merged luke's branch into mine, he fixed all the fetches to catch stuff, need to test
This commit is contained in:
3
package-lock.json
generated
3
package-lock.json
generated
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -52,8 +52,22 @@ export class ChatController {
|
||||
|
||||
let fields = ["name", "type", "users", "protection", "allowed_users"];
|
||||
const rooms = await this.chatService.getMyRooms(req.user.username, fields);
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
|
||||
const ret_rooms = rooms.map(room =>
|
||||
let filtered_rooms = rooms.filter(room =>
|
||||
{
|
||||
if (room.type === 'direct')
|
||||
{
|
||||
let roomname = room.users[0];
|
||||
if (roomname === req.user.username)
|
||||
roomname = room.users[1];
|
||||
if (blocked.includes(roomname))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const ret_rooms = filtered_rooms.map(room =>
|
||||
{
|
||||
let new_room = this.format_room(room);
|
||||
if (room.protection)
|
||||
@@ -78,8 +92,19 @@ export class ChatController {
|
||||
printCaller("- in ");
|
||||
|
||||
const rooms: roomDto[] = await this.chatService.getAllOtherRoomsAndUsers(req.user.username)
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
|
||||
const ret_rooms = rooms.map(room => this.format_room(room));
|
||||
let filtered_rooms = rooms.filter(room =>
|
||||
{
|
||||
if (room.type === 'user')
|
||||
{
|
||||
if (blocked.includes(room.name))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const ret_rooms = filtered_rooms.map(room => this.format_room(room));
|
||||
res.status(HttpStatus.OK).json({ rooms: ret_rooms });
|
||||
printCaller("- out ");
|
||||
}
|
||||
@@ -200,6 +225,19 @@ export class ChatController {
|
||||
let response = "";
|
||||
if (room.type === 'user')
|
||||
{
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
if (blocked.includes(room.name))
|
||||
{
|
||||
console.log("throw error: error: true, code: 'BLOCKED_USER', message: 'you cannot enter this room, you blocked this user'");
|
||||
throw new HttpException({ error: true, code: 'BLOCKED_USER', message: `you cannot enter this room, you blocked this user` }, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
const find_room = await this.chatService.getRoomByName(`${req.user.username} + ${room.name}`);
|
||||
if (find_room)
|
||||
{
|
||||
console.log("throw error: error: true, code: 'ROOM_CONFLICT', message: 'This room name already exist'");
|
||||
throw new HttpException({ error: true, code: 'ROOM_CONFLICT', message: `This room name already exist` }, HttpStatus.CONFLICT);
|
||||
}
|
||||
room.type = 'direct';
|
||||
room.users = [room.name, req.user.username];
|
||||
room.name += ` + ${req.user.username}`;
|
||||
@@ -243,7 +281,7 @@ export class ChatController {
|
||||
{
|
||||
printCaller("- in ");
|
||||
|
||||
let fields = ["protection", "allowed_users"];
|
||||
let fields = ["protection", "allowed_users", "type", "users"];
|
||||
const room_db = await this.chatService.getRoomByName(room.name, fields);
|
||||
|
||||
if (room_db.protection === true)
|
||||
@@ -255,6 +293,19 @@ export class ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
if (room_db.type === 'direct')
|
||||
{
|
||||
let roomname = room_db.users[0];
|
||||
if (roomname === req.user.username)
|
||||
roomname = room.users[1];
|
||||
if (blocked.includes(roomname))
|
||||
{
|
||||
console.log("throw error: error: true, code: 'BLOCKED_USER', message: 'you cannot enter this room, you blocked this user'");
|
||||
throw new HttpException({ error: true, code: 'BLOCKED_USER', message: `you cannot enter this room, you blocked this user` }, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
await this.chatService.setCurrentRoom(req.user.username, room.name);
|
||||
let socket: socketDto = this.chatGateway.sockets.get(req.user.username);
|
||||
await this.chatService.socketChangeRoom(socket, room.name);
|
||||
@@ -361,6 +412,14 @@ export class ChatController {
|
||||
{
|
||||
printCaller("- in ");
|
||||
|
||||
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
if (blocked.includes(username))
|
||||
{
|
||||
console.log("throw error: error: true, code: 'BLOCKED_USER', message: 'you cannot invite this user, you have blocked it'");
|
||||
throw new HttpException({ error: true, code: 'BLOCKED_USER', message: `you cannot invite this user, you have blocked it` }, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
let current_room_name = await this.chatService.getCurrentRoomName(req.user.username);
|
||||
let room = await this.chatService.addUserToRoom(username, current_room_name);
|
||||
let message = `${username} joined the room`;
|
||||
@@ -403,7 +462,17 @@ export class ChatController {
|
||||
printCaller("- in ");
|
||||
|
||||
const messages = await this.chatService.getMessagesFromCurrentRoom(req.user.username);
|
||||
res.status(HttpStatus.OK).json({ messages: messages });
|
||||
|
||||
console.log("messages:", messages);
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
let filtered_messages = messages.filter(message =>
|
||||
{
|
||||
if (blocked.includes(message.name))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json({ messages: filtered_messages });
|
||||
printCaller("- out ");
|
||||
}
|
||||
|
||||
@@ -456,7 +525,15 @@ export class ChatController {
|
||||
const room_name = await this.chatService.getCurrentRoomName(req.user.username);
|
||||
const users = await this.chatService.getAllUsersNotInRoom(room_name);
|
||||
|
||||
res.status(HttpStatus.OK).json({ users: users });
|
||||
const blocked = await this.chatService.getListBlockUser(req.user.username);
|
||||
let filtered_users = users.filter(user =>
|
||||
{
|
||||
if (blocked.includes(user.username))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json({ users: filtered_users });
|
||||
printCaller("- out ");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ implements OnGatewayConnection, OnGatewayDisconnect
|
||||
socket.username = socket.handshake.query.username.toString();
|
||||
this.sockets.set(socket.username, socket);
|
||||
|
||||
printCaller("socket.username:", socket.username);
|
||||
printCaller("--- socket.username:", socket.username);
|
||||
|
||||
let not_emit: string = `${socket.username}_not_emit`;
|
||||
socket.join(not_emit);
|
||||
|
||||
@@ -306,26 +306,22 @@ export class ChatService {
|
||||
|
||||
async findOneRelationshipByUsername(friendUsername : string, username : string)
|
||||
{
|
||||
printCaller("-- in ");
|
||||
|
||||
const friendship = await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.leftJoinAndSelect('friendship.sender', 'sender')
|
||||
.leftJoinAndSelect('friendship.receiver', 'receiver')
|
||||
.where
|
||||
(
|
||||
new Brackets((qb) =>
|
||||
{
|
||||
qb.where
|
||||
(
|
||||
new Brackets((subAQb) =>
|
||||
{
|
||||
.where (
|
||||
new Brackets((qb) => {
|
||||
qb.where (
|
||||
new Brackets((subAQb) => {
|
||||
subAQb.where('sender.username = :username', {username : username})
|
||||
.andWhere('receiver.username = :friendUsername', {friendUsername : friendUsername})
|
||||
})
|
||||
)
|
||||
.orWhere
|
||||
(
|
||||
new Brackets((subBQb) =>
|
||||
{
|
||||
.orWhere (
|
||||
new Brackets((subBQb) => {
|
||||
subBQb.where('sender.username = :friendUsername2', {friendUsername2 : friendUsername})
|
||||
.andWhere('receiver.username = :username2', {username2 : username})
|
||||
.andWhere('friendship.status != :status', {status : FriendshipStatus.BLOCKED})
|
||||
@@ -333,11 +329,14 @@ export class ChatService {
|
||||
)
|
||||
}),
|
||||
)
|
||||
.getOne()
|
||||
.getOne();
|
||||
|
||||
console.log("friendship:", friendship);
|
||||
if (!friendship)
|
||||
return null;
|
||||
return new SendableFriendship(friendship);
|
||||
|
||||
printCaller("-- out ");
|
||||
}
|
||||
|
||||
async addBlockUser(username: string, to_block_username: string): Promise<void>
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
<script lang="ts">
|
||||
import Canvas from "../pieces/Canvas.svelte";
|
||||
import { push } from "svelte-spa-router";
|
||||
import { onMount } from 'svelte';
|
||||
import { push } from "svelte-spa-router";
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let user;
|
||||
import { fetchUser } from "../pieces/utils";
|
||||
|
||||
let user;
|
||||
|
||||
onMount(async () => {
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
.then((resp) => resp.json())
|
||||
|
||||
if (user && user.statusCode && user.statusCode === 403) {
|
||||
console.log('on mount no user, returned status code 403 so logging out of userStore')
|
||||
}
|
||||
|
||||
user = await fetchUser();
|
||||
});
|
||||
|
||||
const login = async() => {
|
||||
window.location.href = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth`;
|
||||
console.log('you are now logged in');
|
||||
}
|
||||
const login = async() => {
|
||||
window.location.href = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth`;
|
||||
console.log('you are now logged in');
|
||||
}
|
||||
|
||||
const logout = async() => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/logout`, {
|
||||
method: 'POST',
|
||||
});
|
||||
user = undefined;
|
||||
const logout = async() => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/logout`,
|
||||
{
|
||||
method: 'POST'
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch logout: ", error);
|
||||
});
|
||||
|
||||
user = null;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,44 +1,59 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { push } from "svelte-spa-router";
|
||||
import { onMount } from "svelte";
|
||||
import { push } from "svelte-spa-router";
|
||||
|
||||
let qrCodeImg;
|
||||
let qrCode = "";
|
||||
let wrongCode = "";
|
||||
|
||||
const fetchQrCodeImg = (async () => {
|
||||
qrCodeImg = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/2fa/generate`,
|
||||
{
|
||||
method: "POST",
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then((blob) => {
|
||||
return URL.createObjectURL(blob);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchQrCodeImg: ", error);
|
||||
});
|
||||
|
||||
let qrCodeImg;
|
||||
let qrCode = "";
|
||||
let wrongCode = "";
|
||||
const fetchQrCodeImg = (async() => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/2fa/generate`,
|
||||
{
|
||||
method: 'POST',
|
||||
})
|
||||
.then(response => {return response.blob()})
|
||||
.then(blob => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
qrCodeImg = url;
|
||||
});
|
||||
})()
|
||||
})();
|
||||
|
||||
const submitCode = async() => {
|
||||
const response = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/2fa/check`,
|
||||
{
|
||||
method : 'POST',
|
||||
headers : {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body : JSON.stringify({
|
||||
"twoFaCode" : qrCode,
|
||||
}),
|
||||
});
|
||||
if (response.status === 401) {
|
||||
qrCode = "";
|
||||
wrongCode = `Wrong code`;
|
||||
}
|
||||
if (response.status === 200) {
|
||||
push('/profile');
|
||||
console.log('valid Code for 2FA')
|
||||
}
|
||||
};
|
||||
const submitCode = async () => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/2fa/check`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
twoFaCode: qrCode,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
qrCode = "";
|
||||
wrongCode = `Wrong code`;
|
||||
}
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
push("/profile");
|
||||
console.log("valid Code for 2FA");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch submitCode: ", error);
|
||||
});
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
let user;
|
||||
let allUsers;
|
||||
|
||||
let playerOneAvatar;
|
||||
let playerTwoAvatar;
|
||||
let playerOneAvatar = "";
|
||||
let playerTwoAvatar = "";
|
||||
|
||||
//Game's stuff
|
||||
const options = new pong.InitOptions();
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
import MatchListElem from "../../pieces/MatchListElem.svelte";
|
||||
import type { Match } from "../../pieces/Match";
|
||||
import { fetchUser, fetchAllUsers, fetchAvatar } from "../../pieces/utils";
|
||||
import { fetchAvatar } from "../../pieces/utils";
|
||||
|
||||
import * as pongSpectator from "./client/pongSpectator";
|
||||
import { gameState } from "./client/ws";
|
||||
|
||||
let playerOneAvatar;
|
||||
let playerTwoAvatar;
|
||||
let playerOneAvatar = "";
|
||||
let playerTwoAvatar = "";
|
||||
|
||||
//Game's stuff
|
||||
const gameAreaId = "game_area";
|
||||
@@ -190,6 +190,7 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#canvas_container {
|
||||
margin-top: 20px;
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { fetchUser } from "../../pieces/utils";
|
||||
|
||||
let user;
|
||||
let allUsersRanking = [];
|
||||
|
||||
let fetchScoresInterval;
|
||||
|
||||
//user's stuff
|
||||
let currentUser;
|
||||
let allUsers = [];
|
||||
let idInterval;
|
||||
onMount( async() => {
|
||||
currentUser = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
.then( x => x.json() );
|
||||
allUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/ranking`)
|
||||
.then( x => x.json() );
|
||||
idInterval = setInterval(fetchScores, 10000);
|
||||
user = await fetchUser();
|
||||
allUsersRanking = await fetchScores();
|
||||
|
||||
fetchScoresInterval = setInterval(fetchScores, 10000);
|
||||
})
|
||||
|
||||
onDestroy( async() => {
|
||||
clearInterval(idInterval);
|
||||
clearInterval(fetchScoresInterval);
|
||||
})
|
||||
|
||||
function fetchScores() {
|
||||
fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/ranking`)
|
||||
.then( x => x.json() )
|
||||
.then( x => allUsers = x );
|
||||
async function fetchScores()
|
||||
{
|
||||
return fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/ranking`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchScores: ", error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -41,18 +50,18 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each allUsers as user, i}
|
||||
{#each allUsersRanking as userRanking, i}
|
||||
<tr>
|
||||
<th>{i + 1}</th>
|
||||
{#if user.username === currentUser.username}
|
||||
<td><b>{user.username} [You]</b></td>
|
||||
{#if userRanking.username === user.username}
|
||||
<td><b>{userRanking.username} [You]</b></td>
|
||||
{:else}
|
||||
<td>{user.username}</td>
|
||||
<td>{userRanking.username}</td>
|
||||
{/if}
|
||||
<td>{user.stats.winGame}</td>
|
||||
<td>{user.stats.loseGame}</td>
|
||||
<td>{user.stats.drawGame}</td>
|
||||
<td>{user.stats.totalGame}</td>
|
||||
<td>{userRanking.stats.winGame}</td>
|
||||
<td>{userRanking.stats.loseGame}</td>
|
||||
<td>{userRanking.stats.drawGame}</td>
|
||||
<td>{userRanking.stats.totalGame}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script lang="ts">
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import GenerateUserDisplay from '../../pieces/GenerateUserDisplay.svelte';
|
||||
import { push } from 'svelte-spa-router';
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
let user;
|
||||
import Chat from '../../pieces/chat/Chat.svelte';
|
||||
import { fetchUser } from "../../pieces/utils";
|
||||
|
||||
onMount( async() => {
|
||||
// console.log('mounting profile display')
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
.then( (x) => x.json() );
|
||||
})
|
||||
let user;
|
||||
|
||||
onMount( async() => {
|
||||
user = await fetchUser();
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,38 +1,25 @@
|
||||
<script lang="ts">
|
||||
|
||||
/* ProfileDisplayOneUser is the same as DisplayAUser except sources the username from params from router rather than
|
||||
from a regular var. But yea it's functionally identical, seemed easier to just have a duplicate rather than figuring
|
||||
out how to get a more complicated things to do 2 jobs.*/
|
||||
/* ProfileDisplayOneUser is the same as DisplayAUser except sources the username from params from router rather than
|
||||
from a regular var. But yea it's functionally identical, seemed easier to just have a duplicate rather than figuring
|
||||
out how to get a more complicated things to do 2 jobs.*/
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import GenerateUserDisplay from '../../pieces/GenerateUserDisplay.svelte';
|
||||
import { fetchUser } from "../../pieces/utils";
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import GenerateUserDisplay from '../../pieces/GenerateUserDisplay.svelte';
|
||||
export let params;
|
||||
let oneUser;
|
||||
|
||||
export let params;
|
||||
let user;
|
||||
onMount( async() => {
|
||||
oneUser = await fetchUser(params.username);
|
||||
})
|
||||
|
||||
onMount( async() => {
|
||||
|
||||
// console.log('Display One User username: '+ params.username)
|
||||
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user?username=${params.username}`)
|
||||
.then( (x) => x.json() );
|
||||
console.log('in display ONE user')
|
||||
console.log({...user})
|
||||
})
|
||||
|
||||
export const updateUser = async() => {
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user?username=${params.username}`)
|
||||
.then( (x) => x.json() );
|
||||
};
|
||||
|
||||
$: params.username, updateUser();
|
||||
|
||||
</script>
|
||||
|
||||
<div class="background-pages">
|
||||
{#if user !== undefined}
|
||||
<GenerateUserDisplay user={user}/>
|
||||
{#if oneUser}
|
||||
<GenerateUserDisplay user={oneUser}/>
|
||||
{:else}
|
||||
<h2>Sorry</h2>
|
||||
<div>Failed to load user {params.username}</div>
|
||||
|
||||
@@ -1,81 +1,89 @@
|
||||
<script lang="ts">
|
||||
|
||||
import Card from '../../pieces/Card.svelte';
|
||||
import {onMount} from 'svelte';
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
import Button from '../../pieces/Button.svelte';
|
||||
import { fetchAvatar } from "../../pieces/utils";
|
||||
import Card from '../../pieces/Card.svelte';
|
||||
import {onMount} from 'svelte';
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
import Button from '../../pieces/Button.svelte';
|
||||
import { fetchUser, fetchAvatar } from "../../pieces/utils";
|
||||
|
||||
let user;
|
||||
let avatar, newAvatar;
|
||||
let uploadAvatarSuccess = false;
|
||||
let user;
|
||||
let avatar, newAvatar;
|
||||
let uploadAvatarSuccess = false;
|
||||
|
||||
// tbh i might not need this...
|
||||
let set = { username: '', tfa: false };
|
||||
let nameTmp; // annoying...
|
||||
const errors = { username: '', checkbox: '', avatar: ''};
|
||||
let success = {username: '', avatar: '' };
|
||||
// tbh i might not need this...
|
||||
let set = { username: '', tfa: false };
|
||||
let nameTmp; // annoying...
|
||||
const errors = { username: '', checkbox: '', avatar: ''};
|
||||
let success = {username: '', avatar: '' };
|
||||
|
||||
onMount( async() => {
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
.then( (x) => x.json() );
|
||||
// do a .catch?
|
||||
user = await fetchUser();
|
||||
avatar = await fetchAvatar();
|
||||
|
||||
if (user === undefined) {
|
||||
if (!user) {
|
||||
console.log('User did not load, something more official should prolly happen')
|
||||
}
|
||||
// i don't unerstand why this is necessary but it really doesn't like it otherwise
|
||||
nameTmp = user.username;
|
||||
|
||||
set.tfa = user.isEnabledTwoFactorAuth;
|
||||
|
||||
avatar = await fetchAvatar(user.username);
|
||||
})
|
||||
|
||||
const settingsHandler = async() => {
|
||||
// I don't really care which i use at this point...
|
||||
// if (set.username === nameTmp) {
|
||||
if ((set.username.trim() === '') && set.tfa === user.isEnabledTwoFactorAuth) {
|
||||
errors.username = 'Invalid new username';
|
||||
return;
|
||||
}
|
||||
else if ((set.username.trim() === '') && set.tfa !== user.isEnabledTwoFactorAuth) {
|
||||
set.username = user.username
|
||||
}
|
||||
else {
|
||||
errors.username = '';
|
||||
}
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"username": set.username,
|
||||
"isEnabledTwoFactorAuth": set.tfa
|
||||
})
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200)
|
||||
success.username = "Your changes have been saved"
|
||||
else if (response.status === 201)
|
||||
push("/2fa");
|
||||
else if (response.status === 409)
|
||||
errors.username = `${set.username} is already in use, pick a different one.`;
|
||||
else
|
||||
errors.username = "Something went wrong";
|
||||
const settingsHandler = async() =>
|
||||
{
|
||||
// TODO Luke <--> Eric : Explications
|
||||
// I don't really care which i use at this point...
|
||||
// if (set.username === nameTmp) {
|
||||
if ((set.username.trim() === '') && set.tfa === user.isEnabledTwoFactorAuth) {
|
||||
errors.username = 'Invalid new username';
|
||||
return;
|
||||
}
|
||||
else if ((set.username.trim() === '') && set.tfa !== user.isEnabledTwoFactorAuth) {
|
||||
set.username = user.username
|
||||
}
|
||||
else {
|
||||
errors.username = '';
|
||||
}
|
||||
)
|
||||
.catch((err) => errors.username = err)
|
||||
|
||||
// .then((result) => console.log(result))
|
||||
// .then(() => console.log('successful sub of new settings'))
|
||||
};
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"username": set.username,
|
||||
"isEnabledTwoFactorAuth": set.tfa
|
||||
})
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
errors.username = "Something went wrong";
|
||||
if (response.status === 409) {
|
||||
errors.username = `${set.username} is already in use, pick a different one.`;
|
||||
}
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
else {
|
||||
if (response.status === 200) {
|
||||
success.username = "Your changes have been saved";
|
||||
}
|
||||
else if (response.status === 201) {
|
||||
push("/2fa");
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch settingsHandler: ", error);
|
||||
});
|
||||
}
|
||||
|
||||
const uploadAvatar = async() => {
|
||||
errors.avatar = '';
|
||||
if (newAvatar === undefined) {
|
||||
if (!newAvatar) {
|
||||
errors.avatar = 'You need to pick a file.'
|
||||
return;
|
||||
}
|
||||
@@ -85,19 +93,23 @@
|
||||
// tmp
|
||||
console.log(data);
|
||||
|
||||
const responseWhenChangeAvatar = fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/avatar`,
|
||||
{
|
||||
method : 'POST',
|
||||
body : data,
|
||||
})
|
||||
const responseFromServer = await responseWhenChangeAvatar;
|
||||
if (responseFromServer.ok === true) {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/avatar`,
|
||||
{
|
||||
method : 'POST',
|
||||
body : data,
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
errors.avatar = response.statusText;
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
uploadAvatarSuccess = true;
|
||||
success.avatar = 'Your avatar has been updated';
|
||||
}
|
||||
else {
|
||||
errors.avatar = responseFromServer.statusText;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch uploadAvatar: ", error);
|
||||
});
|
||||
|
||||
avatar = await fetchAvatar(user.username);
|
||||
}
|
||||
@@ -130,7 +142,7 @@
|
||||
|
||||
<Card>
|
||||
<!-- ok so it can't actually show us the file we upload until we've uploaded it... -->
|
||||
{#if avatar !== undefined}
|
||||
{#if avatar}
|
||||
<img class="avatar" src={avatar} alt="your avatar"/>
|
||||
{/if}
|
||||
<form on:submit|preventDefault={uploadAvatar}>
|
||||
@@ -141,7 +153,7 @@
|
||||
<input type="file" bind:files={newAvatar}/>
|
||||
<div class="error">{errors.avatar}</div>
|
||||
</div>
|
||||
<Button type={newAvatar === undefined ? "primary" : "secondary"}>Upload Avatar</Button>
|
||||
<Button type={!newAvatar ? "primary" : "secondary"}>Upload Avatar</Button>
|
||||
</form>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -1,232 +1,297 @@
|
||||
<script lang="ts">
|
||||
|
||||
import { onMount } from "svelte";
|
||||
import Button from "../../pieces/Button.svelte";
|
||||
import DisplayAUser from "../../pieces/DisplayAUser.svelte";
|
||||
import Tabs from "../../pieces/Tabs.svelte";
|
||||
import Button from "../../pieces/Button.svelte";
|
||||
import DisplayAUser from "../../pieces/DisplayAUser.svelte";
|
||||
import Tabs from "../../pieces/Tabs.svelte";
|
||||
import { fetchUser, fetchAllUsers, fetchAvatar } from "../../pieces/utils";
|
||||
|
||||
|
||||
let user;
|
||||
let allUsers;
|
||||
let myFriendships;
|
||||
let requestsMade, requestsRecieved;
|
||||
let blockedUsers;
|
||||
let usernameBeingViewed;
|
||||
let friendshipStatusFull; // date, reveiverUsername, status
|
||||
let allUsers = [];
|
||||
let myFriendships = [];
|
||||
let requestsMade, requestsRecieved;
|
||||
let blockedUsers = [];
|
||||
let usernameBeingViewed;
|
||||
let friendshipStatusFull; // date, reveiverUsername, status
|
||||
|
||||
/**** Layout variables ****/
|
||||
let tabItems: string[] = ['All Users', 'My Friends', 'Friend Requests', 'Blocked Users']
|
||||
let activeTabItem: string = 'All Users';
|
||||
/**** Layout variables ****/
|
||||
let tabItems: string[] = [
|
||||
"All Users",
|
||||
"My Friends",
|
||||
"Friend Requests",
|
||||
"Blocked Users",
|
||||
];
|
||||
let activeTabItem: string = "All Users";
|
||||
let loadedUser;
|
||||
|
||||
onMount(async () => {
|
||||
user = await fetchUser();
|
||||
|
||||
onMount( async() => {
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
.then( (x) => x.json() );
|
||||
fetchAll();
|
||||
});
|
||||
|
||||
fetchAll();
|
||||
});
|
||||
const fetchAll = async () => {
|
||||
// no need to await i think it can load in the background
|
||||
fetchAllUsers_Wrapper();
|
||||
fetchMyFriendships();
|
||||
fetchRequestsMade();
|
||||
fetchRequestsReceived();
|
||||
fetchBlockedUsers();
|
||||
};
|
||||
|
||||
const fetchAll = async() => {
|
||||
// no need to await i think it can load in the background
|
||||
fetchAllUsers();
|
||||
fetchMyFriendships();
|
||||
fetchRequestsMade();
|
||||
fetchRequestsReceived();
|
||||
fetchBlockedUsers();
|
||||
}
|
||||
/***** Fetch basic things *****/
|
||||
const fetchAllUsers_Wrapper = async () => {
|
||||
allUsers = await fetchAllUsers();
|
||||
if (usernameBeingViewed) {
|
||||
let found = allUsers.find(
|
||||
(e) => e.username === usernameBeingViewed
|
||||
);
|
||||
if (!found) {
|
||||
usernameBeingViewed = null;
|
||||
friendshipStatusFull = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/***** Fetch basic things *****/
|
||||
const fetchAllUsers = async() => {
|
||||
allUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/all`)
|
||||
.then( x => x.json() );
|
||||
console.log('got all users ')
|
||||
console.log({...allUsers})
|
||||
if (usernameBeingViewed !== undefined) {
|
||||
let found = allUsers.find(e => e.username === usernameBeingViewed);
|
||||
// console.log("SEARCHING ALL USERS: ")
|
||||
// console.log({...found})
|
||||
if (found === undefined) {
|
||||
// console.log('none found')
|
||||
usernameBeingViewed = undefined;
|
||||
friendshipStatusFull = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
// it's more like fetch friendships
|
||||
// then i need to extract the users
|
||||
const fetchMyFriendships = async () => {
|
||||
myFriendships = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/myfriends`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchMyFriendships: ", error);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
// it's more like fetch friendships
|
||||
// then i need to extract the users
|
||||
const fetchMyFriendships = async() => {
|
||||
myFriendships = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/myfriends`)
|
||||
.then( x => x.json() );
|
||||
const fetchRequestsMade = async () => {
|
||||
requestsMade = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/pending`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchRequestsMade: ", error);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
console.log('got my friends ')
|
||||
console.log({...myFriendships})
|
||||
};
|
||||
const fetchRequestsReceived = async () => {
|
||||
requestsRecieved = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/received`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchRequestsReceived: ", error);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
const fetchRequestsMade = async() => {
|
||||
requestsMade = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/pending`)
|
||||
.then( x => x.json() );
|
||||
|
||||
console.log('got requests made ')
|
||||
console.log({...requestsMade})
|
||||
};
|
||||
|
||||
const fetchRequestsReceived = async() => {
|
||||
requestsRecieved = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/received`)
|
||||
.then( x => x.json() );
|
||||
|
||||
console.log('got requests received ')
|
||||
console.log({...requestsRecieved})
|
||||
};
|
||||
|
||||
const fetchBlockedUsers = async() => {
|
||||
blockedUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/blocked`)
|
||||
.then( x => x.json() );
|
||||
|
||||
console.log('got blocked users, is it empty?')
|
||||
console.log({...blockedUsers})
|
||||
console.log(Object.keys(blockedUsers))
|
||||
};
|
||||
/**** END OF MAIN FETCH ****/
|
||||
const fetchBlockedUsers = async () => {
|
||||
blockedUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/blocked`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchBlockedUsers: ", error);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
/**** END OF MAIN FETCH ****/
|
||||
|
||||
// returns everything but BLOCKED
|
||||
const fetchFriendshipFull = async(aUsername) => {
|
||||
console.log('fetch friendship from a username')
|
||||
console.log(aUsername)
|
||||
const fetchFriendshipFull = async (aUsername) => {
|
||||
friendshipStatusFull = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/myfriends?username=${aUsername}`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchFriendshipFull: ", error);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
friendshipStatusFull = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/myfriends?username=${aUsername}`)
|
||||
.then( x => x.json());
|
||||
const sendFriendRequest = async (aUsername) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
receiverUsername: aUsername,
|
||||
status: "R",
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch sendFriendRequest: ", error);
|
||||
});
|
||||
|
||||
console.log({...friendshipStatusFull})
|
||||
};
|
||||
await fetchFriendshipFull(aUsername);
|
||||
await fetchAll();
|
||||
};
|
||||
|
||||
|
||||
const sendFriendRequest = async(aUsername) => {
|
||||
console.log('sending a friend request')
|
||||
console.log(aUsername)
|
||||
const viewAUser = async (aUsername) => {
|
||||
usernameBeingViewed = aUsername;
|
||||
await fetchFriendshipFull(aUsername);
|
||||
};
|
||||
|
||||
const resp = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations`, {
|
||||
method : "POST",
|
||||
headers: { 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
"receiverUsername": aUsername,
|
||||
"status": "R"
|
||||
})
|
||||
})
|
||||
.then( x => x.json())
|
||||
// .catch( x => console.log({...x}))
|
||||
await fetchFriendshipFull(aUsername);
|
||||
await fetchAll();
|
||||
};
|
||||
const acceptFriendRequest = async (relationshipId) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/accept`,
|
||||
{
|
||||
method: "PATCH",
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch acceptFriendRequest: ", error);
|
||||
});
|
||||
|
||||
const viewAUser = async(aUsername) => {
|
||||
console.log('Profile Friend updating userBeingViewed')
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
usernameBeingViewed = aUsername;
|
||||
await fetchFriendshipFull(aUsername);
|
||||
const declineFriendRequest = async (relationshipId) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/decline`,
|
||||
{
|
||||
method: "PATCH",
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch declineFriendRequest: ", error);
|
||||
});
|
||||
|
||||
console.log('Friendship Status Full')
|
||||
console.log({...friendshipStatusFull})
|
||||
};
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
const acceptFriendRequest = async(relationshipId) => {
|
||||
console.log('accept friend request')
|
||||
const unfriend = async (relationshipId) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch unfriend: ", error);
|
||||
});
|
||||
|
||||
const resp = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/accept`, {
|
||||
method: "PATCH"})
|
||||
.then( x => x.json());
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
if (Object.keys(friendshipStatusFull).length === 0) {
|
||||
friendshipStatusFull = null;
|
||||
}
|
||||
|
||||
const declineFriendRequest = async(relationshipId) => {
|
||||
console.log('decline friend request')
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
const resp = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/decline`, {
|
||||
method: "PATCH"})
|
||||
.then( x => x.json());
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
const blockANonFriendUser = async (aUsername) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
receiverUsername: aUsername,
|
||||
status: "B",
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch blockANonFriendUser: ", error);
|
||||
});
|
||||
|
||||
const unfriend = async(relationshipId) => {
|
||||
console.log('Unfriend')
|
||||
await fetchAll();
|
||||
usernameBeingViewed = null;
|
||||
friendshipStatusFull = null;
|
||||
|
||||
const resp = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}`, {
|
||||
method: "DELETE"})
|
||||
.then( x => x.json());
|
||||
|
||||
await fetchFriendshipFull(usernameBeingViewed);
|
||||
if (Object.keys(friendshipStatusFull).length === 0)
|
||||
friendshipStatusFull = undefined;
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
await fetchAll();
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
const blockAFriend = async (relationshipId) => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/block`,
|
||||
{
|
||||
method: "PATCH"
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch blockAFriend: ", error);
|
||||
});
|
||||
|
||||
const blockANonFriendUser = async(aUsername) => {
|
||||
console.log('Block a non friend user, their username')
|
||||
console.log(aUsername)
|
||||
await fetchAll();
|
||||
usernameBeingViewed = null;
|
||||
friendshipStatusFull = null;
|
||||
|
||||
let sentFriendRequest = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations`, {
|
||||
method : "POST",
|
||||
headers: { 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
"receiverUsername": aUsername,
|
||||
"status": "B"
|
||||
})
|
||||
})
|
||||
.then( x => x.json())
|
||||
// await fetchBlockedUsers();
|
||||
// await fetchAllUsers();
|
||||
await fetchAll();
|
||||
usernameBeingViewed = undefined;
|
||||
friendshipStatusFull = undefined;
|
||||
// reloads active tab so you get blocked users for example
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
const unblockAUser = async (relationshipId) => {
|
||||
// it's basically the same as unfriending someone cuz unfriending them means the relationship is deleted
|
||||
await unfriend(relationshipId);
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
const blockAFriend = async(relationshipId) => {
|
||||
console.log('blocking a friend, the relationshipID')
|
||||
console.log(relationshipId)
|
||||
|
||||
const resp = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/network/relations/${relationshipId}/block`, {method: "PATCH"})
|
||||
.then( x => x.json() );
|
||||
console.log('blocked a user response')
|
||||
console.log({...resp})
|
||||
// await fetchBlockedUsers();
|
||||
// await fetchAllUsers();
|
||||
await fetchAll();
|
||||
usernameBeingViewed = undefined;
|
||||
friendshipStatusFull = undefined;
|
||||
|
||||
// reloads active tab so you get blocked users for example
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
const unblockAUser = async(relationshipId) => {
|
||||
// it's basically the same as unfriending someone cuz unfriending them means the relationship is deleted
|
||||
await unfriend(relationshipId);
|
||||
activeTabItem = activeTabItem;
|
||||
};
|
||||
|
||||
const switchTab = async(e) => {
|
||||
activeTabItem = e.detail;
|
||||
if (activeTabItem === 'All Users') {
|
||||
await fetchAllUsers();
|
||||
} else if (activeTabItem === 'My Friends') {
|
||||
await fetchMyFriendships();
|
||||
} else if (activeTabItem === 'Friend Requests') {
|
||||
await fetchRequestsReceived();
|
||||
} else if (activeTabItem === 'Blocked Users') {
|
||||
await fetchBlockedUsers();
|
||||
console.log('fetching blocked users')
|
||||
}
|
||||
if (usernameBeingViewed !== undefined)
|
||||
fetchFriendshipFull(usernameBeingViewed);
|
||||
};
|
||||
const switchTab = async (e) => {
|
||||
activeTabItem = e.detail;
|
||||
if (activeTabItem === "All Users") {
|
||||
await fetchAllUsers_Wrapper();
|
||||
} else if (activeTabItem === "My Friends") {
|
||||
await fetchMyFriendships();
|
||||
} else if (activeTabItem === "Friend Requests") {
|
||||
await fetchRequestsReceived();
|
||||
} else if (activeTabItem === "Blocked Users") {
|
||||
await fetchBlockedUsers();
|
||||
console.log("fetching blocked users");
|
||||
}
|
||||
if (usernameBeingViewed)
|
||||
fetchFriendshipFull(usernameBeingViewed);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -240,7 +305,7 @@
|
||||
|
||||
<div class="sidebar-list">
|
||||
<Tabs items={tabItems} activeItem={activeTabItem} size="small" on:tabChange={switchTab}/>
|
||||
{#if activeTabItem === 'All Users' && allUsers !== undefined}
|
||||
{#if activeTabItem === 'All Users' && allUsers}
|
||||
<h3>{activeTabItem}</h3>
|
||||
{#if Object.keys(allUsers).length === 0}
|
||||
<div class="tip">You are alone on this platform...</div>
|
||||
@@ -256,7 +321,7 @@
|
||||
<div class="status sidebar-item">{aUser.status}</div>
|
||||
<br>
|
||||
{/each}
|
||||
{:else if activeTabItem === 'My Friends' && myFriendships !== undefined}
|
||||
{:else if activeTabItem === 'My Friends' && myFriendships}
|
||||
<h3>{activeTabItem}</h3>
|
||||
{#if Object.keys(myFriendships).length === 0}
|
||||
<div class="tip">You don't have any Friends... Yet!</div>
|
||||
@@ -269,7 +334,7 @@
|
||||
{/if}
|
||||
<br>
|
||||
{/each}
|
||||
{:else if activeTabItem === 'Friend Requests' && requestsRecieved !== undefined}
|
||||
{:else if activeTabItem === 'Friend Requests' && requestsRecieved}
|
||||
<h3>{activeTabItem}</h3>
|
||||
{#if Object.keys(requestsRecieved).length === 0}
|
||||
<div class="tip">You don't have any Friend Requests</div>
|
||||
@@ -279,7 +344,7 @@
|
||||
<div class="status sidebar-item">{aUser.status}</div>
|
||||
<br>
|
||||
{/each}
|
||||
{:else if activeTabItem === 'Blocked Users' && blockedUsers !== undefined}
|
||||
{:else if activeTabItem === 'Blocked Users' && blockedUsers}
|
||||
<h3>{activeTabItem}</h3>
|
||||
<!-- seems a little excessive... maybe a lighter way of doing this? doesn't seem like it, i hate it but at least only happens sometimes.default... -->
|
||||
{#if Object.keys(blockedUsers).length === 0}
|
||||
@@ -295,7 +360,7 @@
|
||||
|
||||
|
||||
<div class="main-display">
|
||||
{#if usernameBeingViewed !== undefined}
|
||||
{#if usernameBeingViewed}
|
||||
<DisplayAUser aUsername={usernameBeingViewed} bind:loaded={loadedUser}/>
|
||||
|
||||
{#if loadedUser === true}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
// rename to PotatoCanvas?
|
||||
|
||||
let canvas;
|
||||
// let img;
|
||||
let loaded = false;
|
||||
// i feel like they told me not to do this, new Image(), isn't there another way?
|
||||
// never mind they do seem to do this shit...
|
||||
// no idea if this should be in onMount...
|
||||
const img = new Image();
|
||||
img.src = 'img/potato_logo.png';
|
||||
img.onload = () => {
|
||||
loaded = true;
|
||||
// not sure if i'll use this...
|
||||
}
|
||||
|
||||
// $: scaleRatio = window.innerWidth / 10;
|
||||
$: scaleRatio = 30;
|
||||
$: nPotoatoRows = Math.floor(window.innerHeight / 200);
|
||||
$: nPotoatoCols = Math.floor(window.innerWidth / 200);
|
||||
// $: spacing = (canvas.height - (img.height / scaleRatio * (nPotoatoRows - 1) )) / nPotoatoRows;
|
||||
|
||||
|
||||
// apparently i might need to move all my reactive statements outside the onMount... not sure why...
|
||||
|
||||
|
||||
|
||||
onMount(() => {
|
||||
|
||||
// in this on mount we will set the canvas and the img
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
// let frame = requestAnimationFrame(loop);
|
||||
ctx.width = window.innerWidth;
|
||||
ctx.height = window.innerHeight;
|
||||
|
||||
// console.log(nPotoatoCols);
|
||||
|
||||
// img = fetch('img/potato_logo.png');
|
||||
|
||||
// Moving the IMG stuff from her out of mount
|
||||
|
||||
// let nPotoatoRows = 4;
|
||||
// $: nPotoatoRows = Math.floor(canvas.height / 200);
|
||||
let spacing = (canvas.height - (img.height / scaleRatio * (nPotoatoRows - 1) )) / nPotoatoRows;
|
||||
// $: spacing = (canvas.height - (img.height / scaleRatio * (nPotoatoRows - 1) )) / nPotoatoRows;
|
||||
// i prolly need a number of potatos X and Y vars
|
||||
|
||||
|
||||
|
||||
// i could do it so there are more potatos than can fit on the screen, translate them over, and then after some point
|
||||
// shift them all back to the next position they would be in, so it looks like they keep going to infinity
|
||||
|
||||
// let dx = 1.5;
|
||||
let dx = 1;
|
||||
// let dy = -0.5;
|
||||
let dy = -1;
|
||||
// let startX = spacing;
|
||||
// let startY = spacing;
|
||||
// let startX = 0;
|
||||
// let startY = 0;
|
||||
let startX = -(spacing * 2.5);
|
||||
let startY = -(spacing * 2.5);
|
||||
let x = startX;
|
||||
let y = startY;
|
||||
|
||||
let frame = requestAnimationFrame(loop);
|
||||
// i don't think i need t...
|
||||
function loop(t) {
|
||||
// yea ok a loop in a loop in a loop, horrible idea...
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// this has to be at the end, no?
|
||||
frame = requestAnimationFrame(loop);
|
||||
// if (x > 900) {
|
||||
// x = startX;
|
||||
// y = startY;
|
||||
// }
|
||||
// else {
|
||||
// x += dx;
|
||||
// y += dy;
|
||||
// }
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
// ctx.drawImage(img, x + (i * spacing * 2), y + (j * spacing), img.width / scaleRatio, img.height / scaleRatio);
|
||||
ctx.drawImage(img, x + (i * spacing), y + (j * spacing), img.width / scaleRatio, img.height / scaleRatio);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(frame);
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<canvas
|
||||
bind:this={canvas}
|
||||
width={window.innerWidth}
|
||||
height={window.innerHeight}
|
||||
></canvas>
|
||||
|
||||
<style>
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #666;
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +1,18 @@
|
||||
<script lang="ts">
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import GenerateUserDisplay from './GenerateUserDisplay.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import GenerateUserDisplay from './GenerateUserDisplay.svelte';
|
||||
import { fetchUser } from "../pieces/utils";
|
||||
|
||||
export let aUsername;
|
||||
export let loaded = false;
|
||||
let user;
|
||||
|
||||
onMount( async() => {
|
||||
// console.log('Display aUser username: '+ aUsername)
|
||||
onMount( async() => {
|
||||
aUser = await fetchUser(aUsername);
|
||||
})
|
||||
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user?username=${aUsername}`)
|
||||
.then( (x) => x.json() );
|
||||
})
|
||||
|
||||
export const updateUser = async() => {
|
||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user?username=${aUsername}`)
|
||||
.then( (x) => x.json() );
|
||||
};
|
||||
|
||||
$: aUsername, updateUser();
|
||||
$: aUsername, fetchUser(aUsername);
|
||||
|
||||
$: {
|
||||
if (user === undefined)
|
||||
@@ -31,8 +24,8 @@
|
||||
</script>
|
||||
|
||||
<div class="background-pages">
|
||||
{#if user !== undefined}
|
||||
<GenerateUserDisplay user={user}/>
|
||||
{#if aUser}
|
||||
<GenerateUserDisplay user={aUser}/>
|
||||
{:else}
|
||||
<h2>Sorry</h2>
|
||||
<div>Failed to load user {aUsername}</div>
|
||||
|
||||
@@ -62,11 +62,11 @@
|
||||
|
||||
<!-- is this if excessive? -->
|
||||
<div class="outer">
|
||||
{#if user !== undefined}
|
||||
{#if user}
|
||||
<main>
|
||||
<!-- <img class="icon" src="img/default_user_icon.png" alt="default user icon"> -->
|
||||
<!-- <img class="icon" src="{user.image_url}" alt="default user icon"> -->
|
||||
<img class="avatar" src="{avatar}" alt="default user icon">
|
||||
<img class="avatar" src="{avatar}" alt="user avatar">
|
||||
<div class="error">{errors.avatar}</div>
|
||||
<div class="username">{user.username}</div>
|
||||
<div class="rank">Rank:
|
||||
|
||||
@@ -1,36 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { push } from "svelte-spa-router";
|
||||
import { location } from 'svelte-spa-router';
|
||||
import { push } from "svelte-spa-router";
|
||||
import { location } from 'svelte-spa-router';
|
||||
|
||||
|
||||
// no need, it's just for links
|
||||
import active from 'svelte-spa-router/active'
|
||||
// or i could leave them all and not display if they're active?
|
||||
// no need, it's just for links
|
||||
import active from 'svelte-spa-router/active'
|
||||
// or i could leave them all and not display if they're active?
|
||||
|
||||
$: current = $location;
|
||||
$: current = $location;
|
||||
|
||||
let handleClickLogout = async () => {
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/logout`, {
|
||||
method: 'POST',
|
||||
})
|
||||
.then( () => push('/') )
|
||||
console.log('clicked logout header')
|
||||
};
|
||||
let handleClickLogout = async () =>
|
||||
{
|
||||
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/logout`,
|
||||
{
|
||||
method: 'POST',
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch handleClickLogout: ", error);
|
||||
});
|
||||
|
||||
push('/');
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="header">
|
||||
<img src="/img/logo_potato.png" alt="Potato Pong Logo" on:click={() => (push('/'))}>
|
||||
<div class="center">
|
||||
<button class:selected="{current === '/game'}" on:click={() => (push('/game'))}>Play</button>
|
||||
<button class:selected="{current === '/spectator'}" on:click={() => (push('/spectator'))}>Spectate</button>
|
||||
<button class:selected="{current === '/ranking'}" on:click={() => (push('/ranking'))}>Ranking</button>
|
||||
<button class:selected="{current === '/profile'}" on:click={() => (push('/profile'))}>My Profile</button>
|
||||
<button class:selected="{current === '/profile/users'}" on:click={() => (push('/profile/users'))}>Users</button>
|
||||
</div>
|
||||
<button class="logout" on:click={handleClickLogout}>Log Out</button>
|
||||
<img src="/img/logo_potato.png" alt="Potato Pong Logo" on:click={() => (push('/'))}>
|
||||
<div class="center">
|
||||
<button class:selected="{current === '/game'}" on:click={() => (push('/game'))}>Play</button>
|
||||
<button class:selected="{current === '/spectator'}" on:click={() => (push('/spectator'))}>Spectate</button>
|
||||
<button class:selected="{current === '/ranking'}" on:click={() => (push('/ranking'))}>Ranking</button>
|
||||
<button class:selected="{current === '/profile'}" on:click={() => (push('/profile'))}>My Profile</button>
|
||||
<button class:selected="{current === '/profile/users'}" on:click={() => (push('/profile/users'))}>Users</button>
|
||||
</div>
|
||||
<button class="logout" on:click={handleClickLogout}>Log Out</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -59,7 +70,6 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
resize: vertical;
|
||||
overflow: hidden;
|
||||
background: #FB8B24;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
</script>
|
||||
|
||||
{#if $location !== '/'}
|
||||
{#if $location !== '/' && $location !== '/game'}
|
||||
<Layouts
|
||||
--lines_width={style.lines_width}
|
||||
--lines_color={style.lines_color}
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
let users: User[] = list_block_user();
|
||||
|
||||
function user_profile(room_user: string)
|
||||
async function user_profile(room_user: string)
|
||||
{
|
||||
to_print("in user_profile");
|
||||
settings_user.set(room_user);
|
||||
await settings_user.set(room_user);
|
||||
layout.set("user");
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ export async function remove_block_user(username: string): Promise<void>
|
||||
await fetch_chat_request('unblock', FetchMethod.POST, {username: username} );
|
||||
}
|
||||
|
||||
export async function list_block_user(username: string): Promise<string>
|
||||
export async function list_block_user(username: string): Promise<string[]>
|
||||
{
|
||||
to_print("in list_block_user");
|
||||
|
||||
|
||||
@@ -6,8 +6,11 @@ const address = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}`
|
||||
|
||||
export async function init_socket()
|
||||
{
|
||||
to_print("in init_socket");
|
||||
console.log("here");
|
||||
const response = await fetch(`${address}/api/v2/user`);
|
||||
const response_data = await response.json();
|
||||
to_print("-- response_data:", response_data);
|
||||
|
||||
set_user(response_data);
|
||||
|
||||
@@ -19,6 +22,7 @@ export async function init_socket()
|
||||
username: response_data.username,
|
||||
},
|
||||
});
|
||||
console.log("horo");
|
||||
set_socket(socket);
|
||||
|
||||
socket_states(socket);
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
|
||||
export async function fetchAvatar(username: string)
|
||||
export async function fetchAvatar(username?: string)
|
||||
{
|
||||
return fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/avatar?username=${username}`)
|
||||
let url = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/avatar`;
|
||||
if (username) {
|
||||
url += `?username=${username}`;
|
||||
}
|
||||
|
||||
return fetch(url)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
@@ -17,18 +22,20 @@ export async function fetchAvatar(username: string)
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchUser()
|
||||
export async function fetchUser(username?: string)
|
||||
{
|
||||
return fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||
let url = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`;
|
||||
if (username) {
|
||||
url += `?username=${username}`;
|
||||
}
|
||||
|
||||
return fetch(url)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((body) => {
|
||||
return body;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchUser: ", error);
|
||||
return null;
|
||||
@@ -44,9 +51,6 @@ export async function fetchAllUsers()
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((body) => {
|
||||
return body;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("catch fetchAllUsers: ", error);
|
||||
return [];
|
||||
|
||||
@@ -7,96 +7,41 @@ import { wrap } from 'svelte-spa-router/wrap'
|
||||
import Game from '../pages/game/Game.svelte';
|
||||
import Ranking from '../pages/game/Ranking.svelte';
|
||||
import GameSpectator from '../pages/game/GameSpectator.svelte';
|
||||
import { fetchUser } from "../pieces/utils";
|
||||
|
||||
async function checkLogin(detail) {
|
||||
const user = await fetchUser();
|
||||
if (!user || !user.username) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const primaryRoutes = {
|
||||
'/': SplashPage,
|
||||
'/2fa': TwoFactorAuthentication,
|
||||
'/game': wrap({
|
||||
component: Game,
|
||||
conditions: [
|
||||
async(detail) => {
|
||||
const user = await fetch('http://' + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + '/api/v2/user')
|
||||
.then((resp) => resp.json())
|
||||
|
||||
console.log('in /profile what is in user')
|
||||
console.log(user)
|
||||
|
||||
if (user && user.username)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
]
|
||||
}),
|
||||
'/spectator': wrap({
|
||||
component: GameSpectator,
|
||||
conditions: [
|
||||
async(detail) => {
|
||||
const user = await fetch('http://' + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + '/api/v2/user')
|
||||
.then((resp) => resp.json())
|
||||
|
||||
console.log('in /profile what is in user')
|
||||
console.log(user)
|
||||
|
||||
if (user && user.username)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
]
|
||||
}),
|
||||
'/ranking': wrap({
|
||||
component: Ranking,
|
||||
conditions: [
|
||||
async(detail) => {
|
||||
const user = await fetch('http://' + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + '/api/v2/user')
|
||||
.then((resp) => resp.json())
|
||||
|
||||
console.log('in /profile what is in user')
|
||||
console.log(user)
|
||||
|
||||
if (user && user.username)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
]
|
||||
}),
|
||||
'/profile': wrap({
|
||||
component: ProfilePage,
|
||||
conditions: [
|
||||
async(detail) => {
|
||||
const user = await fetch('http://' + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + '/api/v2/user')
|
||||
.then((resp) => resp.json())
|
||||
|
||||
console.log('in /profile what is in user')
|
||||
console.log(user)
|
||||
|
||||
if (user && user.username)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
]
|
||||
}),
|
||||
'/profile/*': wrap({
|
||||
component: ProfilePage,
|
||||
conditions: [
|
||||
async(detail) => {
|
||||
const user = await fetch('http://' + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + '/api/v2/user')
|
||||
.then((resp) => resp.json())
|
||||
|
||||
console.log('in /profile/* what is in user')
|
||||
console.log(user)
|
||||
|
||||
if (user && user.username)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
]
|
||||
}),
|
||||
'/unauthorized-access': UnauthorizedAccessPage,
|
||||
'*': NotFound
|
||||
'/': SplashPage,
|
||||
'/2fa': TwoFactorAuthentication,
|
||||
'/game': wrap({
|
||||
component: Game,
|
||||
conditions: [checkLogin]
|
||||
}),
|
||||
'/spectator': wrap({
|
||||
component: GameSpectator,
|
||||
conditions: [checkLogin]
|
||||
}),
|
||||
'/ranking': wrap({
|
||||
component: Ranking,
|
||||
conditions: [checkLogin]
|
||||
}),
|
||||
'/profile': wrap({
|
||||
component: ProfilePage,
|
||||
conditions: [checkLogin]
|
||||
}),
|
||||
'/profile/*': wrap({
|
||||
component: ProfilePage,
|
||||
conditions: [checkLogin]
|
||||
}),
|
||||
'/unauthorized-access': UnauthorizedAccessPage,
|
||||
'*': NotFound
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user