mirror of
https://github.com/standardebooks/web.git
synced 2025-07-08 07:40:39 -04:00
Standardize trim and other validation of nullable and non-nullable properties
This commit is contained in:
parent
0eaf2e8e47
commit
85307a7c7e
21 changed files with 347 additions and 16 deletions
|
@ -55,13 +55,34 @@ class Collection{
|
||||||
public function Validate(): void{
|
public function Validate(): void{
|
||||||
$error = new Exceptions\ValidationException();
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
$this->Name = trim($this->Name ?? '');
|
if(isset($this->Name)){
|
||||||
if($this->Name == ''){
|
$this->Name = trim($this->Name);
|
||||||
|
|
||||||
|
if($this->Name == ''){
|
||||||
|
$error->Add(new Exceptions\CollectionNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('Collection name: '. $this->Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
$error->Add(new Exceptions\CollectionNameRequiredException());
|
$error->Add(new Exceptions\CollectionNameRequiredException());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
if(isset($this->UrlName)){
|
||||||
$error->Add(new Exceptions\StringTooLongException('Collection name: '. $this->Name));
|
$this->UrlName = trim($this->UrlName);
|
||||||
|
|
||||||
|
if($this->UrlName == ''){
|
||||||
|
$error->Add(new Exceptions\CollectionUrlNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->UrlName) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('Collection UrlName: '. $this->UrlName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\CollectionUrlNameRequiredException());
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->Type !== null && ($this->Type != CollectionType::Series && $this->Type != CollectionType::Set)){
|
if($this->Type !== null && ($this->Type != CollectionType::Series && $this->Type != CollectionType::Set)){
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<?
|
<?
|
||||||
|
|
||||||
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
|
use function Safe\preg_match;
|
||||||
|
|
||||||
class Contributor{
|
class Contributor{
|
||||||
public ?int $ContributorId = null;
|
public ?int $ContributorId = null;
|
||||||
public ?int $EbookId = null;
|
public ?int $EbookId = null;
|
||||||
|
@ -23,7 +28,100 @@ class Contributor{
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
|
public function Validate(): void{
|
||||||
|
/** @throws void */
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
|
if(!isset($this->EbookId)){
|
||||||
|
$error->Add(new Exceptions\ContributorEbookIdRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->Name)){
|
||||||
|
$this->Name = trim($this->Name);
|
||||||
|
|
||||||
|
if($this->Name == ''){
|
||||||
|
$error->Add(new Exceptions\ContributorNameRequiredException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\ContributorNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->UrlName)){
|
||||||
|
$this->UrlName = trim($this->UrlName);
|
||||||
|
|
||||||
|
if($this->UrlName == ''){
|
||||||
|
$error->Add(new Exceptions\ContributorUrlNameRequiredException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\ContributorUrlNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->SortName = trim($this->SortName ?? '');
|
||||||
|
if($this->SortName == ''){
|
||||||
|
$this->SortName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->FullName = trim($this->FullName ?? '');
|
||||||
|
if($this->FullName == ''){
|
||||||
|
$this->FullName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->WikipediaUrl = trim($this->WikipediaUrl ?? '');
|
||||||
|
if($this->WikipediaUrl == ''){
|
||||||
|
$this->WikipediaUrl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->WikipediaUrl)){
|
||||||
|
if(!preg_match('|https://.*wiki.*|ius', $this->WikipediaUrl)){
|
||||||
|
$error->Add(new Exceptions\InvalidContributorWikipediaUrlException('Invalid Contributor WikipediaUrl: ' . $this->WikipediaUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->WikipediaUrl) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('Contributor WikipediaUrl'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->MarcRole = trim($this->MarcRole ?? '');
|
||||||
|
if($this->MarcRole == ''){
|
||||||
|
$this->MarcRole = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->NacoafUrl = trim($this->NacoafUrl ?? '');
|
||||||
|
if($this->NacoafUrl == ''){
|
||||||
|
$this->NacoafUrl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->NacoafUrl)){
|
||||||
|
if(!preg_match('|https?://id\.loc\.gov/.*|ius', $this->NacoafUrl)){
|
||||||
|
$error->Add(new Exceptions\InvalidContributorNacoafUrlException('Invalid Contributor NacoafUrl: ' . $this->NacoafUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->NacoafUrl) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('Contributor NacoafUrl'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($this->SortOrder)){
|
||||||
|
$error->Add(new Exceptions\ContributorSortOrderRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if($error->HasExceptions){
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
public function Create(): void{
|
public function Create(): void{
|
||||||
|
$this->Validate();
|
||||||
Db::Query('
|
Db::Query('
|
||||||
INSERT into Contributors (EbookId, Name, UrlName, SortName, WikipediaUrl, MarcRole, FullName,
|
INSERT into Contributors (EbookId, Name, UrlName, SortName, WikipediaUrl, MarcRole, FullName,
|
||||||
NacoafUrl, SortOrder)
|
NacoafUrl, SortOrder)
|
||||||
|
|
|
@ -1750,6 +1750,9 @@ class Ebook{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
private function InsertGitCommits(): void{
|
private function InsertGitCommits(): void{
|
||||||
foreach($this->GitCommits as $commit){
|
foreach($this->GitCommits as $commit){
|
||||||
$commit->EbookId = $this->EbookId;
|
$commit->EbookId = $this->EbookId;
|
||||||
|
@ -1765,6 +1768,9 @@ class Ebook{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
private function InsertSources(): void{
|
private function InsertSources(): void{
|
||||||
foreach($this->Sources as $source){
|
foreach($this->Sources as $source){
|
||||||
$source->EbookId = $this->EbookId;
|
$source->EbookId = $this->EbookId;
|
||||||
|
@ -1780,6 +1786,9 @@ class Ebook{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
private function InsertContributors(): void{
|
private function InsertContributors(): void{
|
||||||
$allContributors = array_merge($this->Authors, $this->Illustrators, $this->Translators, $this->Contributors);
|
$allContributors = array_merge($this->Authors, $this->Illustrators, $this->Translators, $this->Contributors);
|
||||||
foreach($allContributors as $sortOrder => $contributor){
|
foreach($allContributors as $sortOrder => $contributor){
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
<?
|
<?
|
||||||
|
|
||||||
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
class EbookSource{
|
class EbookSource{
|
||||||
public ?int $EbookSourceId = null;
|
public ?int $EbookSourceId = null;
|
||||||
public ?int $EbookId = null;
|
public ?int $EbookId = null;
|
||||||
|
@ -12,7 +15,40 @@ class EbookSource{
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
|
public function Validate(): void{
|
||||||
|
/** @throws void */
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
|
if(!isset($this->EbookId)){
|
||||||
|
$error->Add(new Exceptions\EbookSourceEbookIdRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->Url)){
|
||||||
|
$this->Url = trim($this->Url);
|
||||||
|
|
||||||
|
if($this->Url == ''){
|
||||||
|
$error->Add(new Exceptions\EbookSourceUrlRequiredException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\EbookSourceUrlRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if($error->HasExceptions){
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
public function Create(): void{
|
public function Create(): void{
|
||||||
|
$this->Validate();
|
||||||
Db::Query('
|
Db::Query('
|
||||||
INSERT into EbookSources (EbookId, Type, Url)
|
INSERT into EbookSources (EbookId, Type, Url)
|
||||||
values (?,
|
values (?,
|
||||||
|
|
|
@ -33,13 +33,19 @@ class EbookTag extends Tag{
|
||||||
public function Validate(): void{
|
public function Validate(): void{
|
||||||
$error = new Exceptions\ValidationException();
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
$this->Name = trim($this->Name ?? '');
|
if(isset($this->Name)){
|
||||||
if($this->Name == ''){
|
$this->Name = trim($this->Name);
|
||||||
$error->Add(new Exceptions\EbookTagNameRequiredException());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
if($this->Name == ''){
|
||||||
$error->Add(new Exceptions\StringTooLongException('Ebook tag: '. $this->Name));
|
$error->Add(new Exceptions\EbookTagNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('Ebook tag: '. $this->Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\EbookTagNameRequiredException());
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->Type != TagType::Ebook){
|
if($this->Type != TagType::Ebook){
|
||||||
|
|
7
lib/Exceptions/CollectionUrlNameRequiredException.php
Normal file
7
lib/Exceptions/CollectionUrlNameRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class CollectionUrlNameRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Collection UrlName is required.';
|
||||||
|
}
|
7
lib/Exceptions/ContributorEbookIdRequiredException.php
Normal file
7
lib/Exceptions/ContributorEbookIdRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class ContributorEbookIdRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Contributor EbookId required.';
|
||||||
|
}
|
7
lib/Exceptions/ContributorNameRequiredException.php
Normal file
7
lib/Exceptions/ContributorNameRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class ContributorNameRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Contributor name required.';
|
||||||
|
}
|
7
lib/Exceptions/ContributorSortOrderRequiredException.php
Normal file
7
lib/Exceptions/ContributorSortOrderRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class ContributorSortOrderRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Contributor SortOrder required.';
|
||||||
|
}
|
7
lib/Exceptions/ContributorUrlNameRequiredException.php
Normal file
7
lib/Exceptions/ContributorUrlNameRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class ContributorUrlNameRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Contributor UrlName required.';
|
||||||
|
}
|
7
lib/Exceptions/EbookSourceEbookIdRequiredException.php
Normal file
7
lib/Exceptions/EbookSourceEbookIdRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class EbookSourceEbookIdRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'EbookSource EbookId required.';
|
||||||
|
}
|
7
lib/Exceptions/EbookSourceUrlRequiredException.php
Normal file
7
lib/Exceptions/EbookSourceUrlRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class EbookSourceUrlRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'EbookSource Url required.';
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class GitCommitCreatedDatetimeRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'GitCommit Created datetime required.';
|
||||||
|
}
|
7
lib/Exceptions/GitCommitEbookIdRequiredException.php
Normal file
7
lib/Exceptions/GitCommitEbookIdRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class GitCommitEbookIdRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'GitCommit EbookId required.';
|
||||||
|
}
|
7
lib/Exceptions/GitCommitHashRequiredException.php
Normal file
7
lib/Exceptions/GitCommitHashRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class GitCommitHashRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'GitCommit hash required.';
|
||||||
|
}
|
7
lib/Exceptions/GitCommitMessageRequiredException.php
Normal file
7
lib/Exceptions/GitCommitMessageRequiredException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class GitCommitMessageRequiredException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'GitCommit message required.';
|
||||||
|
}
|
5
lib/Exceptions/InvalidContributorNacoafUrlException.php
Normal file
5
lib/Exceptions/InvalidContributorNacoafUrlException.php
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class InvalidContributorNacoafUrlException extends AppException{
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class InvalidContributorWikipediaUrlException extends AppException{
|
||||||
|
}
|
15
lib/Exceptions/InvalidGitCommitCreatedDatetimeException.php
Normal file
15
lib/Exceptions/InvalidGitCommitCreatedDatetimeException.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
|
class InvalidGitCommitCreatedDatetimeException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'Invalid GitCommit Created datetime.';
|
||||||
|
|
||||||
|
public function __construct(DateTimeImmutable $createdDatetime){
|
||||||
|
/** @throws void */
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
$this->message = 'Invalid GitCommit Created datetime. ' . $createdDatetime->format('Y-m-d') . ' is not between ' . EBOOK_EARLIEST_CREATION_DATE->format('Y-m-d') . ' and ' . $now->format('Y-m-d') . '.';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,60 @@ class GitCommit{
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
|
public function Validate(): void{
|
||||||
|
/** @throws void */
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
|
if(!isset($this->EbookId)){
|
||||||
|
$error->Add(new Exceptions\GitCommitEbookIdRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->Created)){
|
||||||
|
if($this->Created > $now || $this->Created < EBOOK_EARLIEST_CREATION_DATE){
|
||||||
|
$error->Add(new Exceptions\InvalidGitCommitCreatedDatetimeException($this->Created));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\GitCommitCreatedDatetimeRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->Message)){
|
||||||
|
$this->Message = trim($this->Message);
|
||||||
|
|
||||||
|
if($this->Message == ''){
|
||||||
|
$error->Add(new Exceptions\GitCommitMessageRequiredException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\GitCommitMessageRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->Hash)){
|
||||||
|
$this->Hash = trim($this->Hash);
|
||||||
|
|
||||||
|
if($this->Hash == ''){
|
||||||
|
$error->Add(new Exceptions\GitCommitHashRequiredException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\GitCommitHashRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if($error->HasExceptions){
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ValidationException
|
||||||
|
*/
|
||||||
public function Create(): void{
|
public function Create(): void{
|
||||||
|
$this->Validate();
|
||||||
Db::Query('
|
Db::Query('
|
||||||
INSERT into GitCommits (EbookId, Created, Message, Hash)
|
INSERT into GitCommits (EbookId, Created, Message, Hash)
|
||||||
values (?,
|
values (?,
|
||||||
|
|
|
@ -9,13 +9,19 @@ class LocSubject{
|
||||||
public function Validate(): void{
|
public function Validate(): void{
|
||||||
$error = new Exceptions\ValidationException();
|
$error = new Exceptions\ValidationException();
|
||||||
|
|
||||||
$this->Name = trim($this->Name ?? '');
|
if(isset($this->Name)){
|
||||||
if($this->Name == ''){
|
$this->Name = trim($this->Name);
|
||||||
$error->Add(new Exceptions\LocSubjectNameRequiredException());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
if($this->Name == ''){
|
||||||
$error->Add(new Exceptions\StringTooLongException('LoC subject: '. $this->Name));
|
$error->Add(new Exceptions\LocSubjectNameRequiredException());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->Name) > EBOOKS_MAX_STRING_LENGTH){
|
||||||
|
$error->Add(new Exceptions\StringTooLongException('LoC subject: '. $this->Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$error->Add(new Exceptions\LocSubjectNameRequiredException());
|
||||||
}
|
}
|
||||||
|
|
||||||
if($error->HasExceptions){
|
if($error->HasExceptions){
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue