Merge remote-tracking branch 'forked/master'

This commit is contained in:
vinceh121
2024-07-30 22:33:37 +02:00
23 changed files with 561 additions and 365 deletions

View File

@@ -142,7 +142,7 @@ export default function App() {
{
key: 'connectors',
icon: <ApiOutlined/>,
label: t`My connectors`,
label: t`My Connectors`,
disabled: !isAuthenticated,
onClick: () => navigate('/tracking/connectors')
}

View File

@@ -1,9 +1,15 @@
import {Button, Form, FormInstance, Input, Select, Space, Typography} from "antd";
import {Button, Checkbox, Form, FormInstance, Input, Select, Space, Typography} from "antd";
import React, {useState} from "react";
import {Connector, ConnectorProvider} from "../../utils/api/connectors";
import {t} from "ttag";
import {BankOutlined} from "@ant-design/icons";
import {regionNames} from "../../i18n";
import {
ovhEndpointList as ovhEndpointListFunction,
ovhFields as ovhFieldsFunction,
ovhPricingMode as ovhPricingModeFunction,
ovhSubsidiaryList as ovhSubsidiaryListFunction
} from "../../utils/providers/ovh";
import {helpGetTokenLink, tosHyperlink} from "../../utils/providers";
const formItemLayoutWithOutLabel = {
wrapperCol: {
@@ -14,31 +20,10 @@ const formItemLayoutWithOutLabel = {
export function ConnectorForm({form, onCreate}: { form: FormInstance, onCreate: (values: Connector) => void }) {
const [provider, setProvider] = useState<string>()
const ovhFields = {
appKey: t`Application key`,
appSecret: t`Application secret`,
consumerKey: t`Consumer key`
}
const ovhEndpointList = [
{
label: t`European Region`,
value: 'ovh-eu'
}
]
const ovhSubsidiaryList = [{value: 'EU', label: t`Europa`}, ...[
'CZ', 'DE', 'ES', 'FI', 'FR', 'GB', 'IE', 'IT', 'LT', 'MA', 'NL', 'PL', 'PT', 'SN', 'TN'
].map(c => ({value: c, label: regionNames.of(c) ?? c}))]
const ovhPricingMode = [
{value: 'create-default', label: t`The domain is free and at the standard price`},
{
value: 'create-premium',
label: t`The domain is free but is a premium. Its price varies from one domain to another`
}
]
const ovhFields = ovhFieldsFunction()
const ovhEndpointList = ovhEndpointListFunction()
const ovhSubsidiaryList = ovhSubsidiaryListFunction()
const ovhPricingMode = ovhPricingModeFunction()
return <Form
{...formItemLayoutWithOutLabel}
@@ -51,9 +36,11 @@ export function ConnectorForm({form, onCreate}: { form: FormInstance, onCreate:
<Form.Item
label={t`Provider`}
name="provider"
help={helpGetTokenLink(provider)}
rules={[{required: true, message: t`Required`}]}
>
<Select
allowClear
placeholder={t`Please select a Provider`}
suffixIcon={<BankOutlined/>}
options={Object.keys(ConnectorProvider).map((c) => ({
@@ -66,22 +53,19 @@ export function ConnectorForm({form, onCreate}: { form: FormInstance, onCreate:
}))}
value={provider}
onChange={setProvider}
autoFocus
/>
</Form.Item>
{
provider === ConnectorProvider.OVH && <>
<Typography.Link target='_blank'
href="https://api.ovh.com/createToken/index.cgi?GET=/*&PUT=/*&POST=/*&DELETE=/*">
Retrieve a token set from the OVH API
</Typography.Link>
{
Object.keys(ovhFields).map(fieldName => <Form.Item
label={ovhFields[fieldName as keyof typeof ovhFields]}
name={['authData', fieldName]}
rules={[{required: true, message: t`Required`}]}
>
<Input/>
<Input autoComplete='off'/>
</Form.Item>)
}
<Form.Item
@@ -106,6 +90,37 @@ export function ConnectorForm({form, onCreate}: { form: FormInstance, onCreate:
>
<Select options={ovhPricingMode} optionFilterProp="label"/>
</Form.Item>
<Form.Item
valuePropName="checked"
label={t`API Terms of Service`}
name={['authData', 'acceptConditions']}
rules={[{required: true, message: t`Required`}]}
>
<Checkbox
required={true}>
<Typography.Link target='_blank' href={tosHyperlink(provider)}>
{t`I certify that I have read and accepted the conditions of use of the Provider API, accessible from this hyperlink`}
</Typography.Link>
</Checkbox>
</Form.Item>
<Form.Item
valuePropName="checked"
label={t`Legal age`}
name={['authData', 'ownerLegalAge']}
rules={[{required: true, message: t`Required`}]}
>
<Checkbox
required={true}>{t`I certify on my honor that I am of the minimum age required to consent to these conditions`}</Checkbox>
</Form.Item>
<Form.Item
valuePropName="checked"
label={t`Withdrawal period`}
name={['authData', 'waiveRetractationPeriod']}
rules={[{required: true, message: t`Required`}]}
>
<Checkbox
required={true}>{t`I expressly waive my right of withdrawal regarding the purchase of domain names via the Provider's API`}</Checkbox>
</Form.Item>
</>
}

View File

@@ -1,7 +1,7 @@
import {Button, Form, FormInstance, Input, Select, Space} from "antd";
import {t} from "ttag";
import {MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
import React, {useState} from "react";
import {ApiOutlined, MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
import React from "react";
import {EventAction} from "../../utils/api";
import {Connector} from "../../utils/api/connectors";
@@ -73,13 +73,8 @@ export function WatchlistForm({form, connectors, onCreateWatchlist}: {
{
label: t`Send me an email`,
value: 'email'
},
{
label: t`Buy the domain if available`,
value: 'buy'
}
]
const [actionsSelect, setActionsSelect] = useState<{ [key: number]: string }>({})
return <Form
{...formItemLayoutWithOutLabel}
@@ -186,27 +181,8 @@ export function WatchlistForm({form, connectors, onCreateWatchlist}: {
noStyle name={[field.name, 'action']}>
<Select style={{minWidth: 300}} options={triggerActionItems} showSearch
placeholder={t`Then do that`}
optionFilterProp="label" value={actionsSelect[field.key]}
onChange={(e) => setActionsSelect({...actionsSelect, [field.key]: e})}/>
optionFilterProp="label"/>
</Form.Item>
{actionsSelect[field.key] === 'buy' && <Form.Item {...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}]}
noStyle
name={[field.name, 'connector']}>
<Select style={{minWidth: 500}} showSearch
placeholder={t`Connector`}
optionFilterProp="label"
options={connectors.map(c => ({
label: `${c.provider} (${c.id})`,
value: c.id
}))}
/>
</Form.Item>
}
</Space>
{fields.length > 1 ? (
@@ -231,6 +207,21 @@ export function WatchlistForm({form, connectors, onCreateWatchlist}: {
</>
)}
</Form.List>
<Form.Item label={t`Connector`}
name='connector'
>
<Select showSearch
allowClear
style={{width: '60%'}}
placeholder={t`Connector`}
suffixIcon={<ApiOutlined/>}
optionFilterProp="label"
options={connectors.map(c => ({
label: `${c.provider} (${c.id})`,
value: c.id
}))}
/>
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">

View File

@@ -52,7 +52,7 @@ export default function Page() {
name="username"
rules={[{required: true, message: t`Required`}]}
>
<Input/>
<Input autoFocus/>
</Form.Item>
<Form.Item<FieldType>

View File

@@ -20,13 +20,14 @@ export default function WatchlistPage() {
const onCreateWatchlist = (values: {
domains: string[],
triggers: { event: string, action: string, connector?: string }[]
connector?: string
}) => {
const domainsURI = values.domains.map(d => '/api/domains/' + d)
postWatchlist(domainsURI, values.triggers.map(({action, event, connector}) => ({
action,
event,
connector: connector !== undefined ? '/api/connectors/' + connector : undefined
}))).then((w) => {
postWatchlist({
domains: domainsURI,
triggers: values.triggers,
connector: values.connector !== undefined ? '/api/connectors/' + values.connector : undefined
}).then((w) => {
form.resetFields()
refreshWatchlists()
messageApi.success(t`Watchlist created !`)

View File

@@ -16,6 +16,8 @@ export type EventAction =
| 'enum validation expiration'
| string
export type TriggerAction = 'email' | string
export interface Event {
action: EventAction
date: string
@@ -62,9 +64,10 @@ export interface User {
roles: string[]
}
export interface Watchlist {
domains: string[]
triggers: Event[]
export interface Watchlist {
domains: string[],
triggers: { event: EventAction, action: TriggerAction }[],
connector?: string
}
export async function request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig): Promise<R> {

View File

@@ -1,4 +1,4 @@
import {Event, EventAction, request, Watchlist} from "./index";
import {Event, request, Watchlist} from "./index";
export async function getWatchlists() {
const response = await request({
@@ -8,24 +8,17 @@ export async function getWatchlists() {
}
export async function getWatchlist(token: string) {
const response = await request<Watchlist>({
const response = await request<Watchlist & { token: string }>({
url: 'watchlists/' + token
})
return response.data
}
export async function postWatchlist(domains: string[], triggers: {
action: string,
event: EventAction,
connector?: string
}[]) {
export async function postWatchlist(watchlist: Watchlist) {
const response = await request<{ token: string }>({
method: 'POST',
url: 'watchlists',
data: {
domains,
triggers
},
data: watchlist,
headers: {
"Content-Type": 'application/json'
}

View File

@@ -0,0 +1,25 @@
import {ConnectorProvider} from "../api/connectors";
import {Typography} from "antd";
import {t} from "ttag";
import React from "react";
export const helpGetTokenLink = (provider?: string) => {
switch (provider) {
case ConnectorProvider.OVH:
return <Typography.Link target='_blank'
href="https://api.ovh.com/createToken/index.cgi?GET=/order/cart/*&POST=/order/cart&POST=/order/cart/*&DELETE=/order/cart/*">
{t`Retrieve a set of tokens from your customer account on the Provider's website`}
</Typography.Link>
default:
return <></>
}
}
export const tosHyperlink = (provider?: string) => {
switch (provider) {
case ConnectorProvider.OVH:
return 'https://www.ovhcloud.com/fr/terms-and-conditions/contracts/'
default:
return ''
}
}

View File

@@ -0,0 +1,27 @@
import {t} from "ttag";
import {regionNames} from "../../i18n";
export const ovhFields = () => ({
appKey: t`Application key`,
appSecret: t`Application secret`,
consumerKey: t`Consumer key`
})
export const ovhEndpointList = () => [
{
label: t`European Region`,
value: 'ovh-eu'
}
]
export const ovhSubsidiaryList = () => [...[
'CZ', 'DE', 'ES', 'FI', 'FR', 'GB', 'IE', 'IT', 'LT', 'MA', 'NL', 'PL', 'PT', 'SN', 'TN'
].map(c => ({value: c, label: regionNames.of(c) ?? c})), {value: 'EU', label: t`Europe`}]
export const ovhPricingMode = () => [
{value: 'create-default', label: t`The domain is free and at the standard price`},
{
value: 'create-premium',
label: t`The domain is free but is a premium. Its price varies from one domain to another`
}
]