1
0
mirror of https://github.com/RSS-Bridge/rss-bridge.git synced 2025-01-16 21:58:21 +01:00

refactor/fix: css organization and error rendering (#3117)

* fix: php notice

* refactor/feat: merge HtmlFormat.css into style.css

Also improve ux of error rendering.

* fix: center-align footer text
This commit is contained in:
Dag 2022-10-29 10:46:37 +02:00 committed by GitHub
parent 1b45a53402
commit 23f8c81646
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 445 additions and 568 deletions

View File

@ -163,14 +163,15 @@ class DisplayAction implements ActionInterface
// Create "new" error message every 24 hours // Create "new" error message every 24 hours
$request['_error_time'] = urlencode((int)(time() / 86400)); $request['_error_time'] = urlencode((int)(time() / 86400));
// todo: I don't think this _error_time in the title is useful. It's confusing.
$itemTitle = sprintf('Bridge returned error %s! (%s)', $e->getCode(), $request['_error_time']); $itemTitle = sprintf('Bridge returned error %s! (%s)', $e->getCode(), $request['_error_time']);
$item->setTitle($itemTitle); $item->setTitle($itemTitle);
$item->setURI(get_current_url()); $item->setURI(get_current_url());
$item->setTimestamp(time()); $item->setTimestamp(time());
// todo: consider giving more helpful error messages
$content = render_template(__DIR__ . '/../templates/bridge-error.html.php', [ $content = render_template(__DIR__ . '/../templates/bridge-error.html.php', [
'message' => create_sane_exception_message($e), 'error' => render_template(__DIR__ . '/../templates/error.html.php', ['e' => $e]),
'trace' => trace_from_exception($e),
'searchUrl' => self::createGithubSearchUrl($bridge), 'searchUrl' => self::createGithubSearchUrl($bridge),
'issueUrl' => self::createGithubIssueUrl($bridge, $e, create_sane_exception_message($e)), 'issueUrl' => self::createGithubIssueUrl($bridge, $e, create_sane_exception_message($e)),
'maintainer' => $bridge->getMaintainer(), 'maintainer' => $bridge->getMaintainer(),

View File

@ -35,6 +35,7 @@ final class FrontpageAction implements ActionInterface
</script> </script>
</head> </head>
<body onload="rssbridge_list_search()"> <body onload="rssbridge_list_search()">
<div class="container">
EOD; EOD;
} }
@ -146,6 +147,7 @@ EOD;
{$inactive} {$inactive}
{$admininfo} {$admininfo}
</section> </section>
</div>
</body></html> </body></html>
EOD; EOD;
} }

View File

@ -59,6 +59,7 @@ TEXT;
foreach ($feeds as $feed) { foreach ($feeds as $feed) {
// Fetch all items from the feed // Fetch all items from the feed
// todo: consider wrapping this in a try..catch to not let a single feed break the entire bridge?
$this->collectExpandableDatas($feed); $this->collectExpandableDatas($feed);
} }

View File

@ -120,11 +120,14 @@ class NovayaGazetaEuropeBridge extends BridgeAbstract
case 'text/quote': case 'text/quote':
return "<figure><blockquote>{$datum->data}</blockquote></figure><br>"; return "<figure><blockquote>{$datum->data}</blockquote></figure><br>";
case 'embed/native': case 'embed/native':
$desc = $datum->link; if (isset($datum->link)) {
if (property_exists($datum, 'caption')) { $desc = $datum->link;
$desc = $datum->caption; if (isset($datum->caption)) {
$desc = $datum->caption;
}
return sprintf('<p><a href="%s">%s</a></p>', $datum->link, $desc);
} }
return "<p><a link=\"{$datum->link}\">{$desc}</a></p>"; return '';
case 'text/framed': case 'text/framed':
$res = ''; $res = '';
if (property_exists($datum, 'typeDisplay')) { if (property_exists($datum, 'typeDisplay')) {

View File

@ -29,26 +29,31 @@ final class Logger
private static function log(string $level, string $message, array $context = []): void private static function log(string $level, string $message, array $context = []): void
{ {
if (isset($context['e'])) { if (isset($context['e'])) {
$context['message'] = create_sane_exception_message($context['e']); /** @var \Throwable $e */
$context['code'] = $context['e']->getCode(); $e = $context['e'];
$context['url'] = get_current_url();
$context['trace'] = trace_to_call_points(trace_from_exception($context['e']));
unset($context['e']); unset($context['e']);
// Don't log these records $context['type'] = get_class($e);
$context['code'] = $e->getCode();
$context['message'] = $e->getMessage();
$context['file'] = trim_path_prefix($e->getFile());
$context['line'] = $e->getLine();
$context['url'] = get_current_url();
$context['trace'] = trace_to_call_points(trace_from_exception($e));
// Don't log these exceptions
$ignoredExceptions = [ $ignoredExceptions = [
'Exception Exception: You must specify a format', 'You must specify a format',
'Exception InvalidArgumentException: Format name invalid', 'Format name invalid',
'Exception InvalidArgumentException: Unknown format given', 'Unknown format given',
'Exception InvalidArgumentException: Bridge name invalid', 'Bridge name invalid',
'Exception Exception: Invalid action', 'Invalid action',
'Exception Exception: twitter: No results for this query', 'twitter: No results for this query',
// telegram // telegram
'Exception Exception: Unable to find channel. The channel is non-existing or non-public', 'Unable to find channel. The channel is non-existing or non-public',
// fb // fb
'Exception Exception: This group is not public! RSS-Bridge only supports public groups!', 'This group is not public! RSS-Bridge only supports public groups!',
]; ];
foreach ($ignoredExceptions as $ignoredException) { foreach ($ignoredExceptions as $ignoredException) {
if (str_starts_with($context['message'], $ignoredException)) { if (str_starts_with($e->getMessage(), $ignoredException)) {
return; return;
} }
} }

View File

@ -16,10 +16,7 @@ final class RssBridge
} catch (\Throwable $e) { } catch (\Throwable $e) {
Logger::error('Exception in main', ['e' => $e]); Logger::error('Exception in main', ['e' => $e]);
http_response_code(500); http_response_code(500);
print render(__DIR__ . '/../templates/error.html.php', [ print render(__DIR__ . '/../templates/error.html.php', ['e' => $e]);
'message' => create_sane_exception_message($e),
'trace' => trace_from_exception($e),
]);
} }
} }

View File

@ -119,7 +119,7 @@ function frame_to_call_point(array $frame): string
/** /**
* Trim path prefix for privacy/security reasons * Trim path prefix for privacy/security reasons
* *
* Example: "/var/www/rss-bridge/index.php" => "index.php" * Example: "/home/davidsf/rss-bridge/index.php" => "index.php"
*/ */
function trim_path_prefix(string $filePath): string function trim_path_prefix(string $filePath): string
{ {

View File

@ -1,145 +0,0 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
/* Let's go for the actual style */
body {
background-color: #f0f0f0;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
}
a, a:link, a:visited {
color: #2196F3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img {
max-width: 100%;
}
/* Section */
section {
background-color: #FFFFFF;
width: 60%;
margin: 30px auto;
padding: 15px 15px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.09);
border-radius: 4px;
}
section > h2 {
font-size: 200%;
font-weight: bold;
text-align: center;
}
h1.pagetitle {
margin: 40px 0 20px;
font-size: 300%;
font-weight: bold;
text-align: center;
color: #2196F3;
}
h1.pagetitle > a {
color: #2196F3;
}
a.backlink, a.backlink:link, a.backlink:visited, a.itemtitle, a.itemtitle:link, a.itemtitle:visited {
color: #2196F3;
}
.buttons {
text-align: center;
}
section > div.content, section > div.attachments {
padding: 10px;
}
section h1, section h2, section h3, section b, section strong {
font-weight: bold;
}
section i, section em {
font-style: italic;
}
section p:not(:last-child) {
margin-bottom: 1em;
}
section li {
margin-left: 1em;
}
section > div.attachments > li.enclosure {
list-style-type: circle;
list-style-position: inside;
}
section > time, section > p.author {
color: #888;
font-size: 80%;
padding: 10px;
}
button {
line-height: 1.9em;
color: #FFF;
font-weight: bold;
vertical-align: middle;
padding: 6px 12px;
margin: 12px auto 0px;
border-radius: 4px;
border: 1px solid transparent;
background: #2196F3 none repeat scroll 0% 0%;
cursor: pointer;
width: 200px;
}
button:hover {
background: #49afff;
}
button.highlight {
background: #ff6600;
}
button.highlight:hover {
background: #ff8a3b;
}
@media screen and (max-width: 767px) {
section {
width: 100%;
padding: 0;
}
button {
display: inline-block;
width: 40%;
padding: 5px auto;
margin: 3px auto 0;
}
}
/* Dark theme, will automatically be set for those that have dark mode on their OS. */
@media (prefers-color-scheme: dark){
* {
scrollbar-color: #202324 #454a4d;
}
body {
background-color: #202325;
color: #e8e6e3;
}
a, a:link, a:visited {
color: #0A6AB6;
}
/* Section */
section {
background-color: #181A1B;
}
}

View File

@ -1,105 +1,110 @@
html { html {
box-sizing: border-box; box-sizing: border-box;
font-size: 16px; font-size: 16px;
} }
*, *:before, *:after { *, *:before, *:after {
box-sizing: inherit; box-sizing: inherit;
} }
body, h1, h2, h3, h4, h5, h6, p, ol, ul { body, h1, h2, h3, h4, h5, h6, p, ol, ul {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-weight: normal; font-weight: normal;
} }
ol, ul { ol, ul {
list-style: none; list-style: none;
} }
img { img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block; display: block;
} }
/* Adjust parameters for browsers that don't support the grid layout */ /* Adjust parameters for browsers that don't support the grid layout */
.parameters label:before { .parameters label:before {
content: " "; content: " ";
display: block; display: block;
} }
/* Let's go for the actual style */ /* Let's go for the actual style */
body { body {
background-color: #f0f0f0; background-color: #f0f0f0;
font-family: sans-serif; font-family: sans-serif;
font-size: 14px;
} }
a, a:link, a:visited { a, a:link, a:visited {
color: #2196F3; color: #2196F3;
text-decoration: none; text-decoration: none;
} }
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
h1,h2 { h1,h2 {
margin-bottom: 10px; margin-bottom: 10px;
} }
p { h5 {
margin-bottom: 10px; margin: 20px;
font-weight: bold;
display: none;
} }
/* Header */
p {
margin-bottom: 10px;
}
/* Header */
header { header {
margin-top: 40px; margin-top: 40px;
text-align: center; padding: 15px;
color: #1182DB; color: #1182DB;
} }
header > div.logo { header > div.logo {
background-image: url(logo_600px.png); background-image: url(logo_600px.png);
width: 599px; width: 599px;
height: 177px; height: 177px;
margin: auto; margin: auto;
} }
header > section.warning { header > section.warning {
width: 40%; background-color: #ffc600;
background-color: #ffc600; color: #5f5f5f;
color: #5f5f5f;
} }
header > section.critical-warning { header > section.critical-warning {
width: 40%; background-color: #cf3e3e;
background-color: #cf3e3e; font-weight: bold;
font-weight: bold; color: white;
color: white;
} }
select, select,
input[type="text"], input[type="text"],
input[type="number"] { input[type="number"] {
background-color: white; background-color: white;
color: #404552; color: #404552;
border: 1px solid #dedede; border: 1px solid #dedede;
margin-left: 8px; margin-left: 8px;
margin-bottom: 10px; margin-bottom: 10px;
padding: 5px 10px; padding: 5px 10px;
} }
select:focus, select:focus,
input[type="text"]:focus, input[type="text"]:focus,
input[type="number"]:focus { input[type="number"]:focus {
outline: none; outline: none;
border-color: #888; border-color: #888;
} }
input:focus::-webkit-input-placeholder { opacity: 0; } input:focus::-webkit-input-placeholder { opacity: 0; }
@ -109,344 +114,336 @@ input:focus:-moz-placeholder { opacity: 0; }
input:focus:-ms-input-placeholder { opacity: 0; } input:focus:-ms-input-placeholder { opacity: 0; }
.searchbar { .searchbar {
width: 40%; width: 60%;
margin: 40px auto 100px; text-align: center;
margin: 0 auto 50px;
} }
.searchbar input[type="text"] { .searchbar input[type="text"] {
width: 90%; width: 90%;
margin: auto; font-size: 1.1em;
font-size: 1.1em; text-align: center;
text-align: center; margin: auto auto 10px;
margin-bottom: 10px;
} }
.searchbar input[type="text"]::placeholder { .searchbar input[type="text"]::placeholder {
text-align: center; text-align: center;
} }
.searchbar > h3 { .searchbar > h3 {
font-size: 200%; font-size: 200%;
font-weight: bold; font-weight: bold;
color: #1182DB; color: #1182DB;
margin-bottom: 10px; margin-bottom: 10px;
}
.container {
width: 60%;
margin: 30px auto;
} }
/* Section */ /* Section */
section { section {
background-color: #FFFFFF; margin-bottom: 10px;
width: 60%; background-color: #FFFFFF;
margin: 30px auto; padding: 15px;
padding: 15px 15px; box-shadow: 0 6px 15px rgba(0, 0, 0, 0.09);
text-align: center; border-radius: 4px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.09); }
border-radius: 4px; section > time,
section > p.author {
color: #888;
font-size: 80%;
padding: 10px;
} }
section.footer { section.footer {
opacity: 0.5; opacity: 0.5;
text-align: center;
} }
section.footer:hover { section.footer:hover {
opacity: 1; opacity: 1;
}
section.footer .version {
font-size: 80%;
} }
section > h2 { section > h2 {
font-size: 200%; font-size: 200%;
font-weight: bold; font-weight: bold;
text-align: center;
}
section li {
margin-left: 1em;
}
.bridge-card {
text-align: center;
} }
/* Buttons */ /* Buttons */
button {
line-height: 1.9em;
color: #FFF;
font-weight: bold;
vertical-align: middle;
padding: 6px 12px;
margin: 12px auto 0px;
border-radius: 4px;
border: 1px solid transparent;
background: #2196F3 none repeat scroll 0% 0%;
cursor: pointer;
width: calc(20% - 4px);
}
button.small { button.small {
width: auto; width: auto;
line-height: 1.2em; line-height: 1.2em;
} }
button:hover { button:hover {
background: #49afff; background: #49afff;
} }
.description { .description {
margin: 10px; margin: 10px;
}
h5 {
margin: 20px;
font-weight: bold;
} }
form { form {
margin-bottom: 6px; margin-bottom: 6px;
} }
.parameters label::first-letter { .parameters label::first-letter {
text-transform: capitalize; text-transform: capitalize;
} }
.parameters label::after { .parameters label::after {
content: ' :'; content: ' :';
} }
.info { .info {
cursor: help; cursor: pointer;
opacity: 0.5; opacity: 0.5;
width: 24px; width: 24px;
height: 24px; height: 24px;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
font-style: italic; font-style: italic;
line-height: 22px; line-height: 22px;
text-align: center; text-align: center;
color: #fff; color: #fff;
background-image: radial-gradient(#49afff, #1182DB); background-image: radial-gradient(#49afff, #1182DB);
-webkit-border-radius: 16px; -webkit-border-radius: 16px;
-moz-border-radius: 16px; -moz-border-radius: 16px;
border-radius: 16px; border-radius: 16px;
} }
.info:hover { .info:hover {
opacity: 1; opacity: 1;
} }
@supports (display: grid) { @supports (display: grid) {
.parameters { .parameters {
display: grid; display: grid;
padding: 12px 0; padding: 12px 0;
grid-template-columns: 40% max-content 24px; grid-template-columns: 40% max-content 24px;
grid-column-gap: 10px; grid-column-gap: 10px;
grid-row-gap: 5px; grid-row-gap: 5px;
} }
.parameters label { .parameters label {
text-align: right; text-align: right;
line-height: 1.5em; line-height: 1.5em;
} }
.parameters label::before { .parameters label::before {
content: none; content: none;
} }
.parameters input[type="text"], .parameters input[type="text"],
.parameters input[type="number"], .parameters input[type="number"],
.parameters input[type="checkbox"], .parameters input[type="checkbox"],
.parameters select { .parameters select {
margin-left: 0; margin-left: 0;
} }
.parameters input[type="text"], .parameters input[type="text"],
.parameters input[type="number"] { .parameters input[type="number"] {
width: auto; width: auto;
color: #404552; color: #404552;
} }
.parameters input[type="checkbox"] { .parameters input[type="checkbox"] {
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
} /* @supports (display: grid) */ } /* @supports (display: grid) */
.maintainer { p.maintainer {
color: #888888; color: #888888;
font-size: 70%; font-size: 70%;
text-align: right; text-align: right;
} }
.secure-warning { .secure-warning {
background-color: #ffc600; background-color: #ffc600;
color: #5f5f5f; color: #5f5f5f;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3); box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
border-radius: 2px; border-radius: 2px;
border: 1px solid transparent; border: 1px solid transparent;
width: 80%; width: 80%;
margin: auto; margin: auto auto 6px;
margin-bottom: 6px;
} }
.error strong {
display: inline-block;
width: 100px;
}
/* Hide all forms on the frontpage by default */
form { form {
display: none; display: none;
} }
select { select {
padding: 5px 10px; padding: 5px 10px;
margin-left: 8px; margin-left: 8px;
} }
h5 { /* Show more/less */
display: none;
}
/* Show more / less */
.showmore-box { .showmore-box {
display: none; display: none;
} }
.showmore, .showless { .showmore, .showless {
color: #888888; color: #888888;
cursor: pointer; cursor: pointer;
} }
.showmore:hover, .showless:hover { .showmore:hover, .showless:hover {
color: #000; color: #000;
cursor: pointer; cursor: pointer;
} }
.showmore-box:checked ~ .showmore { .showmore-box:checked ~ .showmore {
display: none; display: none;
} }
.showmore-box:not(:checked) ~ .showless { .showmore-box:not(:checked) ~ .showless {
display: none; display: none;
} }
.showmore-box:checked ~ form, .showmore-box:checked ~ h5 { .showmore-box:checked ~ form, .showmore-box:checked ~ h5 {
display: block; display: block;
} }
/* Additional styles for error pages */ /* html format */
.exception-message { h1.pagetitle {
background-color: #c00000; margin: 40px 0 20px;
color: #FFFFFF; font-size: 300%;
font-weight: bold; font-weight: bold;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3); text-align: center;
border-radius: 2px; color: #2196F3;
border: 1px solid transparent;
width: 80%;
margin: auto;
margin-bottom: 6px;
} }
h1.pagetitle > a {
.advice > li { color: #2196F3;
text-align: left; }
.buttons {
text-align: center;
margin-bottom: 15px;
}
button {
line-height: 1.9em;
color: #FFF;
font-weight: bold;
vertical-align: middle;
padding: 6px 12px;
margin: 12px auto 0px;
border-radius: 4px;
border: 1px solid transparent;
background: #2196F3 none repeat scroll 0% 0%;
cursor: pointer;
width: 200px;
} }
@media screen and (max-width: 767px) { @media screen and (max-width: 767px) {
body { .container {
font-size: 75%; width: 100%;
} padding: 5px;
}
header > div.logo { .searchbar {
background-image: url(logo_300px.png); margin-bottom: 5px;
width: 300px; }
height: 89px;
}
header > section.warning { header > div.logo {
width: 90%; background-image: url(logo_300px.png);
} width: 300px;
height: 89px;
}
header > section.critical-warning { button {
width: 90%; display: inline-block;
} width: 40%;
padding: 5px auto;
margin: 3px auto 0;
}
.searchbar { .info, .no-info {
width: 90%; display: none;
margin: 0 auto; }
}
section { @supports (display: grid) {
width: 90%;
margin: 10px auto;
overflow: hidden;
}
button { .parameters {
display: inline-block; grid-template-columns: auto auto;
width: 40%; grid-column-gap: 5px;
padding: 5px auto; }
margin: 3px auto 0;
}
.info, .no-info { .parameters label {
display: none; line-height: 2em;
} word-break: break-word;
}
@supports (display: grid) { } /* @supports (display: grid) */
.parameters { .secure-warning {
grid-template-columns: auto auto; width: 100%;
grid-column-gap: 5px; }
}
.parameters label {
line-height: 2em;
word-break: break-word;
}
} /* @supports (display: grid) */
.secure-warning {
width: 100%;
}
} }
/* Dark theme */ /* Dark theme */
@media (prefers-color-scheme: dark){ @media (prefers-color-scheme: dark){
* { * {
scrollbar-color: #202324 #454a4d; scrollbar-color: #202324 #454a4d;
} }
body { body {
background-color: #202325; background-color: #202325;
color: #e8e6e3; color: #e8e6e3;
} }
a, a:link, a:visited { a, a:link, a:visited {
color: #0A6AB6; color: #0A6AB6;
} }
/* Header */ /* Header */
select, select,
input[type="text"], input[type="text"],
input[type="number"] { input[type="number"] {
background-color: #181A1B; background-color: #181A1B;
/* does not apply to placeholder text without !important */ /* does not apply to placeholder text without !important */
color: white !important; color: white !important;
border: 1px solid #393E40; border: 1px solid #393E40;
} }
/* Section */ /* Section */
section { section {
background-color: #181A1B; background-color: #181A1B;
} }
/* Buttons */ /* Buttons */
button { button {
background: #0A6AB6 none repeat scroll 0% 0%; background: #0A6AB6 none repeat scroll 0% 0%;
} }
button:hover { button:hover {
background: #004daa; background: #004daa;
} }
@supports (display: grid){ @supports (display: grid){
.parameters input[type="number"] { .parameters input[type="number"] {
color: #BAB4AB; color: #BAB4AB;
} }
} }
/* Show more / less */ /* Show more / less */
.showmore:hover, .showless:hover { .showmore:hover, .showless:hover {
color: #d8d3cb; color: #d8d3cb;
} }
} }

View File

@ -1,6 +1,4 @@
<section>
<h1>
Please authenticate in order to access this instance
</h1>
</section>
<h1>
Please authenticate in order to access this instance
</h1>

View File

@ -8,11 +8,15 @@
<link href="static/style.css" rel="stylesheet"> <link href="static/style.css" rel="stylesheet">
<link rel="icon" type="image/png" href="static/favicon.png"> <link rel="icon" type="image/png" href="static/favicon.png">
</head> </head>
<body>
<header>
<div class="logo"></div>
</header>
<?= raw($page) ?> <body>
<div class="container">
<header>
<div class="logo"></div>
</header>
<?= raw($page) ?>
</div>
</body>
</html> </html>

View File

@ -1,38 +1,14 @@
<section>
<p class="exception-message">
<?= e($message) ?>
</p>
<?php foreach ($trace as $i => $frame) : ?> <?= raw($error) ?>
#<?= $i ?> <?= e(frame_to_call_point($frame)) ?>
<br>
<?php endforeach; ?>
<br> <a href="<?= raw($searchUrl) ?>" title="Opens GitHub to search for similar issues">
<button>Find similar bugs</button>
</a>
<p> <a href="<?= raw($issueUrl) ?>" title="After clicking this button you can review the issue before submitting it">
Query string: <?= e(urldecode($_SERVER['QUERY_STRING']) ?? '') ?> <button>Create GitHub Issue</button>
</p> </a>
<p>
Version: <?= raw(Configuration::getVersion()) ?>
</p>
<p>
OS: <?= raw(PHP_OS_FAMILY) ?>
</p>
<p>
PHP version: <?= raw(PHP_VERSION ?: 'Unknown') ?>
</p>
<a href="<?= raw($searchUrl) ?>" title="Opens GitHub to search for similar issues">
<button>Find similar bugs</button>
</a>
<a href="<?= raw($issueUrl) ?>" title="After clicking this button you can review the issue before submitting it">
<button>Create GitHub Issue</button>
</a>
<p class="maintainer">
<?= e($maintainer) ?>
</p>
</section>
<p class="maintainer">
<?= e($maintainer) ?>
</p>

View File

@ -1,14 +1,36 @@
<div style="width: 60%; margin: 30px auto"> <div class="error">
<h1>Something went wrong</h1> <h1>Application Error</h1>
<p> <p>The application could not run because of the following error:</p>
<?= e($message) ?>
</p>
<h2>Stacktrace</h2> <h2>Details</h2>
<?php foreach ($trace as $i => $frame) : ?> <div style="margin-bottom: 15px">
<div>
<strong>Type:</strong> <?= e(get_class($e)) ?>
</div>
<div>
<strong>Code:</strong> <?= e($e->getCode()) ?>
</div>
<div>
<strong>Message:</strong> <?= e($e->getMessage()) ?>
</div>
<div>
<strong>File:</strong> <?= e(trim_path_prefix($e->getFile())) ?>
</div>
<div>
<strong>Line:</strong> <?= e($e->getLine()) ?>
</div>
</div>
<h2>Trace</h2>
<?php foreach (trace_from_exception($e) as $i => $frame) : ?>
<code> <code>
#<?= $i ?> <?= e(frame_to_call_point($frame)) ?> #<?= $i ?> <?= e(frame_to_call_point($frame)) ?>
</code> </code>
@ -19,17 +41,24 @@
<h2>Context</h2> <h2>Context</h2>
<p> <div>
Query string: <?= e(urldecode($_SERVER['QUERY_STRING'] ?? '')) ?> <strong>Query:</strong> <?= e(urldecode($_SERVER['QUERY_STRING'] ?? '')) ?>
</p> </div>
<p>
Version: <?= raw(Configuration::getVersion()) ?> <div>
</p> <strong>Version:</strong> <?= raw(Configuration::getVersion()) ?>
<p> </div>
OS: <?= raw(PHP_OS_FAMILY) ?>
</p> <div>
<p> <strong>OS:</strong> <?= raw(PHP_OS_FAMILY) ?>
PHP version: <?= raw(PHP_VERSION ?: 'Unknown') ?> </div>
</p>
<div>
<strong>PHP:</strong> <?= raw(PHP_VERSION ?: 'Unknown') ?>
</div>
<br>
<a href="/">Go back</a>
</div> </div>

View File

@ -1,10 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="<?= $charset ?>"> <meta charset="<?= $charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/ >
<meta name="description" content="RSS-Bridge" />
<title><?= e($title) ?></title> <title><?= e($title) ?></title>
<link href="static/HtmlFormat.css" rel="stylesheet"> <link href="static/style.css" rel="stylesheet">
<link rel="icon" type="image/png" href="static/favicon.png"> <link rel="icon" type="image/png" href="static/favicon.png">
<?php foreach ($linkTags as $link): ?> <?php foreach ($linkTags as $link): ?>
@ -18,73 +19,74 @@
<meta name="robots" content="noindex, follow"> <meta name="robots" content="noindex, follow">
</head> </head>
<body> <body>
<h1 class="pagetitle">
<a href="<?= e($uri) ?>" target="_blank">
<?= e($title) ?>
</a>
</h1>
<div class="buttons"> <div class="container">
<a href="./#bridge-<?= $_GET['bridge'] ?>"> <h1 class="pagetitle">
<button class="backbutton"> back to rss-bridge</button> <a href="<?= e($uri) ?>" target="_blank"><?= e($title) ?></a>
</a> </h1>
<?php foreach ($buttons as $button): ?> <div class="buttons">
<a href="<?= $button['href'] ?>"> <a href="./#bridge-<?= $_GET['bridge'] ?>">
<button class="rss-feed"><?= $button['value'] ?></button> <button class="backbutton"> back to rss-bridge</button>
</a> </a>
<?php foreach ($buttons as $button): ?>
<a href="<?= $button['href'] ?>">
<button class="rss-feed"><?= $button['value'] ?></button>
</a>
<?php endforeach; ?>
</div>
<?php foreach ($items as $item): ?>
<section class="feeditem">
<h2>
<a
class="itemtitle"
href="<?= e($item['url']) ?>"
><?= strip_tags($item['title']) ?></a>
</h2>
<?php if ($item['timestamp']): ?>
<time datetime="<?= date('Y-m-d H:i:s', $item['timestamp']) ?>">
<?= date('Y-m-d H:i:s', $item['timestamp']) ?>
</time>
<?php endif; ?>
<?php if ($item['author']): ?>
<br/>
<p class="author">by: <?= e($item['author']) ?></p>
<?php endif; ?>
<div class="content">
<?= sanitize_html($item['content']) ?>
</div>
<?php if ($item['enclosures']): ?>
<div class="attachments">
<p>Attachments:</p>
<?php foreach ($item['enclosures'] as $enclosure): ?>
<li class="enclosure">
<a href="<?= e($enclosure) ?>" rel="noopener noreferrer nofollow">
<?= e(substr($enclosure, strrpos($enclosure, '/') + 1)) ?>
</a>
</li>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if ($item['categories']): ?>
<div class="categories">
<p>Categories:</p>
<?php foreach ($item['categories'] as $category): ?>
<li class="category"><?= e($category) ?></li>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</body>
<?php foreach ($items as $item): ?>
<section class="feeditem">
<h2>
<a
class="itemtitle"
href="<?= e($item['url']) ?>"
><?= strip_tags($item['title']) ?></a>
</h2>
<?php if ($item['timestamp']): ?>
<time datetime="<?= date('Y-m-d H:i:s', $item['timestamp']) ?>">
<?= date('Y-m-d H:i:s', $item['timestamp']) ?>
</time>
<?php endif; ?>
<?php if ($item['author']): ?>
<br/>
<p class="author">by: <?= e($item['author']) ?></p>
<?php endif; ?>
<div class="content">
<?= sanitize_html($item['content']) ?>
</div>
<?php if ($item['enclosures']): ?>
<div class="attachments">
<p>Attachments:</p>
<?php foreach ($item['enclosures'] as $enclosure): ?>
<li class="enclosure">
<a href="<?= e($enclosure) ?>" rel="noopener noreferrer nofollow">
<?= e(substr($enclosure, strrpos($enclosure, '/') + 1)) ?>
</a>
</li>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if ($item['categories']): ?>
<div class="categories">
<p>Categories:</p>
<?php foreach ($item['categories'] as $category): ?>
<li class="category"><?= e($category) ?></li>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
<?php endforeach; ?>
</body>
</html> </html>

View File

@ -40,4 +40,11 @@ final class UtilsTest extends TestCase
$this->assertIsNumeric($sut->getTime()); $this->assertIsNumeric($sut->getTime());
$sut->purgeCache(-1); $sut->purgeCache(-1);
} }
public function testTrimFilePath()
{
$this->assertSame('', trim_path_prefix(dirname(__DIR__)));
$this->assertSame('tests', trim_path_prefix(__DIR__));
$this->assertSame('tests/UtilsTest.php', trim_path_prefix(__DIR__ . '/UtilsTest.php'));
}
} }