Account API endpoint fixes

pull/584/head
binwiederhier 2022-12-28 15:51:09 -05:00
parent f79348817f
commit 7ca9afad57
7 changed files with 15 additions and 13 deletions

View File

@ -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
} }

View File

@ -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)

View File

@ -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()

View File

@ -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())

View File

@ -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();

View File

@ -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);

View File

@ -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);
} }