diff --git a/images/friendica-404_svg_flexy-o-hare.png b/images/friendica-404_svg_flexy-o-hare.png new file mode 100644 index 0000000000..36d6b5ca3d Binary files /dev/null and b/images/friendica-404_svg_flexy-o-hare.png differ diff --git a/images/friendica-404_svg_hare-bottom-light-inside.png b/images/friendica-404_svg_hare-bottom-light-inside.png new file mode 100644 index 0000000000..6c9189e4ec Binary files /dev/null and b/images/friendica-404_svg_hare-bottom-light-inside.png differ diff --git a/mod/filerm.php b/mod/filerm.php deleted file mode 100644 index 9013dd62b4..0000000000 --- a/mod/filerm.php +++ /dev/null @@ -1,40 +0,0 @@ -argc > 1) ? intval($a->argv[1]) : 0); - - Logger::log('filerm: tag ' . $term . ' item ' . $item_id . ' category ' . ($category ? 'true' : 'false')); - - if ($item_id && strlen($term)) { - if (FileTag::unsaveFile(local_user(), $item_id, $term, $category)) { - info('Item removed'); - } - } - else { - info('Item was not deleted'); - } - - $a->internalRedirect('/network?f=&file=' . rawurlencode($term)); - exit(); -} diff --git a/mod/friendica.php b/mod/friendica.php deleted file mode 100644 index 4942e4c8f5..0000000000 --- a/mod/friendica.php +++ /dev/null @@ -1,141 +0,0 @@ -argv[1]) && ($a->argv[1] == "json")) { - $register_policies = [ - Register::CLOSED => 'REGISTER_CLOSED', - Register::APPROVE => 'REGISTER_APPROVE', - Register::OPEN => 'REGISTER_OPEN' - ]; - - $register_policy_int = intval(Config::get('config', 'register_policy')); - if ($register_policy_int !== Register::CLOSED && Config::get('config', 'invitation_only')) { - $register_policy = 'REGISTER_INVITATION'; - } else { - $register_policy = $register_policies[$register_policy_int]; - } - - $condition = []; - $admin = false; - if (!empty(Config::get('config', 'admin_nickname'))) { - $condition['nickname'] = Config::get('config', 'admin_nickname'); - } - if (!empty(Config::get('config', 'admin_email'))) { - $adminlist = explode(",", str_replace(" ", "", Config::get('config', 'admin_email'))); - $condition['email'] = $adminlist[0]; - $administrator = DBA::selectFirst('user', ['username', 'nickname'], $condition); - if (DBA::isResult($administrator)) { - $admin = [ - 'name' => $administrator['username'], - 'profile'=> System::baseUrl() . '/profile/' . $administrator['nickname'], - ]; - } - } - - $visible_addons = Addon::getVisibleList(); - - Config::load('feature_lock'); - $locked_features = []; - $featureLock = Config::get('config', 'feature_lock'); - if (isset($featureLock)) { - foreach ($featureLock as $k => $v) { - if ($k === 'config_loaded') { - continue; - } - - $locked_features[$k] = intval($v); - } - } - - $data = [ - 'version' => FRIENDICA_VERSION, - 'url' => System::baseUrl(), - 'addons' => $visible_addons, - 'locked_features' => $locked_features, - 'explicit_content' => (int)Config::get('system', 'explicit_content', false), - 'language' => Config::get('system','language'), - 'register_policy' => $register_policy, - 'admin' => $admin, - 'site_name' => Config::get('config', 'sitename'), - 'platform' => FRIENDICA_PLATFORM, - 'info' => Config::get('config', 'info'), - 'no_scrape_url' => System::baseUrl().'/noscrape' - ]; - - header('Content-type: application/json; charset=utf-8'); - echo json_encode($data); - exit(); - } -} - -function friendica_content(App $a) -{ - $o = '

Friendica

' . PHP_EOL; - $o .= '

'; - $o .= L10n::t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.', - '' . FRIENDICA_VERSION . '', System::baseUrl(), '' . DB_UPDATE_VERSION . '', - '' . Config::get("system", "post_update_version") . ''); - $o .= '

' . PHP_EOL; - - $o .= '

'; - $o .= L10n::t('Please visit Friendi.ca to learn more about the Friendica project.') . PHP_EOL; - $o .= '

' . PHP_EOL; - - $o .= '

'; - $o .= L10n::t('Bug reports and issues: please visit') . ' ' . ''.L10n::t('the bugtracker at github').''; - $o .= '

' . PHP_EOL; - $o .= '

'; - $o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'); - $o .= '

