diff --git a/application/config/routes.php b/application/config/routes.php index 9545bde..40dc7a4 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -81,4 +81,5 @@ $route['reset/(:any)/(:any)'] = 'login/reset/$1/$2'; $route['tools/twitch/(:any)'] = 'tools/twitch?twich-channel=$1'; $route['projects/(:any)'] = 'projects/index/$1'; + $route['project/(:any)'] = 'projects/entry/$1'; $route['tools/encrypter/(:any)'] = 'tools/encrypter/index/$1'; \ No newline at end of file diff --git a/application/controllers/Search.php b/application/controllers/Search.php new file mode 100644 index 0000000..113e1a4 --- /dev/null +++ b/application/controllers/Search.php @@ -0,0 +1,53 @@ +load->model('SearchModel', '', TRUE); + $this->load->model('UserModel', '', TRUE); + $this->load->model('PostsModel', '', TRUE); + } + + public function index() + { + $query = html_escape($this->input->get('q')); + + $this->load->view('header', ['active' => 'search', 'title' => "Suche - $query", 'additionalStyles' => []]); + $this->load->view('search', ['query' => $query]); + $this->load->view('footer', ['additionalScripts' => ['search.js']]); + } + + public function getSearchResults() { + header('Content-Type: application/json;charset=utf-8'); + + $query = $this->input->post('query'); + + if(strlen($query) < 3) { + echo json_encode(['error' => true, 'message' => 'search-term']); + exit; + } + + $offset = filter_var($this->input->post('offset'), FILTER_VALIDATE_INT); + $filters = is_array($this->input->post('filters')) ? $this->input->post('filters') : []; + + $results = $this->SearchModel->search($query, 5, $offset, $filters); + + if(empty($results)) { + if($offset > 0) { + $message = 'no-further-results'; + } else { + $message = 'no-results'; + } + echo json_encode(['error' => true, 'message' => $message]); + exit; + } + + echo json_encode($results, JSON_UNESCAPED_UNICODE); + } + } diff --git a/application/language/de/search_lang.php b/application/language/de/search_lang.php new file mode 100644 index 0000000..c309221 --- /dev/null +++ b/application/language/de/search_lang.php @@ -0,0 +1,10 @@ +lang->load('search', $_SESSION['site_lang']); + } + + public function search($query, $amount, $offset, $filters) + { + $results = $this->getRawResults($query, $amount, $offset, $filters); + $results = $this->prepareResults($results); + return $results; + } + + private function getRawResults($query, $amount, $offset, $filters) + { + mb_language('uni'); + mb_internal_encoding('UTF-8'); + + $lang = $_SESSION['site_lang']; + + $query = strtolower($query); + $offset *= $amount; + + list($sql, $attr) = $this->buildQuery($filters); + $attr = str_split($attr); + foreach ($attr as $i => $a) { + $a = $a === 'l' ? $lang : $query; + $attr[$i] = $a; + } + $attr[] = $amount; + $attr[] = $offset; + + $this->db->cache_off(); + $results = $this->db->query($sql, $attr)->result_array(); + $this->db->cache_on(); + + return $results; + } + + private function buildQuery($filters) + { + $attributes = ''; + $query = 'SELECT a.*, u.username authorName, u.displayname authorDisplayname + FROM ('; + + $possibilities = [ + 'blogPost' => [ + 'sql' => 'SELECT "blogPost" type, bp.postUrl url, bp.postAuthorID author, bp.postImage image, bt.postTitle title, bt.postDesc content, bp.postPublishDate date + FROM blog_posts bp + INNER JOIN blog_translations bt ON bt.postID = bp.postID AND bt.language = ? + LEFT JOIN blog_content bc ON bc.postID = bp.postID AND bc.isActive = TRUE AND bc.language = ? + WHERE (LOWER(bt.postTitle) RLIKE ? + OR LOWER(bt.postDesc) RLIKE ? + OR LOWER(bc.content) RLIKE ? + OR bp.postID IN (SELECT bpt.post_id FROM blog_post_tags bpt WHERE bpt.tag_id IN(SELECT bt.ID FROM blog_tags bt WHERE bt.name RLIKE ? OR LOWER(bt.display_name) RLIKE ?)) + OR (SELECT username FROM users WHERE ID = bp.postAuthorID) RLIKE ? + OR (SELECT display_name FROM blog_categories WHERE ID = bp.postCategoryID) RLIKE ?) + AND postState = 1 AND postIsDeleted = FALSE', + 'attributes' => 'llqqqqqqq' + ], + 'blogCategory' => [ + 'sql' => 'SELECT "blogCategory" type, c.name url, 1 author, null image, c.display_name title, null content, null date + FROM blog_categories c + WHERE c.name RLIKE ? OR LOWER(c.display_name) RLIKE ?', + 'attributes' => 'qq' + ], + 'blogTag' => [ + 'sql' => 'SELECT "blogTag" type, t.name url, 1 author, null image, t.display_name title, null content, null date + FROM blog_tags t + WHERE t.name RLIKE ? OR LOWER(t.display_name) RLIKE ?', + 'attributes' => 'qq' + ], + 'user' => [ + 'sql' => 'SELECT "user" type, u.username url, u.ID author, u.header_image image, u.displayname title, u.about content, u.date_created date + FROM users u + WHERE (username RLIKE ? + OR lower(about) RLIKE ?) + AND is_activated AND isDeleted = FALSE', + 'attributes' => 'qq', + ], + 'userPost' => [ + 'sql' => 'SELECT "userPost" type, p.uuid url, p.user_id author, null image, p.content title, null content, p.date date + FROM user_posts p + WHERE LOWER(p.content) RLIKE ? + OR (SELECT username FROM users WHERE ID = p.user_id) RLIKE ?', + 'attributes' => 'qq', + ], + 'project' => [ + 'sql' => 'SELECT "project" type, p.name url, 1 as author, p.source image, t.title title, t.description content, p.datetime date + FROM projects p + INNER JOIN projects_translations t ON t.projectID = p.ID AND t.lang = ? + WHERE LOWER(t.title) RLIKE ? + OR LOWER(t.description) RLIKE ? + OR LOWER(t.content) RLIKE ?', + 'attributes' => 'lqqq', + ], + 'projectCategory' => [ + 'sql' => 'SELECT "projectCategory" type, c.collection url, 1 author, null image, c.displayname title, c.displayname content, null date + FROM projects_categories c + WHERE lower(collection) RLIKE ? + OR lower(displayname) RLIKE ?', + 'attributes' => 'qq' + ], + ]; + + $filters = array_intersect(array_keys($possibilities), $filters); + + if (empty($filters)) + $filters = array_keys($possibilities); + + foreach ($filters as $filter) { + $data = $possibilities[$filter]; + if (empty($data)) + continue; + + $query .= $data['sql']; + $query .= ' UNION '; + $attributes .= $data['attributes']; + } + + $query = substr($query, 0, -6); + + $query .= ') a + LEFT JOIN users u ON a.author = u.ID + ORDER BY date desc LIMIT ? OFFSET ?'; + + return [$query, $attributes]; + } + + private function prepareResults($results) + { + foreach ($results as $i => $result) { + list( + 'author' => $author, + 'authorDisplayname' => $displayname, + 'authorName' => $username, + 'content' => $content, + 'date' => $date, + 'image' => $image, + 'title' => $title, + 'type' => $type, + 'url' => $url, + ) = $result; + + $date = date('d.m.Y', strtotime($date)); + + if (strlen($title) > 75) { + $title = utf8_encode($title); + $title = substr($title, 0, 75) . '...'; + $title = utf8_decode($title); + } + + if (strlen($content) > 200) { + $content = utf8_encode($content); + $content = substr($content, 0, 200) . '...'; + $content = utf8_decode($content); + } + + $showUser = TRUE; + switch ($type) { + case 'blogPost': + $url = base_url('blog/post/' . $url); + break; + case 'project': + $url = base_url('project/' . $url); + break; + case 'projectCategory': + $url = base_url('projects/' . $url); + $showUser = FALSE; + break; + case 'user': + $url = base_url('user/' . $url); + break; + case 'userPost': + $url = base_url('user/' . $username . '/post/' . $url); + break; + } + + $type = lang('search_type_' . $type); + + $newArray = [ + 'showUser' => $showUser, + 'username' => $displayname, + 'authorUrl' => base_url('user/' . $username), + 'content' => $content, + 'date' => $date, + 'image' => $image, + 'title' => $title, + 'type' => $type, + 'url' => $url, + ]; + + + $results[$i] = $newArray; + } + + return $results; + } + + } \ No newline at end of file diff --git a/application/views/header.php b/application/views/header.php index 0ca27df..6a2f0f1 100644 --- a/application/views/header.php +++ b/application/views/header.php @@ -48,110 +48,111 @@ href="= base_url('lang/change/fr?r=' . urlencode(base64_encode(base_url(uri_string())))); ?>" hreflang="fr"> -
-