2023-03-23 10:29:55 +01:00
|
|
|
import axios from 'axios'
|
2023-05-17 17:32:19 +02:00
|
|
|
import { freeSewingConfig } from 'shared/config/freesewing.config.mjs'
|
2023-08-14 19:16:47 +02:00
|
|
|
import { useAccount } from 'shared/hooks/use-account.mjs'
|
2023-07-06 07:26:39 -05:00
|
|
|
import { useMemo } from 'react'
|
2023-03-23 10:29:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper methods to interact with the FreeSewing backend
|
|
|
|
*/
|
|
|
|
const apiHandler = axios.create({
|
2023-05-17 17:32:19 +02:00
|
|
|
baseURL: freeSewingConfig.backend,
|
2023-08-15 17:32:47 +02:00
|
|
|
timeout: 6660,
|
2023-03-23 10:29:55 +01:00
|
|
|
})
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const auth = (token) => (token ? { headers: { Authorization: 'Bearer ' + token } } : {})
|
|
|
|
|
2023-03-23 10:29:55 +01:00
|
|
|
/*
|
|
|
|
* This api object handles async code for different HTTP methods
|
|
|
|
*/
|
|
|
|
const api = {
|
|
|
|
get: async (uri, config = {}) => {
|
|
|
|
let result
|
|
|
|
try {
|
|
|
|
result = await apiHandler.get(uri, config)
|
|
|
|
return result
|
|
|
|
} catch (err) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
},
|
|
|
|
post: async (uri, data = null, config = {}) => {
|
|
|
|
let result
|
|
|
|
try {
|
|
|
|
result = await apiHandler.post(uri, data, config)
|
|
|
|
return result
|
|
|
|
} catch (err) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
},
|
|
|
|
patch: async (uri, data = null, config = {}) => {
|
|
|
|
let result
|
|
|
|
try {
|
|
|
|
result = await apiHandler.patch(uri, data, config)
|
|
|
|
return result
|
|
|
|
} catch (err) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
},
|
|
|
|
delete: async (uri, config = {}) => {
|
|
|
|
let result
|
|
|
|
try {
|
|
|
|
result = await apiHandler.delete(uri, config)
|
|
|
|
return result
|
|
|
|
} catch (err) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper method to handle the response and verify that it was successful
|
|
|
|
*/
|
|
|
|
const responseHandler = (response, expectedStatus = 200, expectData = true) => {
|
|
|
|
if (response && response.status === expectedStatus) {
|
|
|
|
if (!expectData || response.data) {
|
2023-03-24 16:33:14 +01:00
|
|
|
return { success: true, data: response.data, response }
|
2023-03-23 10:29:55 +01:00
|
|
|
}
|
2023-03-24 16:33:14 +01:00
|
|
|
return { success: true, response }
|
2023-03-23 10:29:55 +01:00
|
|
|
}
|
|
|
|
|
2023-03-24 16:33:14 +01:00
|
|
|
return { success: false, response }
|
2023-03-23 10:29:55 +01:00
|
|
|
}
|
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
function Backend(auth) {
|
|
|
|
this.auth = auth
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* backend.signUp: User signup
|
|
|
|
*/
|
|
|
|
Backend.prototype.signUp = async function ({ email, language }) {
|
|
|
|
return responseHandler(await api.post('/signup', { email, language }), 201)
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Backend.prototype.loadConfirmation: Load a confirmation
|
|
|
|
*/
|
|
|
|
Backend.prototype.loadConfirmation = async function ({ id, check }) {
|
|
|
|
return responseHandler(await api.get(`/confirmations/${id}/${check}`))
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Backend.prototype.confirmSignup: Confirm a signup
|
|
|
|
*/
|
|
|
|
Backend.prototype.confirmSignup = async function ({ id, consent }) {
|
|
|
|
return responseHandler(await api.post(`/confirm/signup/${id}`, { consent }))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Backend.prototype.signIn: User signin/login
|
|
|
|
*/
|
|
|
|
Backend.prototype.signIn = async function ({ username, password = false, token = false }) {
|
|
|
|
return password === false
|
|
|
|
? responseHandler(await api.post('/signinlink', { username }))
|
|
|
|
: responseHandler(await api.post('/signin', { username, password, token }))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Backend.prototype.signInFromLink: Trade in sign-in link id & check for JWT token
|
|
|
|
*/
|
|
|
|
Backend.prototype.signInFromLink = async function ({ id, check }) {
|
|
|
|
return responseHandler(await api.post(`/signinlink/${id}/${check}`))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Generic update account method
|
|
|
|
*/
|
|
|
|
Backend.prototype.updateAccount = async function (data) {
|
|
|
|
return responseHandler(await api.patch(`/account/jwt`, data, this.auth))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Checks whether a username is available
|
|
|
|
*/
|
|
|
|
Backend.prototype.isUsernameAvailable = async function (username) {
|
|
|
|
const response = await api.post(`/available/username/jwt`, { username }, this.auth)
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
// 404 means username is available, which is success in this case
|
|
|
|
return response.status === 404
|
|
|
|
? { success: true, data: false, available: true, response }
|
|
|
|
: { success: false, available: false, response }
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Remove account method
|
|
|
|
*/
|
|
|
|
Backend.prototype.removeAccount = async function () {
|
|
|
|
return responseHandler(await api.delete(`/account/jwt`, this.auth))
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Enable MFA
|
|
|
|
*/
|
|
|
|
Backend.prototype.enableMfa = async function () {
|
|
|
|
return responseHandler(await api.post(`/account/mfa/jwt`, { mfa: true }, this.auth))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Confirm MFA
|
|
|
|
*/
|
|
|
|
Backend.prototype.confirmMfa = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/account/mfa/jwt`, { ...data, mfa: true }, this.auth))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Disable MFA
|
|
|
|
*/
|
|
|
|
Backend.prototype.disableMfa = async function (data) {
|
|
|
|
return responseHandler(
|
|
|
|
await await api.post(`/account/mfa/jwt`, { ...data, mfa: false }, this.auth)
|
|
|
|
)
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Reload account
|
|
|
|
*/
|
|
|
|
Backend.prototype.reloadAccount = async function () {
|
|
|
|
return responseHandler(await await api.get(`/whoami/jwt`, this.auth))
|
|
|
|
}
|
2023-08-16 15:54:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Load user profile
|
|
|
|
*/
|
|
|
|
Backend.prototype.getProfile = async function (uid) {
|
|
|
|
return responseHandler(await await api.get(`/users/${uid}`))
|
|
|
|
}
|
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Create API key
|
|
|
|
*/
|
|
|
|
Backend.prototype.createApikey = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/apikeys/jwt`, data, this.auth), 201)
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get API keys
|
|
|
|
*/
|
|
|
|
Backend.prototype.getApikeys = async function () {
|
|
|
|
return responseHandler(await api.get(`/apikeys/jwt`, this.auth))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Remove API key
|
|
|
|
*/
|
|
|
|
Backend.prototype.removeApikey = async function (id) {
|
|
|
|
const response = await api.delete(`/apikeys/${id}/jwt`, this.auth)
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
return response && response.status === 204 ? true : false
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get measurements sets
|
|
|
|
*/
|
|
|
|
Backend.prototype.getSets = async function () {
|
|
|
|
return responseHandler(await api.get(`/sets/jwt`, this.auth))
|
|
|
|
}
|
2023-03-23 10:29:55 +01:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get measurements set
|
|
|
|
*/
|
|
|
|
Backend.prototype.getSet = async function (id) {
|
|
|
|
return responseHandler(await api.get(`/sets/${id}/jwt`, this.auth))
|
|
|
|
}
|
2023-04-22 16:41:13 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Create measurements set
|
|
|
|
*/
|
|
|
|
Backend.prototype.createSet = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/sets/jwt`, data, this.auth), 201)
|
|
|
|
}
|
2023-05-18 11:48:17 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Remove measurements set
|
|
|
|
*/
|
|
|
|
Backend.prototype.removeSet = async function (id) {
|
|
|
|
const response = await api.delete(`/sets/${id}/jwt`, this.auth)
|
2023-04-22 16:41:13 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
return response && response.status === 204 ? true : false
|
|
|
|
}
|
2023-04-29 08:29:12 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Generic update measurements set method
|
|
|
|
*/
|
|
|
|
Backend.prototype.updateSet = async function (id, data) {
|
|
|
|
return responseHandler(await api.patch(`/sets/${id}/jwt`, data, this.auth))
|
|
|
|
}
|
2023-04-29 08:29:12 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get curated measurements sets
|
|
|
|
*/
|
|
|
|
Backend.prototype.getCuratedSets = async function () {
|
|
|
|
return responseHandler(await api.get(`/curated-sets`))
|
|
|
|
}
|
2023-04-23 18:00:52 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get curated measurements set
|
|
|
|
*/
|
|
|
|
Backend.prototype.getCuratedSet = async function (id) {
|
|
|
|
return responseHandler(await api.get(`/curated-sets/${id}`))
|
|
|
|
}
|
2023-05-08 09:31:37 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Remove curated measurements set
|
|
|
|
*/
|
|
|
|
Backend.prototype.removeCuratedMeasurementsSet = async function (id) {
|
|
|
|
const response = await api.delete(`/curated-sets/${id}/jwt`, this.auth)
|
2023-05-08 14:03:47 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
return response && response.status === 204 ? true : false
|
|
|
|
}
|
2023-05-08 09:31:37 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get pattern
|
|
|
|
*/
|
|
|
|
Backend.prototype.getPattern = async function (id) {
|
|
|
|
return responseHandler(await api.get(`/patterns/${id}/jwt`, this.auth))
|
|
|
|
}
|
2023-05-08 09:31:37 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Get patterns
|
|
|
|
*/
|
|
|
|
Backend.prototype.getPatterns = async function () {
|
|
|
|
return responseHandler(await api.get(`/patterns/jwt`, this.auth))
|
|
|
|
}
|
2023-05-30 16:53:23 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Create pattern
|
|
|
|
*/
|
|
|
|
Backend.prototype.createPattern = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/patterns/jwt`, data, this.auth), 201)
|
|
|
|
}
|
2023-05-26 17:24:25 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Remove pattern
|
|
|
|
*/
|
|
|
|
Backend.prototype.removePattern = async function (id) {
|
|
|
|
const response = await api.delete(`/patterns/${id}/jwt`, this.auth)
|
2023-05-26 15:54:43 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
return response && response.status === 204 ? true : false
|
|
|
|
}
|
2023-05-26 17:24:25 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Generic update pattern set method
|
|
|
|
*/
|
|
|
|
Backend.prototype.updatePattern = async function (id, data) {
|
|
|
|
return responseHandler(await api.patch(`/patterns/${id}/jwt`, data, this.auth))
|
|
|
|
}
|
2023-05-26 17:24:25 +02:00
|
|
|
|
2023-07-06 07:26:39 -05:00
|
|
|
/*
|
|
|
|
* Create GitHub issue
|
|
|
|
*/
|
|
|
|
Backend.prototype.createIssue = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/issues`, data), 201)
|
|
|
|
}
|
2023-05-26 17:24:25 +02:00
|
|
|
|
2023-08-16 15:54:32 +02:00
|
|
|
/*
|
|
|
|
* Create showcase Pull Request
|
|
|
|
*/
|
|
|
|
Backend.prototype.createShowcasePr = async function (data) {
|
2023-08-17 17:05:08 +02:00
|
|
|
return responseHandler(await api.post(`/flows/pr/showcase/jwt`, data, this.auth))
|
2023-08-16 15:54:32 +02:00
|
|
|
}
|
2023-07-09 18:50:13 +02:00
|
|
|
/*
|
|
|
|
* Send translation invite
|
|
|
|
*/
|
|
|
|
Backend.prototype.sendTranslatorInvite = async function (language) {
|
|
|
|
return responseHandler(await api.post(`/flows/translator-invite/jwt`, { language }, this.auth))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send language suggestion
|
|
|
|
*/
|
|
|
|
Backend.prototype.sendLanguageSuggestion = async function (data) {
|
|
|
|
return responseHandler(await api.post(`/flows/language-suggestion/jwt`, data, this.auth))
|
|
|
|
}
|
|
|
|
|
2023-07-31 09:03:55 +02:00
|
|
|
/*
|
2023-08-05 18:42:52 +02:00
|
|
|
* Confirm newsletter subscribe
|
2023-07-31 09:03:55 +02:00
|
|
|
*/
|
2023-08-05 18:42:52 +02:00
|
|
|
Backend.prototype.confirmNewsletterSubscribe = async function ({ id, ehash }) {
|
|
|
|
return responseHandler(await api.put('/subscriber', { id, ehash }))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Confirm newsletter unsubscribe
|
|
|
|
*/
|
|
|
|
Backend.prototype.confirmNewsletterUnsubscribe = async function ({ id, ehash }) {
|
|
|
|
return responseHandler(await api.delete('/subscriber', { id, ehash }))
|
2023-07-31 09:03:55 +02:00
|
|
|
}
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
/*
|
|
|
|
* Upload an image
|
|
|
|
*/
|
|
|
|
Backend.prototype.uploadImage = async function (body) {
|
|
|
|
return responseHandler(await api.post('/images/jwt', body, this.auth))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove an (uploaded) image
|
|
|
|
*/
|
|
|
|
Backend.prototype.removeImage = async function (id) {
|
|
|
|
return responseHandler(await api.delete(`/images/${id}/jwt`, this.auth))
|
|
|
|
}
|
|
|
|
|
2023-08-17 17:05:08 +02:00
|
|
|
/*
|
|
|
|
* Ping backend to see if current token is still valid
|
|
|
|
*/
|
|
|
|
Backend.prototype.ping = async function () {
|
|
|
|
return responseHandler(await api.get(`/whoami/jwt`, this.auth))
|
|
|
|
}
|
|
|
|
|
2023-08-14 19:16:47 +02:00
|
|
|
/*
|
|
|
|
* Search user (admin method)
|
|
|
|
*/
|
|
|
|
Backend.prototype.adminSearchUsers = async function (q) {
|
|
|
|
return responseHandler(await api.post('/admin/search/users/jwt', { q }, this.auth))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load user (admin method)
|
|
|
|
*/
|
|
|
|
Backend.prototype.adminLoadUser = async function (id) {
|
|
|
|
return responseHandler(await api.get(`/admin/user/${id}/jwt`, this.auth))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update user (admin method)
|
|
|
|
*/
|
|
|
|
Backend.prototype.adminUpdateUser = async function ({ id, data }) {
|
|
|
|
return responseHandler(await api.patch(`/admin/user/${id}/jwt`, data, this.auth))
|
|
|
|
}
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
/*
|
|
|
|
* Impersonate user (admin method)
|
|
|
|
*/
|
|
|
|
Backend.prototype.adminImpersonateUser = async function (id) {
|
|
|
|
return responseHandler(await api.get(`/admin/impersonate/${id}/jwt`, this.auth))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify an admin account while impersonating another user
|
|
|
|
*/
|
|
|
|
Backend.prototype.adminPing = async function (token) {
|
|
|
|
return responseHandler(await api.get(`/whoami/jwt`, auth(token)))
|
|
|
|
}
|
|
|
|
|
2023-08-14 19:16:47 +02:00
|
|
|
export function useBackend() {
|
|
|
|
const { token } = useAccount()
|
|
|
|
|
2023-05-30 16:53:23 +02:00
|
|
|
/*
|
2023-07-06 07:26:39 -05:00
|
|
|
* This backend object is what we'll end up returning
|
2023-05-30 16:53:23 +02:00
|
|
|
*/
|
2023-08-15 17:32:47 +02:00
|
|
|
const backend = useMemo(() => new Backend(auth(token)), [token])
|
2023-05-30 16:53:23 +02:00
|
|
|
|
2023-03-23 10:29:55 +01:00
|
|
|
return backend
|
|
|
|
}
|