' . PHP_EOL; - - $visible_addons = Addon::getVisibleList(); - if (count($visible_addons)) { - $o .= '

' . L10n::t('Installed addons/apps:') . '

' . PHP_EOL; - $sorted = $visible_addons; - $s = ''; - sort($sorted); - foreach ($sorted as $p) { - if (strlen($p)) { - if (strlen($s)) { - $s .= ', '; - } - $s .= $p; - } - } - $o .= '
' . $s . '
' . PHP_EOL; - } else { - $o .= '

' . L10n::t('No installed addons/apps') . '

' . PHP_EOL; - } - - if (Config::get('system', 'tosdisplay')) - { - $o .= '

'.L10n::t('Read about the Terms of Service of this node.', System::baseurl()).'

'; - } - - $blocklist = Config::get('system', 'blocklist', []); - if (!empty($blocklist)) { - $o .= '

' . L10n::t('On this server the following remote servers are blocked.') . '

' . PHP_EOL; - $o .= '' . PHP_EOL; - foreach ($blocklist as $b) { - $o .= '' . PHP_EOL; - } - $o .= '
' . L10n::t('Blocked domain') . '' . L10n::t('Reason for the block') . '
' . $b['domain'] .'' . $b['reason'] . '
' . PHP_EOL; - } - - Hook::callAll('about_hook', $o); - - return $o; -} diff --git a/mod/maintenance.php b/mod/maintenance.php deleted file mode 100644 index 8e0197b868..0000000000 --- a/mod/maintenance.php +++ /dev/null @@ -1,29 +0,0 @@ - L10n::t('System down for maintenance'), - '$reason' => $reason - ]); -} diff --git a/mod/modexp.php b/mod/modexp.php deleted file mode 100644 index cae91c4648..0000000000 --- a/mod/modexp.php +++ /dev/null @@ -1,36 +0,0 @@ -argc != 2) - exit(); - - $nick = $a->argv[1]; - $r = q("SELECT `spubkey` FROM `user` WHERE `nickname` = '%s' LIMIT 1", - DBA::escape($nick) - ); - - if (! DBA::isResult($r)) { - exit(); - } - - $lines = explode("\n",$r[0]['spubkey']); - unset($lines[0]); - unset($lines[count($lines)]); - $x = base64_decode(implode('',$lines)); - - $r = ASN_BASE::parseASNString($x); - - $m = $r[0]->asnData[1]->asnData[0]->asnData[0]->asnData; - $e = $r[0]->asnData[1]->asnData[0]->asnData[1]->asnData; - - header("Content-type: application/magic-public-key"); - echo 'RSA' . '.' . $m . '.' . $e; - - exit(); - -} - diff --git a/mod/pretheme.php b/mod/pretheme.php deleted file mode 100644 index 14d1f2b9ea..0000000000 --- a/mod/pretheme.php +++ /dev/null @@ -1,25 +0,0 @@ - Theme::getScreenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits]); - } - - exit(); -} diff --git a/mod/robots_txt.php b/mod/robots_txt.php deleted file mode 100644 index 0575742dd8..0000000000 --- a/mod/robots_txt.php +++ /dev/null @@ -1,30 +0,0 @@ -argc > 1) ? intval($a->argv[1]) : 0); - - if (!$item_id) { - throw new \Friendica\Network\HTTPException\NotFoundException(L10n::t('Item not found.')); - } - - $item = Item::selectFirst(['body'], ['uid' => local_user(), 'id' => $item_id]); - - if (DBA::isResult($item)) { - if ($a->isAjax()) { - echo str_replace("\n", '
', $item['body']); - exit(); - } else { - $o .= str_replace("\n", '
', $item['body']); - } - } - return $o; -} diff --git a/src/App.php b/src/App.php index 017661c4ca..0f0c0537e4 100644 --- a/src/App.php +++ b/src/App.php @@ -988,7 +988,7 @@ class App header('Refresh: 120; url=' . $this->getBaseURL() . "/" . $this->query_string); Module\Special\HTTPException::rawContent( - new HTTPException\ServiceUnavaiableException('The node is currently overloaded. Please try again later.') + new HTTPException\ServiceUnavailableException('The node is currently overloaded. Please try again later.') ); } @@ -1077,10 +1077,10 @@ class App // in install mode, any url loads install module // but we need "view" module for stylesheet - if ($this->getMode()->isInstall() && $this->module != 'view') { - $this->module = 'install'; - } elseif (!$this->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $this->module != 'view') { - $this->module = 'maintenance'; + if ($this->getMode()->isInstall() && $this->module !== 'install') { + $this->internalRedirect('install'); + } elseif (!$this->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $this->module !== 'maintenance') { + $this->internalRedirect('maintenance'); } else { $this->checkURL(); Core\Update::check($this->getBasePath(), false, $this->getMode()); diff --git a/src/App/Router.php b/src/App/Router.php index 3f576d7c53..a71f9f0f8c 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -89,12 +89,13 @@ class Router $this->routeCollector->addRoute(['GET'], '/apps', Module\Apps::class); $this->routeCollector->addRoute(['GET'], '/attach/{item:\d+}', Module\Attach::class); $this->routeCollector->addRoute(['GET'], '/babel', Module\Babel::class); - $this->routeCollector->addRoute(['GET'], '/bookmarklet', Module\BookMarklet::class); + $this->routeCollector->addRoute(['GET'], '/bookmarklet', Module\Bookmarklet::class); $this->routeCollector->addGroup('/contact', function (RouteCollector $collector) { $collector->addRoute(['GET'], '[/]', Module\Contact::class); $collector->addRoute(['GET'], '/{id:\d+}[/posts|conversations]', Module\Contact::class); }); $this->routeCollector->addRoute(['GET'], '/credits', Module\Credits::class); + $this->routeCollector->addRoute(['GET'], '/directory', Module\Directory::class); $this->routeCollector->addGroup('/feed', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/{nickname}', Module\Feed::class); $collector->addRoute(['GET'], '/{nickname}/posts', Module\Feed::class); @@ -102,17 +103,18 @@ class Router $collector->addRoute(['GET'], '/{nickname}/replies', Module\Feed::class); $collector->addRoute(['GET'], '/{nickname}/activity', Module\Feed::class); }); - $this->routeCollector->addRoute(['GET'], '/directory', Module\Directory::class); $this->routeCollector->addRoute(['GET'], '/feedtest', Module\Feedtest::class); $this->routeCollector->addGroup('/fetch', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/{guid}/post', Module\Diaspora\Fetch::class); $collector->addRoute(['GET'], '/{guid}/status_message', Module\Diaspora\Fetch::class); $collector->addRoute(['GET'], '/{guid}/reshare', Module\Diaspora\Fetch::class); }); - $this->routeCollector->addRoute(['GET'], '/filer[/{id:\d+}]', Module\Filer::class); + $this->routeCollector->addRoute(['GET'], '/filer[/{id:\d+}]', Module\Filer\SaveTag::class); + $this->routeCollector->addRoute(['GET'], '/filerm/{id:\d+}', Module\Filer\RemoveTag::class); $this->routeCollector->addRoute(['GET', 'POST'], '/follow_confirm', Module\FollowConfirm::class); $this->routeCollector->addRoute(['GET'], '/followers/{owner}', Module\Followers::class); $this->routeCollector->addRoute(['GET'], '/following/{owner}', Module\Following::class); + $this->routeCollector->addRoute(['GET'], '/friendica[/json]', Module\Friendica::class); $this->routeCollector->addGroup('/group', function (RouteCollector $collector) { $collector->addRoute(['GET', 'POST'], '[/]', Module\Group::class); $collector->addRoute(['GET', 'POST'], '/{group:\d+}', Module\Group::class); @@ -139,7 +141,9 @@ class Router $this->routeCollector->addRoute(['GET', 'POST'], '/login', Module\Login::class); $this->routeCollector->addRoute(['GET', 'POST'], '/logout', Module\Logout::class); $this->routeCollector->addRoute(['GET'], '/magic', Module\Magic::class); + $this->routeCollector->addRoute(['GET'], '/maintenance', Module\Maintenance::class); $this->routeCollector->addRoute(['GET'], '/manifest', Module\Manifest::class); + $this->routeCollector->addRoute(['GET'], '/modexp/{nick}', Module\PublicRSAKey::class); $this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class); $this->routeCollector->addRoute(['GET'], '/nogroup', Module\Group::class); $this->routeCollector->addRoute(['GET'], '/objects/{guid}', Module\Objects::class); @@ -154,6 +158,7 @@ class Router $collector->addRoute(['GET'], '/{type}/{name}', Module\Photo::class); $collector->addRoute(['GET'], '/{type}/{customize}/{name}', Module\Photo::class); }); + $this->routeCollector->addRoute(['GET'], '/pretheme', Module\ThemeDetails::class); $this->routeCollector->addGroup('/profile', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/{nickname}', Module\Profile::class); $collector->addRoute(['GET'], '/{profile:\d+}/view', Module\Profile::class); @@ -165,9 +170,11 @@ class Router $collector->addRoute(['GET'], '/{sub1}/{sub2}/{url}' , Module\Proxy::class); }); $this->routeCollector->addRoute(['GET', 'POST'], '/register', Module\Register::class); + $this->routeCollector->addRoute(['GET'], '/robots.txt', Module\RobotsTxt::class); $this->routeCollector->addRoute(['GET'], '/rsd.xml', Module\ReallySimpleDiscovery::class); $this->routeCollector->addRoute(['GET'], '/statistics.json', Module\Statistics::class); $this->routeCollector->addRoute(['GET'], '/tos', Module\Tos::class); + $this->routeCollector->addRoute(['GET'], '/viewsrc/{item:\d+}', Module\ItemBody::class); $this->routeCollector->addRoute(['GET'], '/webfinger', Module\WebFinger::class); $this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class); } diff --git a/src/Core/System.php b/src/Core/System.php index 31934af5a7..42587577da 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -242,6 +242,9 @@ class System extends BaseObject case 301: header('HTTP/1.1 301 Moved Permanently'); break; + case 307: + header('HTTP/1.1 307 Temporary Redirect'); + break; } header("Location: $url"); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 181f7a5e47..a0e746f511 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1174,7 +1174,7 @@ class Contact extends BaseObject // The link could be provided as http although we stored it as https $ssl_url = str_replace('http://', 'https://', $url); - $fields = ['url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick', + $fields = ['id', 'uid', 'url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick', 'photo', 'keywords', 'location', 'about', 'network', 'priority', 'batch', 'request', 'confirm', 'poco']; diff --git a/src/Model/Profile.php b/src/Model/Profile.php index 9d2600b3da..a854b1c9e0 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -1249,56 +1249,96 @@ class Profile */ public static function searchProfiles($start = 0, $count = 100, $search = null) { - if ($search) { - $search = DBA::escape($search); - - $sql_extra = " AND ((`profile`.`name` LIKE '%$search%') OR - (`user`.`nickname` LIKE '%$search%') OR - (`profile`.`pdesc` LIKE '%$search%') OR - (`profile`.`locality` LIKE '%$search%') OR - (`profile`.`region` LIKE '%$search%') OR - (`profile`.`country-name` LIKE '%$search%') OR - (`profile`.`gender` LIKE '%$search%') OR - (`profile`.`marital` LIKE '%$search%') OR - (`profile`.`sexual` LIKE '%$search%') OR - (`profile`.`about` LIKE '%$search%') OR - (`profile`.`romance` LIKE '%$search%') OR - (`profile`.`work` LIKE '%$search%') OR - (`profile`.`education` LIKE '%$search%') OR - (`profile`.`pub_keywords` LIKE '%$search%') OR - (`profile`.`prv_keywords` LIKE '%$search%'))"; - } else { - $sql_extra = ''; - } - $publish = (Config::get('system', 'publish_all') ? '' : " AND `publish` = 1 "); - $total = 0; - $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` + + if (!empty($search)) { + $searchTerm = '%' . $search . '%'; + $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` - WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` $sql_extra"); + WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` + AND ((`profile`.`name` LIKE ?) OR + (`user`.`nickname` LIKE ?) OR + (`profile`.`pdesc` LIKE ?) OR + (`profile`.`locality` LIKE ?) OR + (`profile`.`region` LIKE ?) OR + (`profile`.`country-name` LIKE ?) OR + (`profile`.`gender` LIKE ?) OR + (`profile`.`marital` LIKE ?) OR + (`profile`.`sexual` LIKE ?) OR + (`profile`.`about` LIKE ?) OR + (`profile`.`romance` LIKE ?) OR + (`profile`.`work` LIKE ?) OR + (`profile`.`education` LIKE ?) OR + (`profile`.`pub_keywords` LIKE ?) OR + (`profile`.`prv_keywords` LIKE ?))", + $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, + $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm); + } else { + $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` + FROM `profile` + LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` + WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`"); + } + if (DBA::isResult($cnt)) { $total = $cnt['total']; } $order = " ORDER BY `name` ASC "; - $limit = $start . ',' . $count; + $profiles = []; - $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`, + // If nothing found, don't try to select details + if ($total > 0) { + if (!empty($search)) { + $searchTerm = '%' . $search . '%'; + + $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`, `contact`.`addr`, `contact`.`url` AS `profile_url` FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid` WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self` - $sql_extra $order LIMIT $limit" - ); + AND ((`profile`.`name` LIKE ?) OR + (`user`.`nickname` LIKE ?) OR + (`profile`.`pdesc` LIKE ?) OR + (`profile`.`locality` LIKE ?) OR + (`profile`.`region` LIKE ?) OR + (`profile`.`country-name` LIKE ?) OR + (`profile`.`gender` LIKE ?) OR + (`profile`.`marital` LIKE ?) OR + (`profile`.`sexual` LIKE ?) OR + (`profile`.`about` LIKE ?) OR + (`profile`.`romance` LIKE ?) OR + (`profile`.`work` LIKE ?) OR + (`profile`.`education` LIKE ?) OR + (`profile`.`pub_keywords` LIKE ?) OR + (`profile`.`prv_keywords` LIKE ?)) + $order LIMIT ?,?", + $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, + $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, + $start, $count + ); + } else { + $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`, + `contact`.`addr`, `contact`.`url` AS `profile_url` + FROM `profile` + LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` + LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid` + WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self` + $order LIMIT ?,?", + $start, $count + ); + } + } - if (DBA::isResult($profiles)) { + if (DBA::isResult($profiles) && $total > 0) { return [ 'total' => $total, 'entries' => DBA::toArray($profiles), ]; + } else { return [ 'total' => $total, diff --git a/src/Model/User.php b/src/Model/User.php index c575b44d38..64253946fd 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -129,6 +129,21 @@ class User } } + /** + * Get a user based on its email + * + * @param string $email + * @param array $fields + * + * @return array|boolean User record if it exists, false otherwise + * + * @throws Exception + */ + public static function getByEmail($email, array $fields = []) + { + return DBA::selectFirst('user', $fields, ['email' => $email]); + } + /** * @brief Get owner data by user id * diff --git a/src/Module/BookMarklet.php b/src/Module/Bookmarklet.php similarity index 98% rename from src/Module/BookMarklet.php rename to src/Module/Bookmarklet.php index 51feb25d7b..1b6ff38459 100644 --- a/src/Module/BookMarklet.php +++ b/src/Module/Bookmarklet.php @@ -12,7 +12,7 @@ use Friendica\Util\Strings; * Creates a bookmarklet * Shows either a editor browser or adds the given bookmarklet to the current user */ -class BookMarklet extends BaseModule +class Bookmarklet extends BaseModule { public static function content() { diff --git a/src/Module/Filer/RemoveTag.php b/src/Module/Filer/RemoveTag.php new file mode 100644 index 0000000000..bddaaf9dc2 --- /dev/null +++ b/src/Module/Filer/RemoveTag.php @@ -0,0 +1,51 @@ +getLogger(); + + $item_id = (($app->argc > 1) ? intval($app->argv[1]) : 0); + + $term = XML::unescape(trim(defaults($_GET, 'term', ''))); + $cat = XML::unescape(trim(defaults($_GET, 'cat', ''))); + + $category = (($cat) ? true : false); + + if ($category) { + $term = $cat; + } + + $logger->info('Filer - Remove Tag', [ + 'term' => $term, + 'item' => $item_id, + 'category' => ($category ? 'true' : 'false') + ]); + + if ($item_id && strlen($term)) { + if (FileTag::unsaveFile(local_user(), $item_id, $term, $category)) { + info('Item removed'); + } + } else { + info('Item was not deleted'); + } + + $app->internalRedirect('/network?f=&file=' . rawurlencode($term)); + } +} diff --git a/src/Module/Filer.php b/src/Module/Filer/SaveTag.php similarity index 95% rename from src/Module/Filer.php rename to src/Module/Filer/SaveTag.php index da59084da0..f5d6115199 100644 --- a/src/Module/Filer.php +++ b/src/Module/Filer/SaveTag.php @@ -1,6 +1,6 @@ getConfig(); + + $visibleAddonList = Addon::getVisibleList(); + if (!empty($visibleAddonList)) { + + $sorted = $visibleAddonList; + sort($sorted); + + $sortedAddonList = ''; + + foreach ($sorted as $addon) { + if (strlen($addon)) { + if (strlen($sortedAddonList)) { + $sortedAddonList .= ', '; + } + $sortedAddonList .= $addon; + } + } + $addon = [ + 'title' => L10n::t('Installed addons/apps:'), + 'list' => $sortedAddonList, + ]; + } else { + $addon = [ + 'title' => L10n::t('No installed addons/apps'), + ]; + } + + $tos = ($config->get('system', 'tosdisplay')) ? + L10n::t('Read about the Terms of Service of this node.', $app->getBaseURL()) : + ''; + + $blockList = $config->get('system', 'blocklist'); + + if (!empty($blockList)) { + $blocked = [ + 'title' => L10n::t('On this server the following remote servers are blocked.'), + 'header' => [ + L10n::t('Blocked domain'), + L10n::t('Reason for the block'), + ], + 'list' => $blockList, + ]; + } else { + $blocked = null; + } + + $hooked = ''; + + Hook::callAll('about_hook', $hooked); + + $tpl = Renderer::getMarkupTemplate('friendica.tpl'); + + return Renderer::replaceMacros($tpl, [ + 'about' => L10n::t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.', + '' . FRIENDICA_VERSION . '', + $app->getBaseURL(), + '' . DB_UPDATE_VERSION . '', + '' . $config->get('system', 'post_update_version') . ''), + 'friendica' => L10n::t('Please visit Friendi.ca to learn more about the Friendica project.'), + 'bugs' => L10n::t('Bug reports and issues: please visit') . ' ' . '' . L10n::t('the bugtracker at github') . '', + 'info' => L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'), + + 'visible_addons' => $addon, + 'tos' => $tos, + 'block_list' => $blocked, + 'hooked' => $hooked, + ]); + } + + public static function rawContent() + { + $app = self::getApp(); + + // @TODO: Replace with parameter from router + if ($app->argc <= 1 || ($app->argv[1] !== 'json')) { + return; + } + + $config = $app->getConfig(); + + $register_policies = [ + Register::CLOSED => 'REGISTER_CLOSED', + Register::APPROVE => 'REGISTER_APPROVE', + Register::OPEN => 'REGISTER_OPEN' + ]; + + $register_policy_int = intval($config->get('config', 'register_policy')); + if ($register_policy_int !== Register::CLOSED && $config->get('config', 'invitation_only')) { + $register_policy = 'REGISTER_INVITATION'; + } else { + $register_policy = $register_policies[$register_policy_int]; + } + + $condition = []; + $admin = false; + if (!empty($config->get('config', 'admin_nickname'))) { + $condition['nickname'] = $config->get('config', 'admin_nickname'); + } + if (!empty($config->get('config', 'admin_email'))) { + $adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email'))); + $condition['email'] = $adminList[0]; + $administrator = User::getByEmail($adminList[0], ['username', 'nickname']); + if (!empty($administrator)) { + $admin = [ + 'name' => $administrator['username'], + 'profile' => $app->getBaseURL() . '/profile/' . $administrator['nickname'], + ]; + } + } + + $visible_addons = Addon::getVisibleList(); + + $config->load('feature_lock'); + $locked_features = []; + $featureLocks = $config->get('config', 'feature_lock'); + if (isset($featureLocks)) { + foreach ($featureLocks as $feature => $lock) { + if ($feature === 'config_loaded') { + continue; + } + + $locked_features[$feature] = intval($lock); + } + } + + $data = [ + 'version' => FRIENDICA_VERSION, + 'url' => $app->getBaseURL(), + 'addons' => $visible_addons, + 'locked_features' => $locked_features, + 'explicit_content' => intval($config->get('system', 'explicit_content', 0)), + 'language' => $config->get('system', 'language'), + 'register_policy' => $register_policy, + 'admin' => $admin, + 'site_name' => $config->get('config', 'sitename'), + 'platform' => FRIENDICA_PLATFORM, + 'info' => $config->get('config', 'info'), + 'no_scrape_url' => $app->getBaseURL() . '/noscrape', + ]; + + header('Content-type: application/json; charset=utf-8'); + echo json_encode($data); + exit(); + } +} diff --git a/src/Module/ItemBody.php b/src/Module/ItemBody.php new file mode 100644 index 0000000000..ee50b52b28 --- /dev/null +++ b/src/Module/ItemBody.php @@ -0,0 +1,43 @@ +argc > 1) ? intval($app->argv[1]) : 0); + + if (!$itemId) { + throw new HTTPException\NotFoundException(L10n::t('Item not found.')); + } + + $item = Item::selectFirst(['body'], ['uid' => local_user(), 'id' => $itemId]); + + if (!empty($item)) { + if ($app->isAjax()) { + echo str_replace("\n", '
', $item['body']); + exit(); + } else { + return str_replace("\n", '
', $item['body']); + } + } else { + throw new HTTPException\NotFoundException(L10n::t('Item not found.')); + } + } +} diff --git a/src/Module/Maintenance.php b/src/Module/Maintenance.php new file mode 100644 index 0000000000..24140bb351 --- /dev/null +++ b/src/Module/Maintenance.php @@ -0,0 +1,32 @@ +getConfig(); + + $reason = $config->get('system', 'maintenance_reason'); + + if ((substr(Strings::normaliseLink($reason), 0, 7) === 'http://') || + (substr(Strings::normaliseLink($reason), 0, 8) === 'https://')) { + System::externalRedirect($reason, 307); + } + + $exception = new HTTPException\ServiceUnavailableException($reason); + $exception->httpdesc = L10n::t('System down for maintenance'); + throw $exception; + } +} diff --git a/src/Module/PublicRSAKey.php b/src/Module/PublicRSAKey.php new file mode 100644 index 0000000000..ed099616ad --- /dev/null +++ b/src/Module/PublicRSAKey.php @@ -0,0 +1,47 @@ +argc !== 2) { + throw new BadRequestException(); + } + + // @TODO: Replace with parameter from router + $nick = $app->argv[1]; + + $user = User::getByNickname($nick, ['spubkey']); + if (empty($user) || empty($user['spubkey'])) { + throw new BadRequestException(); + } + + $lines = explode("\n", $user['spubkey']); + unset($lines[0]); + unset($lines[count($lines)]); + + $asnString = base64_decode(implode('', $lines)); + $asnBase = ASN_BASE::parseASNString($asnString); + + $m = $asnBase[0]->asnData[1]->asnData[0]->asnData[0]->asnData; + $e = $asnBase[0]->asnData[1]->asnData[0]->asnData[1]->asnData; + + header('Content-type: application/magic-public-key'); + echo 'RSA' . '.' . $m . '.' . $e; + + exit(); + } +} diff --git a/src/Module/ReallySimpleDiscovery.php b/src/Module/ReallySimpleDiscovery.php index 4c14d3c837..515285dbfc 100644 --- a/src/Module/ReallySimpleDiscovery.php +++ b/src/Module/ReallySimpleDiscovery.php @@ -3,7 +3,7 @@ namespace Friendica\Module; use Friendica\BaseModule; -use Friendica\Core\Renderer; +use Friendica\Util\XML; /** * Prints the rsd.xml @@ -13,9 +13,43 @@ class ReallySimpleDiscovery extends BaseModule { public static function rawContent() { - header ('Content-Type: text/xml'); - $tpl = Renderer::getMarkupTemplate('rsd.tpl'); - echo Renderer::replaceMacros($tpl); + header('Content-Type: text/xml'); + + $app = self::getApp(); + $xml = null; + echo XML::fromArray([ + 'rsd' => [ + '@attributes' => [ + 'version' => '1.0', + 'xmlns' => 'http://archipelago.phrasewise.com/rsd', + ], + 'service' => [ + 'engineName' => 'Friendica', + 'engineLink' => 'http://friendica.com', + 'apis' => [ + 'api' => [ + '@attributes' => [ + 'name' => 'Twitter', + 'preferred' => 'true', + 'apiLink' => $app->getBaseURL(), + 'blogID' => '', + ], + 'settings' => [ + 'docs' => [ + 'http://status.net/wiki/TwitterCompatibleAPI', + ], + 'setting' => [ + '@attributes' => [ + 'name' => 'OAuth', + ], + 'false', + ], + ], + ] + ], + ], + ], + ], $xml); exit(); } } diff --git a/src/Module/RobotsTxt.php b/src/Module/RobotsTxt.php new file mode 100644 index 0000000000..3648f6f9fb --- /dev/null +++ b/src/Module/RobotsTxt.php @@ -0,0 +1,27 @@ +getCode(), ''); } - return ['$title' => $title, '$description' => $message]; + return ['$title' => $title, '$message' => $message, '$back' => L10n::t('Go back')]; } /** * Displays a bare message page with no theming at all. * * @param \Friendica\Network\HTTPException $e - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Exception */ public static function rawContent(\Friendica\Network\HTTPException $e) { @@ -78,7 +78,7 @@ class HTTPException * * @param \Friendica\Network\HTTPException $e * @return string - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Exception */ public static function content(\Friendica\Network\HTTPException $e) { diff --git a/src/Module/ThemeDetails.php b/src/Module/ThemeDetails.php new file mode 100644 index 0000000000..7b53d1cfde --- /dev/null +++ b/src/Module/ThemeDetails.php @@ -0,0 +1,33 @@ + Theme::getScreenshot($theme), + 'desc' => $description, + 'version' => $version, + 'credits' => $credits, + ]); + } + exit(); + } +} diff --git a/src/Network/HTTPException/ServiceUnavaiableException.php b/src/Network/HTTPException/ServiceUnavailableException.php similarity index 67% rename from src/Network/HTTPException/ServiceUnavaiableException.php rename to src/Network/HTTPException/ServiceUnavailableException.php index 6c0e6595d8..257b8c8585 100644 --- a/src/Network/HTTPException/ServiceUnavaiableException.php +++ b/src/Network/HTTPException/ServiceUnavailableException.php @@ -4,7 +4,7 @@ namespace Friendica\Network\HTTPException; use Friendica\Network\HTTPException; -class ServiceUnavaiableException extends HTTPException +class ServiceUnavailableException extends HTTPException { protected $code = 503; } diff --git a/view/global.css b/view/global.css index b48fa1a24a..0eaf4482dc 100644 --- a/view/global.css +++ b/view/global.css @@ -5,7 +5,7 @@ details > summary { cursor: pointer; } -/* General designing elements */ +/* General design elements */ .btn { outline: none; -moz-box-shadow: inset 0px 1px 0px 0px #ffffff; @@ -87,7 +87,6 @@ span.connector { .wall-item-container .wall-item-content .type-link img.attachment-image, .type-link img.attachment-image, .type-video img.attachment-image { - /* max-width: 640px; */ max-width: 100%; max-height: initial; float: initial; @@ -621,3 +620,22 @@ span.emoji.mastodon img { height: 1.2em; vertical-align: middle; } + +/* Exception page */ + +#exception { + overflow: hidden; + background-image: url('../images/friendica-404_svg_hare-bottom-light-inside.png'); + background-position: 50px bottom; + background-repeat: no-repeat; +} + +#exception .hare { + float: right; +} + +@media screen and (max-width: 600px) { + #exception .hare { + display: none; + } +} diff --git a/view/templates/exception.tpl b/view/templates/exception.tpl index 02b7648e3a..6c26168908 100644 --- a/view/templates/exception.tpl +++ b/view/templates/exception.tpl @@ -1,4 +1,6 @@
+

