Skip to content

Commit

Permalink
feat: add tracked domains table
Browse files Browse the repository at this point in the history
  • Loading branch information
maelgangloff committed Sep 9, 2024
1 parent 1241683 commit 0e96404
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 39 deletions.
6 changes: 0 additions & 6 deletions assets/components/tracking/watchlist/DomainList.tsx

This file was deleted.

79 changes: 79 additions & 0 deletions assets/components/tracking/watchlist/TrackedDomainTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, {useEffect, useState} from "react";
import {Domain, getTrackedDomainList} from "../../../utils/api";
import {Table, Tag, Tooltip} from "antd";
import {t} from "ttag";
import useBreakpoint from "../../../hooks/useBreakpoint";
import {ColumnType} from "antd/es/table";
import {rdapStatusCodeDetailTranslation} from "../../../utils/functions/rdapTranslation";
import {eppStatusCodeToColor} from "../../../utils/functions/eppStatusCodeToColor";

export function TrackedDomainTable() {
const sm = useBreakpoint('sm')
const [dataTable, setDataTable] = useState<Domain[]>([])
const [total, setTotal] = useState()


const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()

const fetchData = (params: { page: number, itemsPerPage: number }) => {
getTrackedDomainList(params).then(data => {
setTotal(data['hydra:totalItems'])
setDataTable(data['hydra:member'].map((d: Domain) => {
const expirationDate = d.events.find(e => e.action === 'expiration' && !e.deleted)?.date

return {
key: d.ldhName,
ldhName: d.ldhName,
expirationDate: expirationDate ? new Date(expirationDate).toLocaleString() : '-',
status: d.status.map(s => <Tooltip
placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>
),
updatedAt: new Date(d.updatedAt).toLocaleString()
}
}))
})
}

useEffect(() => {
fetchData({page: 1, itemsPerPage: 30})
}, [])

const columns: ColumnType<any>[] = [
{
title: t`Domain`,
dataIndex: "ldhName"
},
{
title: t`Expiration date`,
dataIndex: 'expirationDate'
},
{
title: t`Status`,
dataIndex: 'status'
},
{
title: t`Updated at`,
dataIndex: 'updatedAt'
}
]


return <Table
loading={total === undefined}
columns={columns}
dataSource={dataTable}
pagination={{
total,
hideOnSinglePage: true,
defaultPageSize: 30,
onChange: (page, itemsPerPage) => {
fetchData({page, itemsPerPage})
}
}}

{...(sm ? {scroll: {y: 'max-content'}} : {scroll: {y: 240}})}
/>
}
17 changes: 10 additions & 7 deletions assets/pages/tracking/WatchlistPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {WatchlistsList} from "../../components/tracking/watchlist/WatchlistsList
import {Connector, getConnectors} from "../../utils/api/connectors";

import {showErrorAPI} from "../../utils/functions/showErrorAPI";
import {TrackedDomainTable} from "../../components/tracking/watchlist/TrackedDomainTable";


