diff options
author | lonkaars <l.leblansch@gmail.com> | 2021-03-20 18:44:58 +0100 |
---|---|---|
committer | lonkaars <l.leblansch@gmail.com> | 2021-03-20 18:44:58 +0100 |
commit | eed11fd96cf1458a7a91659cdf5efafbadda1b2b (patch) | |
tree | d1f6cb2b070b9296f3fa15956307ddf4689e7aa3 | |
parent | 62a3b7fbb4ffcaa16e0b4984d5fa0e59537af146 (diff) |
more event api
-rw-r--r-- | api/readme.md | 49 | ||||
-rw-r--r-- | api/social/create_relation.py | 4 | ||||
-rw-r--r-- | components/navbar.tsx | 26 | ||||
-rw-r--r-- | components/notificationsArea.tsx | 73 | ||||
-rw-r--r-- | pages/_app.tsx | 2 | ||||
-rw-r--r-- | pages/game.tsx | 2 |
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 }); }} |