mirror of
https://github.com/nidebr/as-stats-gui.git
synced 2025-02-20 11:23:18 +08:00
save
This commit is contained in:
parent
bfe57232dc
commit
b79da8b937
1
asset/.gitignore
vendored
Normal file
1
asset/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*
|
@ -4,6 +4,10 @@ config:
|
||||
knownlinksfile: '/home/nidebr/data/DEV/asstats/conf/knownlinks'
|
||||
asinfofile: 'ressources/asinfo.db'
|
||||
myasn: 34863
|
||||
asset:
|
||||
whois: '/usr/bin/whois'
|
||||
assetpath: 'asset'
|
||||
asset_cache_life: 604800 # 604800 seconds = 7 days
|
||||
graph:
|
||||
showv6: true
|
||||
outispositive: false
|
||||
@ -21,7 +25,7 @@ config:
|
||||
top_graph_width: 600
|
||||
top_graph_height: 220
|
||||
linksusage:
|
||||
top: 3
|
||||
top: 10
|
||||
color:
|
||||
- A6CEE3
|
||||
- 1F78B4
|
||||
|
@ -18,10 +18,12 @@
|
||||
"symfony/http-client": "7.0.*",
|
||||
"symfony/process": "7.0.*",
|
||||
"symfony/runtime": "7.0.*",
|
||||
"symfony/translation": "7.0.*",
|
||||
"symfony/twig-bundle": "7.0.*",
|
||||
"symfony/validator": "7.0.*",
|
||||
"symfony/yaml": "7.0.*",
|
||||
"twig/extra-bundle": "^3.0",
|
||||
"twig/intl-extra": "^3.8",
|
||||
"twig/string-extra": "^3.0",
|
||||
"twig/twig": "^3.0"
|
||||
},
|
||||
|
7
config/packages/translation.yaml
Normal file
7
config/packages/translation.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
framework:
|
||||
default_locale: en
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
fallbacks:
|
||||
- en
|
||||
- fr
|
@ -16,3 +16,4 @@ parameters:
|
||||
ignoreErrors:
|
||||
- '#Only booleans are allowed#'
|
||||
- '#Cannot cast mixed to int.#'
|
||||
- '#Cannot cast mixed to string.#'
|
||||
|
@ -66,6 +66,15 @@ class ConfigApplication
|
||||
return self::getAsStatsConfig()['top'];
|
||||
}
|
||||
|
||||
public static function getLangage(): string
|
||||
{
|
||||
if (false === \array_key_exists('langage', self::getAsStatsConfig())) {
|
||||
return 'en';
|
||||
}
|
||||
|
||||
return self::getAsStatsConfig()['langage'];
|
||||
}
|
||||
|
||||
public static function getAsStatsConfigMyAsn(): ?int
|
||||
{
|
||||
if (false === \array_key_exists('myasn', self::getAsStatsConfig())) {
|
||||
@ -174,4 +183,43 @@ class ConfigApplication
|
||||
|
||||
return self::getAsStatsConfig()['linksusage']['top'];
|
||||
}
|
||||
|
||||
public static function getAsStatsAssetPath(): string
|
||||
{
|
||||
if (false === \array_key_exists('asset', self::getAsStatsConfig())) {
|
||||
throw new ConfigErrorException('Unable to found config.asset variable');
|
||||
}
|
||||
|
||||
if (false === \array_key_exists('assetpath', self::getAsStatsConfig()['asset'])) {
|
||||
throw new ConfigErrorException('Unable to found config.asset.assetpath variable');
|
||||
}
|
||||
|
||||
return self::getRootPathApp().self::getAsStatsConfig()['asset']['assetpath'];
|
||||
}
|
||||
|
||||
public static function getAsStatsAssetCacheLife(): int
|
||||
{
|
||||
if (false === \array_key_exists('asset', self::getAsStatsConfig())) {
|
||||
throw new ConfigErrorException('Unable to found config.asset variable');
|
||||
}
|
||||
|
||||
if (false === \array_key_exists('asset_cache_life', self::getAsStatsConfig()['asset'])) {
|
||||
throw new ConfigErrorException('Unable to found config.asset.asset_cache_life variable');
|
||||
}
|
||||
|
||||
return self::getAsStatsConfig()['asset']['asset_cache_life'];
|
||||
}
|
||||
|
||||
public static function getAsStatsAssetWhois(): string
|
||||
{
|
||||
if (false === \array_key_exists('asset', self::getAsStatsConfig())) {
|
||||
throw new ConfigErrorException('Unable to found config.asset variable');
|
||||
}
|
||||
|
||||
if (false === \array_key_exists('whois', self::getAsStatsConfig()['asset'])) {
|
||||
throw new ConfigErrorException('Unable to found config.asset.whois variable');
|
||||
}
|
||||
|
||||
return self::getAsStatsConfig()['asset']['whois'];
|
||||
}
|
||||
}
|
||||
|
70
src/Controller/AssetController.php
Normal file
70
src/Controller/AssetController.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Form\SearchASSetForm;
|
||||
use App\Repository\AsSetRepository;
|
||||
use App\Repository\GetAsDataRepository;
|
||||
use App\Repository\KnowlinksRepository;
|
||||
use App\Util\Annotation\Menu;
|
||||
use App\Util\GetStartEndGraph;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
#[Menu('asset')]
|
||||
class AssetController extends BaseController
|
||||
{
|
||||
protected array $data = [];
|
||||
|
||||
#[Route(
|
||||
path: '/asset',
|
||||
name: 'asset',
|
||||
methods: ['GET|POST'],
|
||||
)]
|
||||
public function index(
|
||||
Request $request,
|
||||
AsSetRepository $asSetRepository,
|
||||
GetAsDataRepository $asDataRepository,
|
||||
GetStartEndGraph $getStartEndGraph,
|
||||
): Response {
|
||||
$this->base_data['content_wrapper']['titre'] = 'History for AS-SET';
|
||||
|
||||
$form = $this->createForm(SearchASSetForm::class);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->data['asset']['name'] = \strtoupper((string) $form->get('asset')->getData());
|
||||
$this->data['asset']['whois'] = $asSetRepository->getAsset($this->data['asset']['name']);
|
||||
|
||||
if (\array_key_exists('as_num', $this->data['asset']['whois'])) {
|
||||
$this->data['asset']['data'] = $asDataRepository::get(200, '', [], $this->data['asset']['whois']['as_num']);
|
||||
|
||||
$this->data['selectedLinks'] = [];
|
||||
$this->data['graph_size'] = [
|
||||
'width' => $this->configApplication::getAsStatsConfigGraph()['top_graph_width'],
|
||||
'height' => $this->configApplication::getAsStatsConfigGraph()['top_graph_height'],
|
||||
];
|
||||
|
||||
$this->data = \array_merge($this->data, $getStartEndGraph->get());
|
||||
|
||||
return $this->render('pages/asset/show.html.twig', [
|
||||
'base_data' => $this->base_data,
|
||||
'data' => $this->data,
|
||||
'form' => $form->createView(),
|
||||
'knownlinks' => KnowlinksRepository::get(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addFlash('info', \sprintf('Unable to find information about asset %s', $this->data['asset']['name']));
|
||||
}
|
||||
|
||||
return $this->render('pages/asset/index.html.twig', [
|
||||
'base_data' => $this->base_data,
|
||||
'data' => $this->data,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Translation\LocaleSwitcher;
|
||||
|
||||
abstract class BaseController extends AbstractController
|
||||
{
|
||||
@ -19,9 +20,12 @@ abstract class BaseController extends AbstractController
|
||||
public function __construct(
|
||||
ConfigApplication $configApplication,
|
||||
RequestStack $requestStack,
|
||||
LocaleSwitcher $localeSwitcher,
|
||||
) {
|
||||
$this->configApplication = $configApplication;
|
||||
$this->base_data = self::getBaseData($requestStack);
|
||||
|
||||
$localeSwitcher->setLocale($this->configApplication::getLangage());
|
||||
}
|
||||
|
||||
private function getBaseData(
|
||||
|
@ -56,6 +56,10 @@ class HistoryController extends BaseController
|
||||
$this->data['as'] = $as;
|
||||
$this->data['asinfo'] = $asInfoRepository->getAsInfo($this->data['as']);
|
||||
|
||||
if ('UNKNOWN' === $this->data['asinfo']['name']) {
|
||||
$this->addFlash('error', \sprintf('Unable to find AS%s in database ASInfo, please update.', $this->data['as']));
|
||||
}
|
||||
|
||||
$this->base_data['content_wrapper']['titre'] = \sprintf(
|
||||
'History for AS%s',
|
||||
$this->data['as'],
|
||||
|
@ -14,6 +14,7 @@ use App\Repository\KnowlinksRepository;
|
||||
use App\Repository\PeeringDBRepository;
|
||||
use App\Util\Annotation\Menu;
|
||||
use App\Util\GetJsonParameters;
|
||||
use App\Util\GetStartEndGraph;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -43,6 +44,7 @@ class IXStatsController extends BaseController
|
||||
Request $request,
|
||||
PeeringDBRepository $peeringDBRepository,
|
||||
GetAsDataRepository $asDataRepository,
|
||||
GetStartEndGraph $getStartEndGraph,
|
||||
): Response {
|
||||
$this->base_data['content_wrapper']['titre'] = 'My IX Stats';
|
||||
|
||||
@ -66,14 +68,14 @@ class IXStatsController extends BaseController
|
||||
$peeringDBRepository->getIXMembers((int) $form->get('myix')->getData()),
|
||||
);
|
||||
|
||||
$this->data['start'] = time() - 24 * 3600;
|
||||
$this->data['end'] = time();
|
||||
$this->data['graph_size'] = [
|
||||
'width' => $this->configApplication::getAsStatsConfigGraph()['top_graph_width'],
|
||||
'height' => $this->configApplication::getAsStatsConfigGraph()['top_graph_height'],
|
||||
];
|
||||
$this->data['selectedLinks'] = [];
|
||||
|
||||
$this->data = \array_merge($this->data, $getStartEndGraph->get());
|
||||
|
||||
return $this->render('pages/ix/my_ix/show.html.twig', [
|
||||
'base_data' => $this->base_data,
|
||||
'data' => $this->data,
|
||||
@ -103,6 +105,7 @@ class IXStatsController extends BaseController
|
||||
Request $request,
|
||||
PeeringDBRepository $peeringDBRepository,
|
||||
GetAsDataRepository $asDataRepository,
|
||||
GetStartEndGraph $getStartEndGraph,
|
||||
): Response {
|
||||
$this->base_data['content_wrapper']['titre'] = 'Search IX Stats';
|
||||
|
||||
@ -125,14 +128,14 @@ class IXStatsController extends BaseController
|
||||
$peeringDBRepository->getIXMembers((int) $form->get('ix_hidden')->getData()),
|
||||
);
|
||||
|
||||
$this->data['start'] = time() - 24 * 3600;
|
||||
$this->data['end'] = time();
|
||||
$this->data['graph_size'] = [
|
||||
'width' => $this->configApplication::getAsStatsConfigGraph()['top_graph_width'],
|
||||
'height' => $this->configApplication::getAsStatsConfigGraph()['top_graph_height'],
|
||||
];
|
||||
$this->data['selectedLinks'] = [];
|
||||
|
||||
$this->data = \array_merge($this->data, $getStartEndGraph->get());
|
||||
|
||||
return $this->render('pages/ix/search_ix/show.html.twig', [
|
||||
'base_data' => $this->base_data,
|
||||
'data' => $this->data,
|
||||
|
@ -16,6 +16,7 @@ use Doctrine\DBAL\Exception;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
#[Menu('top_as')]
|
||||
class IndexController extends BaseController
|
||||
@ -37,11 +38,12 @@ class IndexController extends BaseController
|
||||
Request $request,
|
||||
GetAsDataRepository $asDataRepository,
|
||||
GetStartEndGraph $getStartEndGraph,
|
||||
TranslatorInterface $translator,
|
||||
): Response {
|
||||
$this->base_data['content_wrapper']['titre'] = \sprintf(
|
||||
'Top %s (%s)',
|
||||
$this->base_data['top'],
|
||||
'24 hours'
|
||||
$translator->trans('hour', ['num_hours' => 24]),
|
||||
);
|
||||
|
||||
$form = $this->createForm(LegendForm::class);
|
||||
|
41
src/Form/SearchASSetForm.php
Normal file
41
src/Form/SearchASSetForm.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class SearchASSetForm extends AbstractType
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->setMethod('get')
|
||||
->add('asset', TextType::class, [
|
||||
'attr' => [
|
||||
'placeholder' => 'Search AS-SET',
|
||||
],
|
||||
'translation_domain' => false,
|
||||
'label' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBlockPrefix(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'csrf_protection' => false,
|
||||
]);
|
||||
}
|
||||
}
|
123
src/Repository/AsSetRepository.php
Normal file
123
src/Repository/AsSetRepository.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Application\ConfigApplication;
|
||||
use App\Exception\ConfigErrorException;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class AsSetRepository
|
||||
{
|
||||
private ConfigApplication $config;
|
||||
|
||||
public function __construct(ConfigApplication $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ConfigErrorException
|
||||
*/
|
||||
public function getAsset(string $asset): array
|
||||
{
|
||||
/* sanity check */
|
||||
if (!\preg_match('/^[a-zA-Z0-9:_-]+$/', $asset)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cache = false;
|
||||
|
||||
$assetfile = \sprintf('%s/%s.txt', $this->config::getAsStatsAssetPath(), $asset);
|
||||
|
||||
if (\file_exists($assetfile)) {
|
||||
$filemtime = \filemtime($assetfile);
|
||||
if (!$filemtime || (\time() - $filemtime >= $this->config::getAsStatsAssetCacheLife())) {
|
||||
$list = $this->getWhois($asset);
|
||||
} else {
|
||||
$list = $this->readCacheFile($asset);
|
||||
$cache = true;
|
||||
if ([] === $list) {
|
||||
$list = $this->getWhois($asset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$list = $this->getWhois($asset);
|
||||
}
|
||||
|
||||
return \array_merge(['cache' => $cache], $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ConfigErrorException
|
||||
*/
|
||||
private function getWhois(string $asset): array
|
||||
{
|
||||
$process = new Process([$this->config::getAsStatsAssetWhois(), '-h', 'whois.radb.net', \sprintf('!i%s', $asset)]);
|
||||
$process->run();
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new ProcessFailedException($process);
|
||||
}
|
||||
|
||||
$return_list = \explode(' ', \trim(\str_replace(PHP_EOL, ' ', $process->getOutput())));
|
||||
|
||||
/* write cache file */
|
||||
$this->writeCacheFile($asset, $process->getOutput());
|
||||
|
||||
return $this->parseOtherAsset($this->parseData($return_list));
|
||||
}
|
||||
|
||||
private function parseData(array $asnlist): array
|
||||
{
|
||||
$return = [];
|
||||
foreach ($asnlist as $asn) {
|
||||
if (\str_starts_with($asn, 'AS')) {
|
||||
$return[] = $asn;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
private function writeCacheFile(string $asset, string $asnlist): void
|
||||
{
|
||||
if ('' !== $asset && '0' !== $asset) {
|
||||
\file_put_contents(\sprintf('%s/%s.txt', $this->config::getAsStatsAssetPath(), $asset), $asnlist);
|
||||
}
|
||||
}
|
||||
|
||||
private function readCacheFile(string $asset): array
|
||||
{
|
||||
$return = [];
|
||||
if ('' !== $asset && '0' !== $asset) {
|
||||
$input = \file_get_contents(\sprintf('%s/%s.txt', $this->config::getAsStatsAssetPath(), $asset));
|
||||
|
||||
if (!$input) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$return = \explode(' ', \trim(\str_replace(PHP_EOL, ' ', $input)));
|
||||
}
|
||||
|
||||
return $this->parseOtherAsset($this->parseData($return));
|
||||
}
|
||||
|
||||
private function parseOtherAsset(array $aslist): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
foreach ($aslist as $as) {
|
||||
$as_tmp = \substr($as, 2);
|
||||
if (\is_numeric($as_tmp)) {
|
||||
$return['as_num'][] = $as_tmp;
|
||||
} else {
|
||||
$return['as_other'][] = $as;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
@ -87,12 +87,23 @@ class DbAsInfoRepository
|
||||
public function getAsInfo(int $asn): array
|
||||
{
|
||||
try {
|
||||
return (array) $this->cnx->createQueryBuilder()
|
||||
$return = $this->cnx->createQueryBuilder()
|
||||
->select('*')
|
||||
->from('asinfo')
|
||||
->where('asn = :asn')
|
||||
->setParameter('asn', $asn)
|
||||
->fetchAssociative();
|
||||
|
||||
if (false === $return) {
|
||||
$return = [
|
||||
'asn' => $asn,
|
||||
'country' => 'EU',
|
||||
'name' => 'UNKNOWN',
|
||||
'description' => 'UNKNOWN',
|
||||
];
|
||||
}
|
||||
|
||||
return (array) $return;
|
||||
} catch (Exception) {
|
||||
throw new DbErrorException(\sprintf('Problem with ASInfo DB files %s', $this->dbname));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ enum Icon: string
|
||||
case menu_view = 'ti-chart-histogram icon';
|
||||
case menu_ix = 'ti-list-details icon';
|
||||
case menu_linksusage = 'ti-package icon';
|
||||
case menu_asset = 'ti-file-neutral icon';
|
||||
|
||||
// Form
|
||||
case filter = 'ti-filter';
|
||||
|
13
symfony.lock
13
symfony.lock
@ -106,6 +106,19 @@
|
||||
"config/routes.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/translation": {
|
||||
"version": "7.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.3",
|
||||
"ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/translation.yaml",
|
||||
"translations/.gitignore"
|
||||
]
|
||||
},
|
||||
"symfony/twig-bundle": {
|
||||
"version": "7.0",
|
||||
"recipe": {
|
||||
|
@ -46,6 +46,17 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item {% if "asset" == current_menu %}active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('asset') }}">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
{{ icon('menu_asset') }}
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
View AS-SET
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown {% if "view_ix" == current_menu %}active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
|
@ -1,72 +1,69 @@
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<div class="col-1">
|
||||
<div class="card-body {% if (block('rank') is defined and block('rank') is not empty) %}ps-10{% endif %}">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{% if block('title') is defined and block('title') is not empty %}
|
||||
{% block title %}{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if configapplication_graph('showv6') %}
|
||||
{% set col_ipv4 = 'col-lg-6 col-sm-12' %}
|
||||
{% else %}
|
||||
{% set col_ipv4 = 'col-lg-12' %}
|
||||
{% endif %}
|
||||
|
||||
<div class="{{ col_ipv4 }}">
|
||||
{% set title = "AS#{as} - #{as_data.info.description|default('')} - IPv4" %}
|
||||
<div class="text-center">
|
||||
<a href="{{ path('history.as', {'as': as}) }}">
|
||||
{{ gen_graph(as, 4, title, data.start, data.end, data.selectedLinks|concat_link, data.graph_size.width, data.graph_size.height, configapplication_graph('showlegendontop')) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if configapplication_graph('showv6') %}
|
||||
<div class="col-lg-6 col-sm-12">
|
||||
{% set title = "AS#{as} - #{as_data.info.description|default('')} - IPv6" %}
|
||||
<div class="text-center">
|
||||
<a href="{{ path('history.as', {'as': as}) }}">
|
||||
{{ gen_graph(as, 6, title, data.start, data.end, data.selectedLinks|concat_link, data.graph_size.width, data.graph_size.height, configapplication_graph('showlegendontop')) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<div class="mt-3 list-inline list-inline-dots mb-0 text-secondary d-sm-block d-none">
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_hours', 'icon icon-inline fix-icon-inline') }}
|
||||
In the last {{ hours }}
|
||||
</div>
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_ip', 'icon icon-inline fix-icon-inline') }}
|
||||
IPv4: ~ {{ as_data.v4.in|format_bytes }} in / {{ as_data.v4.out|format_bytes }} out
|
||||
</div>
|
||||
{% if configapplication_graph('showv6') %}
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_ip', 'icon icon-inline fix-icon-inline') }}
|
||||
IPv6: ~ {{ as_data.v6.in|format_bytes }} in / {{ as_data.v6.out|format_bytes }} out
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if block('customlinks') is defined and block('customlinks') is not empty %}
|
||||
{% block customlinks %}{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if (block('rank') is defined and block('rank') is not empty) %}
|
||||
<div class="card-body">
|
||||
<div class="ribbon">
|
||||
{% block rank %}{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card-body {% if (block('rank') is defined and block('rank') is not empty) %}ps-0{% endif %}">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{% if block('title') is defined and block('title') is not empty %}
|
||||
{% block title %}{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if configapplication_graph('showv6') %}
|
||||
{% set col_ipv4 = 'col-lg-6 col-sm-12' %}
|
||||
{% else %}
|
||||
{% set col_ipv4 = 'col-lg-12' %}
|
||||
{% endif %}
|
||||
|
||||
<div class="{{ col_ipv4 }}">
|
||||
{% set title = "AS#{as} - #{as_data.info.description|default('')} - IPv4" %}
|
||||
<div class="text-center">
|
||||
<a href="{{ path('history.as', {'as': as}) }}">
|
||||
{{ gen_graph(as, 4, title, data.start, data.end, data.selectedLinks|concat_link, data.graph_size.width, data.graph_size.height, configapplication_graph('showlegendontop')) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if configapplication_graph('showv6') %}
|
||||
<div class="col-lg-6 col-sm-12">
|
||||
{% set title = "AS#{as} - #{as_data.info.description|default('')} - IPv6" %}
|
||||
<div class="text-center">
|
||||
<a href="{{ path('history.as', {'as': as}) }}">
|
||||
{{ gen_graph(as, 6, title, data.start, data.end, data.selectedLinks|concat_link, data.graph_size.width, data.graph_size.height, configapplication_graph('showlegendontop')) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<div class="mt-3 list-inline list-inline-dots mb-0 text-secondary d-sm-block d-none">
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_hours', 'icon icon-inline fix-icon-inline') }}
|
||||
In the last {{ hours }}
|
||||
</div>
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_ip', 'icon icon-inline fix-icon-inline') }}
|
||||
IPv4: ~ {{ as_data.v4.in|format_bytes }} in / {{ as_data.v4.out|format_bytes }} out
|
||||
</div>
|
||||
{% if configapplication_graph('showv6') %}
|
||||
<div class="list-inline-item">
|
||||
{{ icon('top_ip', 'icon icon-inline fix-icon-inline') }}
|
||||
IPv6: ~ {{ as_data.v6.in|format_bytes }} in / {{ as_data.v6.out|format_bytes }} out
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if block('customlinks') is defined and block('customlinks') is not empty %}
|
||||
{% block customlinks %}{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,10 +3,10 @@
|
||||
{{ form_start(form.legend) }}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">
|
||||
<strong>Legend</strong>
|
||||
</h3>
|
||||
<div class="table-responsive">
|
||||
<div class="ribbon">
|
||||
Legend
|
||||
</div>
|
||||
<div class="table-responsive mt-5">
|
||||
<table class="table table-borderless table-sm">
|
||||
<tbody>
|
||||
{% if knownlinks is defined %}
|
||||
|
15
templates/pages/asset/_search.html.twig
Normal file
15
templates/pages/asset/_search.html.twig
Normal file
@ -0,0 +1,15 @@
|
||||
{{ form_start(form) }}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Search AS-SET</h3>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ form_widget(form.asset, {'value': data.asset.name|default('')}) }}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-icon">{{ icon('search', 'icon') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
22
templates/pages/asset/index.html.twig
Normal file
22
templates/pages/asset/index.html.twig
Normal file
@ -0,0 +1,22 @@
|
||||
{% extends "base/_layout.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row row-cards">
|
||||
<div class="col-lg-2 col-sm-12">
|
||||
<div class="row row-cards">
|
||||
<div class="col-lg-12">
|
||||
{% include 'pages/asset/_search.html.twig' %}
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
{% block legend %}{% endblock %}
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
{% block other_asset %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-10 col-sm-12">
|
||||
{% block graphs %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
60
templates/pages/asset/show.html.twig
Normal file
60
templates/pages/asset/show.html.twig
Normal file
@ -0,0 +1,60 @@
|
||||
{% extends "pages/asset/index.html.twig" %}
|
||||
|
||||
{% set counter = 0 %}
|
||||
|
||||
{% block legend %}
|
||||
{% if knownlinks is defined %}
|
||||
{% include 'core/legend_simple.html.twig' %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block other_asset %}
|
||||
{% if data.asset.whois.as_other is defined %}
|
||||
<div class="card card-sm">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">
|
||||
<strong>Other AS-SET</strong>
|
||||
</h3>
|
||||
|
||||
<div class="list-group list-group-flush">
|
||||
{% for asset in data.asset.whois.as_other %}
|
||||
<a href="#" class="list-group-item list-group-item-action">{{ asset }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block graphs %}
|
||||
<div class="col">
|
||||
<div class="row row-cards">
|
||||
<div class="space-y">
|
||||
{% for as, as_data in data.asset.data.asinfo %}
|
||||
{% set counter = counter + 1 %}
|
||||
{% embed 'core/card_top.html.twig' with {as: as, as_data: as_data, data: data, counter: counter, hours: hours|default('24 hours')} only %}
|
||||
{% block rank %}
|
||||
# {{ counter }}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<h3 class="mb-0">
|
||||
<span class="me-2 flag flag-{{ as_data.info.country|default('eu')|lower }}"></span>
|
||||
<strong>AS{{ as }}:</strong>
|
||||
<span class="small text-uppercase"><i>{{ as_data.info.name|default(as_data.info.description|default('')) }}</i></span>
|
||||
</h3>
|
||||
{% endblock %}
|
||||
|
||||
{% block customlinks %}
|
||||
<div class="col-md-auto">
|
||||
<div class="mt-3 badges">
|
||||
{{ custom_links_top(as)|raw }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -2,7 +2,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Search AS</h3>
|
||||
<div class="row g2">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ form_widget(form.as, {'value': data.as|default('')}) }}
|
||||
</div>
|
||||
|
@ -12,9 +12,7 @@
|
||||
{% set counter = counter + 1 %}
|
||||
{% embed 'core/card_top.html.twig' with {as: as, as_data: as_data, data: data, counter: counter, hours: hours|default('24 hours')} only %}
|
||||
{% block rank %}
|
||||
<div class="display-6 fw-bold rank">
|
||||
# {{ counter }}
|
||||
</div>
|
||||
# {{ counter }}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
|
0
translations/.gitignore
vendored
Normal file
0
translations/.gitignore
vendored
Normal file
6
translations/messages+intl-icu.en.yaml
Normal file
6
translations/messages+intl-icu.en.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
hour: >-
|
||||
{num_hours, plural,
|
||||
=0 {# hour}
|
||||
=1 {# hour}
|
||||
other {# hours}
|
||||
}
|
6
translations/messages+intl-icu.fr.yaml
Normal file
6
translations/messages+intl-icu.fr.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
hour: >-
|
||||
{num_hours, plural,
|
||||
=0 {# heure}
|
||||
=1 {# heure}
|
||||
other {# heures}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user