Account API endpoint fixes
parent
f79348817f
commit
7ca9afad57
|
@ -22,7 +22,6 @@ type fileCache struct {
|
||||||
dir string
|
dir string
|
||||||
totalSizeCurrent int64
|
totalSizeCurrent int64
|
||||||
totalSizeLimit int64
|
totalSizeLimit int64
|
||||||
fileSizeLimit int64
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,14 +50,11 @@ import (
|
||||||
- figure out what settings are "web" or "phone"
|
- figure out what settings are "web" or "phone"
|
||||||
UI:
|
UI:
|
||||||
- Subscription dotmenu dropdown: Move to nav bar, or make same as profile dropdown
|
- Subscription dotmenu dropdown: Move to nav bar, or make same as profile dropdown
|
||||||
- "Logout and delete local storage" option
|
|
||||||
- Delete local storage when deleting account
|
|
||||||
Pages:
|
Pages:
|
||||||
- Home
|
- Home
|
||||||
- Password reset
|
- Password reset
|
||||||
- Pricing
|
- Pricing
|
||||||
- change email
|
- change email
|
||||||
-
|
|
||||||
Polishing:
|
Polishing:
|
||||||
aria-label for everything
|
aria-label for everything
|
||||||
Tests:
|
Tests:
|
||||||
|
@ -345,6 +342,8 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit
|
||||||
return s.handleHealth(w, r, v)
|
return s.handleHealth(w, r, v)
|
||||||
} else if r.Method == http.MethodGet && r.URL.Path == webConfigPath {
|
} else if r.Method == http.MethodGet && r.URL.Path == webConfigPath {
|
||||||
return s.ensureWebEnabled(s.handleWebConfig)(w, r, v)
|
return s.ensureWebEnabled(s.handleWebConfig)(w, r, v)
|
||||||
|
} else if r.Method == http.MethodPost && r.URL.Path == accountTokenPath {
|
||||||
|
return s.ensureAccountsEnabled(s.handleAccountTokenIssue)(w, r, v)
|
||||||
} else if r.Method == http.MethodPost && r.URL.Path == accountPath {
|
} else if r.Method == http.MethodPost && r.URL.Path == accountPath {
|
||||||
return s.ensureAccountsEnabled(s.handleAccountCreate)(w, r, v)
|
return s.ensureAccountsEnabled(s.handleAccountCreate)(w, r, v)
|
||||||
} else if r.Method == http.MethodGet && r.URL.Path == accountPath {
|
} else if r.Method == http.MethodGet && r.URL.Path == accountPath {
|
||||||
|
@ -353,8 +352,6 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit
|
||||||
return s.ensureWithAccount(s.handleAccountDelete)(w, r, v)
|
return s.ensureWithAccount(s.handleAccountDelete)(w, r, v)
|
||||||
} else if r.Method == http.MethodPost && r.URL.Path == accountPasswordPath {
|
} else if r.Method == http.MethodPost && r.URL.Path == accountPasswordPath {
|
||||||
return s.ensureWithAccount(s.handleAccountPasswordChange)(w, r, v)
|
return s.ensureWithAccount(s.handleAccountPasswordChange)(w, r, v)
|
||||||
} else if r.Method == http.MethodPost && r.URL.Path == accountTokenPath {
|
|
||||||
return s.ensureWithAccount(s.handleAccountTokenIssue)(w, r, v)
|
|
||||||
} else if r.Method == http.MethodPatch && r.URL.Path == accountTokenPath {
|
} else if r.Method == http.MethodPatch && r.URL.Path == accountTokenPath {
|
||||||
return s.ensureWithAccount(s.handleAccountTokenExtend)(w, r, v)
|
return s.ensureWithAccount(s.handleAccountTokenExtend)(w, r, v)
|
||||||
} else if r.Method == http.MethodDelete && r.URL.Path == accountTokenPath {
|
} else if r.Method == http.MethodDelete && r.URL.Path == accountTokenPath {
|
||||||
|
@ -1408,7 +1405,7 @@ func (s *Server) ensureWebEnabled(next handleFunc) handleFunc {
|
||||||
|
|
||||||
func (s *Server) ensureAccountsEnabled(next handleFunc) handleFunc {
|
func (s *Server) ensureAccountsEnabled(next handleFunc) handleFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
return func(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||||
if s.userManager != nil {
|
if s.userManager == nil {
|
||||||
return errHTTPNotFound
|
return errHTTPNotFound
|
||||||
}
|
}
|
||||||
return next(w, r, v)
|
return next(w, r, v)
|
||||||
|
@ -1417,7 +1414,7 @@ func (s *Server) ensureAccountsEnabled(next handleFunc) handleFunc {
|
||||||
|
|
||||||
func (s *Server) ensureWithAccount(next handleFunc) handleFunc {
|
func (s *Server) ensureWithAccount(next handleFunc) handleFunc {
|
||||||
return s.ensureAccountsEnabled(func(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
return s.ensureAccountsEnabled(func(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||||
if v.user != nil {
|
if v.user == nil {
|
||||||
return errHTTPNotFound
|
return errHTTPNotFound
|
||||||
}
|
}
|
||||||
return next(w, r, v)
|
return next(w, r, v)
|
||||||
|
|
|
@ -243,6 +243,7 @@ func (a *Manager) RemoveExpiredTokens() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeSettings persists the user settings
|
||||||
func (a *Manager) ChangeSettings(user *User) error {
|
func (a *Manager) ChangeSettings(user *User) error {
|
||||||
settings, err := json.Marshal(user.Prefs)
|
settings, err := json.Marshal(user.Prefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -254,6 +255,8 @@ func (a *Manager) ChangeSettings(user *User) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnqueueStats adds the user to a queue which writes out user stats (messages, emails, ..) in
|
||||||
|
// batches at a regular interval
|
||||||
func (a *Manager) EnqueueStats(user *User) {
|
func (a *Manager) EnqueueStats(user *User) {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
defer a.mu.Unlock()
|
defer a.mu.Unlock()
|
||||||
|
|
|
@ -244,6 +244,7 @@ func TestManager_Token_Valid(t *testing.T) {
|
||||||
|
|
||||||
// Create token for user
|
// Create token for user
|
||||||
token, err := a.CreateToken(u)
|
token, err := a.CreateToken(u)
|
||||||
|
require.Nil(t, err)
|
||||||
require.NotEmpty(t, token.Value)
|
require.NotEmpty(t, token.Value)
|
||||||
require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires.Unix())
|
require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires.Unix())
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,12 @@ class AccountApi {
|
||||||
return json.token;
|
return json.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
async logout(token) {
|
async logout() {
|
||||||
const url = accountTokenUrl(config.baseUrl);
|
const url = accountTokenUrl(config.baseUrl);
|
||||||
console.log(`[AccountApi] Logging out from ${url} using token ${token}`);
|
console.log(`[AccountApi] Logging out from ${url} using token ${session.token()}`);
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: withBearerAuth({}, token)
|
headers: withBearerAuth({}, session.token())
|
||||||
});
|
});
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
throw new UnauthorizedError();
|
throw new UnauthorizedError();
|
||||||
|
|
|
@ -57,7 +57,7 @@ const Stats = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { account } = useOutletContext();
|
const { account } = useOutletContext();
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return <></>; // TODO loading
|
return <></>;
|
||||||
}
|
}
|
||||||
const accountType = account.plan.code ?? "none";
|
const accountType = account.plan.code ?? "none";
|
||||||
const normalize = (value, max) => (value / max * 100);
|
const normalize = (value, max) => (value / max * 100);
|
||||||
|
@ -234,9 +234,9 @@ const DeleteAccount = () => {
|
||||||
const handleDialogSubmit = async (newPassword) => {
|
const handleDialogSubmit = async (newPassword) => {
|
||||||
try {
|
try {
|
||||||
await accountApi.delete();
|
await accountApi.delete();
|
||||||
|
await db.delete();
|
||||||
setDialogOpen(false);
|
setDialogOpen(false);
|
||||||
console.debug(`[Account] Account deleted`);
|
console.debug(`[Account] Account deleted`);
|
||||||
// TODO delete local storage
|
|
||||||
session.resetAndRedirect(routes.app);
|
session.resetAndRedirect(routes.app);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`[Account] Error deleting account`, e);
|
console.log(`[Account] Error deleting account`, e);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as React from "react";
|
||||||
import {useEffect, useRef, useState} from "react";
|
import {useEffect, useRef, useState} from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import {formatShortDateTime, shuffle, topicDisplayName} from "../app/utils";
|
import {formatShortDateTime, shuffle, topicDisplayName} from "../app/utils";
|
||||||
|
import db from "../app/db";
|
||||||
import {useLocation, useNavigate} from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
||||||
import Grow from '@mui/material/Grow';
|
import Grow from '@mui/material/Grow';
|
||||||
|
@ -270,6 +271,7 @@ const ProfileIcon = (props) => {
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await accountApi.logout();
|
await accountApi.logout();
|
||||||
|
await db.delete();
|
||||||
} finally {
|
} finally {
|
||||||
session.resetAndRedirect(routes.app);
|
session.resetAndRedirect(routes.app);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue