diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-08-14 13:03:08 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-08-23 13:53:50 +0200 |
commit | bcd246076540a8353fa55fc0a5e19343c1a2dbc9 (patch) | |
tree | 9fe2c24ca33b3d670267a5cbc8c8c756589f359b /brep/package-search.cxx | |
parent | 24903813d11813f8ff9ac906d23b21e6c33b981d (diff) |
Implement package search service mockup
Diffstat (limited to 'brep/package-search.cxx')
-rw-r--r-- | brep/package-search.cxx | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/brep/package-search.cxx b/brep/package-search.cxx new file mode 100644 index 0000000..3317d43 --- /dev/null +++ b/brep/package-search.cxx @@ -0,0 +1,154 @@ +// file : brep/package-search.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <brep/package-search> + +#include <string> +#include <memory> // make_shared() + +#include <xml/serializer> + +#include <odb/database.hxx> +#include <odb/transaction.hxx> + +#include <web/xhtml> +#include <web/module> +#include <web/mime-url-encoding> + +#include <brep/package> +#include <brep/package-odb> +#include <brep/shared-database> + +using namespace std; +using namespace cli; +using namespace odb::core; + +namespace brep +{ + void package_search:: + init (scanner& s) + { + MODULE_DIAG; + + options_ = make_shared<options::package_search> ( + s, unknown_mode::fail, unknown_mode::fail); + + db_ = shared_database (options_->db_host (), options_->db_port ()); + } + + void package_search:: + handle (request& rq, response& rs) + { + using namespace xml; + using namespace web; + using namespace web::xhtml; + + MODULE_DIAG; + + params::package_search pr; + + try + { + param_scanner s (rq.parameters ()); + pr = params::package_search (s, unknown_mode::fail, unknown_mode::fail); + } + catch (const unknown_argument& e) + { + throw invalid_request (400, e.what ()); + } + + // @@ Would be nice to have a manipulator identing string properly + // according to the most nested element identation. + // + const char* ident ("\n "); + const char* title ("Package Search"); + serializer s (rs.content (), title); + + s << HTML + << HEAD + << TITLE << title << ~TITLE + << STYLE(TYPE="text/css") << ident + << ".package {margin: 0 0 0.5em;}" << ident + << ".name a {text-decoration: none;}" << ident + << ".summary {font-size: small;}" + << ~STYLE + << ~HEAD + << BODY; + + string q ( + pr.query ().empty () ? "" : "q=" + mime_url_encode (pr.query ())); + + transaction t (db_->begin ()); + + // @@ Use appropriate view when clarify which package info to be displayed + // and search index structure get implemented. + // + using query = query<package>; + auto r ( + db_->query<package> ( + "ORDER BY" + query::name + + "OFFSET" + to_string (pr.page () * options_->results_on_page ()) + + "LIMIT" + to_string (options_->results_on_page ()))); + + for (const auto& p: r) + { + s << DIV(CLASS="package") + << DIV(CLASS="name") + << A + << HREF + << "/go/" << mime_url_encode (p.name); + + // Propagate search criteria to the package version search url. + // + if (!q.empty ()) + s << "?" << q; + + s << ~HREF + << p.name + << ~A + << ~DIV + << DIV(CLASS="summary") + << p.summary + << ~DIV + << ~DIV; + } + + t.commit (); + + if (pr.page () || r.size () == options_->results_on_page ()) + { + s << DIV; + + if (pr.page ()) + { + s << A + << HREF << "/?p=" << pr.page () - 1 + << (q.empty () ? "" : "&" + q) + << ~HREF + << "Previous" + << ~A + << " "; + } + + // @@ Not ideal as can produce link to an empty page, but easy to fix + // and most likelly will be replaced with something more meaningful + // based on knowing the total number of matched packages. + // + if (r.size () == options_->results_on_page ()) + { + s << A + << HREF << "/?p=" << pr.page () + 1 + << (q.empty () ? "" : "&" + q) + << ~HREF + << "Next" + << ~A; + } + + s << ~DIV; + } + + s << ~BODY + << ~HTML; + } +} |