aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <l.leblansch@gmail.com>2021-03-20 18:44:58 +0100
committerlonkaars <l.leblansch@gmail.com>2021-03-20 18:44:58 +0100
commiteed11fd96cf1458a7a91659cdf5efafbadda1b2b (patch)
treed1f6cb2b070b9296f3fa15956307ddf4689e7aa3
parent62a3b7fbb4ffcaa16e0b4984d5fa0e59537af146 (diff)
more event api
-rw-r--r--api/readme.md49
-rw-r--r--api/social/create_relation.py4
-rw-r--r--components/navbar.tsx26
-rw-r--r--components/notificationsArea.tsx73
-rw-r--r--pages/_app.tsx2
-rw-r--r--pages/game.tsx2
6 files changed, 126 insertions, 30 deletions
diff --git a/api/readme.md b/api/readme.md
index 7d28259..48e9b14 100644
--- a/api/readme.md
+++ b/api/readme.md
@@ -2,6 +2,55 @@
This is the subdirectory for the API. You can find the API reference in [this](https://docs.google.com/spreadsheets/d/1mDN9IUqRIMjr_9RmLxKybjIgVuaUadalmPEFnG-XeJg/edit?usp=sharing) Google Docs document.
+## Endpoint reference (WIP)
+
+API return type classes are mostly defined in api/api.ts
+
+endpoint|method|description|parameters|authorization
+-|-|-|-|-
+/status | GET | get online user count and active game count
+/auth/login | POST | log in with email or username
+/auth/token | POST | log in using a token (stored as cookie)
+/auth/signup | POST | sign up
+/user/info | GET\|POST | get user info by username or id note: avatar is a uri to a 256x256 .png image
+/user/games | GET\|POST | get games of user
+/user/avatar | GET\|POST | fetch or update avatar note: avatar is a client-resized 256x256 .png base64-encoded image, request returns error when image is not .png or larger than 256x256
+/user/prefrences | GET\|POST | fetch or change user preferences
+/user/password | POST | update password
+/user/email | POST | update email (token used for authentication if password is undefined)
+/user/username | POST | update username (token used for authentication if password is undefined)
+/user/status | POST | update status
+/user/searchFriends | POST | search user's friend list
+/social/request | POST | send a friend request to a user by user id
+/social/accept | POST | accept a friend request
+/social/remove | POST | remove a friend from your friend list or delete a friend request from a user
+/social/search | POST | search for users by username or status
+/social/block | POST | block a user
+/social/unblock | POST | unblock a user
+/social/list/requests | GET | get a list of unaccepted friend requests
+/social/list/blocks | GET | get a list of blocked people
+/social/list/friends | GET | get a list of your friends
+/game/new | POST | create a new private game
+/game/random | POST | join or create a public game
+/game/info | POST |
+/game/accept | POST | accept game invite or rematch
+/game/spectate | POST | spectate a game by id
+
+## Events
+
+These are events that are fired by the socket.io connection
+
+event|description|data|direction|context
+-|-|-|-|-
+fieldUpdate|recieve new playfield from server|`{ field: string }`|`s -> c`|game
+turnUpdate|recieve if it's player 1's move|`{ player1: boolean }`|`s -> c`|game
+gameStart|sent when game starts|`none`|`s -> c`|game
+finish|sent when game finishes|`none`|`s -> c`|game
+resign|send to resign, is then forwarded to all subscribed clients|`none`|`s <-> c`|game
+newMove|send a new move|`{ move: int, game_id: string }`|`s <- c`|game
+registerGameListener|listen to events for a game|`{ id: string }`|`s <- c`|game
+incomingFriendRequest|get notified of friend request|`none`|`s -> c`|global
+
## How to test API endpoints
```sh
# If you're running the standalone flask server:
diff --git a/api/social/create_relation.py b/api/social/create_relation.py
index eded25d..49bb4bc 100644
--- a/api/social/create_relation.py
+++ b/api/social/create_relation.py
@@ -1,6 +1,7 @@
from flask import Blueprint, request
from db import cursor, connection
from auth.login_token import token_login
+from socket_io import io
import time
def create_relation(user_1_id, user_2_id, relation_type):
@@ -31,6 +32,9 @@ def create_relation_route(relation_type):
return "", 403
create_relation(user_1_id, user_2_id, relation_type)
+ if relation_type == "outgoing":
+ io.emit("incomingFriendRequest", room="user-"+user_2_id)
+
return "", 200
return route
diff --git a/components/navbar.tsx b/components/navbar.tsx
index 252635d..f413008 100644
--- a/components/navbar.tsx
+++ b/components/navbar.tsx
@@ -1,10 +1,11 @@
-import { CSSProperties, useEffect, useState } from "react";
+import { CSSProperties, useEffect, useState, useContext } from "react";
import axios from "axios";
import { LogoDark } from "../components/logo";
import { AccountAvatar } from "./account";
import { userInfo } from "../api/api";
import { NotificationsArea } from "./notificationsArea";
+import { SocketContext } from "./socketContext";
import Home from '@material-ui/icons/Home';
import VideogameAssetIcon from '@material-ui/icons/VideogameAsset';
@@ -29,6 +30,18 @@ export function NavBar() {
var [ notificationsAreaVisible, setNotificationsAreaVisible ] = useState(false);
var [ gotNotifications, setGotNotifications ] = useState(false);
+ var { io } = useContext(SocketContext);
+
+ async function getNotifications() {
+ var friendRequestsReq = await axios.request<{ requests: Array<userInfo> }>({
+ method: "get",
+ url: `/api/social/list/requests`
+ });
+ setFriendRequests(friendRequestsReq.data.requests);
+
+ setGotNotifications(friendRequestsReq.data.requests.length > 0);
+ }
+
useEffect(() => {(async () => {
if (gotData) return;
if (typeof window === "undefined") return;
@@ -37,12 +50,8 @@ export function NavBar() {
setLoggedIn(loggedIn);
if (loggedIn) {
- var friendRequestsReq = await axios.request<{ requests: Array<userInfo> }>({
- method: "get",
- url: `/api/social/list/requests`
- });
- setFriendRequests(friendRequestsReq.data.requests);
- setGotNotifications(gotNotifications || friendRequestsReq.data.requests.length > 0);
+ await getNotifications();
+ io.on("incomingFriendRequest", getNotifications);
}
setGotData(true);
@@ -94,7 +103,8 @@ export function NavBar() {
</div>
<NotificationsArea
visible={notificationsAreaVisible}
- friendRequests={friendRequests}/>
+ friendRequests={friendRequests}
+ rerender={getNotifications}/>
</a> }
<a href={loggedIn ? "/user" : "/login"} style={NavBarItemStyle}>
{
diff --git a/components/notificationsArea.tsx b/components/notificationsArea.tsx
index 1e92493..7d2fa49 100644
--- a/components/notificationsArea.tsx
+++ b/components/notificationsArea.tsx
@@ -1,7 +1,7 @@
import { CSSProperties, ReactNode, useState } from 'react';
import axios from 'axios';
-import { userInfo } from "../api/api";
+import { userInfo, gameInfo } from "../api/api";
import { AccountAvatar } from "./account";
import { Bubble, Vierkant, IconLabelButton } from './ui';
@@ -11,7 +11,14 @@ import CloseIcon from '@material-ui/icons/Close';
export function NotificationsArea(props: {
visible?: boolean;
friendRequests?: Array<userInfo>;
+ gameInvites?: Array<gameInfo>;
+ rerender: () => void;
}) {
+ var messages = (
+ (props.friendRequests ? props.friendRequests.length : 0) +
+ (props.gameInvites ? props.gameInvites.length : 0)
+ )
+
return props.visible && <Bubble style={{
left: 48 + 12,
top: 92,
@@ -31,8 +38,27 @@ export function NotificationsArea(props: {
height: 450 - 24 * 4,
borderRadius: 6
}}>
- { /* here should be the game invites */ }
- { props.friendRequests?.map(user => <FriendRequest user={user}/>) }
+ { props.gameInvites?.map(game => <GameInvite hide={props.rerender} game={game}/>) }
+ { props.friendRequests?.map(user => <FriendRequest hide={props.rerender} user={user}/>) }
+ {
+ messages == 0 &&
+ <div style={{
+ position: "absolute",
+ left: 0,
+ right: 0,
+ bottom: 0,
+ top: 0
+ }}>
+ <h1 style={{
+ position: "absolute",
+ top: "50%",
+ left: "50%",
+ whiteSpace: "nowrap",
+ transform: "translate(-50%, -50%)",
+ opacity: .7
+ }}>Geen meldingen</h1>
+ </div>
+ }
</div>
</Bubble>
}
@@ -83,9 +109,15 @@ function Acceptable(props: {
function FriendRequest(props: {
user: userInfo;
+ hide: () => void;
}) {
var [ gone, setGone ] = useState(false);
+ var hide = () => {
+ setGone(true);
+ props.hide();
+ }
+
return !gone && <Acceptable onAccept={() => {
axios.request({
method: "post",
@@ -93,7 +125,7 @@ function FriendRequest(props: {
headers: {"content-type": "application/json"},
data: { "id": props.user?.id }
})
- .then(() => setGone(true));
+ .then(hide);
}} onDeny={() => {
axios.request({
method: "post",
@@ -101,7 +133,7 @@ function FriendRequest(props: {
headers: {"content-type": "application/json"},
data: { "id": props.user?.id }
})
- .then(() => setGone(true));
+ .then(hide);
}}>
<a href={"/user?id=" + props.user.id}>
<AccountAvatar size={48} id={props.user.id}/>
@@ -117,19 +149,20 @@ function FriendRequest(props: {
</Acceptable>
}
-/* function GameInvite(props: { */
-/* game: gameInfo; */
-/* }) { */
-/* return <Acceptable> */
-/* <a> */
-/* <div style={{ */
-/* display: "inline-block", */
-/* verticalAlign: "top", */
-/* }}> */
-/* <i style={{ display: "block" }}>Partijuitnodiging</i> */
-/* <p><b><a href={"/user?id=" + props.game.opponent?.id}>{props.game.opponent?.username}</a></b> wil een potje 4 op een rij spelen!</p> */
-/* </div> */
-/* </a> */
-/* </Acceptable> */
-/* } */
+function GameInvite(props: {
+ game: gameInfo;
+ hide: () => void;
+}) {
+ return <Acceptable>
+ <a>
+ <div style={{
+ display: "inline-block",
+ verticalAlign: "top",
+ }}>
+ <i style={{ display: "block" }}>Partijuitnodiging</i>
+ <p><b><a href={"/user?id=" + props.game.opponent?.id}>{props.game.opponent?.username}</a></b> wil een potje 4 op een rij spelen!</p>
+ </div>
+ </a>
+ </Acceptable>
+}
diff --git a/pages/_app.tsx b/pages/_app.tsx
index bfde0d7..a95caa4 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -18,7 +18,7 @@ export default function VierOpEenRijWebsite({ Component, pageProps }) {
<link rel="icon" href="/favicon.png" type="image/png"/>
<meta property="og:site_name" content="4 op een rij"/>
- <meta property="og:url" content="http://86.80.39.198:2080/"/>
+ <meta property="og:url" content="http://connect4.pipeframe.xyz/"/>
<meta property="og:title" content="Loek's epische vier op een rij website"/>
<meta property="og:description" content="Kom vier op een rij spelen NU"/>
<meta property="og:type" content="website"/>
diff --git a/pages/game.tsx b/pages/game.tsx
index aa90588..030938c 100644
--- a/pages/game.tsx
+++ b/pages/game.tsx
@@ -76,7 +76,7 @@ function VoerGame(props: {
onMove={move => {
props.io.emit("newMove", {
move: move % width + 1,
- token: cookies.load("token"),
+ token: cookies.load("token"), //TODO: get token from request
game_id: props.gameID
});
}}