First release of 2.0! :D

This commit is contained in:
Wruczek
2018-12-27 18:59:49 +01:00
parent 7396a76816
commit 628af52b54
293 changed files with 12641 additions and 3 deletions

0
src/installer/cache/.gitkeep vendored Normal file
View File

View File

@@ -0,0 +1,340 @@
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
DROP TABLE IF EXISTS `tsw_config`;
CREATE TABLE `tsw_config` (
`identifier` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`type` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'STRING' COMMENT 'STRING, INT, FLOAT, BOOL, JSON',
`value` text COLLATE utf8mb4_unicode_ci,
`user_editable` tinyint(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `tsw_config` (`identifier`, `type`, `value`, `user_editable`) VALUES
('cache_servericons', 'INT', '600', 1),
('onlinerecord_value', 'INT', '0', 0),
('onlinerecord_date', 'INT', '0', 0),
('usingcloudflare', 'BOOL', 'false', 1),
('loginpokeclient', 'BOOL', 'true', 1),
('cache_logincode', 'INT', '120', 1),
('cache_adminstatus', 'INT', '60', 1),
('adminstatus_groups', 'JSON', '[]', 1),
('adminstatus_mode', 'INT', '2', 1),
('adminstatus_enabled', 'BOOL', 'true', 1),
('adminstatus_hideoffline', 'BOOL', 'false', 1),
('adminstatus_ignoredusers', 'JSON', '[]', 1),
('assignerconfig', 'JSON', '[]', 1),
('query_nickname', 'STRING', 'TS-website', 1),
('cache_serverinfo', 'INT', '10', 1),
('cache_banlist', 'INT', '60', 1),
('cache_clientlist', 'INT', '15', 1),
('cache_channelist', 'INT', '60', 1),
('cache_servergroups', 'INT', '60', 1),
('cache_channelgroups', 'INT', '60', 1),
('adminstatus_offlinehiddenbydefault', 'BOOL', 'false', 1),
('imprint_enabled', 'BOOL', 'false', 1),
('imprint_url', 'STRING', 'imprint.php', 1);
DROP TABLE IF EXISTS `tsw_faq`;
CREATE TABLE `tsw_faq` (
`faqid` int(11) NOT NULL,
`langid` int(11) NOT NULL DEFAULT '1',
`question` text COLLATE utf8mb4_unicode_ci NOT NULL,
`answer` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`lastmodify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `tsw_faq` (`faqid`, `langid`, `question`, `answer`, `lastmodify`) VALUES
(1, 1, 'What is the FAQ?', '<b>FAQ</b> section allows you to show frequently asked questions and answers to them.', '2018-12-26 13:10:32'),
(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 `tsw_languages`;
CREATE TABLE `tsw_languages` (
`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 `tsw_languages` (`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 `tsw_news`;
CREATE TABLE `tsw_news` (
`newsid` int(11) NOT NULL,
`title` text COLLATE utf8mb4_unicode_ci NOT NULL,
`langid` int(11) NOT NULL DEFAULT '1',
`added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`edited` timestamp NULL DEFAULT NULL,
`content` longtext COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `tsw_news` (`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 `tsw_translations`;
CREATE TABLE `tsw_translations` (
`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 `tsw_translations` (`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);
ALTER TABLE `tsw_config`
ADD UNIQUE KEY `param` (`identifier`);
ALTER TABLE `tsw_faq`
ADD PRIMARY KEY (`faqid`);
ALTER TABLE `tsw_languages`
ADD PRIMARY KEY (`langid`);
ALTER TABLE `tsw_news`
ADD PRIMARY KEY (`newsid`);
ALTER TABLE `tsw_translations`
ADD PRIMARY KEY (`id`);
ALTER TABLE `tsw_faq`
MODIFY `faqid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
ALTER TABLE `tsw_languages`
MODIFY `langid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
ALTER TABLE `tsw_news`
MODIFY `newsid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
ALTER TABLE `tsw_translations`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=228;
COMMIT;

View File

@@ -0,0 +1 @@
--- ¯\_(ツ)_/¯

93
src/installer/index.php Normal file
View File

@@ -0,0 +1,93 @@
<?php
require_once __DIR__ . "/../private/php/constants.php";
if(file_exists(__INSTALLER_LOCK_FILE) && filesize(__INSTALLER_LOCK_FILE) > 1) {
die('File "private/INSTALLER_LOCK" exists. Please remove it if you wish to run the installer again.');
}
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>' .
'Or, if you know what you are doing, run <code>composer update</code> in the ' .
'<code>' . realpath(__BASE_DIR) . '</code> directory'
);
}
ini_set("display_errors", 1);
ini_set("display_startup_errors", 1);
error_reporting(E_ALL);
set_time_limit(0);
$stepNumber = empty($_GET["step"]) || !file_exists(__DIR__ . "/pages/" . (int)$_GET["step"] . ".php") ? 1 : (int) $_GET["step"];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Step <?= $stepNumber ?> | TS-website 2.0 Installer</title>
<!-- Bootswatch Lumen 4.1.3 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/4.1.3/lumen/bootstrap.min.css"
integrity="sha256-S3sZnj5Uxoan2Z6rfF8V+lCFpdDl06yG+3aem63aLmE=" crossorigin="anonymous">
<!-- Bootstrap nav wizard -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/acornejo/bootstrap-nav-wizard@fd0d42fe0c0826e2c753fb67ce7b50c9e7374d56/bootstrap-nav-wizard.min.css"
integrity="sha384-GKSXH8/4s0+zixsbqq0nRRjTCg0PT0t9vSofdQ15kK57B4AJIYjpHA6QQH2GdSoz"
crossorigin="anonymous">
<!-- FontAwesome (CSS) 5.2.0 -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css"
integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<!-- Custom styles -->
<link rel="stylesheet" href="style.css">
<!-- jQuery 3.3.1 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<!-- Popper UMD 1.13.0 JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.13.0/umd/popper.min.js"
integrity="sha256-pS96pU17yq+gVu4KBQJi38VpSuKN7otMrDQprzf/DWY=" crossorigin="anonymous"></script>
<!-- Bootstrap 4.1.3 JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.min.js"
integrity="sha256-VsEqElsCHSGmnmHXGQzvoWjWwoznFSZc6hs7ARLRacQ=" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<div class="text-center">
<h1 class="m-5">TS-website 2.0 Installer</h1>
</div>
<div class="text-center">
<ul class="nav nav-wizard">
<li<?= $stepNumber == 1 ? ' class="active"' : "" ?>><a href="#">Introduction</a></li>
<li<?= $stepNumber == 2 ? ' class="active"' : "" ?>><a href="#">Requirements check</a></li>
<li<?= $stepNumber == 3 ? ' class="active"' : "" ?>><a href="#">Database details</a></li>
<li<?= $stepNumber == 4 ? ' class="active"' : "" ?>><a href="#">Query details</a></li>
<li<?= $stepNumber == 5 ? ' class="active"' : "" ?>><a href="#">Securing web server</a></li>
<li<?= $stepNumber == 6 ? ' class="active"' : "" ?>><a href="#">Configure your site</a></li>
<li<?= $stepNumber == 7 ? ' class="active"' : "" ?>><a href="#">Finish</a></li>
</ul>
</div>
<?php require_once __DIR__ . "/pages/$stepNumber.php" ?>
</div>
<script>
$(function () {
$('[data-toggle="tooltip"]').tooltip({"html": true, "placement": "right"})
})
</script>
</body>
</html>

172
src/installer/pages/1.php Normal file
View File

@@ -0,0 +1,172 @@
<?php if (!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed"); ?>
<?php if(file_exists(__CONFIG_FILE)) { ?>
<div class="alert alert-danger text-center" role="alert">
dbconfig.php file found! TS-website might have already been installed.
If you proceed, you will loose data!
</div>
<?php } ?>
<div class="modal" tabindex="-1" role="dialog" id="dev-release-notice">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Welcome to the development version of TS-website 2!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
<b>Development version</b> is great to test and explore TS-website.
Remember, that this version is not finished and only intended for testing.
<b>We strongly advise you to NOT use it in production.</b>
</p>
<p><b>Continue only if you:</b></p>
<ul>
<li class="mb-2">
<b>Want to try out development version of TS-website</b>
</li>
<li class="mb-2">
<b>Understand how websites work</b> and will be able to fix common problems with PHP, your web server and your database
</li>
</ul>
<p><b>Things that you might not like:</b></p>
<ul>
<li class="mb-2">
<b>There is NO admin panel</b><br>
Configure it by modifying files and values in the database
</li>
<li class="mb-2">
<b>You break it, you fix it</b><br>
If something breaks, you need to read the error messages and fix the problem yourself.
</li>
<li>
<b>You might find bugs and problems</b><br>
If you do, please
<a href="https://github.com/Wruczek/ts-website/issues" target="_blank">create an issue</a>
on GitHub
</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">I understand</button>
</div>
</div>
</div>
</div>
<div class="modal" tabindex="-1" role="dialog" id="metrics-info">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Metrics send by TS-website</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
You might allow TS-website to send one-time metrics during the installation process.
The data send contains only publicly known information, no private info is send.
The collected data will be used only to learn more about our users and improve TS-website.
We will never sell or share it to 3rd-parties. We might, however, publish some statistics
collected via the metrics. The published data will always be fully anonymous.
</p>
<p>
The data send will be indexed with the sending server's IP address, to prevent abuse.
</p>
<p>
You can check all of the data send yourself by looking at the source code:
<code>installer/pages/2.php</code>
</p>
<p><b>Data send by TS-website:</b></p>
<ul>
<li class="mb-1">
Version of TS-website and PHP
</li>
<li class="mb-1">
List of loaded PHP extensions names
</li>
<li class="mb-1">
Server identification string (contains mainly web server name and version)
</li>
<li class="mb-1">
Basic OS info (type, version, architecture, hostname)
</li>
<li class="mb-1">
TeamSpeak server info (version, build number, host OS name, slot count,
are you using serveradmin for query, server's unique ID)
</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Welcome to TS-website <?= __TSWEBSITE_VERSION ?> Installer!</h4>
<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">
If you encounter any problems please make sure you check the
<a href="https://github.com/Wruczek/ts-website/wiki" target="_blank">wiki</a>.
</p>
<p class="card-text">Go to the next step whenever you are ready!</p>
<form method="post" action="?step=<?= $stepNumber + 1 ?>">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="allow-metrics-checkbox" name="allow-metrics-checkbox" checked>
<label class="custom-control-label" for="allow-metrics-checkbox">
Send one-time statistics to help improve TS-website
<a href="#" data-toggle="modal" data-target="#metrics-info">(learn more)</a>
</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="accept-license-checkbox" name="accept-license-checkbox" required>
<label class="custom-control-label" for="accept-license-checkbox">
I read and accept the <a href="https://github.com/Wruczek/ts-website/blob/2.0/LICENSE.txt" target="_blank">license</a>
</label>
</div>
<button id="submitform" type="submit" style="display: none"></button>
</form>
</div>
<div class="card-footer">
<a id="nextbutton" href="#" class="btn btn-primary float-right disabled" style="display: none">
Start <i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
<script>
$("#dev-release-notice").modal("show")
$("#hidejs").css("display", "none");
$("#nextbutton").css("display", "inline-block");
$("#nextbutton").click(function () {
$("#submitform").click();
});
$("#accept-license-checkbox").change(function () {
if (this.checked) {
$("#nextbutton").removeClass("disabled");
} else {
$("#nextbutton").addClass("disabled");
}
});
</script>

264
src/installer/pages/2.php Normal file
View File

@@ -0,0 +1,264 @@
<?php
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
if(!empty($_POST["allow-metrics-checkbox"])) {
setcookie("tsw_allow_metrics", "true", PHP_INT_MAX);
}
?>
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Requirements check</h4>
<div class="text-center mb-2">
<button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#requirementsTableCollapse">
Show details
</button>
</div>
<div class="collapse" id="requirementsTableCollapse">
<div class="text-center">
<table class="table table-responsive requirements-check-table">
<tbody>
<?php checkRequirements(); ?>
</tbody>
</table>
</div>
</div>
<?php if(defined("CANNOT_INSTALL")) { ?>
<div class="col-md-10 offset-md-1">
<div class="alert alert-danger">
<strong>Oh snap!</strong> Looks like your current web server configuration does not allow to run TS-website 2.0.
Please fix the above problems and try again.<br>If you have any problems, please check
<a href="https://github.com/Wruczek/ts-website/wiki" target="_blank">wiki</a> and follow the installation guide.
</div>
</div>
<script>
// Show requirements table on error
$("#requirementsTableCollapse").collapse("show")
</script>
<?php } else { ?>
<div class="text-center">
<div class="alert alert-success" style="display: inline-block">
<strong>Success!</strong> Looks like you can run TS-website 2.0!
</div>
</div>
<?php } ?>
</div>
<div class="card-footer text-right">
<a href="?step=<?= $stepNumber - 1 ?>" class="btn btn-primary float-left">
<i class="fas fa-chevron-left"></i> Back
</a>
<?php if(defined("CANNOT_INSTALL")) { ?>
<a href="#" onclick="location.reload(); this.className += ' disabled'; return false" class="btn btn-warning float-right">
Re-check <i class="fas fa-sync"></i>
</a>
<?php } else { ?>
<a href="?step=<?= $stepNumber + 1 ?>" class="btn btn-primary float-right">
Next <i class="fas fa-chevron-right"></i>
</a>
<?php } ?>
</div>
</div>
<?php
function checkRequirements() {
if (!defined("PHP_VERSION_ID")) {
$version = explode(".", PHP_VERSION);
define("PHP_VERSION_ID", $version[0] * 10000 + $version[1] * 100 + $version[2]);
}
// PHP version - 5.6.0 minimum, < 7 warning, > 7 ok
{
$result = PHP_VERSION_ID < 50600 ? 2 : (PHP_VERSION_ID < 70000 ? 1 : 0);
showCheckResult(
"PHP 5.6.0+ (7.0+ recommended)",
$result,
"Current PHP version: " . phpversion()
);
}
// Check if we are using polyfill for utf8_encode
{
$result = defined("__USING_U8ENC_POLYFILL");
showCheckResult(
"Function <code>utf8_encode</code> exists",
$result ? 1 : 0,
$result ?
"Function not found, using polyfill" :
"Function exists"
);
}
// password_hash and password_verify
{
$result = PHP_VERSION_ID >= 50500 && password_verify(
"ayy-lmao-m88", password_hash("ayy-lmao-m88", PASSWORD_DEFAULT)
);
showCheckResult(
"password_hash & password_verify",
$result ? 0 : 2,
$result ?
"Functions exists and work" :
"Please make sure your PHP version supports BCRYPT and BLOWFISH"
);
}
displayCategory("Extension checks");
// Extensions check
{
foreach (["mbstring", "json", "pdo_mysql", "tokenizer", "curl"] as $extension) {
$result = extension_loaded($extension);
showCheckResult(
"<code>$extension</code> extension",
$result ? 0 : 2,
$result ?
"Extension installed and loaded" :
'Please install or enable <code>' . $extension . '</code> extension'
);
}
}
displayCategory("File / directory permission checks");
// file / directory writable checks
{
// path => true if file, false if directory
$paths = [
__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);
// If file / directory doesnt exists try to create it and update the variable
if(!$exists)
$exists = $isFile ? @touch($path) : @mkdir($path);
$writable = is_writable($path);
$basename = basename($path);
// we are using a custom method instead of realpath,
// because it does not work with non-existing files
$realpath = resolveFilename($path);
$msg = "Yes";
if(!$writable)
$msg = "Please make <code>$realpath</code> writable";
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);
}
}
displayCategory("Miscellaneous");
// cache test
{
$result = false;
try {
require_once __PRIVATE_DIR . "/vendor/autoload.php";
$cache = new Wruczek\PhpFileCache\PhpFileCache();
$teststring = "cachetest123";
$cache->store("installertest", $teststring, 3);
$result = $cache->retrieve("installertest") === $teststring;
$cache->clearCache();
} catch (Exception $e) {}
showCheckResult(
"Cache save and read test",
$result ? 0 : 2,
$result ?
"Save and read success" :
"Something went wrong! Please make sure that <code>private/cache</code> directory is writable"
);
}
// template test
{
if($result) {
if(extension_loaded("mbstring")) {
$result = false;
try {
$latte = new Latte\Engine();
$latte->setTempDirectory(__CACHE_DIR);
$latte->setLoader(new Latte\Loaders\StringLoader());
$render = @$latte->renderToString('Hello, {$test|upper}!', array("test" => "Wruczek"));
$result = $render === "Hello, WRUCZEK!";
} catch (Exception $e) {}
showCheckResult(
"Template render and cache test",
$result ? 0 : 2,
$result ?
"Render and cache success" :
"Something went wrong! Please make sure that <code>private/cache</code> directory is writable"
);
} else {
showCheckResult("Template render and cache test", 2, "<code>mbstring</code> extension not found, cannot start the test");
}
} else {
showCheckResult("Template render and cache test", 2, "<code>private/cache</code> directory is not writable, cannot start the test");
}
}
}
// Utils
function showCheckResult($name, $state, $resulttext) {
if($state === 0) {
$attr = "fa-check-circle color-success";
} else if($state === 1) {
$attr = "fa-minus-circle color-warning";
} else {
$attr = "fa-times-circle color-danger";
if(!defined("CANNOT_INSTALL"))
define("CANNOT_INSTALL", true);
}
?>
<tr>
<td class="text-right"><?= $name ?></td>
<td><i class="fas <?= $attr ?> fa-lg"></i></td>
<td><?= $resulttext ?></td>
</tr>
<?php }
function displayCategory($name) {
echo '<tr><td colspan="3" class="text-center lead">' . $name . '</td></tr>';
}
// https://tomnomnom.com/posts/realish-paths-without-realpath
function resolveFilename($filename) {
$filename = str_replace('//', '/', $filename);
$parts = explode('/', $filename);
$out = array();
foreach ($parts as $part){
if ($part === '.') continue;
if ($part === '..') {
array_pop($out);
continue;
}
$out[] = $part;
}
return implode('/', $out);
}

213
src/installer/pages/3.php Normal file
View File

@@ -0,0 +1,213 @@
<?php
use Medoo\Medoo;
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
if (!empty($_POST)) {
$dbhostname = trim($_POST["dbhostname"]);
$dbusername = trim($_POST["dbusername"]);
$dbpassword = trim($_POST["dbpassword"]);
$dbname = trim($_POST["dbname"]);
$dbprefix = trim($_POST["dbprefix"]);
$usingMysql = true;
require_once __PRIVATE_DIR . "/vendor/autoload.php";
if (empty($dbprefix)) {
$dbprefix = "tsw_";
}
if (!empty($dbhostname) && !empty($dbusername) && !empty($dbname)) {
$dbconfig = [
"database_type" => "mysql",
"server" => $dbhostname,
"username" => $dbusername,
"password" => $dbpassword,
"database_name" => $dbname,
"prefix" => $dbprefix,
"port" => 3306,
"charset" => "utf8mb4"
];
} else {
// no sqlite support for now :(
$errormessage = "Please fill in your database details";
// $usingMysql = false;
// $dbconfig = [
// "database_type" => "sqlite",
// "database_file" => __LOCALDB_FILE
// ];
}
// try to connect only if dbconfig is defined
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!";
} else {
$sqlquery = str_replace("DBPREFIX", $dbprefix, $sqlquery);
$sqlresult = $db->query($sqlquery);
if($sqlresult === false || !empty($db->error()[1])) {
throw new Exception($db->error()[2], $db->error()[1]);
}
$phpcode = <<<EOT
<?php
/*
* TS-website database config file
* Generated at %s with TS-website %s
*/
return [
%s
];
EOT;
$confarray = "";
// 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);
// Replace all variables with sprintf
$phpcode = sprintf($phpcode, date("d-m-Y H:i:s"), __TSWEBSITE_VERSION, $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));
}
}
} catch (Exception $e) {
$errormessage = htmlspecialchars("Error " . $e->getCode() . ": " . $e->getMessage());
if($e->getCode() === 1045) {
$errormessage .= '<br>You have entered wrong username and/or password. Please check it and try again.';
}
if($e->getCode() === 1049) {
$errormessage .= '<br>Please manually create database "' . htmlspecialchars($dbname) . '" and try again.';
}
}
}
}
?>
<?php if(!empty($errormessage)) { ?>
<div class="text-center">
<div class="alert alert-danger" style="display: inline-block">
<?= $errormessage ?>
</div>
</div>
<?php } ?>
<div class="card">
<div class="card-body">
<h3 class="card-title text-center">Database details</h3>
<div class="text-center mb-3">
<div class="custom-control custom-radio">
<input type="radio" id="use-mysql-db" name="dbselection" class="custom-control-input" checked>
<label class="custom-control-label" for="use-mysql-db">Use MySQL / MariaDB</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="use-sqlite-db" name="dbselection" class="custom-control-input" disabled>
<label class="custom-control-label" for="use-sqlite-db">Use SQLite database</label>
</div>
</div>
<div class="row justify-content-md-center">
<form id="dbform" class="col-md-4" method="post" action="<?= "?step=$stepNumber" ?>"> <!-- style="display: none" novalidate -->
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-link fa-fw"></i></span>
</div>
<input class="form-control" name="dbhostname" placeholder="Hostname" required autofocus autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip" title="Use '127.0.0.1' for localhost">
<i class="fa fa-question-circle fa-fw"></i>
</span>
</div>
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-user fa-fw"></i></span>
</div>
<input class="form-control" name="dbusername" placeholder="Username" required autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip" title="Its recommended to create seperate user account instead of using root">
<i class="fa fa-exclamation-triangle color-danger fa-fw"></i>
</span>
</div>
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-lock fa-fw"></i></span>
</div>
<input class="form-control" name="dbpassword" placeholder="Password" autocomplete="off">
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-database fa-fw"></i></span>
</div>
<input class="form-control" name="dbname" placeholder="Database name" required autocomplete="off">
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-font fa-fw"></i></span>
</div>
<input class="form-control" name="dbprefix" placeholder="Table prefix (optional)" autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip" title="Defaults to 'tsw_'">
<i class="fa fa-question-circle fa-fw"></i>
</span>
</div>
</div>
<button id="submitform" type="submit" style="display: none"></button>
</form>
</div>
</div>
<div class="card-footer text-right">
<a href="?step=<?= $stepNumber - 1 ?>" class="btn btn-primary float-left">
<i class="fas fa-chevron-left"></i> Back
</a>
<a href="#" id="submitformalt" class="btn btn-primary float-right">
Submit <i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
<script>
$("#submitformalt").click(function () {
$("#submitform").click()
});
$("#use-mysql-db").change(function () {
$("#dbform").show()
$("#dbform").removeAttr("novalidate")
});
$("#use-sqlite-db").change(function () {
$("#dbform").hide()
$("#dbform").attr("novalidate", "")
});
</script>

