[ABANDONED] React/Redux front end for the Flexor social network.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

168 lines
4.9 KiB

// authentication.ts
// Copyright (C) 2020 Dwayne Harris
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import { Action } from 'redux'
import { apiFetch } from '../api'
import { setEntities } from '../actions/entities'
import { startRequest, finishRequest } from '../actions/requests'
import { normalize } from '../utils/normalization'
import {
LOCAL_STORAGE_ACCESS_TOKEN_KEY,
LOCAL_STORAGE_REFRESH_TOKEN_KEY,
LOCAL_STORAGE_ACCESS_TOKEN_EXPIRES_AT_KEY,
} from '../constants'
import { AppThunkAction, Entity, RequestKey, EntityType, Settings } from '../types'
export interface SetCheckedAction extends Action {
type: 'AUTHENTICATION_SET_CHECKED'
}
export interface SetAuthenticatedAction extends Action {
type: 'AUTHENTICATION_SET_AUTHENTICATED'
payload: boolean
}
export interface SetUserAction extends Action {
type: 'AUTHENTICATION_SET_USER'
payload: string
}
export interface UnauthenticateAction extends Action {
type: 'AUTHENTICATION_UNAUTHENTICATE'
}
export type AuthenticationActions = SetCheckedAction | SetAuthenticatedAction | SetUserAction | UnauthenticateAction
export const setChecked = (): SetCheckedAction => ({
type: 'AUTHENTICATION_SET_CHECKED',
})
export const setAuthenticated = (authenticated: boolean): SetAuthenticatedAction => ({
type: 'AUTHENTICATION_SET_AUTHENTICATED',
payload: authenticated,
})
export const setUser = (userId: string): SetUserAction => ({
type: 'AUTHENTICATION_SET_USER',
payload: userId,
})
export const unauthenticate = (): UnauthenticateAction => ({
type: 'AUTHENTICATION_UNAUTHENTICATE',
})
export const fetchSelf = (): AppThunkAction => async dispatch => {
dispatch(startRequest(RequestKey.FetchSelf))
try {
const self = await apiFetch<Entity>({
path: '/v1/self',
})
const result = normalize([self], EntityType.User)
dispatch(setEntities(result.entities))
dispatch(setUser(self.id))
dispatch(setAuthenticated(true))
dispatch(finishRequest(RequestKey.FetchSelf, true))
} catch (err) {
dispatch(setAuthenticated(false))
dispatch(finishRequest(RequestKey.FetchSelf, false))
throw err
}
}
interface AuthenticateResponse {
id: string
access: string
refresh: string
expires: number
}
export const authenticate = (name: string, password: string): AppThunkAction<string> => async dispatch => {
dispatch(startRequest(RequestKey.Authenticate))
try {
const response = await apiFetch<AuthenticateResponse>({
path: '/v1/authenticate',
method: 'post',
body: {
id: name,
password,
},
})
localStorage.setItem(LOCAL_STORAGE_ACCESS_TOKEN_KEY, response.access)
localStorage.setItem(LOCAL_STORAGE_REFRESH_TOKEN_KEY, response.refresh)
if (response.expires) localStorage.setItem(LOCAL_STORAGE_ACCESS_TOKEN_EXPIRES_AT_KEY, response.expires.toString())
dispatch(finishRequest(RequestKey.Authenticate, true))
await dispatch(fetchSelf())
return response.id
} catch (err) {
dispatch(finishRequest(RequestKey.Authenticate, false))
throw err
}
}
interface UpdateSelfOptions {
name: string
about: string
requiresApproval: boolean
privacy: string
imageUrl: string
coverImageUrl: string
theme: string
settings: Settings
}
export const updateSelf = (options: UpdateSelfOptions): AppThunkAction => async dispatch => {
const { name, about, requiresApproval, privacy, imageUrl, coverImageUrl, theme, settings } = options
dispatch(startRequest(RequestKey.UpdateSelf))
try {
const self = await apiFetch<Entity>({
path: '/v1/self',
method: 'put',
body: {
name,
about,
requiresApproval,
privacy,
imageUrl,
coverImageUrl,
theme,
settings,
},
})
const result = normalize([self], EntityType.User)
dispatch(setEntities(result.entities))
dispatch(setUser(self.id))
dispatch(setAuthenticated(true))
dispatch(finishRequest(RequestKey.UpdateSelf, true))
} catch (err) {
dispatch(finishRequest(RequestKey.UpdateSelf, false))
throw err
}
}