export type Watchlist = {
Expand Down Expand Up @@ -97,13 +98,15 @@ export default function WatchlistPage() {

return <Flex gap="middle" align="center" justify="center" vertical>
{contextHolder}
{
<Card loading={connectors === undefined} title={t`Create a Watchlist`} style={{width: '100%'}}>
{connectors &&
<WatchlistForm form={form} onFinish={onCreateWatchlist} connectors={connectors} isCreation={true}/>
}
</Card>
}
<Card loading={connectors === undefined} title={t`Create a Watchlist`} style={{width: '100%'}}>
{connectors &&
<WatchlistForm form={form} onFinish={onCreateWatchlist} connectors={connectors} isCreation={true}/>
}
</Card>
<Divider/>
<Card title={t`Tracked Domains`} style={{width: '100%'}}>
<TrackedDomainTable/>
</Card>
<Divider/>
{connectors && watchlists && watchlists.length > 0 &&
<WatchlistsList watchlists={watchlists} onDelete={refreshWatchlists}
Expand Down
1 change: 1 addition & 0 deletions assets/utils/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface Domain {
nameservers: Nameserver[]
tld: Tld
deleted: boolean
updatedAt: string
}

export interface User {
Expand Down
14 changes: 12 additions & 2 deletions assets/utils/api/watchlist.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {request, Watchlist, WatchlistRequest} from "./index";
import {Domain, request, Watchlist, WatchlistRequest} from "./index";

export async function getWatchlists() {
const response = await request({
Expand Down Expand Up @@ -40,4 +40,14 @@ export async function putWatchlist(watchlist: Partial<WatchlistRequest> & { toke
data: watchlist,
})
return response.data
}
}

export async function getTrackedDomainList(params: { page: number, itemsPerPage: number }): Promise<any> {
const response = await request({
method: 'GET',
url: 'tracked',
params
})
return response.data
}

6 changes: 3 additions & 3 deletions assets/utils/functions/eppStatusCodeToColor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const eppStatusCodeToColor = (s: string) =>
['active', 'ok'].includes(s) ? 'green' :
s.startsWith('client') ? 'purple' :
s.startsWith('server') ? 'geekblue' :
s.includes('prohibited') ? 'red' : 'blue'
['pending delete', 'redemption period'].includes(s) ? 'red' :
s.startsWith('client') ? 'purple' :
s.startsWith('server') ? 'geekblue' : 'blue'
52 changes: 52 additions & 0 deletions src/Controller/WatchListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,56 @@ public function getWatchlistCalendar(string $token): Response
'Content-Type' => 'text/calendar; charset=utf-8',
]);
}

/**
* @throws \Exception
*/
#[Route(
path: '/api/tracked',
name: 'watchlist_get_tracked_domains',
defaults: [
'_api_resource_class' => WatchList::class,
'_api_operation_name' => 'get_tracked_domains',
]
)]
public function getTrackedDomains(): array
{
/** @var User $user */
$user = $this->getUser();

$domains = [];
/** @var WatchList $watchList */
foreach ($user->getWatchLists()->getIterator() as $watchList) {
/** @var Domain $domain */
foreach ($watchList->getDomains()->getIterator() as $domain) {
/** @var DomainEvent|null $exp */
$exp = $domain->getEvents()->findFirst(fn (int $key, DomainEvent $e) => !$e->getDeleted() && 'expiration' === $e->getAction());

if (!$domain->getDeleted()
&& null !== $exp && $exp->getDate() > new \DateTimeImmutable()
&& count(array_filter($domain->getEvents()->toArray(), fn (DomainEvent $e) => !$e->getDeleted() && 'expiration' === $e->getAction())) > 0
&& !in_array($domain, $domains)) {
$domains[] = $domain;
}
}
}

usort($domains, function (Domain $d1, Domain $d2) {
$IMPORTANT_STATUS = ['pending delete', 'redemption period', 'auto renew period'];

/** @var \DateTimeImmutable $exp1 */
$exp1 = $d1->getEvents()->findFirst(fn (int $key, DomainEvent $e) => !$e->getDeleted() && 'expiration' === $e->getAction())->getDate();
/** @var \DateTimeImmutable $exp2 */
$exp2 = $d2->getEvents()->findFirst(fn (int $key, DomainEvent $e) => !$e->getDeleted() && 'expiration' === $e->getAction())->getDate();
$impStatus1 = count(array_intersect($IMPORTANT_STATUS, $d1->getStatus())) > 0;
$impStatus2 = count(array_intersect($IMPORTANT_STATUS, $d2->getStatus())) > 0;

return $impStatus1 && !$impStatus2 ? -1 : (
!$impStatus1 && $impStatus2 ? 2 :
$exp1 <=> $exp2
);
});

return $domains;
}
}
9 changes: 5 additions & 4 deletions src/Entity/Domain.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Domain
* @var Collection<int, DomainEvent>
*/
#[ORM\OneToMany(targetEntity: DomainEvent::class, mappedBy: 'domain', cascade: ['persist'], orphanRemoval: true)]
#[Groups(['domain:item'])]
#[Groups(['domain:item', 'domain:list'])]
private Collection $events;

