mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Refactor post calls from lib/common/fetch in auth pages to data/fetchers (#36506)
* Deprecate use of getWithTimeout, refactor BuildingState and RestoringState to use RQ * Refactor profile-create-mutation to use data/fetchers, and edge-function-status-query to use fetch * Shift post from lib/common/fetch, refactor bucket-object-download-mutation * Address feedback * Minor fix * Refactor post calls from lib/common/fetch in auth pages to data/fetchers * Add missing POST users endpoint + small fix when deleting user via context menu * simplify handleFetchError * allow handleFetchError to accept unknown * non-breaking change --------- Co-authored-by: Alaister Young <a@alaisteryoung.com>
This commit is contained in:
1 parent
88dca021d6
commit
b9a0908331
13 files changed
+121
-393
No files matched your search
@@ -587,7 +587,10 @@ export const UsersV2 = () => {
|
||||
visible={!!selectedUserToDelete}
|
||||
selectedUser={selectedUserToDelete}
|
||||
onClose={() => setSelectedUserToDelete(undefined)}
|
||||
onDeleteSuccess={() => setSelectedUserToDelete(undefined)}
|
||||
onDeleteSuccess={() => {
|
||||
if (selectedUserToDelete?.id === selectedUser) setSelectedUser(undefined)
|
||||
setSelectedUserToDelete(undefined)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query'
|
||||
import type { components } from 'data/api'
|
||||
import { get, handleError } from 'data/fetchers'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useCallback } from 'react'
|
||||
import type { ResponseError } from 'types'
|
||||
import { authKeys } from './keys'
|
||||
@@ -40,7 +41,7 @@ export const useAuthConfigQuery = <TData = ProjectAuthConfigData>(
|
||||
authKeys.authConfig(projectRef),
|
||||
({ signal }) => getProjectAuthConfig({ projectRef }, signal),
|
||||
{
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined',
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -193,6 +193,39 @@ async function handleFetchResponse<T>(response: Response): Promise<T | ResponseE
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFetchError(response: unknown): Promise<ResponseError> {
|
||||
let resJson: any = {}
|
||||
|
||||
if (response instanceof Error) {
|
||||
resJson = response
|
||||
}
|
||||
|
||||
if (response instanceof Response) {
|
||||
resJson = await response.json()
|
||||
}
|
||||
|
||||
const status = response instanceof Response ? response.status : undefined
|
||||
|
||||
const message =
|
||||
resJson.message ??
|
||||
resJson.msg ??
|
||||
resJson.error ??
|
||||
`An error has occurred: ${status ?? 'Unknown error'}`
|
||||
const retryAfter =
|
||||
response instanceof Response && response.headers.get('Retry-After')
|
||||
? parseInt(response.headers.get('Retry-After')!)
|
||||
: undefined
|
||||
|
||||
let error = new ResponseError(message, status, undefined, retryAfter)
|
||||
|
||||
// @ts-expect-error - [Alaister] many of our local api routes check `if (response.error)`.
|
||||
// This is a fix to keep those checks working without breaking changes.
|
||||
// In future we should check for `if (response instanceof ResponseError)` instead.
|
||||
error.error = error
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used only for dashboard API endpoints. Use `fetch` directly if calling a non dashboard API endpoint
|
||||
*
|
||||
@@ -218,9 +251,9 @@ export async function fetchPost<T = any>(
|
||||
...otherOptions,
|
||||
signal: abortSignal,
|
||||
})
|
||||
if (!response.ok) return handleError(response)
|
||||
if (!response.ok) return handleFetchError(response)
|
||||
return handleFetchResponse(response)
|
||||
} catch (error) {
|
||||
return handleError(error)
|
||||
return handleFetchError(error)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { PG_META_URL } from 'lib/constants'
|
||||
import type { ResponseError } from 'types'
|
||||
|
||||
export async function queryPgMetaSelfHosted(sql: string, headersInit?: { [prop: string]: any }) {
|
||||
const headers = constructHeaders(headersInit ?? {})
|
||||
const response = await post(`${PG_META_URL}/query`, { query: sql }, { headers })
|
||||
const response = await fetchPost(`${PG_META_URL}/query`, { query: sql }, { headers })
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error as ResponseError }
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGetAll(req, res)
|
||||
case 'POST':
|
||||
return handlePost(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['GET', 'POST'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const headers = constructHeaders({})
|
||||
const url = `${process.env.SUPABASE_URL}/auth/v1/settings`
|
||||
const { external, disable_signup, mailer_autoconfirm, phone_autoconfirm } = await get(url, {
|
||||
headers,
|
||||
})
|
||||
// Platform only API
|
||||
return res.status(200).json({
|
||||
app_version: '',
|
||||
config_override_id: '',
|
||||
project_id: '',
|
||||
jwt_secret_encrypted: '',
|
||||
isFreeTier: true,
|
||||
SITE_URL: '',
|
||||
OPERATOR_TOKEN: null,
|
||||
DISABLE_SIGNUP: disable_signup ?? false,
|
||||
RATE_LIMIT_HEADER: null,
|
||||
JWT_EXP: 3600,
|
||||
JWT_AUD: '',
|
||||
JWT_DEFAULT_GROUP_NAME: '',
|
||||
URI_ALLOW_LIST: '',
|
||||
MAILER_AUTOCONFIRM: mailer_autoconfirm ?? false,
|
||||
MAILER_OTP_EXP: 3600,
|
||||
MAILER_OTP_LENGTH: 6,
|
||||
MAILER_URLPATHS_INVITE: '',
|
||||
MAILER_URLPATHS_CONFIRMATION: '',
|
||||
MAILER_URLPATHS_RECOVERY: '',
|
||||
MAILER_URLPATHS_EMAIL_CHANGE: '',
|
||||
SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION: false,
|
||||
SMTP_ADMIN_EMAIL: '',
|
||||
SMTP_HOST: null,
|
||||
SMTP_PORT: null,
|
||||
SMTP_USER: null,
|
||||
SMTP_PASS: null,
|
||||
SMTP_MAX_FREQUENCY: 0,
|
||||
EXTERNAL_ANONYMOUS_USERS_ENABLED: external?.anonymous_users ?? true,
|
||||
EXTERNAL_EMAIL_ENABLED: external?.email ?? true,
|
||||
EXTERNAL_PHONE_ENABLED: external?.phone ?? true,
|
||||
EXTERNAL_APPLE_ENABLED: external?.apple ?? false,
|
||||
EXTERNAL_APPLE_CLIENT_ID: null,
|
||||
EXTERNAL_APPLE_SECRET: null,
|
||||
EXTERNAL_AZURE_ENABLED: external?.azure ?? false,
|
||||
EXTERNAL_AZURE_CLIENT_ID: null,
|
||||
EXTERNAL_AZURE_SECRET: null,
|
||||
EXTERNAL_AZURE_URL: null,
|
||||
EXTERNAL_BITBUCKET_ENABLED: external?.bitbucket ?? false,
|
||||
EXTERNAL_BITBUCKET_CLIENT_ID: null,
|
||||
EXTERNAL_BITBUCKET_SECRET: null,
|
||||
EXTERNAL_DISCORD_ENABLED: external?.discord ?? false,
|
||||
EXTERNAL_DISCORD_CLIENT_ID: null,
|
||||
EXTERNAL_DISCORD_SECRET: null,
|
||||
EXTERNAL_FACEBOOK_ENABLED: external?.facebook ?? false,
|
||||
EXTERNAL_FACEBOOK_CLIENT_ID: null,
|
||||
EXTERNAL_FACEBOOK_SECRET: null,
|
||||
EXTERNAL_FIGMA_ENABLED: external?.figma ?? false,
|
||||
EXTERNAL_FIGMA_CLIENT_ID: null,
|
||||
EXTERNAL_FIGMA_SECRET: null,
|
||||
EXTERNAL_GITHUB_ENABLED: external?.github ?? false,
|
||||
EXTERNAL_GITHUB_CLIENT_ID: null,
|
||||
EXTERNAL_GITHUB_SECRET: null,
|
||||
EXTERNAL_GITLAB_ENABLED: external?.gitlab ?? false,
|
||||
EXTERNAL_GITLAB_CLIENT_ID: null,
|
||||
EXTERNAL_GITLAB_SECRET: null,
|
||||
EXTERNAL_GITLAB_REDIRECT_URI: null,
|
||||
EXTERNAL_GOOGLE_ENABLED: external?.google ?? false,
|
||||
EXTERNAL_GOOGLE_CLIENT_ID: null,
|
||||
EXTERNAL_GOOGLE_SECRET: null,
|
||||
EXTERNAL_KAKAO_ENABLED: external?.kakao ?? false,
|
||||
EXTERNAL_KAKAO_CLIENT_ID: null,
|
||||
EXTERNAL_KAKAO_SECRET: null,
|
||||
EXTERNAL_KEYCLOAK_ENABLED: external?.keycloak ?? false,
|
||||
EXTERNAL_KEYCLOAK_CLIENT_ID: null,
|
||||
EXTERNAL_KEYCLOAK_SECRET: null,
|
||||
EXTERNAL_KEYCLOAK_URL: null,
|
||||
EXTERNAL_NOTION_ENABLED: external?.notion ?? false,
|
||||
EXTERNAL_NOTION_CLIENT_ID: null,
|
||||
EXTERNAL_NOTION_SECRET: null,
|
||||
EXTERNAL_SPOTIFY_ENABLED: external?.spotify ?? false,
|
||||
EXTERNAL_SPOTIFY_CLIENT_ID: null,
|
||||
EXTERNAL_SPOTIFY_SECRET: null,
|
||||
EXTERNAL_SLACK_OIDC_ENABLED: external?.slack ?? false,
|
||||
EXTERNAL_SLACK_OIDC_CLIENT_ID: null,
|
||||
EXTERNAL_SLACK_OIDC_SECRET: null,
|
||||
EXTERNAL_TWITTER_ENABLED: external?.twitter ?? false,
|
||||
EXTERNAL_TWITTER_CLIENT_ID: null,
|
||||
EXTERNAL_TWITTER_SECRET: null,
|
||||
EXTERNAL_TWITCH_ENABLED: external?.twitch ?? false,
|
||||
EXTERNAL_TWITCH_CLIENT_ID: null,
|
||||
EXTERNAL_TWITCH_SECRET: null,
|
||||
EXTERNAL_WORKOS_ENABLED: external?.workos ?? false,
|
||||
EXTERNAL_WORKOS_CLIENT_ID: null,
|
||||
EXTERNAL_WORKOS_SECRET: null,
|
||||
EXTERNAL_WORKOS_URL: null,
|
||||
EXTERNAL_ZOOM_ENABLED: external?.zoom ?? false,
|
||||
EXTERNAL_ZOOM_CLIENT_ID: null,
|
||||
EXTERNAL_ZOOM_SECRET: null,
|
||||
MAILER_SUBJECTS_INVITE: 'You have been invited',
|
||||
MAILER_SUBJECTS_CONFIRMATION: 'Confirm Your Signup',
|
||||
MAILER_SUBJECTS_RECOVERY: 'Reset Your Password',
|
||||
MAILER_SUBJECTS_EMAIL_CHANGE: 'Confirm Email Change',
|
||||
MAILER_SUBJECTS_MAGIC_LINK: 'Your Magic Link',
|
||||
MAILER_SUBJECTS_REAUTHENTICATION: 'Confirm Reauthentication',
|
||||
MAILER_TEMPLATES_INVITE: null,
|
||||
MAILER_TEMPLATES_INVITE_CONTENT:
|
||||
'<h2>You have been invited</h2>\n\n<p>You have been invited to create a user on {{ .SiteURL }}. Follow this link to accept the invite:</p>\n<p><a href="{{ .ConfirmationURL }}">Accept the invite</a></p>',
|
||||
MAILER_TEMPLATES_CONFIRMATION: null,
|
||||
MAILER_TEMPLATES_CONFIRMATION_CONTENT:
|
||||
'<h2>Confirm your email</h2>\n\n<p>Follow this link to confirm your email:</p>\n\n<p><a href="{{ .ConfirmationURL }}">Confirm your email address</a></p>',
|
||||
MAILER_TEMPLATES_RECOVERY: null,
|
||||
MAILER_TEMPLATES_RECOVERY_CONTENT:
|
||||
'<h2>Reset Password</h2>\n\n<p>Follow this link to reset the password for your user:</p>\n<p><a href="{{ .ConfirmationURL }}">Reset Password</a></p>',
|
||||
MAILER_TEMPLATES_EMAIL_CHANGE: null,
|
||||
MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT:
|
||||
'<h2>Confirm Change of Email</h2>\n\n<p>Follow this link to confirm the update of your email from {{ .Email }} to {{ .NewEmail }}:</p>\n<p><a href="{{ .ConfirmationURL }}">Change Email</a></p>',
|
||||
MAILER_TEMPLATES_MAGIC_LINK: null,
|
||||
MAILER_TEMPLATES_MAGIC_LINK_CONTENT:
|
||||
'<h2>Magic Link</h2>\n\n<p>Follow this link to login:</p>\n<p><a href="{{ .ConfirmationURL }}">Log In</a></p>',
|
||||
PASSWORD_MIN_LENGTH: 6,
|
||||
SMTP_SENDER_NAME: null,
|
||||
SMS_AUTOCONFIRM: phone_autoconfirm ?? false,
|
||||
SMS_MAX_FREQUENCY: 0,
|
||||
SMS_OTP_EXP: 60,
|
||||
SMS_OTP_LENGTH: 6,
|
||||
SMS_PROVIDER: 'twilio',
|
||||
SMS_TWILIO_ACCOUNT_SID: null,
|
||||
SMS_TWILIO_AUTH_TOKEN: null,
|
||||
SMS_TWILIO_CONTENT_SID: null,
|
||||
SMS_TWILIO_MESSAGE_SERVICE_SID: null,
|
||||
SMS_TWILIO_VERIFY_ACCOUNT_SID: null,
|
||||
SMS_TWILIO_VERIFY_AUTH_TOKEN: null,
|
||||
SMS_TWILIO_VERIFY_MESSAGE_SERVICE_SID: null,
|
||||
SMS_TEMPLATE: 'Your code is {{ .Code }}',
|
||||
SECURITY_CAPTCHA_ENABLED: false,
|
||||
SECURITY_CAPTCHA_PROVIDER: 'hcaptcha',
|
||||
SECURITY_CAPTCHA_SECRET: null,
|
||||
SECURITY_MANUAL_LINKING_ENABLED: false,
|
||||
SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: '10',
|
||||
RATE_LIMIT_EMAIL_SENT: 0,
|
||||
RATE_LIMIT_SMS_SENT: 0,
|
||||
RATE_LIMIT_ANONYMOUS_USERS: 0,
|
||||
MAILER_SECURE_EMAIL_CHANGE_ENABLED: true,
|
||||
SMS_MESSAGEBIRD_ACCESS_KEY: null,
|
||||
SMS_MESSAGEBIRD_ORIGINATOR: null,
|
||||
SMS_VONAGE_API_KEY: null,
|
||||
SMS_VONAGE_API_SECRET: null,
|
||||
SMS_VONAGE_FROM: null,
|
||||
SMS_TEXTLOCAL_API_KEY: null,
|
||||
SMS_TEXTLOCAL_SENDER: null,
|
||||
MAILER_TEMPLATES_REAUTHENTICATION: null,
|
||||
MAILER_TEMPLATES_REAUTHENTICATION_CONTENT:
|
||||
'<h2>Confirm reauthentication</h2> <p>Enter the code: {{ .Token }}</p>',
|
||||
})
|
||||
}
|
||||
|
||||
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
// Platform only API
|
||||
return res.status(200).json({})
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
@@ -25,6 +29,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
})
|
||||
const url = `${process.env.SUPABASE_URL}/auth/v1/invite`
|
||||
const payload = { email: req.body.email }
|
||||
const response = await post(url, payload, { headers })
|
||||
return res.status(200).json(response)
|
||||
|
||||
const response = await fetchPost(url, payload, { headers })
|
||||
if (response.error) {
|
||||
const { code, message } = response.error
|
||||
return res.status(code).json({ message })
|
||||
} else {
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import SqlString from 'sqlstring'
|
||||
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { tryParseInt } from 'lib/helpers'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
})
|
||||
const url = `${process.env.SUPABASE_URL}/auth/v1/magiclink`
|
||||
const payload = { email: req.body.email }
|
||||
const response = await post(url, payload, { headers })
|
||||
return res.status(200).json(response)
|
||||
|
||||
const response = await fetchPost(url, payload, { headers })
|
||||
if (response.error) {
|
||||
const { code, message } = response.error
|
||||
return res.status(code).json({ message })
|
||||
} else {
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import SqlString from 'sqlstring'
|
||||
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { tryParseInt } from 'lib/helpers'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
})
|
||||
const url = `${process.env.SUPABASE_URL}/auth/v1/otp`
|
||||
const payload = { phone: req.body.phone }
|
||||
const response = await post(url, payload, { headers })
|
||||
return res.status(200).json(response)
|
||||
|
||||
const response = await fetchPost(url, payload, { headers })
|
||||
if (response.error) {
|
||||
const { code, message } = response.error
|
||||
return res.status(code).json({ message })
|
||||
} else {
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import SqlString from 'sqlstring'
|
||||
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { tryParseInt } from 'lib/helpers'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
})
|
||||
const url = `${process.env.SUPABASE_URL}/auth/v1/recover`
|
||||
const payload = { email: req.body.email }
|
||||
const response = await post(url, payload, { headers })
|
||||
return res.status(200).json(response)
|
||||
|
||||
const response = await fetchPost(url, payload, { headers })
|
||||
if (response.error) {
|
||||
const { code, message } = response.error
|
||||
return res.status(code).json({ message })
|
||||
} else {
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import SqlString from 'sqlstring'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { tryParseInt } from 'lib/helpers'
|
||||
import { PG_META_URL } from 'lib/constants'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
|
||||
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGetAll(req, res)
|
||||
case 'POST':
|
||||
return handlePost(req, res)
|
||||
case 'DELETE':
|
||||
return handleDelete(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['GET', 'POST', 'DELETE'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const headers = constructHeaders(req.headers)
|
||||
const { keywords, limit, offset, verified } = req.query
|
||||
const limitInt = tryParseInt(limit as string) || 10
|
||||
const offsetInt = tryParseInt(offset as string) || 0
|
||||
const hasValidKeywords = keywords && keywords != ''
|
||||
const hasVerifiedValue = verified && verified != ''
|
||||
|
||||
let queryCount = ''
|
||||
let queryUsers = ''
|
||||
|
||||
if (hasValidKeywords && !hasVerifiedValue) {
|
||||
queryCount = SqlString.format(
|
||||
'SELECT count(*) from auth.users WHERE (email ilike ? OR id::text ilike ?);',
|
||||
[`%${keywords}%`, `%${keywords}%`]
|
||||
)
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users WHERE (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
|
||||
if (!hasValidKeywords && hasVerifiedValue) {
|
||||
if (verified === 'verified') {
|
||||
queryCount = SqlString.format(
|
||||
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL);'
|
||||
)
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
if (verified === 'unverified') {
|
||||
queryCount = SqlString.format(
|
||||
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL);'
|
||||
)
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasValidKeywords && hasVerifiedValue) {
|
||||
if (verified === 'verified') {
|
||||
queryCount = SqlString.format(
|
||||
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) AND (email ilike ? OR id::text ilike ?);',
|
||||
[`%${keywords}%`, `%${keywords}%`]
|
||||
)
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) AND (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
if (verified === 'unverified') {
|
||||
queryCount = SqlString.format(
|
||||
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) AND (email ilike ? OR id::text ilike ?);',
|
||||
[`%${keywords}%`, `%${keywords}%`]
|
||||
)
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) AND (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidKeywords && !hasVerifiedValue) {
|
||||
queryCount = 'SELECT count(*) from auth.users;'
|
||||
queryUsers = SqlString.format(
|
||||
'SELECT * from auth.users ORDER BY created_at DESC LIMIT ? OFFSET ?;',
|
||||
[limitInt, offsetInt]
|
||||
)
|
||||
}
|
||||
|
||||
const [getTotal, getUsers] = await Promise.all([
|
||||
post(`${PG_META_URL}/query`, { query: queryCount }, { headers }),
|
||||
post(`${PG_META_URL}/query`, { query: queryUsers }, { headers }),
|
||||
])
|
||||
|
||||
let total = 0
|
||||
if (getTotal && (getTotal as any[]).length > 0) {
|
||||
total = (getTotal[0] as any).count
|
||||
}
|
||||
|
||||
return res.status(200).json({ total, users: getUsers })
|
||||
}
|
||||
|
||||
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { email, password, email_confirm } = req.body
|
||||
const { data, error } = await supabase.auth.admin.createUser({ email, password, email_confirm })
|
||||
|
||||
if (error) return res.status(400).json({ error: { message: error.message } })
|
||||
return res.status(200).json(data.user)
|
||||
}
|
||||
|
||||
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { id } = req.body
|
||||
const { data, error } = await supabase.auth.admin.deleteUser(id)
|
||||
|
||||
if (error) return res.status(400).json({ error: { message: error.message } })
|
||||
return res.status(200).json(data.user)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'POST':
|
||||
return handlePost(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['POST'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { data, error } = await supabase.auth.admin.createUser(req.body)
|
||||
|
||||
if (error) return res.status(400).json({ error: { message: error.message } })
|
||||
return res.status(200).json(data.user)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { PG_META_URL } from 'lib/constants'
|
||||
import { delete_, get, patch, post } from 'lib/common/fetch'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) =>
|
||||
apiWrapper(req, res, handler, { withAuth: true })
|
||||
@@ -13,12 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGetAll(req, res)
|
||||
case 'POST':
|
||||
return handlePost(req, res)
|
||||
case 'PATCH':
|
||||
return handlePatch(req, res)
|
||||
case 'DELETE':
|
||||
return handleDelete(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
|
||||
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
|
||||
@@ -35,45 +29,3 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
}
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
|
||||
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const headers = constructHeaders(req.headers)
|
||||
const payload = toSnakeCase(req.body)
|
||||
const response = await post(`${PG_META_URL}/policies`, payload, {
|
||||
headers,
|
||||
})
|
||||
|
||||
if (response.error) {
|
||||
console.error('Policies POST:', response.error)
|
||||
return res.status(400).json({ error: response.error })
|
||||
}
|
||||
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
|
||||
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const headers = constructHeaders(req.headers)
|
||||
const payload = toSnakeCase(req.body)
|
||||
const response = await patch(`${PG_META_URL}/policies/${req.query.id}`, payload, {
|
||||
headers,
|
||||
})
|
||||
|
||||
if (response.error) {
|
||||
console.error('Policies PATCH:', response)
|
||||
return res.status(400).json({ error: response.error })
|
||||
}
|
||||
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
|
||||
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const headers = constructHeaders(req.headers)
|
||||
const response = await delete_(`${PG_META_URL}/policies/${req.query.id}`, {}, { headers })
|
||||
|
||||
if (response.error) {
|
||||
console.error('Policies DELETE:', response.error)
|
||||
return res.status(400).json({ error: response.error })
|
||||
}
|
||||
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fetchPost } from 'data/fetchers'
|
||||
import { constructHeaders } from 'lib/api/apiHelpers'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { PG_META_URL } from 'lib/constants'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
@@ -22,10 +22,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { query } = req.body
|
||||
const headers = constructHeaders(req.headers)
|
||||
const response = await post(`${PG_META_URL}/query`, { query }, { headers })
|
||||
const response = await fetchPost(`${PG_META_URL}/query`, { query }, { headers })
|
||||
|
||||
if (response.error) {
|
||||
return res.status(400).json(response.error)
|
||||
const { code, message } = response.error
|
||||
return res.status(code).json({ message, formattedError: message })
|
||||
} else {
|
||||
return res.status(200).json(response)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user