adding login reset

This commit is contained in:
Roland Osborne 2022-05-31 15:29:04 -07:00
parent c8030d27e6
commit c144356252
8 changed files with 169 additions and 7 deletions

View File

@ -68,6 +68,8 @@ func AddChannelTopicAsset(w http.ResponseWriter, r *http.Request) {
garbageSync.Lock()
defer garbageSync.Unlock()
PrintMsg("SAVE NEW ASSET");
// save new file
id := uuid.New().String()
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + channelSlot.Account.Guid + "/" + id

View File

@ -0,0 +1,46 @@
package databag
import (
"net/http"
"gorm.io/gorm"
"databag/internal/store"
)
func SetAccountLogin(w http.ResponseWriter, r *http.Request) {
account, code, err := ParamAgentToken(r, true);
if err != nil {
ErrResponse(w, code, err)
return
}
username, password, ret := BasicCredentials(r);
if ret != nil {
ErrResponse(w, http.StatusUnauthorized, ret)
return
}
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(&account).Update("account_revision", account.AccountRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("profile_revision", account.AccountRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("Username", username).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("Password", password).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, nil)
}

View File

@ -165,6 +165,13 @@ var routes = Routes{
SetAccountNode,
},
Route{
"SetAccountLogin",
strings.ToUpper("Put"),
"/account/login",
SetAccountLogin,
},
Route{
"SetAccountSerchable",
strings.ToUpper("Put"),

View File

@ -1,13 +1,14 @@
import { Avatar, Image } from 'antd';
import React from 'react'
import { Avatar, Space, Image, Modal, Form, Input } from 'antd';
import React, { useState } from 'react'
import { IdentityWrapper, IdentityDropdown, MenuWrapper } from './Identity.styled';
import { RightOutlined, EditOutlined, UserOutlined } from '@ant-design/icons';
import { RightOutlined, EditOutlined, UserOutlined, LockOutlined } from '@ant-design/icons';
import { useIdentity } from './useIdentity.hook';
import { Menu, Dropdown } from 'antd';
import { Logo } from '../../../Logo/Logo';
export function Identity() {
const [ showLogin, setShowLogin ] = useState(false);
const { state, actions } = useIdentity()
const menu = (
@ -16,7 +17,7 @@ export function Identity() {
<div onClick={() => actions.editProfile()}>Edit Profile</div>
</Menu.Item>
<Menu.Item key="1">
<div>Change Login</div>
<div onClick={() => setShowLogin(true)}>Change Login</div>
</Menu.Item>
<Menu.Item key="2">
<div onClick={() => actions.logout()}>Sign Out</div>
@ -24,6 +25,11 @@ export function Identity() {
</MenuWrapper>
);
const onChangeLogin = () => {
let saved = actions.setLogin();
setShowLogin(false);
};
return (
<IdentityWrapper>
<IdentityDropdown overlay={menu} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="rightTop">
@ -38,6 +44,23 @@ export function Identity() {
<RightOutlined />
</div>
</IdentityDropdown>
<Modal title="Change Login" visible={showLogin} centered okText="Save"
onOk={() => onChangeLogin()} onCancel={() => setShowLogin(false)}>
<Space direction="vertical" style={{ width: '100%' }}>
<Input size="large" spelleCheck="false" placeholder="Username" prefix={<UserOutlined />}
onChange={(e) => actions.setUsername(e.target.value)} defaultValue={state.handle}
addonAfter={state.usernameStatus} />
<Input.Password size="large" spelleCheck="false" placeholder="Password" prefix={<LockOutlined />}
onChange={(e) => actions.setPassword(e.target.value)}
addonAfter={state.passwordStatus} />
<Input.Password size="large" spelleCheck="false" placeholder="Confirm Password" prefix={<LockOutlined />}
onChange={(e) => actions.setConfirm(e.target.value)}
addonAfter={state.confirmStatus} />
</Space>
</Modal>
</IdentityWrapper>
)
}

View File

@ -1,7 +1,9 @@
import { useContext, useState, useEffect } from 'react';
import { useContext, useState, useRef, useEffect } from 'react';
import { AppContext } from 'context/AppContext';
import { ProfileContext } from 'context/ProfileContext';
import { AccountContext } from 'context/AccountContext';
import { useNavigate } from "react-router-dom";
import { getUsername } from 'api/getUsername';
export function useIdentity() {
@ -11,11 +13,21 @@ export function useIdentity() {
domain: '',
imageUrl: null,
image: null,
username: null,
usernameStatus: null,
password: null,
passwordStatus: null,
confirm: null,
confirmStatus: null,
});
const navigate = useNavigate();
const profile = useContext(ProfileContext);
const account = useContext(AccountContext);
const app = useContext(AppContext);
const debounce = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
@ -31,7 +43,56 @@ export function useIdentity() {
},
editProfile: () => {
navigate('/user/profile');
}
},
setUsername: (value) => {
if (debounce.current) {
clearTimeout(debounce.current);
}
updateState({ username: value });
if (state.handle.toLowerCase() == value.toLowerCase() || value == null || value == '') {
updateState({ usernameStatus: null });
return;
}
debounce.current = setTimeout(async () => {
let available = await getUsername(value);
if (available) {
updateState({ usernameStatus: null });
}
else {
updateState({ usernameStatus: 'not available' });
}
}, 500);
},
setPassword: (value) => {
updateState({ password: value });
},
setConfirm: (value) => {
updateState({ confirm: value });
},
setLogin: async () => {
if (state.username == null || state.username == '') {
updateState({ usernameStatus: 'username required' });
throw 'username required';
}
else {
updateState({ usernameStatus: null });
}
if (state.password == null || state.password == '') {
updateState({ passwordStatus: 'password required' });
throw 'password required';
}
else {
updateState({ passwordStatus: null });
}
if (state.confirm != state.password) {
updateState({ confirmStatus: 'password mismatch' });
throw 'password mismatch';
}
else {
updateState({ confirmStatus: null });
}
await account.actions.setLogin(state.username, state.password);
},
};
useEffect(() => {
@ -47,6 +108,7 @@ export function useIdentity() {
updateState({ image: identity.image });
updateState({ name: identity.name });
updateState({ handle: identity.handle });
updateState({ username: identity.handle });
updateState({ domain: identity.node });
}
}, [profile])

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getUsername(name) {
let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name), { method: 'GET' })
checkResponse(available)
return await available.json()
}

View File

@ -0,0 +1,10 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
var base64 = require('base-64');
export async function setAccountLogin(token, username, password) {
let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let res = await fetchWithTimeout(`/account/login?agent=${token}`, { method: 'PUT', headers })
checkResponse(res);
}

View File

@ -1,6 +1,7 @@
import { useEffect, useState, useRef } from 'react';
import { setAccountSearchable } from 'api/setAccountSearchable';
import { getAccountStatus } from 'api/getAccountStatus';
import { setAccountLogin } from 'api/setAccountLogin';
export function useAccountContext() {
const [state, setState] = useState({
@ -47,6 +48,9 @@ export function useAccountContext() {
setSearchable: async (flag) => {
await setAccountSearchable(access.current, flag);
},
setLogin: async (username, password) => {
await setAccountLogin(access.current, username, password);
},
}
return { state, actions }