/**
Expand All @@ -69,7 +69,7 @@ class Domain
private Collection $domainEntities;

#[ORM\Column(type: Types::SIMPLE_ARRAY, nullable: true)]
#[Groups(['domain:item'])]
#[Groups(['domain:item', 'domain:list'])]
private array $status = [];

/**
Expand All @@ -93,15 +93,16 @@ class Domain
private ?\DateTimeImmutable $createdAt;

#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
#[Groups(['domain:item', 'domain:list'])]
private ?\DateTimeImmutable $updatedAt;

#[ORM\ManyToOne]
#[ORM\JoinColumn(referencedColumnName: 'tld', nullable: false)]
#[Groups(['domain:item'])]
#[Groups(['domain:item', 'domain:list'])]
private ?Tld $tld = null;

#[ORM\Column(nullable: false)]
#[Groups(['domain:item'])]
#[Groups(['domain:item', 'domain:list'])]
private ?bool $deleted;

public function __construct()
Expand Down
12 changes: 10 additions & 2 deletions src/Entity/WatchList.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Controller\WatchListController;
use App\Repository\WatchListRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
Expand All @@ -27,6 +26,16 @@
normalizationContext: ['groups' => 'watchlist:list'],
name: 'get_all_mine',
),
new GetCollection(
uriTemplate: '/tracked',
routeName: 'watchlist_get_tracked_domains',
normalizationContext: ['groups' => [
'domain:list',
'tld:list',
'event:list',
]],
name: 'get_tracked_domains'
),
new Get(
normalizationContext: ['groups' => [
'watchlist:item',
Expand All @@ -42,7 +51,6 @@
),
new Get(
routeName: 'watchlist_calendar',
controller: WatchListController::class,
openapiContext: [
'responses' => [
'200' => [
Expand Down
12 changes: 6 additions & 6 deletions src/MessageHandler/UpdateDomainsFromWatchlistHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,16 @@ public function __invoke(UpdateDomainsFromWatchlist $message): void
/** @var Domain $domain */
foreach ($watchList->getDomains()
->filter(fn ($domain) => $domain->getUpdatedAt()
->diff(
new \DateTimeImmutable())->days >= 7
->diff(new \DateTimeImmutable())->days >= 7
|| (
($domain->getUpdatedAt()
->diff(
new \DateTimeImmutable())->h * 60 + $domain->getUpdatedAt()
->diff(
new \DateTimeImmutable())->i) >= 50
->diff(new \DateTimeImmutable())->h * 60 + $domain->getUpdatedAt()
->diff(new \DateTimeImmutable())->i) >= 50
&& $this->RDAPService::isToBeWatchClosely($domain)
)
|| (count(array_intersect($domain->getStatus(), ['auto renew period', 'client hold', 'server hold'])) > 0
&& $domain->getUpdatedAt()->diff(new \DateTimeImmutable())->days >= 1
)
) as $domain
) {
$updatedAt = $domain->getUpdatedAt();
Expand Down
3 changes: 0 additions & 3 deletions src/Service/RDAPService.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,13 @@

private const IMPORTANT_EVENTS = [EventAction::Deletion->value, EventAction::Expiration->value];
private const IMPORTANT_STATUS = [
'auto renew period',
'redemption period',
'pending delete',
'pending create',
'pending renew',
'pending restore',
'pending transfer',
'pending update',
'client hold',
'server hold',
'add period',
];

Expand Down
29 changes: 23 additions & 6 deletions translations/translations.pot
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,23 @@ msgstr ""
msgid "Are you sure to delete this Watchlist?"
msgstr ""

#: assets/components/Sider.tsx:40
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:46
msgid "Domain"
msgstr ""

#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:50
msgid "Expiration date"
msgstr ""

#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:54
msgid "Status"
msgstr ""

#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:58
msgid "Updated at"
msgstr ""

#: assets/components/tracking/watchlist/WatchlistCard.tsx:47
msgid "This Watchlist is not linked to a Connector."
msgstr ""
Expand All @@ -314,10 +331,6 @@ msgstr ""
msgid "Search"
msgstr ""

#: assets/components/Sider.tsx:40
msgid "Domain"
msgstr ""

#: assets/components/Sider.tsx:41
msgid "Domain Finder"
msgstr ""
Expand Down Expand Up @@ -470,18 +483,22 @@ msgstr ""
msgid "Create a Connector"
msgstr ""

#: assets/pages/tracking/WatchlistPage.tsx:65
#: assets/pages/tracking/WatchlistPage.tsx:66
msgid "Watchlist created !"
msgstr ""

#: assets/pages/tracking/WatchlistPage.tsx:77
#: assets/pages/tracking/WatchlistPage.tsx:78
msgid "Watchlist updated !"
msgstr ""

#: assets/pages/tracking/WatchlistPage.tsx:101
msgid "Create a Watchlist"
msgstr ""

#: assets/pages/tracking/WatchlistPage.tsx:107
msgid "Tracked Domains"
msgstr ""

#: assets/pages/NotFoundPage.tsx:10
msgid "Sorry, the page you visited does not exist."
msgstr ""
Expand Down

0 comments on commit 0e96404

Please sign in to comment.