190
src/installer/pages/4.php Normal file
View File

@@ -0,0 +1,190 @@
<?php
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
use Wruczek\TSWebsite\Config;
if (!empty($_POST)) {
$queryhostname = trim($_POST["queryhostname"]);
$queryport = trim($_POST["queryport"]);
$queryserverport = trim($_POST["queryserverport"]);
$queryusername = trim($_POST["queryusername"]);
$querypassword = trim($_POST["querypassword"]);
$querydisplayip = trim($_POST["querydisplayip"]);
if (!empty($queryhostname) && !empty($queryport)
&& !empty($queryserverport) && !empty($queryusername)
&& !empty($querypassword) && !empty($querydisplayip)
) {
require_once __PRIVATE_DIR . "/vendor/autoload.php";
try {
$tsNodeHost = TeamSpeak3::factory("serverquery://$queryhostname:$queryport/");
$tsNodeHost->login($queryusername, $querypassword);
$tsServer = $tsNodeHost->serverGetByPort($queryserverport);
if(is_array($tsServer->getInfo())) {
$utils = Config::i();
$configdata = [
"query_hostname" => $queryhostname,
"query_port" => $queryport,
"tsserver_port" => $queryserverport,
"query_username" => $queryusername,
"query_password" => $querypassword,
"query_displayip" => $querydisplayip,
];
foreach ($configdata as $key => $value) {
if(!$utils->setValue($key, $value)) {
die("Error while inserting query data to database, at " . htmlspecialchars($key) . " => " . htmlspecialchars($value));
}
}
header("Location: ?step=" . ($stepNumber + 1));
} else {
$errormessage .= '<br>Cannot retrieve server information';
}
} catch (Exception $e) {
$errormessage = htmlspecialchars("Error " . $e->getCode() . ": " . $e->getMessage());
if($e->getCode() === 520) {
$errormessage .= '<br>You have entered wrong username and/or password. Please check it and try again.';
}
if($e->getCode() === 2568) {
$errormessage .= '<br>Query account does not have permissions. ' . 'Click <a href="#" data-toggle="modal" ' .
'data-target="#queryperms">here</a> to view required permissions list.';
}
}
}
}
?>
<!-- Modal -->
<div class="modal fade" id="queryperms" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Query permissions required by TS-website</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul>
<?php
if(!empty($GLOBALS["__REQUIRED_QUERY_PERMS"])) {
foreach ($GLOBALS["__REQUIRED_QUERY_PERMS"] as $perm) {
echo "<li><code>" . htmlspecialchars($perm) . "</code></li>";
}
} else {
echo "Error! <code>\$GLOBALS[\"__REQUIRED_QUERY_PERMS\"]</code> is not defined!";
}
?>
</ul>
</div>
</div>
</div>
</div>
<?php if(!empty($errormessage)) { ?>
<div class="text-center">
<div class="alert alert-danger" style="display: inline-block">
<?= $errormessage ?>
</div>
</div>
<?php } ?>
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Query details</h4>
<div class="row justify-content-md-center">
<form id="tsform" class="col-md-4" method="post" action="<?= "?step=$stepNumber" ?>">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-link fa-fw"></i></span>
</div>
<input class="form-control" name="queryhostname" placeholder="Hostname" required autofocus autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip" title="Your TeamSpeak IP address (without port).<br>Use '127.0.0.1' for localhost">
<i class="fa fa-question-circle fa-fw"></i>
</span>
</div>
</div>
<div class="row">
<div class="col input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-signal fa-fw"></i></span>
</div>
<input type="number" class="form-control" name="queryport" placeholder="Query port" required autocomplete="off">
</div>
<div class="col input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-signal fa-fw"></i></span>
</div>
<input type="number" class="form-control" name="queryserverport" placeholder="Server port" required autocomplete="off">
</div>
</div>
<p class="text-muted text-center" style="font-size: 100%">
Default query port: 10011, default server port: 9987.
</p>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-user fa-fw"></i></span>
</div>
<input class="form-control" name="queryusername" placeholder="Query username" required autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip" title="Its recommended to create special user account instead of serveradmin">
<i class="fa fa-exclamation-triangle color-danger fa-fw"></i>
</span>
</div>
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-lock fa-fw"></i></span>
</div>
<input type="password" class="form-control" name="querypassword" placeholder="Query password" required autocomplete="off">
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-font fa-fw"></i></span>
</div>
<input class="form-control" name="querydisplayip" placeholder="Displayed address" required autocomplete="off">
<div class="input-group-append">
<span class="input-group-text" data-toggle="tooltip"
title="Friendly server address displayed to end users.<br>For example 'myserver.com' or 'ts.myclan.net'">
<i class="fa fa-question-circle fa-fw"></i>
</span>
</div>
</div>
<a href="#" data-toggle="modal" data-target="#queryperms" class="text-center">
<p>Query permissions required by TS-website</p>
</a>
<button id="submitform" type="submit" style="display: none"></button>
</form>
</div>
</div>
<div class="card-footer text-right">
<a href="#" id="submitformalt" class="btn btn-primary float-right">
Submit <i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
<script>
$("#submitformalt").click(function () {
$("#submitform").click();
});
</script>