{{$title}}

{{$message}}

+

diff --git a/view/templates/feedtest.tpl b/view/templates/feedtest.tpl index 2147198f1d..709ad4de43 100644 --- a/view/templates/feedtest.tpl +++ b/view/templates/feedtest.tpl @@ -1,30 +1,32 @@ -

Feed Test

-
-
-
- {{include file="field_input.tpl" field=$url}} +
+

Feed Test

+ +
+
+ {{include file="field_input.tpl" field=$url}} +
+

-

-
- + -{{if $result}} -
-
-
-

Output Items

+ {{if $result}} +
+
+
+

Output Items

+
+
+
{{$result.output}}
+
-
-
{{$result.output}}
-
-
-
-
-

Input Feed XML

-
-
- {{$result.input}} +
+
+

Input Feed XML

+
+
+ {{$result.input}} +
+ {{/if}}
-{{/if}} \ No newline at end of file diff --git a/view/templates/friendica.tpl b/view/templates/friendica.tpl new file mode 100644 index 0000000000..f890a58a95 --- /dev/null +++ b/view/templates/friendica.tpl @@ -0,0 +1,47 @@ +
+

Friendica

+
+

{{$about nofilter}}

+
+

{{$friendica nofilter}}

+
+

{{$bugs nofilter}}

