Add: Simple user login/register function
This commit is contained in:
@@ -70,6 +70,9 @@ func NewAPI(config Config) (*API, error) {
|
|||||||
apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo)
|
apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo)
|
||||||
apiMux.HandleFunc("/get_file_stream_direct", api.HandleGetFileStreamDirect)
|
apiMux.HandleFunc("/get_file_stream_direct", api.HandleGetFileStreamDirect)
|
||||||
apiMux.HandleFunc("/prepare_file_stream_direct", api.HandlePrepareFileStreamDirect)
|
apiMux.HandleFunc("/prepare_file_stream_direct", api.HandlePrepareFileStreamDirect)
|
||||||
|
// user
|
||||||
|
apiMux.HandleFunc("/login", api.HandleLogin)
|
||||||
|
apiMux.HandleFunc("/register", api.HandleRegister)
|
||||||
// below needs token
|
// below needs token
|
||||||
apiMux.HandleFunc("/walk", api.HandleWalk)
|
apiMux.HandleFunc("/walk", api.HandleWalk)
|
||||||
apiMux.HandleFunc("/reset", api.HandleReset)
|
apiMux.HandleFunc("/reset", api.HandleReset)
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) HandleError(w http.ResponseWriter, r *http.Request, err error) {
|
func (api *API) HandleError(w http.ResponseWriter, r *http.Request, err error) {
|
||||||
api.HandleErrorString(w, r, err.Error())
|
api.HandleErrorString(w, r, err.Error())
|
||||||
}
|
}
|
||||||
@@ -20,8 +24,8 @@ func (api *API) HandleErrorString(w http.ResponseWriter, r *http.Request, errorS
|
|||||||
|
|
||||||
func (api *API) HandleErrorStringCode(w http.ResponseWriter, r *http.Request, errorString string, code int) {
|
func (api *API) HandleErrorStringCode(w http.ResponseWriter, r *http.Request, errorString string, code int) {
|
||||||
log.Println("[api] [Error]", code, errorString)
|
log.Println("[api] [Error]", code, errorString)
|
||||||
errStatus := &Status{
|
errStatus := &Error{
|
||||||
Status: errorString,
|
Error: errorString,
|
||||||
}
|
}
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
json.NewEncoder(w).Encode(errStatus)
|
json.NewEncoder(w).Encode(errStatus)
|
||||||
|
|||||||
83
pkg/api/handle_user.go
Normal file
83
pkg/api/handle_user.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"msw-open-music/pkg/database"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginRequest struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginResponse struct {
|
||||||
|
User *database.User `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) HandleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Get method will login as anonymous user
|
||||||
|
if r.Method == "GET" {
|
||||||
|
log.Println("Login as anonymous user")
|
||||||
|
user, err := api.Db.LoginAsAnonymous()
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp := &LoginResponse{
|
||||||
|
User: user,
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var request LoginRequest
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&request)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Login as user", request.Username)
|
||||||
|
|
||||||
|
user, err := api.Db.Login(request.Username, request.Password)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &LoginResponse{
|
||||||
|
User: user,
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(resp)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterRequest struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Role int64 `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) HandleRegister(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var request RegisterRequest
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&request)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Register user", request.Username)
|
||||||
|
|
||||||
|
err = api.Db.Register(request.Username, request.Password, request.Role)
|
||||||
|
if err != nil {
|
||||||
|
api.HandleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.HandleOK(w, r)
|
||||||
|
}
|
||||||
31
pkg/database/method_user.go
Normal file
31
pkg/database/method_user.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
func (database *Database) Login(username string, password string) (*User, error) {
|
||||||
|
user := &User{}
|
||||||
|
|
||||||
|
// get user from database
|
||||||
|
err := database.stmt.getUser.QueryRow(username, password).Scan(&user.ID, &user.Username, &user.Role, &user.AvatarId)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (database *Database) LoginAsAnonymous() (*User, error) {
|
||||||
|
user := &User{}
|
||||||
|
|
||||||
|
// get user from database
|
||||||
|
err := database.stmt.getAnonymousUser.QueryRow().Scan(&user.ID, &user.Username, &user.Role, &user.AvatarId)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (database *Database) Register(username string, password string, usertype int64) (error) {
|
||||||
|
_, err := database.stmt.insertUser.Exec(username, password, usertype, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -25,10 +25,13 @@ var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks (
|
|||||||
header TEXT NOT NULL
|
header TEXT NOT NULL
|
||||||
);`
|
);`
|
||||||
|
|
||||||
|
// User table schema definition
|
||||||
|
// role: 0 - Anonymous User, 1 - Admin, 2 - User
|
||||||
var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users (
|
var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
|
role INTEGER NOT NULL,
|
||||||
avatar_id INTEGER NOT NULL,
|
avatar_id INTEGER NOT NULL,
|
||||||
FOREIGN KEY(avatar_id) REFERENCES avatars(id)
|
FOREIGN KEY(avatar_id) REFERENCES avatars(id)
|
||||||
);`
|
);`
|
||||||
@@ -153,6 +156,17 @@ LIMIT ?;`
|
|||||||
var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header)
|
var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header)
|
||||||
VALUES (?, ?, ?);`
|
VALUES (?, ?, ?);`
|
||||||
|
|
||||||
|
var insertUserQuery = `INSERT INTO users (username, password, role, avatar_id)
|
||||||
|
VALUES (?, ?, ?, ?);`
|
||||||
|
|
||||||
|
var countUserQuery = `SELECT count(*) FROM users;`
|
||||||
|
|
||||||
|
var countAdminQuery = `SELECT count(*) FROM users WHERE role= 1;`
|
||||||
|
|
||||||
|
var getUserQuery = `SELECT id, username, role, avatar_id FROM users WHERE username = ? AND password = ? LIMIT 1;`
|
||||||
|
|
||||||
|
var getAnonymousUserQuery = `SELECT id, username, role, avatar_id FROM users WHERE role = 0 LIMIT 1;`
|
||||||
|
|
||||||
type Stmt struct {
|
type Stmt struct {
|
||||||
initFilesTable *sql.Stmt
|
initFilesTable *sql.Stmt
|
||||||
initFoldersTable *sql.Stmt
|
initFoldersTable *sql.Stmt
|
||||||
@@ -179,6 +193,11 @@ type Stmt struct {
|
|||||||
getFilesInFolder *sql.Stmt
|
getFilesInFolder *sql.Stmt
|
||||||
getRandomFiles *sql.Stmt
|
getRandomFiles *sql.Stmt
|
||||||
insertFeedback *sql.Stmt
|
insertFeedback *sql.Stmt
|
||||||
|
insertUser *sql.Stmt
|
||||||
|
countUser *sql.Stmt
|
||||||
|
countAdmin *sql.Stmt
|
||||||
|
getUser *sql.Stmt
|
||||||
|
getAnonymousUser *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
||||||
@@ -386,5 +405,48 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init insertUser
|
||||||
|
stmt.insertUser, err = sqlConn.Prepare(insertUserQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// init countUser
|
||||||
|
stmt.countUser, err = sqlConn.Prepare(countUserQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// init countAdmin
|
||||||
|
stmt.countAdmin, err = sqlConn.Prepare(countAdminQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// init getUser
|
||||||
|
stmt.getUser, err = sqlConn.Prepare(getUserQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// init getAnonymousUser
|
||||||
|
stmt.getAnonymousUser, err = sqlConn.Prepare(getAnonymousUserQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert Anonymous user if users is empty
|
||||||
|
userCount := 0
|
||||||
|
err = stmt.countUser.QueryRow().Scan(&userCount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userCount == 0 {
|
||||||
|
_, err = stmt.insertUser.Exec("Anonymous user", "", 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return stmt, err
|
return stmt, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ type Folder struct {
|
|||||||
Foldername string `json:"foldername"`
|
Foldername string `json:"foldername"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"-"`
|
||||||
|
Role int64 `json:"role"`
|
||||||
|
AvatarId int64 `json:"avatar_id"`
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) Path() (string, error) {
|
func (f *File) Path() (string, error) {
|
||||||
folder, err := f.Db.GetFolder(f.Folder_id)
|
folder, err := f.Db.GetFolder(f.Folder_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -27,4 +35,3 @@ func (f *File) Path() (string, error) {
|
|||||||
}
|
}
|
||||||
return filepath.Join(folder.Folder, f.Filename), nil
|
return filepath.Join(folder.Folder, f.Filename), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { HashRouter as Router, Routes, Route, NavLink } from "react-router-dom";
|
||||||
HashRouter as Router,
|
|
||||||
Routes,
|
|
||||||
Route,
|
|
||||||
NavLink,
|
|
||||||
} from "react-router-dom";
|
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
import GetRandomFiles from "./component/GetRandomFiles";
|
import GetRandomFiles from "./component/GetRandomFiles";
|
||||||
@@ -12,11 +7,15 @@ import SearchFolders from "./component/SearchFolders";
|
|||||||
import FilesInFolder from "./component/FilesInFolder";
|
import FilesInFolder from "./component/FilesInFolder";
|
||||||
import Manage from "./component/Manage";
|
import Manage from "./component/Manage";
|
||||||
import Share from "./component/Share";
|
import Share from "./component/Share";
|
||||||
|
import Login from "./component/Login";
|
||||||
|
import Register from "./component/Register";
|
||||||
import AudioPlayer from "./component/AudioPlayer";
|
import AudioPlayer from "./component/AudioPlayer";
|
||||||
|
import UserStatus from "./component/UserStatus";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [playingFile, setPlayingFile] = useState({});
|
const [playingFile, setPlayingFile] = useState({});
|
||||||
|
const [user, setUser] = useState({});
|
||||||
return (
|
return (
|
||||||
<div className="base">
|
<div className="base">
|
||||||
<Router>
|
<Router>
|
||||||
@@ -24,6 +23,7 @@ function App() {
|
|||||||
<h3 className="title">
|
<h3 className="title">
|
||||||
<img src="favicon.png" alt="logo" className="logo" />
|
<img src="favicon.png" alt="logo" className="logo" />
|
||||||
<span className="title-text">MSW Open Music Project</span>
|
<span className="title-text">MSW Open Music Project</span>
|
||||||
|
<UserStatus user={user} setUser={setUser} />
|
||||||
</h3>
|
</h3>
|
||||||
<nav className="nav">
|
<nav className="nav">
|
||||||
<NavLink to="/" className="nav-link">
|
<NavLink to="/" className="nav-link">
|
||||||
@@ -59,7 +59,9 @@ function App() {
|
|||||||
path="/folders/:id"
|
path="/folders/:id"
|
||||||
element={<FilesInFolder setPlayingFile={setPlayingFile} />}
|
element={<FilesInFolder setPlayingFile={setPlayingFile} />}
|
||||||
/>
|
/>
|
||||||
<Route path="/manage" element={<Manage />} />
|
<Route path="/manage" element={<Manage user={user} setUser={setUser} />} />
|
||||||
|
<Route path="/manage/login" element={<Login user={user} setUser={setUser} />} />
|
||||||
|
<Route path="/manage/register" element={<Register user={user} setUser={setUser} />} />
|
||||||
<Route
|
<Route
|
||||||
path="/files/:id/share"
|
path="/files/:id/share"
|
||||||
element={<Share setPlayingFile={setPlayingFile} />}
|
element={<Share setPlayingFile={setPlayingFile} />}
|
||||||
|
|||||||
65
web/src/component/Login.js
Normal file
65
web/src/component/Login.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
function Login(props) {
|
||||||
|
let navigate = useNavigate();
|
||||||
|
let [username, setUsername] = useState("");
|
||||||
|
let [password, setPassword] = useState("");
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Login</h2>
|
||||||
|
<label htmlFor="username">Username</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
<label htmlFor="password">Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
if (!username || !password) {
|
||||||
|
alert("Please enter username and password");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch("/api/v1/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
alert(data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.setUser(data.user);
|
||||||
|
navigate("/");
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/manage/register");
|
||||||
|
}}
|
||||||
|
>Register</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login;
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useNavigate } from "react-router";
|
||||||
|
|
||||||
|
function Manage(props) {
|
||||||
|
let navigate = useNavigate();
|
||||||
|
|
||||||
function Manage() {
|
|
||||||
const [token, setToken] = useState("");
|
const [token, setToken] = useState("");
|
||||||
const [walkPath, setWalkPath] = useState("");
|
const [walkPath, setWalkPath] = useState("");
|
||||||
|
|
||||||
@@ -25,6 +28,20 @@ function Manage() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Manage</h2>
|
<h2>Manage</h2>
|
||||||
|
<p>Hi, {props.user.username}</p>
|
||||||
|
{props.user.role === 0 && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/manage/login");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{props.user.role !== 0 && (
|
||||||
|
<button onClick={() => props.setUser({})}>Logout</button>
|
||||||
|
)}
|
||||||
|
<hr />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={token}
|
value={token}
|
||||||
|
|||||||
76
web/src/component/Register.js
Normal file
76
web/src/component/Register.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
function Register(props) {
|
||||||
|
let navigate = useNavigate();
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [password2, setPassword2] = useState("");
|
||||||
|
const [role, setRole] = useState("");
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Register</h2>
|
||||||
|
<label htmlFor="username">Username</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
<label htmlFor="password">Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
<label htmlFor="password2">Confirm Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password2"
|
||||||
|
value={password2}
|
||||||
|
onChange={(e) => setPassword2(e.target.value)}
|
||||||
|
/>
|
||||||
|
<label htmlFor="role">Role</label>
|
||||||
|
<select value={role} onChange={(e) => setRole(e.target.value)}>
|
||||||
|
<option value="">Select a role</option>
|
||||||
|
<option value="2">User</option>
|
||||||
|
<option value="1">Admin</option>
|
||||||
|
</select>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
if (!username || !password || !password2 || !role) {
|
||||||
|
alert("Please fill out all fields");
|
||||||
|
} else if (password !== password2) {
|
||||||
|
alert("Passwords do not match");
|
||||||
|
} else {
|
||||||
|
fetch("/api/v1/register", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
role: parseInt(role),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
alert(data.error);
|
||||||
|
} else {
|
||||||
|
props.setUser(data.user);
|
||||||
|
navigate("/login");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Register;
|
||||||
16
web/src/component/UserStatus.js
Normal file
16
web/src/component/UserStatus.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
function UserStatus(props) {
|
||||||
|
// props.user
|
||||||
|
// props.setUser
|
||||||
|
useEffect(() => {
|
||||||
|
fetch("/api/v1/login")
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
props.setUser(data.user);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
return <div>{props.user.username}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserStatus;
|
||||||
Reference in New Issue
Block a user