39
src/installer/pages/5.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
?>
<?php if(!empty($errormessage)) { ?>
<div class="text-center">
<div class="alert alert-danger" style="display: inline-block">
<?= $errormessage ?>
</div>
</div>
<?php } ?>
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Secure your web server</h4>
<div class="col-md-10 offset-md-1">
<div class="alert alert-warning text-center">
Securing your web server is very important. Please read
<a href="https://github.com/Wruczek/ts-website/wiki/%5BEN%5D-Securing-private-directory" target="_blank">this</a>
guide on how to properly isolate the "private" directory
</div>
</div>
</div>
<div class="card-footer text-right">
<a href="?step=<?= $stepNumber + 1 ?>" class="btn btn-primary float-right">
Next <i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
<script>
$("#submitformalt").click(function () {
$("#submitform").click();
});
</script>

125
src/installer/pages/6.php Normal file
View File

@@ -0,0 +1,125 @@
<?php
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
use Wruczek\TSWebsite\Config;
require_once __PRIVATE_DIR . "/../private/vendor/autoload.php";
if (!empty($_POST)) {
$baseUrl = @$_POST["base-url"];
$websiteName = @$_POST["website-name"];
$timezone = @$_POST["timezone"];
$usingCloudflare = isset($_POST["using-cloudflare"]);
if (!in_array($timezone, timezone_identifiers_list())) {
$errormessage = "Invalid timezone";
} else {
try {
Config::i()->setValue("baseurl", $baseUrl);
Config::i()->setValue("website_title", $websiteName);
Config::i()->setValue("nav_brand", $websiteName);
Config::i()->setValue("timezone", $timezone);
Config::i()->setValue("usingcloudflare", $usingCloudflare);
header("Location: ?step=" . ($stepNumber + 1));
} catch (\Exception $e) {
$errormessage = "Error saving config: " . htmlspecialchars($e->getMessage());
}
}
}
$defaultTimezone = date_default_timezone_get();
$defaultBase = (@$_SERVER["HTTPS"] === "on" ? "https" : "http") . "://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
$defaultBase = dirname(dirname($defaultBase)); // get the path for the previous directory, not the installer
$displayip = Config::get("query_displayip"); // default website name to the display IP
?>
<?php if(!empty($errormessage)) { ?>
<div class="text-center">
<div class="alert alert-danger" style="display: inline-block">
<?= $errormessage ?>
</div>
</div>
<?php } ?>
<div class="card">
<div class="card-body">
<h4 class="card-title text-center">Configure your site</h4>
<div class="row justify-content-md-center">
<form id="configureform" class="col-md-5" method="post" action="<?= "?step=$stepNumber" ?>">
<div class="alert alert-info mb-4">
<b>Almost done!</b> Here you can adjust some basic settings of ts-website.
Don't worry, you will be able to change them in the admin panel after installation.
</div>
<div class="form-group mb-4">
<label for="base-url">Base URL of ts-website. No trailing slash!</label>
<input class="form-control"
id="base-url"
name="base-url"
placeholder="Base URL of ts-website. No trailing slash!"
value="<?= htmlspecialchars($defaultBase) ?>"
required autofocus autocomplete="off">
</div>
<div class="form-group mb-4">
<label for="website-name">Website name / title</label>
<input class="form-control"
id="website-name"
name="website-name"
placeholder="Website name / title"
value="<?= htmlspecialchars($displayip) ?>"
required autocomplete="off">
</div>
<div class="form-group mb-4">
<label for="timezone">Choose your time zone</label>
<select class="form-control" name="timezone" id="timezone" required>
<!-- Set this as selected if there is no default timezone -->
<option <?= empty($defaultTimezone) ? "selected" : "" ?> disabled value="">
Choose your time zone
</option>
<?php foreach (timezone_identifiers_list() as $timezone) {
$selected = $timezone === $defaultTimezone;
$time = (new DateTime("now", new DateTimeZone($timezone)))->format("H:i (P)");
?>
<option <?= $selected ? "selected" : "" ?> value="<?= $timezone ?>">
<?= "$timezone - $time" ?>
</option>
<?php } ?>
</select>
</div>
<div class="form-group mb-4">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="using-cloudflare" name="using-cloudflare">
<label class="custom-control-label" for="using-cloudflare">
I am using CloudFlare
</label>
</div>
<p><small>This will change the way ts-website detects user IP address</small></p>
</div>
<button id="submitform" type="submit" style="display: none"></button>
</form>
</div>
</div>
<div class="card-footer text-right">
<a href="#" id="submitformalt" class="btn btn-primary float-right">
Submit <i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
<script>
$("#submitformalt").click(function () {
$("#submitform").click();
});
</script>

