Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge, Toggle } from 'ui'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { X } from 'lucide-react'
import { toast } from 'sonner'
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge, Toggle } from 'ui'

import { useConsentState } from 'common'
import { LOCAL_STORAGE_KEYS } from 'common/constants/local-storage'
import Panel from 'components/ui/Panel'
import { useSendResetMutation } from 'data/telemetry/send-reset-mutation'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { LOCAL_STORAGE_KEYS } from 'common/constants/local-storage'

export const TermsUpdateBanner = () => {
const [termsUpdateAcknowledged, setTermsUpdateAcknowledged] = useLocalStorageQuery(
const [termsUpdateAcknowledged, setTermsUpdateAcknowledged, { isSuccess }] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.TERMS_OF_SERVICE_ACKNOWLEDGED,
false
)

if (termsUpdateAcknowledged) return null
if (!isSuccess || termsUpdateAcknowledged) return null

return (
<Alert_Shadcn_ className="mb-4 relative">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ const PROVIDER_EMAIL = {
description: 'This will enable Email based signup and login for your application',
type: 'boolean',
},
MAILER_AUTOCONFIRM: {
title: 'Confirm email',
description: `Users will need to confirm their email address before signing in for the first time.`,
type: 'boolean',
},
MAILER_SECURE_EMAIL_CHANGE_ENABLED: {
title: 'Secure email change',
description: `Users will be required to confirm any email change on both the old email address and new email address.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const schema = object({
DISABLE_SIGNUP: boolean().required(),
EXTERNAL_ANONYMOUS_USERS_ENABLED: boolean().required(),
SECURITY_MANUAL_LINKING_ENABLED: boolean().required(),
MAILER_AUTOCONFIRM: boolean().required(),
SITE_URL: string().required('Must have a Site URL'),
})

Expand All @@ -52,6 +53,7 @@ const BasicAuthSettingsForm = () => {
DISABLE_SIGNUP: true,
EXTERNAL_ANONYMOUS_USERS_ENABLED: false,
SECURITY_MANUAL_LINKING_ENABLED: false,
MAILER_AUTOCONFIRM: true,
SITE_URL: '',
},
})
Expand All @@ -61,7 +63,8 @@ const BasicAuthSettingsForm = () => {
form.reset({
DISABLE_SIGNUP: !authConfig.DISABLE_SIGNUP,
EXTERNAL_ANONYMOUS_USERS_ENABLED: authConfig.EXTERNAL_ANONYMOUS_USERS_ENABLED,
SECURITY_MANUAL_LINKING_ENABLED: authConfig.SECURITY_MANUAL_LINKING_ENABLED || false,
SECURITY_MANUAL_LINKING_ENABLED: authConfig.SECURITY_MANUAL_LINKING_ENABLED,
MAILER_AUTOCONFIRM: authConfig.MAILER_AUTOCONFIRM,
SITE_URL: authConfig.SITE_URL,
})
}
Expand Down Expand Up @@ -250,6 +253,27 @@ const BasicAuthSettingsForm = () => {
</Alert_Shadcn_>
)}
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="MAILER_AUTOCONFIRM"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Confirm email"
description="Users will need to confirm their email address before signing in for the first time"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</CardContent>
<CardFooter className="justify-end space-x-2">
{form.formState.isDirty && (
<Button type="default" onClick={() => form.reset()}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { CronJob, useCronJobsQuery } from 'data/database-cron-jobs/database-cron
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import {
Button,
Form_Shadcn_,
Expand Down Expand Up @@ -199,7 +199,7 @@ export const CreateCronJobSheet = ({
onClose,
}: CreateCronJobSheetProps) => {
const { project } = useProjectContext()
const org = useSelectedOrganization()
const { data: org } = useSelectedOrganizationQuery()
const isEditing = !!selectedCronJob?.jobname

const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false)
Expand All @@ -209,6 +209,13 @@ export const CreateCronJobSheet = ({
connectionString: project?.connectionString,
})

const { data } = useDatabaseExtensionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const pgNetExtension = (data ?? []).find((ext) => ext.name === 'pg_net')
const pgNetExtensionInstalled = pgNetExtension?.installed_version != undefined

const { mutate: sendEvent } = useSendEventMutation()
const { mutate: upsertCronJob, isLoading } = useDatabaseCronJobCreateMutation()

Expand All @@ -230,11 +237,8 @@ export const CreateCronJobSheet = ({
})

const isEdited = form.formState.isDirty

// if the form hasn't been touched and the user clicked esc or the backdrop, close the sheet
if (!isEdited && isClosing) {
onClose()
}
if (!isEdited && isClosing) onClose()

const onClosePanel = () => {
if (isEdited) {
Expand Down Expand Up @@ -286,6 +290,7 @@ export const CreateCronJobSheet = ({
if (command) {
form.setValue('values.snippet', command)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
edgeFunctionName,
endpoint,
Expand Down Expand Up @@ -362,14 +367,6 @@ export const CreateCronJobSheet = ({
)
}

const { data } = useDatabaseExtensionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})

const pgNetExtension = (data ?? []).find((ext) => ext.name === 'pg_net')
const pgNetExtensionInstalled = pgNetExtension?.installed_version != undefined

return (
<>
<div className="flex flex-col h-full" tabIndex={-1}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,20 @@ describe('parseCronJobCommand', () => {
})
})

it('should return a sql function command when the command is SELECT public.test_fn(1, 2)', () => {
const command = 'SELECT public.test_fn(1, 2)'
it('should return a sql function command when the command is SELECT auth.jwt () and ends with ;', () => {
const command = 'SELECT auth.jwt ();'
expect(parseCronJobCommand(command, 'random_project_ref')).toStrictEqual({
type: 'sql_function',
schema: 'public',
functionName: 'test_fn',
schema: 'auth',
functionName: 'jwt',
snippet: command,
})
})

it('should return a sql snippet command when the command is SELECT public.test_fn(1, 2)', () => {
const command = 'SELECT public.test_fn(1, 2)'
expect(parseCronJobCommand(command, 'random_project_ref')).toStrictEqual({
type: 'sql_snippet',
snippet: command,
})
})
Expand Down Expand Up @@ -194,6 +202,14 @@ describe('parseCronJobCommand', () => {
})
})

it('should return SQL snippet type if the command is a HTTP request that cannot be parsed properly due to positional notationa', () => {
const command = `SELECT net.http_post( 'https://webhook.site/dacc2028-a588-462c-9597-c8968e61d0fa', '{"message":"Hello from Supabase"}'::jsonb, '{}'::jsonb, '{"Content-Type":"application/json"}'::jsonb );`
expect(parseCronJobCommand(command, 'random_project_ref')).toStrictEqual({
type: 'sql_snippet',
snippet: command,
})
})

// Array of test cases for secondsPattern
const secondsPatternTests = [
{ description: '10 seconds', command: '10 seconds' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const parseCronJobCommand = (originalCommand: string, projectRef: string)
}
} else {
const headersStringMatch = command.match(/headers:='([^']*)'/i)
const headersString = headersStringMatch?.[1] || ''
const headersString = headersStringMatch?.[1] || '{}'
try {
const parsedHeaders = JSON.parse(headersString)
headersObjs = Object.entries(parsedHeaders).map(([name, value]) => ({
Expand Down Expand Up @@ -112,22 +112,25 @@ export const parseCronJobCommand = (originalCommand: string, projectRef: string)
}
}

return {
type: 'http_request',
method: method === 'http_get' ? 'GET' : 'POST',
endpoint: url,
httpHeaders: headersObjs,
httpBody: body,
timeoutMs: Number(timeout ?? 1000),
snippet: originalCommand,
if (url !== '') {
return {
type: 'http_request',
method: method === 'http_get' ? 'GET' : 'POST',
endpoint: url,
httpHeaders: headersObjs,
httpBody: body,
timeoutMs: Number(timeout ?? 1000),
snippet: originalCommand,
}
}
}

const regexDBFunction = /select\s+[a-zA-Z-_]*\.?[a-zA-Z-_]*\s*\(.+/g
const regexDBFunction = /select\s+[a-zA-Z-_]*\.?[a-zA-Z-_]*\s*\(\)/g
if (command.toLocaleLowerCase().match(regexDBFunction)) {
const [schemaName, functionName] = command
.replace('SELECT ', '')
.replace(/\(.*\)/, '')
.replace(/\(.*\);*/, '')

.trim()
.split('.')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,16 @@ export const CreateWrapperSheet = ({
}

setFormErrors(errors)
if (!isEmpty(errors)) {
return
}
if (!isEmpty(errors)) return

try {
await createSchema({
projectRef: project?.ref,
connectionString: project?.connectionString,
name: values.target_schema,
})
if (selectedMode === 'schema') {
await createSchema({
projectRef: project?.ref,
connectionString: project?.connectionString,
name: values.target_schema,
})
}

await createFDW({
projectRef: project?.ref,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}

const proxyRequest = async (req: NextApiRequest) => {
const { name, ...toForward } = req.query
const project_tier = 'ENTERPRISE'
const { name, ref: project, ...toForward } = req.query

if (req.method === 'GET') {
const payload = { ...toForward, project_tier }
const payload = { ...toForward, project }
return retrieveAnalyticsData(name as string, payload)
} else if (req.method === 'POST') {
const payload = { ...req.body, project_tier }
const payload = { ...req.body, project }
return retrieveAnalyticsData(name as string, payload)
}
}
Expand Down
Loading