mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-18 02:05:36 +00:00
Merge remote-tracking branch 'forked/master'
This commit is contained in:
commit
cd1c555973
47
README.md
47
README.md
@ -42,12 +42,6 @@ Clone the repository:
|
||||
git clone https://github.com/maelgangloff/domain-watchdog.git
|
||||
```
|
||||
|
||||
Navigate to the project directory:
|
||||
|
||||
```shell
|
||||
cd domain-watchdog
|
||||
```
|
||||
|
||||
#### Backend
|
||||
|
||||
1. Install dependencies:
|
||||
@ -66,7 +60,6 @@ cd domain-watchdog
|
||||
```shell
|
||||
php bin/console doctrine:migrations:migrate
|
||||
```
|
||||
```
|
||||
5. Start the Symfony server:
|
||||
```shell
|
||||
symfony server:start
|
||||
@ -74,6 +67,46 @@ cd domain-watchdog
|
||||
|
||||
#### Frontend
|
||||
|
||||
1. Install dependencies:
|
||||
```shell
|
||||
yarn install
|
||||
```
|
||||
2. Generate language files:
|
||||
```shell
|
||||
yarn run ttag:po2json
|
||||
```
|
||||
3. Make the final build:
|
||||
```shell
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Update
|
||||
|
||||
**Any updates are your responsibility. Make a backup of the data if necessary.**
|
||||
|
||||
Fetch updates from the remote repository:
|
||||
|
||||
```shell
|
||||
git pull origin master
|
||||
```
|
||||
|
||||
### Backend
|
||||
|
||||
1. Install dependencies:
|
||||
```shell
|
||||
composer install
|
||||
```
|
||||
2. Run database migrations:
|
||||
```shell
|
||||
php bin/console doctrine:migrations:migrate
|
||||
```
|
||||
3. Clearing the Symfony cache:
|
||||
```shell
|
||||
php bin/console cache:clear
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
1. Install dependencies:
|
||||
```shell
|
||||
yarn install
|
||||
|
||||
@ -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')
|
||||
}
|
||||
|
||||
@ -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>
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -52,7 +52,7 @@ export default function Page() {
|
||||
name="username"
|
||||
rules={[{required: true, message: t`Required`}]}
|
||||
>
|
||||
<Input/>
|
||||
<Input autoFocus/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<FieldType>
|
||||
|
||||
@ -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 !`)
|
||||
|
||||
@ -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> {
|
||||
|
||||
@ -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'
|
||||
}
|
||||
|
||||
25
assets/utils/providers/index.tsx
Normal file
25
assets/utils/providers/index.tsx
Normal 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 ''
|
||||
}
|
||||
}
|
||||
27
assets/utils/providers/ovh.tsx
Normal file
27
assets/utils/providers/ovh.tsx
Normal 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`
|
||||
}
|
||||
]
|
||||
44
migrations/Version20240730193422.php
Normal file
44
migrations/Version20240730193422.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240730193422 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE watch_list ADD connector_id UUID DEFAULT NULL');
|
||||
$this->addSql('COMMENT ON COLUMN watch_list.connector_id IS \'(DC2Type:uuid)\'');
|
||||
$this->addSql('ALTER TABLE watch_list ADD CONSTRAINT FK_152B584B4D085745 FOREIGN KEY (connector_id) REFERENCES connector (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_152B584B4D085745 ON watch_list (connector_id)');
|
||||
$this->addSql('ALTER TABLE watch_list_trigger DROP CONSTRAINT fk_cf857a4c4d085745');
|
||||
$this->addSql('DROP INDEX idx_cf857a4c4d085745');
|
||||
$this->addSql('ALTER TABLE watch_list_trigger DROP connector_id');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('ALTER TABLE watch_list_trigger ADD connector_id UUID DEFAULT NULL');
|
||||
$this->addSql('COMMENT ON COLUMN watch_list_trigger.connector_id IS \'(DC2Type:uuid)\'');
|
||||
$this->addSql('ALTER TABLE watch_list_trigger ADD CONSTRAINT fk_cf857a4c4d085745 FOREIGN KEY (connector_id) REFERENCES connector (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX idx_cf857a4c4d085745 ON watch_list_trigger (connector_id)');
|
||||
$this->addSql('ALTER TABLE watch_list DROP CONSTRAINT FK_152B584B4D085745');
|
||||
$this->addSql('DROP INDEX IDX_152B584B4D085745');
|
||||
$this->addSql('ALTER TABLE watch_list DROP connector_id');
|
||||
}
|
||||
}
|
||||
@ -8,10 +8,5 @@ interface ConnectorInterface
|
||||
{
|
||||
public static function verifyAuthData(array $authData): array;
|
||||
|
||||
public function orderDomain(Domain $domain,
|
||||
bool $acceptConditions,
|
||||
bool $ownerLegalAge,
|
||||
bool $waiveRetractationPeriod,
|
||||
bool $dryRyn
|
||||
): void;
|
||||
public function orderDomain(Domain $domain, bool $dryRun): void;
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Config\Connector;
|
||||
|
||||
use App\Entity\Domain;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Ovh\Api;
|
||||
|
||||
@ -18,11 +19,7 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
* Order a domain name with the OVH API
|
||||
* @throws Exception
|
||||
*/
|
||||
public function orderDomain(Domain $domain,
|
||||
bool $acceptConditions,
|
||||
bool $ownerLegalAge,
|
||||
bool $waiveRetractationPeriod,
|
||||
bool $dryRyn = false
|
||||
public function orderDomain(Domain $domain, bool $dryRun = false
|
||||
): void
|
||||
{
|
||||
if (!$domain->getDeleted()) throw new Exception('The domain name still appears in the WHOIS database');
|
||||
@ -32,22 +29,19 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
|
||||
$authData = self::verifyAuthData($this->authData);
|
||||
|
||||
$appKey = $authData['appKey'];
|
||||
$appSecret = $authData['appSecret'];
|
||||
$apiEndpoint = $authData['apiEndpoint'];
|
||||
$consumerKey = $authData['consumerKey'];
|
||||
$ovhSubsidiary = $authData['ovhSubsidiary'];
|
||||
$pricingMode = $authData['pricingMode'];
|
||||
$acceptConditions = $authData['acceptConditions'];
|
||||
$ownerLegalAge = $authData['ownerLegalAge'];
|
||||
$waiveRetractationPeriod = $authData['waiveRetractationPeriod'];
|
||||
|
||||
$conn = new Api(
|
||||
$appKey,
|
||||
$appSecret,
|
||||
$apiEndpoint,
|
||||
$consumerKey
|
||||
$authData['appKey'],
|
||||
$authData['appSecret'],
|
||||
$authData['apiEndpoint'],
|
||||
$authData['consumerKey']
|
||||
);
|
||||
|
||||
$cart = $conn->post('/order/cart', [
|
||||
"ovhSubsidiary" => $ovhSubsidiary,
|
||||
"ovhSubsidiary" => $authData['ovhSubsidiary'],
|
||||
"description" => "Domain Watchdog"
|
||||
]);
|
||||
$cartId = $cart['cartId'];
|
||||
@ -57,7 +51,7 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
]);
|
||||
$offer = array_filter($offers, fn($offer) => $offer['action'] === 'create' &&
|
||||
$offer['orderable'] === true &&
|
||||
$offer['pricingMode'] === $pricingMode
|
||||
$offer['pricingMode'] === $authData['pricingMode']
|
||||
);
|
||||
if (empty($offer)) {
|
||||
$conn->delete("/order/cart/{$cartId}");
|
||||
@ -89,7 +83,7 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
}
|
||||
$conn->get("/order/cart/{$cartId}/checkout");
|
||||
|
||||
if ($dryRyn) return;
|
||||
if ($dryRun) return;
|
||||
$conn->post("/order/cart/{$cartId}/checkout", [
|
||||
"autoPayWithPreferredPaymentMethod" => true,
|
||||
"waiveRetractationPeriod" => $waiveRetractationPeriod
|
||||
@ -108,13 +102,36 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
$ovhSubsidiary = $authData['ovhSubsidiary'];
|
||||
$pricingMode = $authData['pricingMode'];
|
||||
|
||||
$acceptConditions = $authData['acceptConditions'];
|
||||
$ownerLegalAge = $authData['ownerLegalAge'];
|
||||
$waiveRetractationPeriod = $authData['waiveRetractationPeriod'];
|
||||
|
||||
if (!is_string($appKey) || empty($appKey) ||
|
||||
!is_string($appSecret) || empty($appSecret) ||
|
||||
!is_string($consumerKey) || empty($consumerKey) ||
|
||||
!is_string($apiEndpoint) || empty($apiEndpoint) ||
|
||||
!is_string($ovhSubsidiary) || empty($ovhSubsidiary) ||
|
||||
!is_string($pricingMode) || empty($pricingMode)
|
||||
) throw new Exception("Bad data schema.");
|
||||
!is_string($pricingMode) || empty($pricingMode) ||
|
||||
|
||||
true !== $acceptConditions ||
|
||||
true !== $ownerLegalAge ||
|
||||
true !== $waiveRetractationPeriod
|
||||
|
||||
) throw new Exception("Bad authData schema");
|
||||
|
||||
$conn = new Api(
|
||||
$appKey,
|
||||
$appSecret,
|
||||
$apiEndpoint,
|
||||
$consumerKey
|
||||
);
|
||||
|
||||
$res = $conn->get('/auth/currentCredential');
|
||||
if ($res['expiration'] !== null && new DateTime($res['expiration']) < new DateTime())
|
||||
throw new Exception('These credentials have expired');
|
||||
|
||||
$status = $res['status'];
|
||||
if ($status !== 'validated') throw new Exception("The status of these credentials is not valid ($status)");
|
||||
|
||||
return [
|
||||
"appKey" => $appKey,
|
||||
@ -122,7 +139,10 @@ readonly class OvhConnector implements ConnectorInterface
|
||||
"apiEndpoint" => $apiEndpoint,
|
||||
"consumerKey" => $consumerKey,
|
||||
"ovhSubsidiary" => $ovhSubsidiary,
|
||||
"pricingMode" => $pricingMode
|
||||
"pricingMode" => $pricingMode,
|
||||
"acceptConditions" => $acceptConditions,
|
||||
"ownerLegalAge" => $ownerLegalAge,
|
||||
"waiveRetractationPeriod" => $waiveRetractationPeriod
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -6,5 +6,4 @@ namespace App\Config;
|
||||
enum TriggerAction: string
|
||||
{
|
||||
case SendEmail = 'email';
|
||||
case BuyDomain = 'buy';
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ use App\Entity\User;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
use Ovh\Api;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
@ -59,14 +58,6 @@ class ConnectorController extends AbstractController
|
||||
if ($connector->getProvider() === ConnectorProvider::OVH) {
|
||||
$authData = OvhConnector::verifyAuthData($connector->getAuthData());
|
||||
$connector->setAuthData($authData);
|
||||
$ovh = new Api(
|
||||
$authData['appKey'],
|
||||
$authData['appSecret'],
|
||||
$authData['apiEndpoint'],
|
||||
$authData['consumerKey']
|
||||
);
|
||||
|
||||
|
||||
} else throw new Exception('Unknown provider');
|
||||
|
||||
$this->em->persist($connector);
|
||||
|
||||
@ -2,10 +2,8 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Config\TriggerAction;
|
||||
use App\Entity\User;
|
||||
use App\Entity\WatchList;
|
||||
use App\Entity\WatchListTrigger;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
@ -55,13 +53,6 @@ class WatchListController extends AbstractController
|
||||
{
|
||||
$watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']);
|
||||
$watchList->setUser($this->getUser());
|
||||
/** @var WatchListTrigger $trigger */
|
||||
foreach ($watchList->getWatchListTriggers()->toArray() as $trigger) {
|
||||
if ($trigger->getAction() === TriggerAction::SendEmail && $trigger->getConnector() !== null)
|
||||
throw new Exception('No connector needed to send email');
|
||||
if ($trigger->getAction() === TriggerAction::BuyDomain && $trigger->getConnector() === null)
|
||||
throw new Exception('Unable to order a domain name without a Connector');
|
||||
}
|
||||
|
||||
$this->em->persist($watchList);
|
||||
$this->em->flush();
|
||||
|
||||
@ -56,16 +56,16 @@ class Connector
|
||||
private array $authData = [];
|
||||
|
||||
/**
|
||||
* @var Collection<int, WatchListTrigger>
|
||||
* @var Collection<int, WatchList>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: WatchListTrigger::class, mappedBy: 'connector')]
|
||||
private Collection $watchListTriggers;
|
||||
#[ORM\OneToMany(targetEntity: WatchList::class, mappedBy: 'connector')]
|
||||
private Collection $watchLists;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->id = Uuid::v4();
|
||||
$this->watchListTriggers = new ArrayCollection();
|
||||
$this->watchLists = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
@ -97,36 +97,6 @@ class Connector
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, WatchListTrigger>
|
||||
*/
|
||||
public function getWatchListTriggers(): Collection
|
||||
{
|
||||
return $this->watchListTriggers;
|
||||
}
|
||||
|
||||
public function addWatchListTrigger(WatchListTrigger $watchListTrigger): static
|
||||
{
|
||||
if (!$this->watchListTriggers->contains($watchListTrigger)) {
|
||||
$this->watchListTriggers->add($watchListTrigger);
|
||||
$watchListTrigger->setConnector($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeWatchListTrigger(WatchListTrigger $watchListTrigger): static
|
||||
{
|
||||
if ($this->watchListTriggers->removeElement($watchListTrigger)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($watchListTrigger->getConnector() === $this) {
|
||||
$watchListTrigger->setConnector(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProvider(): ?ConnectorProvider
|
||||
{
|
||||
return $this->provider;
|
||||
@ -139,4 +109,34 @@ class Connector
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, WatchList>
|
||||
*/
|
||||
public function getWatchLists(): Collection
|
||||
{
|
||||
return $this->watchLists;
|
||||
}
|
||||
|
||||
public function addWatchList(WatchList $watchList): static
|
||||
{
|
||||
if (!$this->watchLists->contains($watchList)) {
|
||||
$this->watchLists->add($watchList);
|
||||
$watchList->setConnector($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeWatchList(WatchList $watchList): static
|
||||
{
|
||||
if ($this->watchLists->removeElement($watchList)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($watchList->getConnector() === $this) {
|
||||
$watchList->setConnector(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -69,6 +69,11 @@ class WatchList
|
||||
#[SerializedName("triggers")]
|
||||
private Collection $watchListTriggers;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'watchLists')]
|
||||
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||
private ?Connector $connector = null;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->token = Uuid::v4();
|
||||
@ -146,4 +151,16 @@ class WatchList
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConnector(): ?Connector
|
||||
{
|
||||
return $this->connector;
|
||||
}
|
||||
|
||||
public function setConnector(?Connector $connector): static
|
||||
{
|
||||
$this->connector = $connector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,10 +25,6 @@ class WatchListTrigger
|
||||
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||
private ?TriggerAction $action = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'watchListTriggers')]
|
||||
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||
private ?Connector $connector = null;
|
||||
|
||||
public function getEvent(): ?string
|
||||
{
|
||||
return $this->event;
|
||||
@ -64,16 +60,4 @@ class WatchListTrigger
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConnector(): ?Connector
|
||||
{
|
||||
return $this->connector;
|
||||
}
|
||||
|
||||
public function setConnector(?Connector $connector): static
|
||||
{
|
||||
$this->connector = $connector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,37 +48,28 @@ final readonly class ProcessDomainTriggerHandler
|
||||
/** @var Domain $domain */
|
||||
$domain = $this->domainRepository->findOneBy(["ldhName" => $message->ldhName]);
|
||||
|
||||
$watchListTriggers = $watchList->getWatchListTriggers();
|
||||
$connector = $watchList->getConnector();
|
||||
if (null !== $connector && $domain->getDeleted()) {
|
||||
try {
|
||||
if ($connector->getProvider() === ConnectorProvider::OVH) {
|
||||
$ovh = new OVHConnector($connector->getAuthData());
|
||||
$isDebug = $this->kernel->isDebug();
|
||||
|
||||
/** @var WatchListTrigger $watchListTrigger */
|
||||
foreach ($watchListTriggers->getIterator() as $watchListTrigger) {
|
||||
|
||||
if ($watchListTrigger->getAction() === TriggerAction::BuyDomain) {
|
||||
|
||||
try {
|
||||
if ($watchListTrigger->getConnector() === null) throw new Exception('Connector is missing');
|
||||
$connector = $watchListTrigger->getConnector();
|
||||
|
||||
if ($connector->getProvider() === ConnectorProvider::OVH) {
|
||||
$ovh = new OVHConnector($connector->getAuthData());
|
||||
$isDebug = $this->kernel->isDebug();
|
||||
|
||||
$ovh->orderDomain(
|
||||
$domain,
|
||||
true, // TODO: Infer from the user
|
||||
true, // TODO: Infer from the user
|
||||
true, // TODO: Infer from the user
|
||||
$isDebug
|
||||
);
|
||||
$this->sendEmailDomainOrdered($domain, $connector, $watchList->getUser());
|
||||
} else throw new Exception("Unknown provider");
|
||||
} catch (Throwable) {
|
||||
$this->sendEmailDomainOrderError($domain, $watchList->getUser());
|
||||
}
|
||||
$ovh->orderDomain($domain, $isDebug);
|
||||
$this->sendEmailDomainOrdered($domain, $connector, $watchList->getUser());
|
||||
} else throw new Exception("Unknown provider");
|
||||
} catch (Throwable) {
|
||||
$this->sendEmailDomainOrderError($domain, $watchList->getUser());
|
||||
}
|
||||
}
|
||||
|
||||
/** @var DomainEvent $event */
|
||||
foreach ($domain->getEvents()->filter(fn($event) => $message->updatedAt < $event->getDate()) as $event) {
|
||||
/** @var DomainEvent $event */
|
||||
foreach ($domain->getEvents()->filter(fn($event) => $message->updatedAt < $event->getDate()) as $event) {
|
||||
$watchListTriggers = $watchList->getWatchListTriggers()
|
||||
->filter(fn($trigger) => $trigger->getEvent() === $event->getAction());
|
||||
|
||||
/** @var WatchListTrigger $watchListTrigger */
|
||||
foreach ($watchListTriggers->getIterator() as $watchListTrigger) {
|
||||
if ($watchListTrigger->getAction() == TriggerAction::SendEmail) {
|
||||
$this->sendEmailDomainUpdated($event, $watchList->getUser());
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
<p>Hello,</p>
|
||||
<p>We are pleased to inform you that a new action has been detected on a domain name in your watchlist.</p>
|
||||
<p><strong>Domain name:</strong> {{ event.domain.ldhName }}</p>
|
||||
<p><strong>Action:</strong> {{ event.action.value }}</p>
|
||||
<p><strong>Action:</strong> {{ event.action }}</p>
|
||||
<p><strong>Effective Date:</strong> {{ event.date | date("c") }}</p>
|
||||
<br/>
|
||||
<p>Thank you for your understanding,</p>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-07-30 00:46+0000\n"
|
||||
"PO-Revision-Date: 2024-07-30 18:40+0000\n"
|
||||
"Last-Translator: Maël Gangloff <contact@maelgangloff.fr>\n"
|
||||
"Language-Team: French <https://weblate.vinceh121.me/projects/domain-watchdog/"
|
||||
"domain-watchdog-dashboard/fr/>\n"
|
||||
@ -56,21 +56,23 @@ msgid "ENUM validation expiration"
|
||||
msgstr "Expiration de la validation ENUM"
|
||||
|
||||
#: assets/components/search/DomainSearchBar.tsx:23
|
||||
#: assets/components/tracking/ConnectorForm.tsx:54
|
||||
#: assets/components/tracking/ConnectorForm.tsx:82
|
||||
#: assets/components/tracking/ConnectorForm.tsx:90
|
||||
#: assets/components/tracking/ConnectorForm.tsx:40
|
||||
#: assets/components/tracking/ConnectorForm.tsx:66
|
||||
#: assets/components/tracking/ConnectorForm.tsx:74
|
||||
#: assets/components/tracking/ConnectorForm.tsx:81
|
||||
#: assets/components/tracking/ConnectorForm.tsx:89
|
||||
#: assets/components/tracking/ConnectorForm.tsx:97
|
||||
#: assets/components/tracking/ConnectorForm.tsx:105
|
||||
#: assets/components/tracking/WatchlistForm.tsx:115
|
||||
#: assets/components/tracking/WatchlistForm.tsx:174
|
||||
#: assets/components/tracking/WatchlistForm.tsx:184
|
||||
#: assets/components/tracking/WatchlistForm.tsx:196
|
||||
#: assets/components/tracking/ConnectorForm.tsx:110
|
||||
#: assets/components/tracking/ConnectorForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistForm.tsx:110
|
||||
#: assets/components/tracking/WatchlistForm.tsx:169
|
||||
#: assets/components/tracking/WatchlistForm.tsx:179
|
||||
#: assets/pages/LoginPage.tsx:53 assets/pages/LoginPage.tsx:61
|
||||
msgid "Required"
|
||||
msgstr "Requis"
|
||||
|
||||
#: assets/components/search/DomainSearchBar.tsx:26
|
||||
#: assets/components/tracking/WatchlistForm.tsx:118
|
||||
#: assets/components/tracking/WatchlistForm.tsx:113
|
||||
msgid "This domain name does not appear to be valid"
|
||||
msgstr "Ce nom de domaine ne semble pas être valide"
|
||||
|
||||
@ -158,114 +160,115 @@ msgstr "Lorsqu'un domaine est enregistré"
|
||||
msgid "Send me an email"
|
||||
msgstr "Envoie-moi un email"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:78
|
||||
msgid "Buy the domain if available"
|
||||
msgstr "Acheter le domaine s'il est disponible"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:95
|
||||
#: assets/components/tracking/WatchlistForm.tsx:90
|
||||
msgid "At least one domain name"
|
||||
msgstr "Au moins un nom de domaine"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:106
|
||||
#: assets/components/tracking/WatchlistForm.tsx:101
|
||||
msgid "Domain names"
|
||||
msgstr "Noms de domaines"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:124
|
||||
#: assets/components/tracking/WatchlistForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistsList.tsx:22
|
||||
msgid "Domain name"
|
||||
msgstr "Nom de domaine"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:141
|
||||
#: assets/components/tracking/WatchlistForm.tsx:136
|
||||
msgid "Add a Domain name"
|
||||
msgstr "Ajouter un nom de domaine"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:154
|
||||
#: assets/components/tracking/WatchlistForm.tsx:149
|
||||
msgid "At least one domain trigger"
|
||||
msgstr "Au moins une action"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:165
|
||||
#: assets/components/tracking/WatchlistForm.tsx:160
|
||||
msgid "Domain trigger"
|
||||
msgstr "Action"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:178
|
||||
#: assets/components/tracking/WatchlistForm.tsx:173
|
||||
msgid "If this happens"
|
||||
msgstr "Si ça arrive"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:188
|
||||
#: assets/components/tracking/WatchlistForm.tsx:183
|
||||
msgid "Then do that"
|
||||
msgstr "Alors fais ça"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:201
|
||||
msgid "Connector"
|
||||
msgstr "Connecteur"
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:227
|
||||
#: assets/components/tracking/WatchlistForm.tsx:203
|
||||
msgid "Add a Trigger"
|
||||
msgstr "Ajouter une action"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:116
|
||||
#: assets/components/tracking/WatchlistForm.tsx:237
|
||||
#: assets/components/tracking/WatchlistForm.tsx:210
|
||||
#: assets/components/tracking/WatchlistForm.tsx:216
|
||||
msgid "Connector"
|
||||
msgstr "Connecteur"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:131
|
||||
#: assets/components/tracking/WatchlistForm.tsx:228
|
||||
msgid "Create"
|
||||
msgstr "Créer"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistForm.tsx:240
|
||||
#: assets/components/tracking/ConnectorForm.tsx:134
|
||||
#: assets/components/tracking/WatchlistForm.tsx:231
|
||||
msgid "Reset"
|
||||
msgstr "Réinitialiser"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:19
|
||||
msgid "Application key"
|
||||
msgstr "Clé d'application"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:20
|
||||
msgid "Application secret"
|
||||
msgstr "Clé secrète d'application"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:21
|
||||
msgid "Consumer key"
|
||||
msgstr "Clé d'utilisateur"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:26
|
||||
msgid "European Region"
|
||||
msgstr "Continent Européen"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:31
|
||||
msgid "Europa"
|
||||
msgstr "Europe"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:36
|
||||
msgid "The domain is free and at the standard price"
|
||||
msgstr "Le domaine est libre et au prix standard"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:39
|
||||
msgid ""
|
||||
"The domain is free but is a premium. Its price varies from one domain to "
|
||||
"another"
|
||||
msgstr ""
|
||||
"Le domaine est libre mais est un premium. Son prix est variable d'un domaine "
|
||||
"à l'autre"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:52
|
||||
#: assets/components/tracking/ConnectorForm.tsx:37
|
||||
#: assets/components/tracking/ConnectorsList.tsx:21
|
||||
msgid "Provider"
|
||||
msgstr "Fournisseur"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:57
|
||||
#: assets/components/tracking/ConnectorForm.tsx:44
|
||||
msgid "Please select a Provider"
|
||||
msgstr "Veuillez sélectionner un fournisseur"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:88
|
||||
#: assets/components/tracking/ConnectorForm.tsx:72
|
||||
msgid "OVH Endpoint"
|
||||
msgstr "Endpoint OVH"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:95
|
||||
#: assets/components/tracking/ConnectorForm.tsx:79
|
||||
msgid "OVH subsidiary"
|
||||
msgstr "Filiale d'OVH"
|
||||
msgstr "Filiale OVH"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:103
|
||||
#: assets/components/tracking/ConnectorForm.tsx:87
|
||||
msgid "OVH pricing mode"
|
||||
msgstr "Mode de tarification OVH"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:95
|
||||
msgid "API Terms of Service"
|
||||
msgstr "Conditions d'utilisation de l'API"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:102
|
||||
msgid ""
|
||||
"I certify that I have read and accepted the conditions of use of the "
|
||||
"Provider API, accessible from this hyperlink"
|
||||
msgstr ""
|
||||
"Je certifie avoir lu et accepté les conditions d'utilisation de l'API du "
|
||||
"Fournisseur, accessibles à partir de ce lien hypertexte"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:108
|
||||
msgid "Legal age"
|
||||
msgstr "Âge minimum légal"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:113
|
||||
msgid ""
|
||||
"I certify on my honor that I am of the minimum age required to consent to "
|
||||
"these conditions"
|
||||
msgstr ""
|
||||
"Je certifie sur l'honneur que j'ai l'âge minimum requis pour consentir à ces "
|
||||
"conditions"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:117
|
||||
msgid "Withdrawal period"
|
||||
msgstr "Délai de rétractation"
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:122
|
||||
msgid ""
|
||||
"I expressly waive my right of withdrawal regarding the purchase of domain "
|
||||
"names via the Provider's API"
|
||||
msgstr ""
|
||||
"Je renonce expressément à mon droit de rétractation concernant l'achat de "
|
||||
"noms de domaine via l'API du Fournisseur"
|
||||
|
||||
#: assets/components/tracking/WatchlistsList.tsx:14
|
||||
#, javascript-format
|
||||
msgid "Watchlist ${ watchlist.token }"
|
||||
@ -313,8 +316,8 @@ msgstr "Trouvé !"
|
||||
#: assets/pages/search/DomainSearchPage.tsx:23
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:23
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:31
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:35
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:43
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:36
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:44
|
||||
msgid "An error occurred"
|
||||
msgstr "Une erreur s'est produite"
|
||||
|
||||
@ -454,19 +457,19 @@ msgstr "Connecteur créé !"
|
||||
msgid "Create a Connector"
|
||||
msgstr "Créer un Connecteur"
|
||||
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:48
|
||||
#: assets/App.tsx:143 assets/pages/tracking/ConnectorsPage.tsx:48
|
||||
msgid "My Connectors"
|
||||
msgstr "Mes Connecteurs"
|
||||
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:32
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:33
|
||||
msgid "Watchlist created !"
|
||||
msgstr "Watchlist créée !"
|
||||
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:53
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:54
|
||||
msgid "Create a Watchlist"
|
||||
msgstr "Créer une Watchlist"
|
||||
|
||||
#: assets/App.tsx:136 assets/pages/tracking/WatchlistPage.tsx:63
|
||||
#: assets/App.tsx:136 assets/pages/tracking/WatchlistPage.tsx:64
|
||||
msgid "My Watchlists"
|
||||
msgstr "Mes Watchlists"
|
||||
|
||||
@ -494,6 +497,45 @@ msgstr "Se connecter"
|
||||
msgid "Log in with SSO"
|
||||
msgstr "Se connecter par SSO"
|
||||
|
||||
#: assets/utils/providers/index.tsx:11
|
||||
msgid ""
|
||||
"Retrieve a set of tokens from your customer account on the Provider's website"
|
||||
msgstr ""
|
||||
"Récupérer un ensemble de jetons à partir de votre compte client sur le site "
|
||||
"web du Fournisseur"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:5
|
||||
msgid "Application key"
|
||||
msgstr "Clé d'application"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:6
|
||||
msgid "Application secret"
|
||||
msgstr "Clé secrète d'application"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:7
|
||||
msgid "Consumer key"
|
||||
msgstr "Clé d'utilisateur"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:12
|
||||
msgid "European Region"
|
||||
msgstr "Continent Européen"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:19
|
||||
msgid "Europe"
|
||||
msgstr "Europe"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:22
|
||||
msgid "The domain is free and at the standard price"
|
||||
msgstr "Le domaine est libre et au prix standard"
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:25
|
||||
msgid ""
|
||||
"The domain is free but is a premium. Its price varies from one domain to "
|
||||
"another"
|
||||
msgstr ""
|
||||
"Le domaine est libre mais est un premium. Son prix est variable d'un domaine "
|
||||
"à l'autre"
|
||||
|
||||
#: assets/App.tsx:71
|
||||
msgid "Home"
|
||||
msgstr "Accueil"
|
||||
@ -542,10 +584,6 @@ msgstr "Statistiques"
|
||||
msgid "Tracking"
|
||||
msgstr "Suivi"
|
||||
|
||||
#: assets/App.tsx:143
|
||||
msgid "My connectors"
|
||||
msgstr "Mes connecteurs"
|
||||
|
||||
#: assets/App.tsx:151
|
||||
msgid "My Watchdog"
|
||||
msgstr "Mon Watchdog"
|
||||
@ -565,3 +603,9 @@ msgstr "FAQ"
|
||||
#: assets/App.tsx:196
|
||||
msgid "Log out"
|
||||
msgstr "Se déconnecter"
|
||||
|
||||
#~ msgid "Buy the domain if available"
|
||||
#~ msgstr "Acheter le domaine s'il est disponible"
|
||||
|
||||
#~ msgid "My connectors"
|
||||
#~ msgstr "Mes connecteurs"
|
||||
|
||||
@ -48,22 +48,24 @@ msgid "ENUM validation expiration"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/search/DomainSearchBar.tsx:23
|
||||
#: assets/components/tracking/ConnectorForm.tsx:54
|
||||
#: assets/components/tracking/ConnectorForm.tsx:82
|
||||
#: assets/components/tracking/ConnectorForm.tsx:90
|
||||
#: assets/components/tracking/ConnectorForm.tsx:40
|
||||
#: assets/components/tracking/ConnectorForm.tsx:66
|
||||
#: assets/components/tracking/ConnectorForm.tsx:74
|
||||
#: assets/components/tracking/ConnectorForm.tsx:81
|
||||
#: assets/components/tracking/ConnectorForm.tsx:89
|
||||
#: assets/components/tracking/ConnectorForm.tsx:97
|
||||
#: assets/components/tracking/ConnectorForm.tsx:105
|
||||
#: assets/components/tracking/WatchlistForm.tsx:115
|
||||
#: assets/components/tracking/WatchlistForm.tsx:174
|
||||
#: assets/components/tracking/WatchlistForm.tsx:184
|
||||
#: assets/components/tracking/WatchlistForm.tsx:196
|
||||
#: assets/components/tracking/ConnectorForm.tsx:110
|
||||
#: assets/components/tracking/ConnectorForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistForm.tsx:110
|
||||
#: assets/components/tracking/WatchlistForm.tsx:169
|
||||
#: assets/components/tracking/WatchlistForm.tsx:179
|
||||
#: assets/pages/LoginPage.tsx:53
|
||||
#: assets/pages/LoginPage.tsx:61
|
||||
msgid "Required"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/search/DomainSearchBar.tsx:26
|
||||
#: assets/components/tracking/WatchlistForm.tsx:118
|
||||
#: assets/components/tracking/WatchlistForm.tsx:113
|
||||
msgid "This domain name does not appear to be valid"
|
||||
msgstr ""
|
||||
|
||||
@ -151,112 +153,109 @@ msgstr ""
|
||||
msgid "Send me an email"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:78
|
||||
msgid "Buy the domain if available"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:95
|
||||
#: assets/components/tracking/WatchlistForm.tsx:90
|
||||
msgid "At least one domain name"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:106
|
||||
#: assets/components/tracking/WatchlistForm.tsx:101
|
||||
msgid "Domain names"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:124
|
||||
#: assets/components/tracking/WatchlistForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistsList.tsx:22
|
||||
msgid "Domain name"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:141
|
||||
#: assets/components/tracking/WatchlistForm.tsx:136
|
||||
msgid "Add a Domain name"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:154
|
||||
#: assets/components/tracking/WatchlistForm.tsx:149
|
||||
msgid "At least one domain trigger"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:165
|
||||
#: assets/components/tracking/WatchlistForm.tsx:160
|
||||
msgid "Domain trigger"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:178
|
||||
#: assets/components/tracking/WatchlistForm.tsx:173
|
||||
msgid "If this happens"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:188
|
||||
#: assets/components/tracking/WatchlistForm.tsx:183
|
||||
msgid "Then do that"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:201
|
||||
msgid "Connector"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistForm.tsx:227
|
||||
#: assets/components/tracking/WatchlistForm.tsx:203
|
||||
msgid "Add a Trigger"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:116
|
||||
#: assets/components/tracking/WatchlistForm.tsx:237
|
||||
#: assets/components/tracking/WatchlistForm.tsx:210
|
||||
#: assets/components/tracking/WatchlistForm.tsx:216
|
||||
msgid "Connector"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:131
|
||||
#: assets/components/tracking/WatchlistForm.tsx:228
|
||||
msgid "Create"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:119
|
||||
#: assets/components/tracking/WatchlistForm.tsx:240
|
||||
#: assets/components/tracking/ConnectorForm.tsx:134
|
||||
#: assets/components/tracking/WatchlistForm.tsx:231
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:19
|
||||
msgid "Application key"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:20
|
||||
msgid "Application secret"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:21
|
||||
msgid "Consumer key"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:26
|
||||
msgid "European Region"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:31
|
||||
msgid "Europa"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:36
|
||||
msgid "The domain is free and at the standard price"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:39
|
||||
msgid ""
|
||||
"The domain is free but is a premium. Its price varies from one domain to "
|
||||
"another"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:52
|
||||
#: assets/components/tracking/ConnectorForm.tsx:37
|
||||
#: assets/components/tracking/ConnectorsList.tsx:21
|
||||
msgid "Provider"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:57
|
||||
#: assets/components/tracking/ConnectorForm.tsx:44
|
||||
msgid "Please select a Provider"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:88
|
||||
#: assets/components/tracking/ConnectorForm.tsx:72
|
||||
msgid "OVH Endpoint"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:95
|
||||
#: assets/components/tracking/ConnectorForm.tsx:79
|
||||
msgid "OVH subsidiary"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:103
|
||||
#: assets/components/tracking/ConnectorForm.tsx:87
|
||||
msgid "OVH pricing mode"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:95
|
||||
msgid "API Terms of Service"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:102
|
||||
msgid ""
|
||||
"I certify that I have read and accepted the conditions of use of the "
|
||||
"Provider API, accessible from this hyperlink"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:108
|
||||
msgid "Legal age"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:113
|
||||
msgid ""
|
||||
"I certify on my honor that I am of the minimum age required to consent to "
|
||||
"these conditions"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:117
|
||||
msgid "Withdrawal period"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/ConnectorForm.tsx:122
|
||||
msgid ""
|
||||
"I expressly waive my right of withdrawal regarding the purchase of domain "
|
||||
"names via the Provider's API"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/WatchlistsList.tsx:14
|
||||
#, javascript-format
|
||||
msgid "Watchlist ${ watchlist.token }"
|
||||
@ -304,8 +303,8 @@ msgstr ""
|
||||
#: assets/pages/search/DomainSearchPage.tsx:23
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:23
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:31
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:35
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:43
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:36
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:44
|
||||
msgid "An error occurred"
|
||||
msgstr ""
|
||||
|
||||
@ -427,20 +426,21 @@ msgstr ""
|
||||
msgid "Create a Connector"
|
||||
msgstr ""
|
||||
|
||||
#: assets/App.tsx:143
|
||||
#: assets/pages/tracking/ConnectorsPage.tsx:48
|
||||
msgid "My Connectors"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:32
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:33
|
||||
msgid "Watchlist created !"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:53
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:54
|
||||
msgid "Create a Watchlist"
|
||||
msgstr ""
|
||||
|
||||
#: assets/App.tsx:136
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:63
|
||||
#: assets/pages/tracking/WatchlistPage.tsx:64
|
||||
msgid "My Watchlists"
|
||||
msgstr ""
|
||||
|
||||
@ -469,6 +469,42 @@ msgstr ""
|
||||
msgid "Log in with SSO"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/index.tsx:11
|
||||
msgid ""
|
||||
"Retrieve a set of tokens from your customer account on the Provider's "
|
||||
"website"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:5
|
||||
msgid "Application key"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:6
|
||||
msgid "Application secret"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:7
|
||||
msgid "Consumer key"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:12
|
||||
msgid "European Region"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:19
|
||||
msgid "Europe"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:22
|
||||
msgid "The domain is free and at the standard price"
|
||||
msgstr ""
|
||||
|
||||
#: assets/utils/providers/ovh.tsx:25
|
||||
msgid ""
|
||||
"The domain is free but is a premium. Its price varies from one domain to "
|
||||
"another"
|
||||
msgstr ""
|
||||
|
||||
#: assets/App.tsx:71
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
@ -517,10 +553,6 @@ msgstr ""
|
||||
msgid "Tracking"
|
||||
msgstr ""
|
||||
|
||||
#: assets/App.tsx:143
|
||||
msgid "My connectors"
|
||||
msgstr ""
|
||||
|
||||
#: assets/App.tsx:151
|
||||
msgid "My Watchdog"
|
||||
msgstr ""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user