From 6eca8a647c79e9a5b100672b55f5d02273a28772 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 16 Nov 2015 12:08:41 +0200 Subject: Implement 'about' web page --- brep/buildfile | 4 +- brep/options.cli | 4 ++ brep/package-details.cxx | 5 +-- brep/package-search.cxx | 6 +-- brep/package-version-details.cxx | 7 ++- brep/page | 22 ++++++--- brep/page.cxx | 65 ++++++++++++++++++++++++--- brep/repository-details | 32 ++++++++++++++ brep/repository-details.cxx | 96 ++++++++++++++++++++++++++++++++++++++++ brep/services.cxx | 7 +++ 10 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 brep/repository-details create mode 100644 brep/repository-details.cxx (limited to 'brep') diff --git a/brep/buildfile b/brep/buildfile index 6676095..464118d 100644 --- a/brep/buildfile +++ b/brep/buildfile @@ -22,8 +22,8 @@ libso{brep}: cxx.export.poptions = -I$out_root -I$src_root import libs += libstudxml%lib{studxml} brep = cxx{diagnostics module services package-search package-details \ - package-version-details shared-database page types-parsers} \ - cli.cxx{options} + package-version-details repository-details shared-database page \ + types-parsers} cli.cxx{options} web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding} diff --git a/brep/options.cli b/brep/options.cli index 6c3c7f1..77dc45a 100644 --- a/brep/options.cli +++ b/brep/options.cli @@ -43,6 +43,10 @@ namespace brep std::uint16_t description-length = 400; std::uint16_t changes-length = 800; }; + + class repository_details: module, db + { + }; } // Web module HTTP request parameters. diff --git a/brep/package-details.cxx b/brep/package-details.cxx index ef787b0..780d98a 100644 --- a/brep/package-details.cxx +++ b/brep/package-details.cxx @@ -61,7 +61,6 @@ namespace brep void package_details:: handle (request& rq, response& rs) { - using namespace xml; using namespace web; using namespace web::xhtml; @@ -108,7 +107,7 @@ namespace brep return u; }); - serializer s (rs.content (), name); + xml::serializer s (rs.content (), name); const string& title (sq.empty () ? name : name + " " + sq); static const path sp ("package-details.css"); @@ -219,7 +218,7 @@ namespace brep // // Hm, I am not so sure about this. Consider: stable/testing/unstable. // - s << TR_LOCATION (p->internal_repository.object_id ()) + s << TR_LOCATION (p->internal_repository.object_id (), rt) << TR_DEPENDS (p->dependencies, rt) << TR_REQUIRES (p->requirements) << ~TBODY diff --git a/brep/package-search.cxx b/brep/package-search.cxx index b0352f3..1617e58 100644 --- a/brep/package-search.cxx +++ b/brep/package-search.cxx @@ -57,8 +57,6 @@ namespace brep void package_search:: handle (request& rq, response& rs) { - using namespace xml; - using namespace web; using namespace web::xhtml; MODULE_DIAG; @@ -82,10 +80,10 @@ namespace brep } const string& sq (pr.query ()); // Search query. - string qp (sq.empty () ? "" : "q=" + mime_url_encode (sq)); + string qp (sq.empty () ? "" : "q=" + web::mime_url_encode (sq)); size_t pg (pr.page ()); - serializer s (rs.content (), "Packages"); + xml::serializer s (rs.content (), "Packages"); const string& title ( sq.empty () ? s.output_name () : s.output_name () + " " + sq); diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx index b8f30ff..d00c10a 100644 --- a/brep/package-version-details.cxx +++ b/brep/package-version-details.cxx @@ -46,7 +46,6 @@ namespace brep void package_version_details:: handle (request& rq, response& rs) { - using namespace xml; using namespace web; using namespace web::xhtml; @@ -99,7 +98,7 @@ namespace brep return u; }); - serializer s (rs.content (), name); + xml::serializer s (rs.content (), name); static const path go ("go"); static const path sp ("package-version-details.css"); @@ -171,7 +170,7 @@ namespace brep << TR_PRIORITY (p->priority) << TR_LICENSES (p->license_alternatives) - << TR_LOCATION (p->internal_repository.object_id ()) + << TR_LOCATION (p->internal_repository.object_id (), rt) << TR_DOWNLOAD (du) << ~TBODY << ~TABLE @@ -249,7 +248,7 @@ namespace brep s << ' ' << A(HREF=u / path (p->version.string ())) << *dc << ~A; } else - // Display the dependency as a plain text in no repository URL + // Display the dependency as a plain text if no repository URL // available. // s << d; diff --git a/brep/page b/brep/page index c968389..0d0887f 100644 --- a/brep/page +++ b/brep/page @@ -22,8 +22,7 @@ namespace brep class CSS_LINKS { public: - CSS_LINKS (const path& p, const dir_path& r): - path_ (p), root_ (r) {} + CSS_LINKS (const path& p, const dir_path& r): path_ (p), root_ (r) {} void operator() (xml::serializer& s) const; @@ -263,13 +262,15 @@ namespace brep class TR_LOCATION { public: - TR_LOCATION (const std::string& l): location_ (l) {} + TR_LOCATION (const std::string& n, const dir_path& r) + : name_ (n), root_ (r) {} void operator() (xml::serializer& s) const; private: - const std::string& location_; + const std::string& name_; + const dir_path& root_; }; // Generates package download URL element. @@ -307,13 +308,13 @@ namespace brep public: // Genereate full description. // - P_DESCRIPTION (const std::string& d) - : description_ (d), length_ (d.size ()), url_ (nullptr) {} + P_DESCRIPTION (const std::string& d, bool u = true) + : description_ (d), length_ (d.size ()), url_ (nullptr), unique_ (u) {} // Genereate brief description. // P_DESCRIPTION (const std::string& d, size_t l, const std::string& u) - : description_ (d), length_ (l), url_ (&u) {} + : description_ (d), length_ (l), url_ (&u), unique_ (false) {} void operator() (xml::serializer& s) const; @@ -322,6 +323,7 @@ namespace brep const std::string& description_; std::size_t length_; const std::string* url_; // Full page url. + bool unique_; }; // Generates package description element. @@ -369,6 +371,12 @@ namespace brep std::size_t page_number_count_; const std::string& url_; }; + + // Convert the argument to a string representing the valid HTML 5 'id' + // attribute value. + // + std::string + id_attribute (const std::string& v); } #endif // BREP_PAGE diff --git a/brep/page.cxx b/brep/page.cxx index fbbcda8..5b650a3 100644 --- a/brep/page.cxx +++ b/brep/page.cxx @@ -5,10 +5,13 @@ #include #include +#include // hex, uppercase, right #include #include // shared_ptr #include // size_t #include +#include +#include // setw(), setfill() #include // min() #include @@ -27,6 +30,7 @@ using namespace web::xhtml; namespace brep { static const path go ("go"); + static const path about ("about"); // CSS_LINKS // @@ -44,12 +48,10 @@ namespace brep void DIV_HEADER:: operator() (serializer& s) const { - static const path a ("about"); - s << DIV(ID="header") << DIV(ID="header-menu") << A(HREF=root_) << "packages" << ~A - << A(HREF=root_ / a) << "about" << ~A + << A(HREF=root_ / about) << "about" << ~A << ~DIV << ~DIV; } @@ -305,7 +307,7 @@ namespace brep else if (p->internal ()) s << A(HREF=root_ / go / path (en)) << n << ~A; else - // Display the dependency as a plain text in no repository URL + // Display the dependency as a plain text if no repository URL // available. // s << n; @@ -440,7 +442,16 @@ namespace brep { s << TR(CLASS="location") << TH << "location" << ~TH - << TD << SPAN(CLASS="value") << location_ << ~SPAN << ~TD + << TD + << SPAN(CLASS="value") + << A + << HREF + << root_ / about << "#" << mime_url_encode (id_attribute (name_)) + << ~HREF + << name_ + << ~A + << ~SPAN + << ~TD << ~TR; } @@ -486,7 +497,10 @@ namespace brep // Format the description into paragraphs, recognizing a blank line as // paragraph separator, and replacing single newlines with a space. // - s << P(ID="description"); + s << P; + + if (unique_) + s << ID("description"); bool nl (false); // The previous character is '\n'. for (const auto& c: d) @@ -614,4 +628,43 @@ namespace brep s << ~DIV; } } + + // Convert the argument to a string conformant to the section + // "3.2.5.1 The id attribute" of the HTML 5 specification at + // http://www.w3.org/TR/html5/dom.html#the-id-attribute. + // + string + id_attribute (const string& v) + { + ostringstream o; + o << hex << uppercase << right << setfill ('0'); + + // Replace space characters (as specified at + // http://www.w3.org/TR/html5/infrastructure.html#space-character) with + // the respective escape sequences. + // + for (auto c: v) + { + switch (c) + { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + case '~': + { + // Intentionally use '~' as an escape character to leave it unescaped + // being a part of URL. For example + // http://cppget.org/about#cppget.org%2Fmath~20lab + // + o << "~" << setw (2) << static_cast (c); + break; + } + default: o << c; break; + } + } + + return o.str (); + } } diff --git a/brep/repository-details b/brep/repository-details new file mode 100644 index 0000000..a3008dc --- /dev/null +++ b/brep/repository-details @@ -0,0 +1,32 @@ +// file : brep/repository-details -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_REPOSITORY_DETAILS +#define BREP_REPOSITORY_DETAILS + +#include // shared_ptr + +#include // database + +#include +#include + +namespace brep +{ + class repository_details: public module + { + private: + virtual void + handle (request&, response&); + + virtual void + init (cli::scanner&); + + private: + std::shared_ptr options_; + std::shared_ptr db_; + }; +} + +#endif // BREP_REPOSITORY_DETAILS diff --git a/brep/repository-details.cxx b/brep/repository-details.cxx new file mode 100644 index 0000000..4302c15 --- /dev/null +++ b/brep/repository-details.cxx @@ -0,0 +1,96 @@ +// file : brep/repository-details.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include // make_shared() + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace odb::core; + +namespace brep +{ + using namespace cli; + + void repository_details:: + init (scanner& s) + { + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + db_ = shared_database (options_->db_host (), options_->db_port ()); + } + + void repository_details:: + handle (request&, response& rs) + { + using namespace web::xhtml; + + MODULE_DIAG; + + // The module options object is not changed after being created once per + // server process. + // + static const dir_path& rt (options_->root ()); + + xml::serializer s (rs.content (), "About"); + const string& title (s.output_name ()); + static const path sp ("repository-details.css"); + + s << HTML + << HEAD + << TITLE << title << ~TITLE + << CSS_LINKS (sp, rt) + << ~HEAD + << BODY + << DIV_HEADER (rt) + << DIV(ID="content"); + + transaction t (db_->begin ()); + + using query = query; + auto rp (db_->query (query::internal + "ORDER BY name")); + + for (const auto& r: rp) + { + string id (id_attribute (r.name)); + s << H1(ID=id) + << A(HREF="#" + web::mime_url_encode (id)) << r.name << ~A + << ~H1; + + if (r.email) + s << A << HREF << "mailto:" << *r.email << ~HREF << *r.email << ~A; + + if (r.summary) + s << H2 << *r.summary << ~H2; + + if (r.description) + s << P_DESCRIPTION (*r.description, false); + } + + t.commit (); + + s << ~DIV + << ~BODY + << ~HTML; + } +} diff --git a/brep/services.cxx b/brep/services.cxx index 9b7043c..e41d3f3 100644 --- a/brep/services.cxx +++ b/brep/services.cxx @@ -8,6 +8,7 @@ #include #include +#include #include using namespace brep; @@ -30,3 +31,9 @@ service AP_MODULE_DECLARE_DATA package_version_details_srv ( "package-version-details", package_version_details_mod, {"root", "db-host", "db-port", "conf"}); + +static repository_details repository_details_mod; +service AP_MODULE_DECLARE_DATA repository_details_srv ( + "repository-details", + repository_details_mod, + {"root", "db-host", "db-port", "conf"}); -- cgit v1.1