1.18.2 (#3190)
* improve console version output * fix empty string issue in csv export (DDE protection) - fixes #3189 * fix twig sort deprecation in php 8 * sort user by displayName in users report * fix missing custom translations in edit modal * fix font-family in invoice.css * invoice template "freelancer pdf" - added customer number, moved some fields around * invoice template "default" - relocate customer number and order number in
This commit is contained in:
@@ -34,6 +34,9 @@ p {
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -77,7 +80,7 @@ table.footer {
|
||||
line-height: 14px;
|
||||
}
|
||||
table.footer td {
|
||||
vertical-align: bottom;
|
||||
vertical-align: top;
|
||||
}
|
||||
/* The invoice items list */
|
||||
table.items {
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
@import "~bootstrap-sass/assets/stylesheets/bootstrap/utilities";
|
||||
@import "~bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";
|
||||
|
||||
body.invoice_print {
|
||||
body {
|
||||
font-family: $font-family-sans-serif;
|
||||
|
||||
&.invoice_print {
|
||||
background-color: #eee;
|
||||
|
||||
.table.no-border, .table.no-border td, .table.no-border th {
|
||||
@@ -27,7 +30,7 @@ body.invoice_print {
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
font-family: $font-family-sans-serif;
|
||||
}
|
||||
|
||||
.invoice {
|
||||
@@ -36,7 +39,7 @@ body.invoice_print {
|
||||
min-height: 297mm;
|
||||
position: relative;
|
||||
max-width: 210mm;
|
||||
box-shadow: 0 0 20px rgba(80,80,80,0.7);
|
||||
box-shadow: 0 0 20px rgba(80, 80, 80, 0.7);
|
||||
background: #fff;
|
||||
border: none;
|
||||
}
|
||||
@@ -44,21 +47,18 @@ body.invoice_print {
|
||||
.page-header {
|
||||
margin: 10px 0 20px 0;
|
||||
font-size: 22px;
|
||||
>small {
|
||||
|
||||
> small {
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
border-color: #ddd;
|
||||
}
|
||||
}
|
||||
/*
|
||||
.page-header {
|
||||
margin: 10px 0 20px 0;
|
||||
font-size: 22px;
|
||||
}
|
||||
*/
|
||||
|
||||
div.invoice-address {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
@@ -67,9 +67,11 @@ body.invoice_print {
|
||||
table.invoice-meta th {
|
||||
padding-right: 40px;
|
||||
}
|
||||
|
||||
table.invoice-sum th {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
table.invoice-sum th, table.invoice-sum td {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -84,6 +86,7 @@ body.invoice_print {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 15px
|
||||
}
|
||||
|
||||
tfoot {
|
||||
border-top: 1px solid #ddd;
|
||||
|
||||
@@ -91,9 +94,10 @@ body.invoice_print {
|
||||
tr:first-child td {
|
||||
padding-top: 15px
|
||||
}
|
||||
|
||||
tr {
|
||||
th,td {
|
||||
border:none;
|
||||
th, td {
|
||||
border: none;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
}
|
||||
@@ -164,7 +168,7 @@ body.invoice_print {
|
||||
}
|
||||
|
||||
article.address {
|
||||
margin:1em 0 1.5em 0;
|
||||
margin: 1em 0 1.5em 0;
|
||||
}
|
||||
|
||||
/* article */
|
||||
@@ -215,6 +219,7 @@ body.invoice_print {
|
||||
table.balance {
|
||||
float: right;
|
||||
margin-top: 1em;
|
||||
|
||||
th {
|
||||
text-align: right;
|
||||
font-weight: normal;
|
||||
@@ -280,6 +285,7 @@ body.invoice_print {
|
||||
span:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.add, .cut {
|
||||
display: none;
|
||||
}
|
||||
@@ -295,4 +301,5 @@ body.invoice_print {
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"build/invoice.19f36eca.js"
|
||||
],
|
||||
"css": [
|
||||
"build/invoice.ff32661a.css"
|
||||
"build/invoice.ccdecd42.css"
|
||||
]
|
||||
},
|
||||
"invoice-pdf": {
|
||||
@@ -24,7 +24,7 @@
|
||||
"build/invoice-pdf.0ce1f3ce.js"
|
||||
],
|
||||
"css": [
|
||||
"build/invoice-pdf.9a7468ef.css"
|
||||
"build/invoice-pdf.e73a6dda.css"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
body{font-family:sans-serif;font-size:10pt}body,h1,h2,h3,h4,h5,p,table,td,th,tr{margin:0;padding:0}th{border:none;text-align:left}td{vertical-align:top}p{margin-bottom:12px}.text-small{font-size:7pt}.padding-left{padding-left:15px}.text-center{text-align:center}.text-right{text-align:right}.text-nowrap{white-space:nowrap}.date{color:#666;font-size:80%;text-align:right;padding-top:6px}.wrapper{margin:4px}table{width:100%;border-spacing:0}p,table.addresses{line-height:14pt}table.addresses{margin-bottom:30px}table.header{padding-bottom:4px;border-bottom:1px solid #999}table.header .title{font-weight:400;font-size:140%}table.footer{border-top:1px solid #999;font-size:80%;padding-top:8px;line-height:14px}table.footer td{vertical-align:bottom}table.items{border-collapse:collapse;margin-top:50px;margin-bottom:60px}table.items tbody td,table.items thead th{border-bottom:1px solid #ccc}table.items tbody td.first,table.items thead th.first{padding-left:0}table.items tbody td.last,table.items tfoot td.last,table.items thead th.last{padding-right:0}table.items td,table.items th{padding:8px 6px}table.items tfoot td,table.items tfoot th{padding:20px 0 0;line-height:1px}table.items tfoot td.last{padding-left:10px}table.items tr.odd{background-color:#f5f5f5}
|
||||
1
public/build/invoice-pdf.e73a6dda.css
Normal file
1
public/build/invoice-pdf.e73a6dda.css
Normal file
@@ -0,0 +1 @@
|
||||
body{font-family:sans-serif;font-size:10pt}body,h1,h2,h3,h4,h5,p,table,td,th,tr{margin:0;padding:0}th{border:none;text-align:left}td{vertical-align:top}p{margin-bottom:12px}.text-small{font-size:7pt}.padding-left{padding-left:15px}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.text-nowrap{white-space:nowrap}.date{color:#666;font-size:80%;text-align:right;padding-top:6px}.wrapper{margin:4px}table{width:100%;border-spacing:0}p,table.addresses{line-height:14pt}table.addresses{margin-bottom:30px}table.header{padding-bottom:4px;border-bottom:1px solid #999}table.header .title{font-weight:400;font-size:140%}table.footer{border-top:1px solid #999;font-size:80%;padding-top:8px;line-height:14px}table.footer td{vertical-align:top}table.items{border-collapse:collapse;margin-top:50px;margin-bottom:60px}table.items tbody td,table.items thead th{border-bottom:1px solid #ccc}table.items tbody td.first,table.items thead th.first{padding-left:0}table.items tbody td.last,table.items tfoot td.last,table.items thead th.last{padding-right:0}table.items td,table.items th{padding:8px 6px}table.items tfoot td,table.items tfoot th{padding:20px 0 0;line-height:1px}table.items tfoot td.last{padding-left:10px}table.items tr.odd{background-color:#f5f5f5}
|
||||
1
public/build/invoice.ccdecd42.css
Normal file
1
public/build/invoice.ccdecd42.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"build/app.css": "build/app.7efa8299.css",
|
||||
"build/app.js": "build/app.7d469ea7.js",
|
||||
"build/invoice.css": "build/invoice.ff32661a.css",
|
||||
"build/invoice.css": "build/invoice.ccdecd42.css",
|
||||
"build/invoice.js": "build/invoice.19f36eca.js",
|
||||
"build/invoice-pdf.css": "build/invoice-pdf.9a7468ef.css",
|
||||
"build/invoice-pdf.css": "build/invoice-pdf.e73a6dda.css",
|
||||
"build/invoice-pdf.js": "build/invoice-pdf.0ce1f3ce.js",
|
||||
"build/chart.js": "build/chart.e845e930.js",
|
||||
"build/calendar.css": "build/calendar.25e7e872.css",
|
||||
|
||||
@@ -30,9 +30,10 @@ class VersionCommand extends Command
|
||||
->setName('kimai:version')
|
||||
->setDescription('Receive version information')
|
||||
->setHelp('This command allows you to fetch various version information about Kimai.')
|
||||
->addOption('name', null, InputOption::VALUE_NONE, 'Display the major release name')
|
||||
->addOption('short', null, InputOption::VALUE_NONE, 'Display the version only')
|
||||
->addOption('number', null, InputOption::VALUE_NONE, 'Display the version identifier only only')
|
||||
// @deprecated since 1.14.1
|
||||
->addOption('name', null, InputOption::VALUE_NONE, 'DEPRECATED: Display the major release name')
|
||||
->addOption('candidate', null, InputOption::VALUE_NONE, 'DEPRECATED: Display the current version candidate (e.g. "stable" or "dev")')
|
||||
->addOption('semver', null, InputOption::VALUE_NONE, 'DEPRECATED: Semantical versioning (SEMVER) compatible version string')
|
||||
;
|
||||
@@ -46,6 +47,7 @@ class VersionCommand extends Command
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if ($input->getOption('semver')) {
|
||||
@trigger_error('bin/console kimai:version --semver is deprecated and will be removed with 2.0', E_USER_DEPRECATED);
|
||||
$io->writeln(Constants::VERSION . '-' . Constants::STATUS);
|
||||
|
||||
return 0;
|
||||
@@ -58,18 +60,26 @@ class VersionCommand extends Command
|
||||
}
|
||||
|
||||
if ($input->getOption('name')) {
|
||||
@trigger_error('bin/console kimai:version --name is deprecated and will be removed with 2.0', E_USER_DEPRECATED);
|
||||
$io->writeln(Constants::NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($input->getOption('candidate')) {
|
||||
@trigger_error('bin/console kimai:version --candidate is deprecated and will be removed with 2.0', E_USER_DEPRECATED);
|
||||
$io->writeln(Constants::STATUS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$io->writeln(Constants::SOFTWARE . ' ' . Constants::VERSION . ' by Kevin Papst and contributors.');
|
||||
if ($input->getOption('number')) {
|
||||
$io->writeln((string) Constants::VERSION_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$io->writeln(sprintf('%s <info>%s</info> by Kevin Papst and contributors.', Constants::SOFTWARE, Constants::VERSION));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -22,4 +22,14 @@ class ConsoleApplication extends Application
|
||||
{
|
||||
return Constants::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten to prevent unwanted SF core messages to show up here.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLongVersion()
|
||||
{
|
||||
return sprintf('%s <info>%s</info> (env: <comment>%s</>, debug: <comment>%s</>)', $this->getName(), $this->getVersion(), $this->getKernel()->getEnvironment(), $this->getKernel()->isDebug() ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ final class StringHelper
|
||||
|
||||
public static function sanitizeDDE(string $text): string
|
||||
{
|
||||
// see #3189
|
||||
if (\strlen($text) === 0) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$sanitize = false;
|
||||
|
||||
if (\in_array($text[0], self::DDE_PAYLOADS)) {
|
||||
|
||||
@@ -25,7 +25,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $localDomains = [];
|
||||
private $localDomains;
|
||||
|
||||
public function __construct(BaseTranslator $translator, array $localDomains = [])
|
||||
{
|
||||
@@ -51,8 +51,6 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
|
||||
protected function hasLocalOverwrite($id, $domain, $locale = null): bool
|
||||
{
|
||||
$found = false;
|
||||
|
||||
$catalogue = $this->getCatalogue($locale);
|
||||
while (false === ($found = $catalogue->defines($id, $domain))) {
|
||||
if ($cat = $catalogue->getFallbackCatalogue()) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app.request.locale }}">
|
||||
<head></head>
|
||||
<head>
|
||||
<title>{% block page_title %}{{- get_title() -}}{% endblock %}</title>
|
||||
</head>
|
||||
<body class="ajax-forms">
|
||||
<div id="ajax-messages">
|
||||
{{ include('@AdminLTE/Partials/_flash_messages.html.twig') }}
|
||||
|
||||
@@ -47,7 +47,7 @@ mpdf-->
|
||||
<div class="wrapper">
|
||||
<table class="addresses">
|
||||
<tr>
|
||||
<td width="60%">
|
||||
<td style="width:60%">
|
||||
{{ 'invoice.to'|trans }}
|
||||
<br>
|
||||
<strong>{{ model.customer.company|default(model.customer.name) }}</strong>
|
||||
@@ -57,14 +57,6 @@ mpdf-->
|
||||
<br>
|
||||
{{ 'label.vat_id'|trans }}: {{ model.customer.vatId }}
|
||||
{% endif %}
|
||||
{% if model.customer.number is not empty %}
|
||||
<br>
|
||||
{{ 'label.number'|trans }}: {{ model.customer.number }}
|
||||
{% endif %}
|
||||
{% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
|
||||
<br>
|
||||
{{ 'label.orderNumber'|trans }}: {{ model.query.project.orderNumber }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ 'invoice.from'|trans }}
|
||||
@@ -82,12 +74,24 @@ mpdf-->
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<strong>{{ 'invoice.number'|trans }}:</strong>
|
||||
{{ 'invoice.number'|trans }}:
|
||||
{{ model.invoiceNumber }}
|
||||
|
||||
<br>
|
||||
<strong>{{ 'invoice.due_days'|trans }}:</strong>
|
||||
{{ 'invoice.due_days'|trans }}:
|
||||
{{ model.dueDate|date_short }}
|
||||
|
||||
{% if model.customer.number is not empty %}
|
||||
<br>
|
||||
{{ 'label.number'|trans }}:
|
||||
{{ model.customer.number }}
|
||||
{% endif %}
|
||||
|
||||
{% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
|
||||
<br>
|
||||
{{ 'label.orderNumber'|trans }}:
|
||||
{{ model.query.project.orderNumber }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<table class="items">
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
<tr>
|
||||
<td class="text-small">
|
||||
{{ model.template.company }} – {{ model.template.address|nl2str(' – ') }}
|
||||
{% if model.template.vatId is not empty %}
|
||||
– {{ 'label.vat_id'|trans }}: {{ model.template.vatId }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-small text-right">
|
||||
{{ 'export.page_of'|trans({'%page%': '{PAGENO}', '%pages%': '{nb}'}) }}
|
||||
@@ -56,39 +59,43 @@ mpdf-->
|
||||
<td>
|
||||
<strong>{{ model.customer.company|default(model.customer.name) }}</strong><br>
|
||||
{{ model.customer.address|nl2br }}
|
||||
{% if model.customer.vatId is not empty %}
|
||||
<br>
|
||||
{{ 'label.vat_id'|trans }}: {{ model.customer.vatId }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{% set classLeft = 'text-left' %}
|
||||
{% set classRight = 'text-right text-nowrap padding-left' %}
|
||||
<table style="width: 240px">
|
||||
<tr>
|
||||
<td>{{ 'label.date'|trans }}:</td>
|
||||
<td class="text-nowrap padding-left">{{ model.invoiceDate|date_short }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'label.date'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.invoiceDate|date_short }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'invoice.service_date'|trans }}:</td>
|
||||
<td class="text-nowrap padding-left">{{ model.query.end|month_name }} {{ model.query.end|date('Y') }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'invoice.service_date'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.query.end|month_name }} {{ model.query.end|date('Y') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'invoice.number'|trans }}:</td>
|
||||
<td class="text-nowrap padding-left">{{ model.invoiceNumber }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'invoice.number'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.invoiceNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'invoice.due_days'|trans }}:</td>
|
||||
<td class="text-nowrap padding-left">{{ model.dueDate|date_short }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'invoice.due_days'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.dueDate|date_short }}</td>
|
||||
</tr>
|
||||
{% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
|
||||
{% if model.customer.number is not empty %}
|
||||
<tr>
|
||||
<td>{{ 'label.orderNumber'|trans }}</td>
|
||||
<td class="text-nowrap padding-left">{{ model.query.project.orderNumber }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'label.number'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.customer.number }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if model.template.vatId is not empty %}
|
||||
{% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
|
||||
<tr>
|
||||
<td>{{ 'label.vat_id'|trans }}:</td>
|
||||
<td class="text-nowrap padding-left">{{ model.template.vatId }}</td>
|
||||
<td class="{{ classLeft }}">{{ 'label.orderNumber'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.query.project.orderNumber }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if model.customer.vatId is not empty %}
|
||||
<tr>
|
||||
<td class="{{ classLeft }}">{{ 'label.vat_id'|trans }}</td>
|
||||
<td class="{{ classRight }}">{{ model.customer.vatId }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
<td class="avatars">
|
||||
{% set teamHiddenId = 'team_' ~ team.id ~ '_hiddenUser' ~ random() %}
|
||||
{% set counter = 0 %}
|
||||
{% for member in members|sort((a, b) => a.teamlead < b.teamlead) %}
|
||||
{% for member in members|sort((a, b) => b.teamlead <=> a.teamlead) %}
|
||||
{% set user = member.user %}
|
||||
{% if member.teamlead %}
|
||||
{{ _self.user_avatar(user, ('label.teamlead'|trans ~ ': ' ~ user.displayName), 'teamlead') }}
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% set yearTotal = 0 %}
|
||||
{% for userYearStat in userYearStats|sort((a, b) => a.duration <= b.duration) %}
|
||||
{% for userYearStat in userYearStats|sort((a, b) => b.duration <=> a.duration) %}
|
||||
{% set user = userYearStat.user %}
|
||||
{% set userYear = userYearStat.year %}
|
||||
{% set userTotal = userYearStat.duration %}
|
||||
@@ -216,7 +216,7 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-9 col-md-8 col-lg-6">
|
||||
<table class="table table-hover dataTable">
|
||||
{% for stat in activities|sort((a, b) => a.duration <= b.duration) %}
|
||||
{% for stat in activities|sort((a, b) => b.duration <=> a.duration) %}
|
||||
{% set dataset = dataset|merge([{'value': stat.duration, 'name': stat.name, 'color': stat.activity.color|colorize(stat.activity.name), 'duration': stat.duration|duration, 'rate': stat.rate|money(currency)}]) %}
|
||||
{% set percentage = 0 %}
|
||||
{% if totalDuration > 0 and stat.duration > 0 %}
|
||||
@@ -413,7 +413,7 @@
|
||||
{% set totalDuration = 0 %}
|
||||
{% set datasets = [] %}
|
||||
{% set labels = [] %}
|
||||
{% for userStat in project_details.userStats|sort((a, b) => a.duration <= b.duration) %}
|
||||
{% for userStat in project_details.userStats|sort((a, b) => b.duration <=> a.duration) %}
|
||||
{% set user = userStat.user %}
|
||||
{% set color = user.color|colorize(user.displayName) %}
|
||||
{% set rateTotal = rateTotal + userStat.rate %}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for userPeriod in stats|filter(row => row.user is not null) %}
|
||||
{% for userPeriod in stats|filter(row => row.user is not null)|sort((a,b) => a.user.displayName|lower <=> b.user.displayName|lower) %}
|
||||
{% set usersTotalDuration = 0 %}
|
||||
{% set usersTotalInternalRate = 0 %}
|
||||
{% set usersTotalRate = 0 %}
|
||||
|
||||
@@ -49,9 +49,10 @@ class VersionCommandTest extends KernelTestCase
|
||||
{
|
||||
return [
|
||||
[[], 'Kimai ' . Constants::VERSION . ' by Kevin Papst and contributors.'],
|
||||
[['--name' => true], Constants::NAME],
|
||||
[['--short' => true], Constants::VERSION],
|
||||
[['--number' => true], Constants::VERSION_ID],
|
||||
// @deprecated since 1.14.1
|
||||
[['--name' => true], Constants::NAME],
|
||||
[['--candidate' => true], Constants::STATUS],
|
||||
[['--semver' => true], Constants::VERSION . '-' . Constants::STATUS],
|
||||
];
|
||||
|
||||
@@ -25,5 +25,6 @@ class ConsoleApplicationTest extends TestCase
|
||||
$sut = new ConsoleApplication($kernel);
|
||||
self::assertEquals(Constants::SOFTWARE, $sut->getName());
|
||||
self::assertEquals(Constants::VERSION, $sut->getVersion());
|
||||
self::assertEquals(sprintf('%s <info>%s</info> (env: <comment></>, debug: <comment>false</>)', Constants::SOFTWARE, Constants::VERSION), $sut->getLongVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ class StringHelperTest extends TestCase
|
||||
public function getDdeAttackStrings()
|
||||
{
|
||||
yield ['DDE ("cmd";"/C calc";"!A0")A0'];
|
||||
yield [' DDE ("cmd";"/C calc";"!A0")A0'];
|
||||
yield ["@SUM(1+9)*cmd|' /C calc'!A0"];
|
||||
yield ["-10+20+cmd|' /C calc'!A0"];
|
||||
yield ["+10+20+cmd|' /C calc'!A0"];
|
||||
@@ -54,4 +55,18 @@ class StringHelperTest extends TestCase
|
||||
{
|
||||
self::assertEquals("' " . $input, StringHelper::sanitizeDDE($input));
|
||||
}
|
||||
|
||||
public function getNonDdeAttackStrings()
|
||||
{
|
||||
yield [''];
|
||||
yield [' '];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNonDdeAttackStrings
|
||||
*/
|
||||
public function testSanitizeDdeWithCorrectStrings(string $input)
|
||||
{
|
||||
self::assertEquals($input, StringHelper::sanitizeDDE($input));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user