136
src/installer/pages/7.php Normal file
View File

@@ -0,0 +1,136 @@
<?php
if(!defined("__TSWEBSITE_VERSION")) die("Direct access not allowed");
use Wruczek\TSWebsite\Utils\TeamSpeakUtils;
//if(file_put_contents(__INSTALLER_LOCK_FILE, "WEBSITE_INSTALLED") === false) {
// die("Cannot write to <code>private/INSTALLER_LOCK</code>! Please check the file/directory permissions");
//}
// If we are allowed to collect metrics
if(!empty($_COOKIE["tsw_allow_metrics"])) {
setcookie("tsw_allow_metrics", "false", 1); // remove the cookie
$data = [
"tswVersion" => __TSWEBSITE_VERSION,
"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"],
"loadedExtensions" => get_loaded_extensions()
];
// Os details
{
$lsb = shell_exec('lsb_release -a | grep "Description"');
if (strpos($lsb, "Description:") !== false) {
// Split string by ":", get the 2nd part and trim the string
// "Description: Ubuntu 18.04.1 LTS" --> "Ubuntu 18.04.1 LTS"
$osversion = trim(explode(":", $lsb, 2)[1]);
$data["osDetails"] = $osversion;
}
}
// TS info
{
try {
require_once __DIR__ . "/../../private/vendor/autoload.php";
$tsNode = TeamSpeakUtils::i()->getTSNodeHost();
$tsAdmin = TeamSpeakUtils::i()->getTSNodeServer();
$tsInfo = $tsAdmin->getInfo();
$data["ts"] = [
"uid" => (string) $tsInfo["virtualserver_unique_identifier"],
"version" => (string) $tsInfo["virtualserver_version"],
"platform" => (string) $tsInfo["virtualserver_platform"],
"slotCount" => $tsInfo["virtualserver_maxclients"],
"usingServeradmin" => $tsNode->whoami()["client_unique_identifier"] == "serveradmin"
];
} catch (\Exception $e) {}
}
// Send it
$data = json_encode($data);
$url = "https://wruczek.tech/tsw-metrics/";
// If cURL is available, use it
if (function_exists("curl_version")) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
//echo $response;
} else { // else try file_get_contents
$context = stream_context_create([
"http" => [
"method" => "POST",
"header" => "Content-type: application/json\r\n" .
"Accept: application/json\r\n" .
"Connection: close\r\n" .
"Content-length: " . strlen($data) . "\r\n",
"content" => $data
]
]);
$response = file_get_contents($url, false, $context);
//echo $response;
}
}
?>
<div class="card">
<div class="card-body">
<h3 class="card-title text-center">TS-website <?= __TSWEBSITE_VERSION ?> has been successfully installed! &#x1F44D;</h3>
<p class="text-center">
If you wish, you can remove the <code>installer</code> directory.
</p>
<br>
<h1 class="card-title text-center mb-4">What now?</h1>
<div class="col-lg-11" style="left: 4.166666666%">
<div class="row whatnow-row">
<div class="col-lg-2">
<i class="fab fa-paypal whatnow-icon fa-fw" style="color: #003087"></i>
</div>
<div class="col-lg-10">
<h1><a href="https://paypal.me/#" target="_blank">Donate</a></h1>
<h3>to keep this project alive</h3>
</div>
</div>
<div class="row whatnow-row">
<div class="col-lg-10 text-right">
<h1><a href="https://t.me/tswebsite" target="_blank">Join</a> <small>our telegram group</small></h1>
<h3>news, announcements and support</h3>
</div>
<div class="col-lg-2">
<i class="fab fa-telegram-plane whatnow-icon fa-fw" style="color: #0088cc"></i>
</div>
</div>
<div class="row whatnow-row">
<div class="col-lg-2">
<i class="fa fa-eye whatnow-icon fa-fw" style="color: #fbb034"></i>
</div>
<div class="col-lg-10">
<h1><a href="../">Visit</a> <small>your new website</small></h1>
<h3>or login to your <a href="../admin">Admin Panel</a></h3>
</div>
</div>
<div class="row whatnow-row">
<div class="col-lg-10 text-right">
<h1>Spread <small>the message</small></h1>
<h3>Let others know about this project</h3>
</div>
<div class="col-lg-2">
<i class="fa fa-heart whatnow-icon fa-fw" style="color: #ff4d4d"></i>
</div>
</div>
</div>
</div>
</div>

