Merge pull request #2 from Wruczek/2.0

-
pull/105/head
Robin 6 years ago committed by GitHub
commit a3a7213b5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitignore vendored

@ -1,5 +1,6 @@
.idea
PROTOTYPING
tools
src/installer/cache
src/private/cache
src/private/vendor

@ -18,32 +18,74 @@ if ($banlist !== null) {
$data = [];
foreach ($banlist as $ban) {
// Bans abbreviations:
// if we see a UID, IP or MyTSID ban, and we know
// the nickname of the banned user, we will show
// the user's name and then the type of ban
// that should be enough info for most users.
// it is possible to hover over the ban type to
// view the exact ban target
//
// for example, Wruczek got banned on his UID. we know that
// his last nickname was "Wruczek", so we simply show, that
// the ban is issued for:
// Wruczek (UID)
// after hovering over the "UID", you will see the exact UID
//
// if we dont know the last name of the banned user, we
// will just show the UID, IP or MyTSID
$name = "(cannot determine a name)";
$target = "(unknown)";
$lastNickname = Utils::escape($ban["lastnickname"]);
$filter = "";
$abbreviation = null;
if ($ban["lastnickname"]) {
$name = (string)$ban["lastnickname"];
} else if ($ban["uid"]) {
$name = new Html("<code>" . $ban["uid"] . "</code>");
} else if ($ban["name"]) {
$name = (string)$ban["name"];
} else if ($ban["ip"]) {
$ip = str_replace("\\", "", (string) $ban["ip"]);
if ($ban["ip"]) {
$ip = str_replace("\\", "", (string)$ban["ip"]);
try {
$name = Utils::censorIpAddress($ip);
$ip = Utils::censorIpAddress($ip);
} catch (\Exception $e) {}
if ($lastNickname) {
$abbreviation = [$ip, "IP"];
} else {
$target = $ip;
}
if ($ip === Utils::getClientIp()) {
$ipbanned = [
"invoker" => (string)$ban["invokername"],
"reason" => (string)$ban["reason"]
];
}
} else if ($ban["uid"]) {
if ($lastNickname) {
$abbreviation = [$ban["uid"], "UID"];
} else {
$target = new Html("<code>" . $ban["uid"] . "</code>");
}
} else if ($ban["name"]) {
$target = $ban["name"];
} else if (!empty($ban["mytsid"])) { // empty, older TS servers dont have MYTS bans, so the key might not exist
if ($lastNickname) {
$abbreviation = [$ban["mytsid"], "MyTSID"];
} else {
$target = new Html("<code>" . $ban["mytsid"] . "</code>");
}
}
if ($abbreviation) {
$html = '%s (<span class="bans-highlight" data-toggle="tooltip" title="%s">%s</span>)';
$target = new Html(sprintf($html, $lastNickname, $abbreviation[0], $abbreviation[1]));
// make sure that the "full" data is also searchable in DataTables
$filter = "{$abbreviation[0]} $lastNickname";
}
$data[] = [
"name" => $name,
"filter" => $filter,
"target" => $target,
"reason" => (string)$ban["reason"],
"invoker" => (string)$ban["invokername"],
"created" => $ban["created"],

@ -178,6 +178,11 @@ body {
align-items: center;
}
.bans-highlight {
color: #e83e8c;
font-family: var(--font-family-monospace);
}
/* Responsive datatables styles */
table.dataTable>tbody>tr.child ul.dtr-details>li:first-child {

@ -19,6 +19,7 @@ INSERT INTO `DBPREFIXconfig` (`identifier`, `type`, `value`, `user_editable`) VA
('loginpokeclient', 'BOOL', 'true', 1),
('cache_logincode', 'INT', '120', 1),
('cache_adminstatus', 'INT', '60', 1),
('cache_languages', 'INT', '300', 1),
('adminstatus_groups', 'JSON', '[]', 1),
('adminstatus_mode', 'INT', '2', 1),
('adminstatus_enabled', 'BOOL', 'true', 1),
@ -50,20 +51,6 @@ INSERT INTO `DBPREFIXfaq` (`faqid`, `langid`, `question`, `answer`, `lastmodify`
(2, 1, 'How can I configure the FAQ?', 'An administrator can add, edit and remove questions in <a href=\"admin\">admin panel</a>.', '2018-12-26 12:33:18'),
(3, 1, 'Question 3', 'Answer 3 in <b>HTML</b>', '2018-12-26 13:10:32');
DROP TABLE IF EXISTS `DBPREFIXlanguages`;
CREATE TABLE `DBPREFIXlanguages` (
`langid` int(11) NOT NULL,
`englishname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`nativename` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`langcode` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'In this format: https://bit.ly/2MCGg6M',
`isdefault` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `DBPREFIXlanguages` (`langid`, `englishname`, `nativename`, `langcode`, `isdefault`) VALUES
(1, 'English', 'English', 'en', 1),
(2, 'English (US)', 'English (US)', 'en-us', 0),
(3, 'Polish', 'Polski', 'pl', 0);
DROP TABLE IF EXISTS `DBPREFIXnews`;
CREATE TABLE `DBPREFIXnews` (
`newsid` int(11) NOT NULL,
@ -75,239 +62,7 @@ CREATE TABLE `DBPREFIXnews` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `DBPREFIXnews` (`newsid`, `title`, `langid`, `added`, `edited`, `content`) VALUES
(1, 'Welcome to ts-website!', 1, '2018-12-26 13:10:32', NULL, '<b>Hi there!</b> If you are reading this, it means that TS-website has been installed successfully.<br>\r\nYou can login to your <a href=\"admin\">ACP</a> to configure many parts of it.<br>\r\nNeed help? Join our <a href=\"https://t.me/tswebsite\" target=\"_blank\">Telegram group</a> for support.\r\nHave a good day!');
DROP TABLE IF EXISTS `DBPREFIXtranslations`;
CREATE TABLE `DBPREFIXtranslations` (
`id` int(10) NOT NULL,
`langid` int(10) NOT NULL,
`identifier` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL,
`value` text COLLATE utf8mb4_unicode_ci NOT NULL,
`comment` text COLLATE utf8mb4_unicode_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `DBPREFIXtranslations` (`id`, `langid`, `identifier`, `value`, `comment`) VALUES
(1, 1, 'AUTHORS', 'Wruczek <wruczekk@gmail.com>', 'Language authors'),
(2, 3, 'AUTHORS', 'Wruczek <wruczekk@gmail.com>', NULL),
(3, 1, 'COOKIEALERT_MESSAGE', '<b>Do you like cookies?</b> &#x1F36A; We use cookies to ensure you get the best experience on our website. <a href=\"http://cookiesandyou.com/\" target=\"_blank\">Learn more</a>', 'Remember to change link to a website in your language'),
(4, 3, 'COOKIEALERT_MESSAGE', '<b>Lubisz ciasteczka?</b> &#x1F36A; Używamy ciasteczek, aby zapewnić najwyższą jakość usług. <a href=\"http://wszystkoociasteczkach.pl/\" target=\"_blank\">Dowiedz się więcej</a>', NULL),
(5, 1, 'COOKIEALERT_AGREE', 'I agree', NULL),
(6, 3, 'COOKIEALERT_AGREE', 'Zgadzam się', NULL),
(7, 1, 'OUTDATED_DATA', '<b>Warning!</b> Some information cannot be obtained now. Showing outdated data from {0}.', '{0} will be replaced with fuzzy date (for example \"8 hours ago\"). Please try to match the your message grammatically'),
(8, 3, 'OUTDATED_DATA', '<b>Uwaga!</b> Niektóre dane nie mogą być teraz uzyskane. Pokazuje nieaktualne dane z {0}.', NULL),
(9, 1, 'SHOW_PROBLEMS', 'Show problems', NULL),
(10, 3, 'SHOW_PROBLEMS', 'Pokaż problemy', NULL),
(11, 1, 'PROBLEMS_DESCRIPTION', 'Problems encountered while connecting to the TeamSpeak server', NULL),
(12, 3, 'PROBLEMS_DESCRIPTION', 'Problemy napotkane podczas próby połączenia się z serwerem TeamSpeak', NULL),
(13, 1, 'NO_JAVASCRIPT_ENABLED', 'This website will not work without <a href=\"https://www.enable-javascript.com/\" target=\"_blank\">JavaScript enabled</a>.', 'Remember to change the website address to include instructions in your language'),
(14, 3, 'NO_JAVASCRIPT_ENABLED', 'Ta stronie nie będzie działać bez <a href=\"https://www.enable-javascript.com/pl/\" target=\"_blank\">włączonej obsługi JavaScript</a>.', NULL),
(15, 1, 'CANNOT_GET_DATA', 'Cannot get data for \"{0}\"! Please contact website owner.', '{0} will be replaced with component name that cannot be refreshed (for example banlist or viewer)'),
(16, 3, 'CANNOT_GET_DATA', 'Nie mogę pobrać informacji o \"{0}\"! Skontaktuj się z właścicielem strony.', NULL),
(17, 1, 'NO_REASON_SET', '<b>(no reason set)</b>', 'Please keep the \"<b>\" tags in place, as they help to distinguish a placeholder form a real message'),
(18, 3, 'NO_REASON_SET', '<b>(brak powodu)</b>', NULL),
(19, 1, 'BANS_HEADER_NAME', 'Name / IP / UID', NULL),
(20, 3, 'BANS_HEADER_NAME', 'Nazwa / IP / UID', NULL),
(21, 1, 'BANS_HEADER_REASON', 'Reason', NULL),
(22, 3, 'BANS_HEADER_REASON', 'Powód', NULL),
(23, 1, 'BANS_HEADER_INVOKER', 'Banned by', NULL),
(24, 3, 'BANS_HEADER_INVOKER', 'Zbanowany przez', NULL),
(25, 1, 'BANS_HEADER_BANDATE', 'Ban date', NULL),
(26, 3, 'BANS_HEADER_BANDATE', 'Data zbanowania', NULL),
(27, 1, 'BANS_HEADER_EXPIRES', 'Expires', NULL),
(28, 3, 'BANS_HEADER_EXPIRES', 'Wygasa', NULL),
(29, 1, 'DATATABLES_LANGUAGE_NAME', 'English', 'This language will be used to load language file for DataTables. Please choose a language from this list: https://datatables.net/plug-ins/i18n/#Translations.\r\n\r\nIf chosen correctly, this url: \"//cdn.datatables.net/plug-ins/1.10.12/i18n/{NAME}.json\" should return a valid JSON object with translations. For example: \"//cdn.datatables.net/plug-ins/1.10.12/i18n/English.json\"'),
(30, 3, 'DATATABLES_LANGUAGE_NAME', 'Polish', NULL),
(31, 1, 'BANS_NEVEREXPIRES', 'Never', NULL),
(32, 3, 'BANS_NEVEREXPIRES', 'Nigdy', NULL),
(33, 1, 'STATUS_ADDRESS', 'Address:', ''),
(34, 3, 'STATUS_ADDRESS', 'Adres:', NULL),
(35, 1, 'STATUS_CLIENTS_ONLINE', 'Online:', NULL),
(36, 3, 'STATUS_CLIENTS_ONLINE', 'Online:', NULL),
(37, 1, 'STATUS_RESERVED_SLOTS', '{0} reserved slots', NULL),
(38, 3, 'STATUS_RESERVED_SLOTS', '{0} zarezerwowanych slotów', NULL),
(39, 1, 'STATUS_TOP_ONLINE', 'Top online:', NULL),
(40, 3, 'STATUS_TOP_ONLINE', 'Rekord online:', NULL),
(41, 1, 'STATUS_TOP_ONLINE_DESC', 'Achieved on {0}', NULL),
(42, 3, 'STATUS_TOP_ONLINE_DESC', 'Ustanowiono {0}', NULL),
(43, 1, 'STATUS_UPTIME', 'Uptime:', NULL),
(44, 3, 'STATUS_UPTIME', 'Uptime:', NULL),
(45, 1, 'STATUS_VERSION', 'Version:', NULL),
(46, 3, 'STATUS_VERSION', 'Wersja:', NULL),
(47, 1, 'STATUS_VERSION_DESC', '{0} on {1}', NULL),
(48, 3, 'STATUS_VERSION_DESC', '{0} na {1}', NULL),
(49, 1, 'STATUS_PING', 'Avg. ping:', NULL),
(50, 3, 'STATUS_PING', 'Śr. ping:', NULL),
(51, 1, 'STATUS_PACKETLOSS', 'Avg. packet loss:', NULL),
(52, 3, 'STATUS_PACKETLOSS', 'Śr. utrata pakietów:', NULL),
(53, 1, 'STATUS_ERROR', 'Cannot retrieve server status', NULL),
(54, 3, 'STATUS_ERROR', 'Błąd podczas wczytywania statusu serwera', NULL),
(55, 1, 'STATUS_PANEL_TITLE', 'Server status', NULL),
(56, 3, 'STATUS_PANEL_TITLE', 'Status serwera', NULL),
(57, 1, 'MOMENTJS_LANG', 'en-gb', 'Language for Moment.js, full list: https://github.com/moment/moment/tree/develop/locale'),
(58, 2, 'MOMENTJS_LANG', 'en-us', NULL),
(59, 3, 'MOMENTJS_LANG', 'pl', NULL),
(60, 1, 'LOGIN_CONFIRMATION_CODE', 'Hi, here\'s your confirmation code to login: [b]{0}[/b]', 'You can use BBCode. Use {0} for the confirmation code.'),
(61, 3, 'LOGIN_CONFIRMATION_CODE', 'Cześć, oto twój kod potwierdzający logowanie: [b]{0}[/b]', NULL),
(62, 1, 'UNSUPPORTED_BROWSER', 'Your browser is not supported. Please switch to the latest version of Chrome, Firefox, Safari or Edge to use this website.', ''),
(63, 3, 'UNSUPPORTED_BROWSER', 'Twoja przeglądarka nie jest wspierana. Zainstaluj najnowszą wersję Chrome, Firefox, Safari lub Edge by korzystać z tej strony.', NULL),
(64, 1, 'DATATABLES_PLACEHOLDER_SEARCH', 'Search...', NULL),
(65, 3, 'DATATABLES_PLACEHOLDER_SEARCH', 'Szukaj...', NULL),
(66, 1, 'WEBSITE_TITLE', ' | TS-website English Language', NULL),
(67, 3, 'WEBSITE_TITLE', ' | TS-website Język Polski', NULL),
(68, 1, 'ADMIN_STATUS_ONLINE', 'Online', NULL),
(69, 3, 'ADMIN_STATUS_ONLINE', 'Online', NULL),
(70, 1, 'ADMIN_STATUS_AWAY', 'Away', NULL),
(71, 3, 'ADMIN_STATUS_AWAY', 'Zaraz wracam', NULL),
(72, 1, 'ADMIN_STATUS_OFFLINE', 'Offline', NULL),
(73, 3, 'ADMIN_STATUS_OFFLINE', 'Offline', NULL),
(76, 1, 'ADMIN_STATUS_EMPTY_GROUP', 'Nothing to show', NULL),
(77, 3, 'ADMIN_STATUS_EMPTY_GROUP', 'Nic do pokazania', NULL),
(78, 1, 'ADMIN_STATUS_EMPTY_STATUS', 'Admin status is empty', NULL),
(79, 3, 'ADMIN_STATUS_EMPTY_STATUS', 'Status administracji jest pusty', NULL),
(80, 1, 'ASSIGNER_PANEL_TITLE', 'Group assigner', NULL),
(81, 3, 'ASSIGNER_PANEL_TITLE', 'Przydzielanie grup', NULL),
(82, 1, 'ASSIGNER_TITLE', 'Group assigner', NULL),
(83, 3, 'ASSIGNER_TITLE', 'Przydzielanie grup', NULL),
(84, 1, 'BANS_EMPTY', 'Banlist is empty', NULL),
(85, 3, 'BANS_EMPTY', 'Lista banów jest pusta', NULL),
(86, 1, 'BANS_TITLE', 'Banlist', NULL),
(87, 3, 'BANS_TITLE', 'Lista banów', NULL),
(88, 1, 'BANS_PANEL_TITLE', 'Banlist', NULL),
(89, 3, 'BANS_PANEL_TITLE', 'Lista banów', NULL),
(90, 1, 'BANS_BANNED_ALERT_TITLE', 'Your IP has been banned by {0}', NULL),
(91, 3, 'BANS_BANNED_ALERT_TITLE', 'Twoje IP zostało zbanowane przez {0}', NULL),
(92, 1, 'BANS_BANNED_ALERT_REASON', 'Reason: {0}', NULL),
(93, 3, 'BANS_BANNED_ALERT_REASON', 'Powód: {0}', NULL),
(94, 1, 'BANS_VIEW_MORE_TIP', 'Click on a row to view more details about a ban', NULL),
(95, 3, 'BANS_VIEW_MORE_TIP', 'Kliknij na wiersz by pokazać więcej informacji o banie', NULL),
(96, 1, 'RULES_TITLE', 'Rules', NULL),
(97, 3, 'RULES_TITLE', 'Regulamin', NULL),
(98, 1, 'RULES_PANEL_TITLE', 'Rules', NULL),
(99, 3, 'RULES_PANEL_TITLE', 'Regulamin', NULL),
(100, 1, 'FAQ_COPY_LINK', 'Copy link to that answer', NULL),
(101, 3, 'FAQ_COPY_LINK', 'Kopiuj link do tej odpowiedzi', NULL),
(102, 1, 'FAQ_PANEL_TITLE', 'FAQ', NULL),
(103, 3, 'FAQ_PANEL_TITLE', 'FAQ', NULL),
(104, 1, 'FAQ_TITLE', 'FAQ', NULL),
(105, 3, 'FAQ_TITLE', 'FAQ', NULL),
(106, 1, 'FAQ_COPY_LINK_SUCCESS', 'Copied!', NULL),
(107, 3, 'FAQ_COPY_LINK_SUCCESS', 'Skopiowano!', NULL),
(108, 1, 'FAQ_COPY_LINK_ERROR', 'Error!', NULL),
(109, 3, 'FAQ_COPY_LINK_ERROR', 'Błąd!', NULL),
(110, 1, 'HOME_TITLE', 'News', NULL),
(111, 3, 'HOME_TITLE', 'Aktualności', NULL),
(112, 1, 'HOME_PANEL_TITLE', 'News', NULL),
(113, 3, 'HOME_PANEL_TITLE', 'Aktualności', NULL),
(114, 1, 'HOME_EMPTY', 'No news available at this moment', NULL),
(115, 3, 'HOME_EMPTY', 'Brak atualności', NULL),
(116, 1, 'HOME_INVALID_PAGE', 'Invalid page number', NULL),
(117, 3, 'HOME_INVALID_PAGE', 'Zły numer strony', NULL),
(118, 1, 'HOME_PREVIOUS_NEWS', 'Previous', 'This value is only used by assistive technologies (screen readers ect.)'),
(119, 3, 'HOME_PREVIOUS_NEWS', 'Poprzednia', NULL),
(120, 1, 'HOME_NEXT_NEWS', 'Next', 'This value is only used by assistive technologies (screen readers ect.)'),
(121, 3, 'HOME_NEXT_NEWS', 'Następna', NULL),
(122, 1, 'ADMIN_STATUS_PANEL_TITLE', 'Admin status', NULL),
(123, 3, 'ADMIN_STATUS_PANEL_TITLE', 'Status administracji', NULL),
(124, 1, 'ADMIN_STATUS_HIDE_OFFLINE_TIP', 'Hide offline admins', NULL),
(125, 3, 'ADMIN_STATUS_HIDE_OFFLINE_TIP', 'Ukryj administratorów offline', NULL),
(126, 1, 'ADMIN_STATUS_SHOW_OFFLINE_TIP', 'Show offline admins', NULL),
(127, 3, 'ADMIN_STATUS_SHOW_OFFLINE_TIP', 'Pokaż administratorów offline', NULL),
(128, 1, 'ADMIN_STATUS_ERROR', 'Admin status error', NULL),
(129, 3, 'ADMIN_STATUS_ERROR', 'Błąd statusu administracji', NULL),
(130, 1, 'NAV_TOGGLE', 'Toggle navigation', 'This value is only used by assistive technologies (screen readers ect.)'),
(131, 3, 'NAV_TOGGLE', 'Przełącz nawigację', NULL),
(132, 1, 'NAV_VIEWER', 'Viewer', NULL),
(133, 3, 'NAV_VIEWER', 'Podgląd', NULL),
(134, 1, 'NAV_ASSIGNER', 'Assigner', NULL),
(135, 3, 'NAV_ASSIGNER', 'Grupy', NULL),
(136, 1, 'NAV_BANS', 'Bans', NULL),
(137, 3, 'NAV_BANS', 'Bany', NULL),
(138, 1, 'NAV_RULES', 'Rules', NULL),
(139, 3, 'NAV_RULES', 'Regulamin', NULL),
(140, 1, 'NAV_FAQ', 'FAQ', NULL),
(141, 3, 'NAV_FAQ', 'FAQ', NULL),
(142, 1, 'NAV_ACCOUNT_LOGIN', 'Login', NULL),
(143, 3, 'NAV_ACCOUNT_LOGIN', 'Zaloguj się', NULL),
(144, 1, 'NAV_ACCOUNT_LOGOUT', 'Logout', NULL),
(145, 3, 'NAV_ACCOUNT_LOGOUT', 'Wyloguj się', NULL),
(146, 1, 'VIEWER_TITLE', 'Server viewer', NULL),
(147, 3, 'VIEWER_TITLE', 'Podgląd serwera', NULL),
(148, 1, 'VIEWER_PANEL_TITLE', 'Server viewer', NULL),
(149, 3, 'VIEWER_PANEL_TITLE', 'Podgląd serwera', NULL),
(150, 1, 'VIEWER_SHOW_EMPTY', 'Show empty channels', NULL),
(151, 3, 'VIEWER_SHOW_EMPTY', 'Pokaż puste kanały', NULL),
(152, 1, 'VIEWER_HIDE_EMPTY', 'Hide empty channels', NULL),
(153, 3, 'VIEWER_HIDE_EMPTY', 'Ukryj puste kanały', NULL),
(154, 1, 'VIEWER_TIP_ALERT', 'Click on a channel to join it. Hover over a user to check their info', NULL),
(155, 3, 'VIEWER_TIP_ALERT', 'Kliknij na kanał, by na niego dołączyć. Nakieruj na użytkownika, by sprawdzić informacje o nim', NULL),
(158, 1, 'ARIA_CLOSE', 'Close', 'This value is only used by assistive technologies (screen readers ect.)'),
(159, 3, 'ARIA_CLOSE', 'Zamknij', NULL),
(160, 1, 'VIEWER_ERROR', 'Viewer error', NULL),
(161, 3, 'VIEWER_ERROR', 'Błąd podglądu', NULL),
(162, 1, 'VIEWER_CONNECTION_CONFIRMATION', 'Do you want to connect to this channel?', NULL),
(163, 3, 'VIEWER_CONNECTION_CONFIRMATION', 'Czy chcesz dołączyć na ten kanał?', NULL),
(164, 1, 'VIEWER_CLIENT_LASTACTIVE', 'Last active:', NULL),
(165, 3, 'VIEWER_CLIENT_LASTACTIVE', 'Aktywny:', NULL),
(166, 1, 'VIEWER_CLIENT_ONLINE', 'Online time:', NULL),
(167, 3, 'VIEWER_CLIENT_ONLINE', 'Online przez:', NULL),
(168, 1, 'VIEWER_CLIENT_JOINED', 'First joined:', NULL),
(169, 3, 'VIEWER_CLIENT_JOINED', 'Dołączył:', NULL),
(170, 1, 'VIEWER_CLIENT_TITLE', 'Client info', NULL),
(171, 3, 'VIEWER_CLIENT_TITLE', 'Informacje o kliencie', NULL),
(172, 1, 'VIEWER_SERVER_ICON', 'Server icon', NULL),
(173, 3, 'VIEWER_SERVER_ICON', 'Ikona serwera', NULL),
(174, 1, 'VIEWER_DEFAULT_CHANNEL', 'Default channel', NULL),
(175, 3, 'VIEWER_DEFAULT_CHANNEL', 'Kanał domyślny', NULL),
(176, 1, 'VIEWER_CHANNEL_UNSUB1', ', unsubscribed', 'Please note that this string starts with \", \"'),
(177, 3, 'VIEWER_CHANNEL_UNSUB1', ', odsubskrybowany', NULL),
(178, 1, 'VIEWER_CHANNEL_OCCUPIED', 'Fully occupied', NULL),
(179, 3, 'VIEWER_CHANNEL_OCCUPIED', 'Zajęty', NULL),
(180, 1, 'VIEWER_CHANNEL_PASSWORD', 'Password-protected', NULL),
(181, 3, 'VIEWER_CHANNEL_PASSWORD', 'Zabezpieczony hasłem', NULL),
(182, 1, 'VIEWER_CHANNEL_UNSUB2', 'Unsubscribed', NULL),
(183, 3, 'VIEWER_CHANNEL_UNSUB2', 'Odsubskrybowany', NULL),
(184, 1, 'VIEWER_CHANNEL_ICON', 'Channel icon', NULL),
(185, 3, 'VIEWER_CHANNEL_ICON', 'Ikona kanału', NULL),
(186, 1, 'VIEWER_CHANNEL_MODERATED', 'Moderated', NULL),
(187, 3, 'VIEWER_CHANNEL_MODERATED', 'Moderowany', NULL),
(188, 1, 'VIEWER_CHANNEL_MUSIC_CODED', 'Music codec', NULL),
(189, 3, 'VIEWER_CHANNEL_MUSIC_CODED', 'Kodek muzyczny', NULL),
(190, 1, 'VIEWER_CLIENT_AWAY', 'Away', NULL),
(191, 3, 'VIEWER_CLIENT_AWAY', 'Zaraz wracam', NULL),
(194, 1, 'VIEWER_CLIENT_OUTPUT_DISABLED', 'Sound disabled', NULL),
(195, 3, 'VIEWER_CLIENT_OUTPUT_DISABLED', 'Głos wyłączony', NULL),
(196, 1, 'VIEWER_CLIENT_OUTPUT_MUTED', 'Deafened', NULL),
(197, 3, 'VIEWER_CLIENT_OUTPUT_MUTED', 'Głos wyciszony', NULL),
(198, 1, 'VIEWER_CLIENT_MIC_DISABLED', 'Microphone disabled', NULL),
(199, 3, 'VIEWER_CLIENT_MIC_DISABLED', 'Mikrofon wyłączony', NULL),
(200, 1, 'VIEWER_CLIENT_MIC_MUTED', 'Muted', NULL),
(201, 3, 'VIEWER_CLIENT_MIC_MUTED', 'Mikrofon wyciszony', NULL),
(202, 1, 'VIEWER_CLIENT_COMMANDER', 'Channel commander', NULL),
(203, 3, 'VIEWER_CLIENT_COMMANDER', 'Dowódca kanału', NULL),
(204, 1, 'VIEWER_CLIENT_ICON', 'Client icon', NULL),
(205, 3, 'VIEWER_CLIENT_ICON', 'Ikona klienta', NULL),
(206, 1, 'VIEWER_CLIENT_PRIORITY_SPEAKER', 'Priority speaker', NULL),
(207, 3, 'VIEWER_CLIENT_PRIORITY_SPEAKER', 'Mówca priorytetowy', NULL),
(208, 1, 'VIEWER_CLIENT_TALK_POWER_GRANTED', 'Talk power granted', NULL),
(209, 3, 'VIEWER_CLIENT_TALK_POWER_GRANTED', 'Moc konwersacji przyznana', NULL),
(210, 1, 'VIEWER_CLIENT_TALK_POWER_INSUFFICIENT', 'Insufficient talk power', NULL),
(211, 3, 'VIEWER_CLIENT_TALK_POWER_INSUFFICIENT', 'Niewystarczająca moc konwersacji', NULL),
(212, 1, 'ASSIGNER_NOT_LOGGED_IN', 'Log in before using group assigner', NULL),
(213, 3, 'ASSIGNER_NOT_LOGGED_IN', 'Zaloguj się przed przydzielaniem grup', NULL),
(214, 1, 'ASSIGNER_LOGIN_BUTTON', 'Login', NULL),
(215, 3, 'ASSIGNER_LOGIN_BUTTON', 'Zaloguj się', NULL),
(216, 1, 'ASSIGNER_SAVE_BUTTON', 'Save', NULL),
(217, 3, 'ASSIGNER_SAVE_BUTTON', 'Zapisz', NULL),
(218, 1, 'ASSIGNER_INVALID_GROUPS', 'Invalid group settings', NULL),
(219, 3, 'ASSIGNER_INVALID_GROUPS', 'Nieprawidłowe ustawienia grup', NULL),
(220, 1, 'ASSIGNER_NOT_CONFIGURED', 'Group assigner is not configured by the website administrator', NULL),
(221, 3, 'ASSIGNER_NOT_CONFIGURED', 'Przydzielanie grup nie jest skonfigurowane przez administratora strony', NULL),
(222, 1, 'ASSIGNER_SAVE_SUCCESS', 'Your groups have been updated', NULL),
(223, 3, 'ASSIGNER_SAVE_SUCCESS', 'Twoje grupy zostały zaktualizowane', NULL),
(224, 1, 'ASSIGNER_SAVE_ERROR', 'Group change error', NULL),
(225, 3, 'ASSIGNER_SAVE_ERROR', 'Błąd zmiany grup', NULL),
(226, 1, 'ASSIGNER_SAVE_NO_CHANGE', 'No changes has been made', NULL),
(227, 3, 'ASSIGNER_SAVE_NO_CHANGE', 'Nie wprowadzono żadnych zmian', NULL);
(1, 'Welcome to ts-website!', 1, '2018-12-26 03:10:32', NULL, '<b>Hi there!</b> If you are reading this, it means that TS-website has been installed successfully.<br>\r\nYou can login to your <a href=\"admin\">ACP</a> to configure many parts of it.<br>\r\nNeed help? Join our <a href=\"https://t.me/tswebsite\" target=\"_blank\">Telegram group</a> for support.\r\nHave a good day!');
ALTER TABLE `DBPREFIXconfig`
@ -316,25 +71,13 @@ ALTER TABLE `DBPREFIXconfig`
ALTER TABLE `DBPREFIXfaq`
ADD PRIMARY KEY (`faqid`);
ALTER TABLE `DBPREFIXlanguages`
ADD PRIMARY KEY (`langid`);
ALTER TABLE `DBPREFIXnews`
ADD PRIMARY KEY (`newsid`);
ALTER TABLE `DBPREFIXtranslations`
ADD PRIMARY KEY (`id`);
ALTER TABLE `DBPREFIXfaq`
MODIFY `faqid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
ALTER TABLE `DBPREFIXlanguages`
MODIFY `langid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
ALTER TABLE `DBPREFIXnews`
MODIFY `newsid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
ALTER TABLE `DBPREFIXtranslations`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=228;
COMMIT;

File diff suppressed because it is too large Load Diff

@ -9,8 +9,8 @@ if (!file_exists(__PRIVATE_DIR . "/vendor/autoload.php")) {
die(
'<h2>Oops! We cannot find Composer\'s autoload file.</h2>' .
'<h3>In 2.0, the installation procedure is a little different. Go to the ' .
'<a href="https://github.com/Wruczek/ts-website/releases" target="_blank">releases</a> on GitHub, ' .
'download the latest version and upload in on your server.</h3>' .
'<a href="https://github.com/Wruczek/ts-website/wiki/%5BEN%5D-Website-Installation" target="_blank">wiki</a> ' .
'and follow the installation tutorial.</h3>' .
'Or, if you know what you are doing, run <code>composer update</code> in the ' .
'<code>' . realpath(__BASE_DIR) . '</code> directory'
);
@ -22,6 +22,10 @@ error_reporting(E_ALL);
set_time_limit(0);
$stepNumber = empty($_GET["step"]) || !file_exists(__DIR__ . "/pages/" . (int)$_GET["step"] . ".php") ? 1 : (int) $_GET["step"];
ob_start();
require __DIR__ . "/pages/$stepNumber.php";
$pageContent = ob_get_clean();
?>
<!DOCTYPE html>
<html>
@ -80,7 +84,7 @@ $stepNumber = empty($_GET["step"]) || !file_exists(__DIR__ . "/pages/" . (int)$_
</ul>
</div>
<?php require_once __DIR__ . "/pages/$stepNumber.php" ?>
<?= $pageContent ?>
</div>
<script>

@ -117,7 +117,12 @@
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Welcome to TS-website <?= __TSWEBSITE_VERSION ?> Installer!</h4>
<h4 class="card-title text-center mb-0">Welcome to TS-website Installer!</h4>
<p class="card-text text-center text-muted font-italic mb-5">
Version <?= __TSWEBSITE_VERSION ?> (<?= __TSWEBSITE_COMMIT ?>)
</p>
<p class="card-text">This wizard will guide you through the installation process of TS-website.</p>
<p class="card-text text-danger" id="hidejs">Please enable Javascript before continuing!</p>
<p class="card-text">

@ -11,6 +11,11 @@ if(!empty($_POST["allow-metrics-checkbox"])) {
<div class="card-body">
<h4 class="card-title text-center">Requirements check</h4>
<div class="alert alert-dark text-center mb-3" id="filePermError" style="display: none">
Looks like you have failed file permission checks. Try running:<br>
<code>sudo chown -R www-data:www-data "<?= realpath(__BASE_DIR) ?>"</code>
</div>
<div class="text-center mb-2">
<button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#requirementsTableCollapse">
Show details
@ -38,6 +43,11 @@ if(!empty($_POST["allow-metrics-checkbox"])) {
<script>
// Show requirements table on error
$("#requirementsTableCollapse").collapse("show")
<?php if(defined("FILE_PERM_ERROR")) { ?>
// Show file permission fix tip
$("#filePermError").show()
<?php } ?>
</script>
<?php } else { ?>
<div class="text-center">
@ -131,13 +141,13 @@ function checkRequirements() {
// file / directory writable checks
{
// path => true if file, false if directory
$paths = [
$paths = array(
__CONFIG_FILE => true,
__INSTALLER_LOCK_FILE => true,
__CACHE_DIR => false,
__CACHE_DIR . "/templates" => false,
__CACHE_DIR . "/servericons" => false,
];
);
foreach ($paths as $path => $isFile) {
$exists = file_exists($path);
@ -161,7 +171,13 @@ function checkRequirements() {
if(!$exists)
$msg = ($isFile ? "File" : "Directory") . " <code>$realpath</code> does not exists, please create it";
showCheckResult("Is <code>$basename</code> writable?", $exists && $writable ? 0 : 2, $msg);
$success = $exists && $writable;
if (!$success && !defined("FILE_PERM_ERROR")) {
define("FILE_PERM_ERROR", true);
}
showCheckResult("Is <code>$basename</code> writable?", $success ? 0 : 2, $msg);
}
}
@ -232,8 +248,9 @@ function showCheckResult($name, $state, $resulttext) {
} else {
$attr = "fa-times-circle color-danger";
if(!defined("CANNOT_INSTALL"))
if(!defined("CANNOT_INSTALL")) {
define("CANNOT_INSTALL", true);
}
}
?>

@ -44,24 +44,39 @@ if (!empty($_POST)) {
if (isset($dbconfig)) {
try {
$db = new Medoo($dbconfig);
$sqlfile = $usingMysql ? "dbinstall_mysql" : "dbinstall_sqlite";
$sqlquery = file_get_contents(__DIR__ . "/../$sqlfile.sql");
if($sqlquery === false) {
$errormessage = "Cannot read $sqlfile.sql file!";
$sqlfiles = [];
if ($usingMysql) {
$sqlfiles = [
"dbinstall_mysql",
"dbinstall_mysql_lang"
];
} else {
// no other option yet
}
foreach ($sqlfiles as $file) {
$sqlquery = file_get_contents(__DIR__ . "/../$file.sql");
if($sqlquery === false) {
throw new Exception("Cannot read SQL file: $file.sql");
}
$sqlquery = str_replace("DBPREFIX", $dbprefix, $sqlquery);
$sqlresult = $db->pdo->exec($sqlquery);
if($sqlresult === false) {
if ($sqlresult === false) {
throw new Exception("EXEC returned false");
}
}
$phpcode = <<<EOT
// if all queries succeeded, create a config file and save connection info there
$phpcode = <<<EOT
<?php
/*
* TS-website database config file
* Generated at %s with TS-website %s
* Generated at %s with TS-website %s (%s)
*/
return [
@ -69,24 +84,24 @@ return [
];
EOT;
$confarray = "";
$confarray = "";
// Add all variables to the config
foreach ($dbconfig as $key => $value) {
$confarray .= sprintf(' "%s" => "%s",' . PHP_EOL, addcslashes($key, '"'), addcslashes($value, '"'));
}
// Add all variables to the config
foreach ($dbconfig as $key => $value) {
$confarray .= sprintf(" '%s' => '%s'," . PHP_EOL, addcslashes($key, '"'), addcslashes($value, '"'));
}
// Remove semicolon and new line from the end
$confarray = rtrim($confarray, "," . PHP_EOL);
// Remove semicolon and new line from the end
$confarray = rtrim($confarray, "," . PHP_EOL);
// Replace all variables with sprintf
$phpcode = sprintf($phpcode, date("d-m-Y H:i:s"), __TSWEBSITE_VERSION, $confarray);
// Replace all variables with sprintf
$phpcode = sprintf($phpcode, date("d-m-Y H:i:s"), __TSWEBSITE_VERSION, __TSWEBSITE_COMMIT, $confarray);
if(file_put_contents(__CONFIG_FILE, $phpcode) === false) {
$errormessage = "Cannot write to <code>" . __CONFIG_FILE . "</code>! Please check the file/directory permissions";
} else {
header("Location: ?step=" . ($stepNumber + 1));
}
if(file_put_contents(__CONFIG_FILE, $phpcode) === false) {
$errormessage = "Cannot write to <code>" . __CONFIG_FILE . "</code>! Please check the file/directory permissions";
} else {
// redirect to next step on success
header("Location: ?step=" . ($stepNumber + 1));
}
} catch (Exception $e) {
$errormessage = htmlspecialchars("Error " . $e->getCode() . ": " . $e->getMessage());

@ -13,6 +13,7 @@ if(!empty($_COOKIE["tsw_allow_metrics"])) {
$data = [
"tswVersion" => __TSWEBSITE_VERSION,
"tswCommit" => __TSWEBSITE_COMMIT,
"phpVersion" => PHP_VERSION,
"os" => sprintf("%s %s %s %s", php_uname("s"), php_uname("r"), php_uname("v"), php_uname("m")), // no hostname
"webServer" => $_SERVER["SERVER_SOFTWARE"],

@ -5,12 +5,13 @@ namespace Wruczek\TSWebsite\Utils;
use Wruczek\TSWebsite\Utils\Language\LanguageUtils;
class DateUtils {
/**
* Returns current date format based on current user language. If it cannot
* be retrieved, default value is returned
* @return string date format
*/
public function getDateFormat() {
public static function getDateFormat() {
try {
return LanguageUtils::i()->translate("DATE_FORMAT");
} catch (\Exception $e) {
@ -23,7 +24,7 @@ class DateUtils {
* be retrieved, default value is returned
* @return string time format
*/
public function getTimeFormat() {
public static function getTimeFormat() {
try {
return LanguageUtils::i()->translate("TIME_FORMAT");
} catch (\Exception $e) {
@ -36,8 +37,8 @@ class DateUtils {
* @param $timestamp
* @return false|string
*/
public function formatToDate($timestamp) {
return date($this->getDateFormat(), $timestamp);
public static function formatDate($timestamp) {
return date(self::getDateFormat(), $timestamp);
}
/**
@ -45,8 +46,8 @@ class DateUtils {
* @param $timestamp
* @return false|string
*/
public function formatToTime($timestamp) {
return date($this->getTimeFormat(), $timestamp);
public static function foramtTime($timestamp) {
return date(self::getTimeFormat(), $timestamp);
}
/**
@ -55,63 +56,8 @@ class DateUtils {
* @param string $additional additional date format
* @return false|string
*/
public function formatToDateTime($timestamp, $additional = "") {
return date("{$this->getDateFormat()} {$this->getTimeFormat()} $additional", $timestamp);
public static function formatDatetime($timestamp, $additional = "") {
return date(trim(self::getDateFormat() . ", " . self::getTimeFormat() . " " . $additional), $timestamp);
}
/**
* Formats timestamp into "time ago" string
* For example, timestamp set to 60 seconds ago will return "1 minute ago"
*
* Taken from StackOverflow: https://stackoverflow.com/a/18602474
* @param $timestamp int timestamp with past date
* @param bool $full if true, full date will be returned. For example "5 hours, 2 minutes, 8 seconds"
* @return string timestamp formatted to fuzzy date. Marf.
*/
public function fuzzyDate($timestamp, $full = false) {
$now = new \DateTime;
$ago = (new \DateTime)->setTimestamp($timestamp);
$diff = $now->diff($ago);
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
$string = [
'y' => 'year',
'm' => 'month',
'w' => 'week',
'd' => 'day',
'h' => 'hour',
'i' => 'minute',
's' => 'second'
];
foreach ($string as $k => &$v) {
if ($diff->$k) {
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
} else {
unset($string[$k]);
}
}
if (!$full) $string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
/**
* Returns fuzzy date with abbreviation showing precise date
* @see fuzzyDate
* @param $timestamp
* @param bool $full
* @return string
*/
public function fuzzyDateHTML($timestamp, $full = false) {
$fuzzyDate = $this->fuzzyDate($timestamp, $full);
$fullDate = $this->formatToDateTime($timestamp, "T");
return '<abbr data-fuzzydate="' . $timestamp . '"></abbr>';
// return '<abbr data-toggle="tooltip" title="' . htmlentities($fullDate) . '">' . htmlentities($fuzzyDate) . '</abbr>';
}
}

@ -2,8 +2,8 @@
namespace Wruczek\TSWebsite\Utils\Language;
use function htmlspecialchars;
use Wruczek\PhpFileCache\PhpFileCache;
use Wruczek\TSWebsite\Config;
use Wruczek\TSWebsite\Utils\DatabaseUtils;
use Wruczek\TSWebsite\Utils\SingletonTait;
@ -148,10 +148,18 @@ class LanguageUtils {
$langs[] = new Language($langid, $englishname, $nativename, $langcode, $isdefault, $languageItems);
}
uasort($langs, function ($a, $b) {
if ($a->getLanguageId() === $b->getLanguageId()) {
return 0;
}
return strnatcmp($a->getLanguageNameNative(), $b->getLanguageNameNative());
});
$this->languages = $langs;
if($updateCache)
$this->cache->store("languages", $langs, 300);
$this->cache->store("languages", $langs, Config::get("cache_languages", 300));
return $langs;
}

@ -27,11 +27,13 @@ class TemplateUtils {
// Add custom filters...
$this->getLatte()->addFilter("fuzzyDateAbbr", function ($s) {
return new Html('<span data-relativetime="fuzzydate" data-timestamp="' . $s . '">{cannot convert ' . $s . '}</span>');
$default = DateUtils::formatDatetime($s);
return new Html('<span data-relativetime="fuzzydate" data-timestamp="' . $s . '">' . $default . '</span>');
});
$this->getLatte()->addFilter("fullDate", function ($s) {
return new Html('<span data-relativetime="fulldate" data-timestamp="' . $s . '">{cannot convert ' . $s . '}</span>');
$default = DateUtils::formatDatetime($s);
return new Html('<span data-relativetime="fulldate" data-timestamp="' . $s . '">' . $default . '</span>');
});
$this->getLatte()->addFilter("translate", function ($s, ...$args) {
@ -165,13 +167,13 @@ class TemplateUtils {
}
} else if (is_string($parameter)) {
// NEEDS to start with a space!
$attributes = ' integrity="' . htmlspecialchars($parameter) . '" crossorigin="anonymous"';
$attributes = ' integrity="' . Utils::escape($parameter) . '" crossorigin="anonymous"';
}
if ($resourceType === "stylesheet") {
echo '<link rel="stylesheet" href="' . htmlspecialchars($url) . '"' . $attributes . '>';
echo '<link rel="stylesheet" href="' . Utils::escape($url) . '"' . $attributes . '>';
} else if ($resourceType === "script") {
echo '<script src="' . htmlspecialchars($url) . '"' . $attributes . '></script>';
echo '<script src="' . Utils::escape($url) . '"' . $attributes . '></script>';
} else {
throw new \InvalidArgumentException("$resourceType is not a valid resource type");
}

@ -9,12 +9,21 @@ use Wruczek\TSWebsite\News\INewsStore;
/**
* Class Utils
* @package Wruczek\TSWebsite\Utils
* @author Wruczek 2017
* @author Wruczek 2017 - 2019
*/
class Utils {
private function __construct() {}
/**
* Escapes HTML characters with htmlspecialchars
* @param $string string String to be escaped
* @return string escaped string
*/
public static function escape($string) {
return htmlspecialchars((string) $string, ENT_QUOTES, "UTF-8");
}
/**
* Strips the first line from string
* https://stackoverflow.com/a/7740485
@ -100,7 +109,7 @@ class Utils {
*/
public static function getClientIp($useCfip = null) {
if ($useCfip === null) {
$useCfip = (bool) Config::get("usingcloudflare");
$useCfip = Config::get("usingcloudflare");
}
// If IPv6 localhost, return IPv4 localhost
@ -108,7 +117,7 @@ class Utils {
return "127.0.0.1";
}
if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"]) && $useCfip) {
if ($useCfip && !empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
return $_SERVER["HTTP_CF_CONNECTING_IP"];
}

@ -4,6 +4,7 @@ namespace Wruczek\TSWebsite;
use function __get;
use TeamSpeak3;
use Wruczek\TSWebsite\Utils\Utils;
class ViewerRenderer {
@ -77,7 +78,7 @@ EOD;
$this->add(
$html,
$this->getIcon("server_green.svg"),
htmlspecialchars($this->serverInfo["virtualserver_name"]),
Utils::escape($this->serverInfo["virtualserver_name"]),
$suffixIcons
);
@ -99,8 +100,8 @@ EOD;
$path = "api/geticon.php?iconid=" . (int) $name;
}
$ttip = $tooltip ? ' data-toggle="tooltip" title="' . htmlspecialchars($tooltip) . '"' : "";
return '<img class="icon" src="' . $path . '" alt="' . htmlspecialchars($alt) . '"' . $ttip . '>';
$ttip = $tooltip ? ' data-toggle="tooltip" title="' . Utils::escape($tooltip) . '"' : "";
return '<img class="icon" src="' . $path . '" alt="' . Utils::escape($alt) . '"' . $ttip . '>';
}
/**
@ -162,7 +163,7 @@ EOD;
$channel->getId(),
$channel->isSpacer() ? "" : ' tabindex="0"',
$channelIcon,
htmlspecialchars($channelDisplayName),
Utils::escape($channelDisplayName),
$suffixIcons
);
@ -222,7 +223,7 @@ EOD;
$clientName = implode(" ", $beforeName); // prefix groups
$clientName .= " {$client["client_nickname"]} "; // nickname
$clientName .= implode(" ", $afterName); // suffix groups
$clientName = htmlspecialchars(trim($clientName)); // trim and sanitize
$clientName = Utils::escape(trim($clientName)); // trim and sanitize
$this->add(
$html,
@ -286,7 +287,7 @@ EOD;
}
if($client["client_away"]) {
return $this->getIcon("away.svg", htmlspecialchars($client["client_away_message"]) ?: __get("VIEWER_CLIENT_AWAY"));
return $this->getIcon("away.svg", Utils::escape($client["client_away_message"]) ?: __get("VIEWER_CLIENT_AWAY"));
}
if(!$client["client_output_hardware"]) {
@ -340,7 +341,7 @@ EOD;
// to show the group with a "broken-image" icons.
}
$html .= $this->getIcon($icon, htmlspecialchars($group["name"]));
$html .= $this->getIcon($icon, Utils::escape($group["name"]));
}
if($client["client_icon_id"]) {

@ -1,5 +1,6 @@
<?php
define("__TSWEBSITE_VERSION", "dev-2.0.0");
define("__TSWEBSITE_VERSION", "dev-2.0.1");
define("__TSWEBSITE_COMMIT", "no-commit");
define("__BASE_DIR", __DIR__ . "/../..");
define("__PRIVATE_DIR", __BASE_DIR . "/private");
define("__CACHE_DIR", __PRIVATE_DIR . "/cache");

@ -4,6 +4,7 @@ use Wruczek\TSWebsite\Config;
use Wruczek\TSWebsite\ServerIconCache;
use Wruczek\TSWebsite\Utils\CsrfUtils;
use Wruczek\TSWebsite\Utils\Language\LanguageUtils;
use Wruczek\TSWebsite\Utils\Utils;
session_name("tswebsite_sessionid");
@ -71,7 +72,7 @@ if(!isset($_SESSION["userlanguageid"])) {
try {
return LanguageUtils::i()->translate($identifier, $args);
} catch (\Exception $e) {
return "(unknown translation for " . htmlspecialchars($identifier) . ")";
return "(unknown translation for " . Utils::escape($identifier) . ")";
}
}
}

@ -35,10 +35,10 @@
</div>
{/if}
<table id="banlist" class="table table-responsive">
<table id="banlist" class="table display dt-responsive no-wrap" width="100%">
<thead>
<tr>
<th data-priority="1">{_"BANS_HEADER_NAME"}</th>
<th data-priority="1">{_"BANS_HEADER_TARGET"}</th>
<th data-priority="3">{_"BANS_HEADER_REASON"}</th>
<th>{_"BANS_HEADER_INVOKER"}</th>
<th>{_"BANS_HEADER_BANDATE"}</th>
@ -49,8 +49,14 @@
{foreach $banlist as $ban}
{var $expiretime = $ban["created"] + $ban["duration"]}
<tr>
<td>{$ban["name"]}</td>
<td>{$ban["reason"]}</td>
<td data-filter="{$ban["filter"]}">{$ban["target"]}</td>
<td>
{if $ban["reason"]}
{$ban["reason"]}
{else}
{_"NO_REASON_SET"|noescape}
{/if}
</td>
<td>{$ban["invoker"]}</td>
<td data-order="{$ban["created"]}">{$ban["created"]|fullDate}</td>
<td data-order="{$ban["duration"]}">{$ban["duration"] ? ($expiretime|fuzzyDateAbbr) : ("BANS_NEVEREXPIRES"|translate)}</td>

@ -12,6 +12,7 @@ $navActiveIndex = isset($navActiveIndex) ? (int) $navActiveIndex : 0;
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="TS-website {\__TSWEBSITE_VERSION} by Wruczek / https://github.com/Wruczek/ts-website">
<meta name="csrf-token" content="{$csrfToken}">
<link rel="shortcut icon" href="img/icons/defaulticon-16.png">
<!-- TODO make it use the language variable "WEBSITE_TITLE" after the ACP update -->
<title>{$title} | {$config["website_title"]}</title>
@ -210,7 +211,7 @@ $navActiveIndex = isset($navActiveIndex) ? (int) $navActiveIndex : 0;
{block footerbottom}{/block}
<!--
TS-website {\__TSWEBSITE_VERSION} by Wruczek
TS-website {\__TSWEBSITE_VERSION} ({\__TSWEBSITE_COMMIT}) by Wruczek
Generated in {@$tplutils::getRenderTime()} s
MySQL queries: {$sqlCount}
-->

Loading…
Cancel
Save