[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

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. // authentication.ts
  2. // Copyright (C) 2020 Dwayne Harris
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License for more details.
  11. // You should have received a copy of the GNU General Public License
  12. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. import { Action } from 'redux'
  14. import { apiFetch } from '../api'
  15. import { setEntities } from '../actions/entities'
  16. import { startRequest, finishRequest } from '../actions/requests'
  17. import { normalize } from '../utils/normalization'
  18. import {
  19. LOCAL_STORAGE_ACCESS_TOKEN_KEY,
  20. LOCAL_STORAGE_REFRESH_TOKEN_KEY,
  21. LOCAL_STORAGE_ACCESS_TOKEN_EXPIRES_AT_KEY,
  22. } from '../constants'
  23. import { AppThunkAction, Entity, RequestKey, EntityType, Settings } from '../types'
  24. export interface SetCheckedAction extends Action {
  25. type: 'AUTHENTICATION_SET_CHECKED'
  26. }
  27. export interface SetAuthenticatedAction extends Action {
  28. type: 'AUTHENTICATION_SET_AUTHENTICATED'
  29. payload: boolean
  30. }
  31. export interface SetUserAction extends Action {
  32. type: 'AUTHENTICATION_SET_USER'
  33. payload: string
  34. }
  35. export interface UnauthenticateAction extends Action {
  36. type: 'AUTHENTICATION_UNAUTHENTICATE'
  37. }
  38. export type AuthenticationActions = SetCheckedAction | SetAuthenticatedAction | SetUserAction | UnauthenticateAction
  39. export const setChecked = (): SetCheckedAction => ({
  40. type: 'AUTHENTICATION_SET_CHECKED',
  41. })
  42. export const setAuthenticated = (authenticated: boolean): SetAuthenticatedAction => ({
  43. type: 'AUTHENTICATION_SET_AUTHENTICATED',
  44. payload: authenticated,
  45. })
  46. export const setUser = (userId: string): SetUserAction => ({
  47. type: 'AUTHENTICATION_SET_USER',
  48. payload: userId,
  49. })
  50. export const unauthenticate = (): UnauthenticateAction => ({
  51. type: 'AUTHENTICATION_UNAUTHENTICATE',
  52. })
  53. export const fetchSelf = (): AppThunkAction => async dispatch => {
  54. dispatch(startRequest(RequestKey.FetchSelf))
  55. try {
  56. const self = await apiFetch<Entity>({
  57. path: '/v1/self',
  58. })
  59. const result = normalize([self], EntityType.User)
  60. dispatch(setEntities(result.entities))
  61. dispatch(setUser(self.id))
  62. dispatch(setAuthenticated(true))
  63. dispatch(finishRequest(RequestKey.FetchSelf, true))
  64. } catch (err) {
  65. dispatch(setAuthenticated(false))
  66. dispatch(finishRequest(RequestKey.FetchSelf, false))
  67. throw err
  68. }
  69. }
  70. interface AuthenticateResponse {
  71. id: string
  72. access: string
  73. refresh: string
  74. expires: number
  75. }
  76. export const authenticate = (name: string, password: string): AppThunkAction<string> => async dispatch => {
  77. dispatch(startRequest(RequestKey.Authenticate))
  78. try {
  79. const response = await apiFetch<AuthenticateResponse>({
  80. path: '/v1/authenticate',
  81. method: 'post',
  82. body: {
  83. id: name,
  84. password,
  85. },
  86. })
  87. localStorage.setItem(LOCAL_STORAGE_ACCESS_TOKEN_KEY, response.access)
  88. localStorage.setItem(LOCAL_STORAGE_REFRESH_TOKEN_KEY, response.refresh)
  89. if (response.expires) localStorage.setItem(LOCAL_STORAGE_ACCESS_TOKEN_EXPIRES_AT_KEY, response.expires.toString())
  90. dispatch(finishRequest(RequestKey.Authenticate, true))
  91. await dispatch(fetchSelf())
  92. return response.id
  93. } catch (err) {
  94. dispatch(finishRequest(RequestKey.Authenticate, false))
  95. throw err
  96. }
  97. }
  98. interface UpdateSelfOptions {
  99. name: string
  100. about: string
  101. requiresApproval: boolean
  102. privacy: string
  103. imageUrl: string
  104. coverImageUrl: string
  105. theme: string
  106. settings: Settings
  107. }
  108. export const updateSelf = (options: UpdateSelfOptions): AppThunkAction => async dispatch => {
  109. const { name, about, requiresApproval, privacy, imageUrl, coverImageUrl, theme, settings } = options
  110. dispatch(startRequest(RequestKey.UpdateSelf))
  111. try {
  112. const self = await apiFetch<Entity>({
  113. path: '/v1/self',
  114. method: 'put',
  115. body: {
  116. name,
  117. about,
  118. requiresApproval,
  119. privacy,
  120. imageUrl,
  121. coverImageUrl,
  122. theme,
  123. settings,
  124. },
  125. })
  126. const result = normalize([self], EntityType.User)
  127. dispatch(setEntities(result.entities))
  128. dispatch(setUser(self.id))
  129. dispatch(setAuthenticated(true))
  130. dispatch(finishRequest(RequestKey.UpdateSelf, true))
  131. } catch (err) {
  132. dispatch(finishRequest(RequestKey.UpdateSelf, false))
  133. throw err
  134. }
  135. }