+
+

{{$info nofilter}}

+
+ +

{{$visible_addons.title nofilter}}

+ {{if $visible_addons.list}} +
{{$visible_addons.list nofilter}}
+ {{/if}} + + {{if $tos}} +

{{$tos nofilter}}

+ {{/if}} + + {{if $block_list}} +
+

{{$block_list.title nofilter}}

+
+ + + + + + + + + {{foreach $block_list.list as $blocked}} + + + + + {{/foreach}} + +
{{$block_list.header[0] nofilter}}{{$block_list.header[1] nofilter}}
{{$blocked.domain nofilter}}{{$blocked.reason nofilter}}
+
+ + {{/if}} + +{{$hooked nofilter}} +
diff --git a/view/templates/rsd.tpl b/view/templates/rsd.tpl deleted file mode 100644 index c194e8f26b..0000000000 --- a/view/templates/rsd.tpl +++ /dev/null @@ -1,15 +0,0 @@ - - - - Friendica - http://friendica.com/ - - - - http://status.net/wiki/TwitterCompatibleAPI - false - - - - - diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index e6b42e52ea..4a72628352 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -105,6 +105,9 @@ blockquote { * mobile aside */ @media screen and (max-width: 990px) { + body { + padding-top: 105px; + } aside{ position: fixed!important; top: 0!important; @@ -616,6 +619,10 @@ nav.navbar a, nav.navbar .btn-link { display: flex; } +#friendica-logo-mask { + display: block; +} + /* Notification Menu */ #topbar-first #nav-notifications-menu {