103
src/installer/style.css Normal file
View File

@@ -0,0 +1,103 @@
body {
margin-bottom: 40px;
}
h4 {
margin-bottom: 2rem !important;
}
.nav-wizard {
display: inline-block;
margin-bottom: 40px;
}
.nav-wizard > li {
display: block;
}
.nav-wizard > li > a {
display: block;
padding: 10px 15px;
cursor: default;
text-decoration: none !important;
}
.btn {
font-family: Helvetica, Arial, sans-serif;
line-height: 12px;
}
p, label {
font-size: 115%;
}
.license {
margin: 1rem auto;
display: inline-block;
max-height: 400px;
text-align: initial;
}
.license-container {
text-align: center;
}
.fa-larger {
font-size: 1.5em;
}
.fa-chevron-left {
margin-right: 3px;
}
.fa-chevron-right, .fa-sync {
margin-left: 3px;
}
.requirements-check-table {
display: inline-block;
width: auto;
text-align: initial
}
.color-success {
color: #28B62C;
}
.color-warning {
color: #FF851B;
}
.color-danger {
color: #FF4136;
}
.whatnow-row {
margin-bottom: 30px;
}
.whatnow-row h1, .whatnow-row h3 {
margin: 0;
}
.whatnow-icon {
font-size: 5rem;
}
.tooltip-inner {
max-width: 300px;
}
@media (max-width: 1200px) {
.nav-wizard > li:not(:first-child) > a:before {
border: 0;
}
.nav-wizard {
width: 100%;
}
.nav-wizard > li {
float: none;
}
}