diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2019-06-10 20:48:15 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2019-06-10 20:48:15 +0100 |
commit | 94b448a70011b201a354fa7824dc5eb8b457f2ae (patch) | |
tree | bdce0862955e3c1af860573e683896551d54f9a1 | |
parent | Return mime basic parts (diff) | |
download | gentoobrowse-api-94b448a70011b201a354fa7824dc5eb8b457f2ae.tar.bz2 gentoobrowse-api-94b448a70011b201a354fa7824dc5eb8b457f2ae.tar.xz gentoobrowse-api-94b448a70011b201a354fa7824dc5eb8b457f2ae.zip |
Split CSS into a related mime part not a big inlined mess
-rw-r--r-- | gentoobrowse-api/service/Jamfile.jam | 3 | ||||
-rw-r--r-- | gentoobrowse-api/service/notifications/css/style.css | 50 | ||||
-rw-r--r-- | gentoobrowse-api/service/notifications/xslt/base.xslt | 53 | ||||
-rw-r--r-- | gentoobrowse-api/service/xsltStreamSerializer.cpp | 9 | ||||
-rw-r--r-- | gentoobrowse-api/unittests/mockDefs.cpp | 32 | ||||
-rw-r--r-- | gentoobrowse-api/unittests/mockDefs.h | 3 | ||||
-rw-r--r-- | gentoobrowse-api/unittests/testNotifications.cpp | 16 |
7 files changed, 96 insertions, 70 deletions
diff --git a/gentoobrowse-api/service/Jamfile.jam b/gentoobrowse-api/service/Jamfile.jam index 164db97..bcd52ff 100644 --- a/gentoobrowse-api/service/Jamfile.jam +++ b/gentoobrowse-api/service/Jamfile.jam @@ -5,6 +5,7 @@ import generators : register-standard ; type.register XSLT : xslt ; generators.register-standard xxd.i : XSLT : C H ; +generators.register-standard xxd.i : CSS : C H ; actions xxd.i { @@ -23,7 +24,7 @@ lib systemd ; lib gentoobrowse-service++11 : [ glob-tree *.cpp : bin ] - [ glob-tree *.xslt ] + [ glob-tree *.xslt *.css ] [ glob-tree *.sql ] [ glob-tree *.ice ] : diff --git a/gentoobrowse-api/service/notifications/css/style.css b/gentoobrowse-api/service/notifications/css/style.css new file mode 100644 index 0000000..912234e --- /dev/null +++ b/gentoobrowse-api/service/notifications/css/style.css @@ -0,0 +1,50 @@ +body{position:relative;padding-top:40px} +body>.navbar{font-size:13px} +body>.navbar .brand{padding-right:0;padding-left:0;margin-left:20px;float:right;font-weight:bold;color:#000;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.125);-webkit-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear} +body>.navbar .brand:hover{text-decoration:none;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.4)} +section>.page-header{color:#5a5a5a} +.jumbotron{position:relative;padding:25px 0;color:#fff;text-align:center;text-shadow:0 1px 3px rgba(0,0,0,.4),0 0 30px rgba(0,0,0,.075);background:#020031;background:-moz-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-webkit-gradient(linear,left bottom,right top,color-stop(0,#020031),color-stop(100%,#6d3353));background:-webkit-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-o-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-ms-linear-gradient(45deg,#020031 0,#6d3353 100%);background:linear-gradient(45deg,#020031 0,#6d3353 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#020031',endColorstr='#6d3353',GradientType=1);-webkit-box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);-moz-box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2)} +.jumbotron h1{font-size:80px;font-weight:bold;letter-spacing:-1px;line-height:1} +.jumbotron .container{position:relative;z-index:2} +.jumbotron:after{content:'';display:block;position:absolute;top:0;right:0;bottom:0;left:0;opacity:.4} +@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (-o-min-device-pixel-ratio:2/1){ +.jumbotron:after{background-size:150px 150px} +} +.subhead{text-align:left;border-bottom:1px solid #ddd} +.subhead h1{font-size:50px} +.footer{text-align:center;padding:30px 0;margin-top:70px;border-top:1px solid #e5e5e5;background-color:#f5f5f5} +.footer p{margin-bottom:0;color:#777} +.footer-links{margin:10px 0} +.footer-links li{display:inline;padding:0 2px} +.footer-links li:first-child{padding-left:0} +.bs-docs-sidenav{width:208px;margin:20px 0 0;padding:0;background-color:#fff;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)} +.bs-docs-sidenav>li>a{display:block;width:190px \9;margin:0 0 -1px;padding:4px 10px;border:1px solid #e5e5e5} +.bs-docs-sidenav>li:first-child>a{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0} +.bs-docs-sidenav>li:last-child>a{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px} +.bs-docs-sidenav i{float:right;margin-top:2px;margin-right:-6px;opacity:.25} +.bs-docs-sidenav>li>a:hover{background-color:#f5f5f5} +.bs-docs-sidenav a:hover i{opacity:.5} +@media (min-width:1200px){ +.bs-docs-sidenav{width:258px} +.bs-docs-sidenav>li>a{width:230px \9} +} +@media (max-width:980px){body>.navbar-fixed-top .brand{float:left;margin-left:0;padding-left:10px;padding-right:10px} +.bs-docs-sidenav{top:0;width:218px;margin-top:30px;margin-right:0} +} +@media (min-width:768px) and (max-width:979px){body{padding-top:0} +.jumbotron{margin-top:-20px} +.bs-docs-sidenav{width:166px;margin-top:20px} +} +@media (max-width:767px){body{padding-top:0} +.jumbotron{padding:40px 20px;margin-top:-20px;margin-right:-20px;margin-left:-20px} +.bs-docs-sidenav{width:auto;margin-bottom:20px} +.footer{margin-left:-20px;margin-right:-20px;padding-left:20px;padding-right:20px} +.footer p{margin-bottom:9px} +} +@media (max-width:480px){body{padding-top:0} +.jumbotron h1{font-size:45px} +.subhead h1{text-align:center} +.footer{padding-top:20px;padding-bottom:20px} +} +a{cursor:pointer} +ul.footer-links li::before, ul.footer-links li:last-child::after {content:'·';color:#999} diff --git a/gentoobrowse-api/service/notifications/xslt/base.xslt b/gentoobrowse-api/service/notifications/xslt/base.xslt index fe45cba..e107902 100644 --- a/gentoobrowse-api/service/notifications/xslt/base.xslt +++ b/gentoobrowse-api/service/notifications/xslt/base.xslt @@ -10,58 +10,7 @@ <meta charset="utf-8" /> <link href="{$tbscdn}/css/bootstrap.min.css" rel="stylesheet" media="screen" /> <link href="{$tbscdn}/css/bootstrap-responsive.min.css" rel="stylesheet" media="screen" /> - <style media="screen"> -body{position:relative;padding-top:40px} -body>.navbar{font-size:13px} -body>.navbar .brand{padding-right:0;padding-left:0;margin-left:20px;float:right;font-weight:bold;color:#000;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.125);-webkit-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear} -body>.navbar .brand:hover{text-decoration:none;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.4)} -section>.page-header{color:#5a5a5a} -.jumbotron{position:relative;padding:25px 0;color:#fff;text-align:center;text-shadow:0 1px 3px rgba(0,0,0,.4),0 0 30px rgba(0,0,0,.075);background:#020031;background:-moz-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-webkit-gradient(linear,left bottom,right top,color-stop(0,#020031),color-stop(100%,#6d3353));background:-webkit-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-o-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-ms-linear-gradient(45deg,#020031 0,#6d3353 100%);background:linear-gradient(45deg,#020031 0,#6d3353 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#020031',endColorstr='#6d3353',GradientType=1);-webkit-box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);-moz-box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2)} -.jumbotron h1{font-size:80px;font-weight:bold;letter-spacing:-1px;line-height:1} -.jumbotron .container{position:relative;z-index:2} -.jumbotron:after{content:'';display:block;position:absolute;top:0;right:0;bottom:0;left:0;opacity:.4} -@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (-o-min-device-pixel-ratio:2/1){ -.jumbotron:after{background-size:150px 150px} -} -.subhead{text-align:left;border-bottom:1px solid #ddd} -.subhead h1{font-size:50px} -.footer{text-align:center;padding:30px 0;margin-top:70px;border-top:1px solid #e5e5e5;background-color:#f5f5f5} -.footer p{margin-bottom:0;color:#777} -.footer-links{margin:10px 0} -.footer-links li{display:inline;padding:0 2px} -.footer-links li:first-child{padding-left:0} -.bs-docs-sidenav{width:208px;margin:20px 0 0;padding:0;background-color:#fff;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)} -.bs-docs-sidenav>li>a{display:block;width:190px \9;margin:0 0 -1px;padding:4px 10px;border:1px solid #e5e5e5} -.bs-docs-sidenav>li:first-child>a{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0} -.bs-docs-sidenav>li:last-child>a{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px} -.bs-docs-sidenav i{float:right;margin-top:2px;margin-right:-6px;opacity:.25} -.bs-docs-sidenav>li>a:hover{background-color:#f5f5f5} -.bs-docs-sidenav a:hover i{opacity:.5} -@media (min-width:1200px){ -.bs-docs-sidenav{width:258px} -.bs-docs-sidenav>li>a{width:230px \9} -} -@media (max-width:980px){body>.navbar-fixed-top .brand{float:left;margin-left:0;padding-left:10px;padding-right:10px} -.bs-docs-sidenav{top:0;width:218px;margin-top:30px;margin-right:0} -} -@media (min-width:768px) and (max-width:979px){body{padding-top:0} -.jumbotron{margin-top:-20px} -.bs-docs-sidenav{width:166px;margin-top:20px} -} -@media (max-width:767px){body{padding-top:0} -.jumbotron{padding:40px 20px;margin-top:-20px;margin-right:-20px;margin-left:-20px} -.bs-docs-sidenav{width:auto;margin-bottom:20px} -.footer{margin-left:-20px;margin-right:-20px;padding-left:20px;padding-right:20px} -.footer p{margin-bottom:9px} -} -@media (max-width:480px){body{padding-top:0} -.jumbotron h1{font-size:45px} -.subhead h1{text-align:center} -.footer{padding-top:20px;padding-bottom:20px} -} -a{cursor:pointer} -ul.footer-links li::before, ul.footer-links li:last-child::after {content:'·';color:#999} - </style> + <link href="cid:style.css@gentoobrowse.randomdan.homeip.net" rel="stylesheet" media="screen" /> <title><xsl:call-template name="title" /></title> </head> <body data-spy="scroll" data-target=".bs-docs-sidebar"> diff --git a/gentoobrowse-api/service/xsltStreamSerializer.cpp b/gentoobrowse-api/service/xsltStreamSerializer.cpp index f796300..7df6f00 100644 --- a/gentoobrowse-api/service/xsltStreamSerializer.cpp +++ b/gentoobrowse-api/service/xsltStreamSerializer.cpp @@ -5,9 +5,11 @@ #include <processPipes.h> #include <sys/wait.h> #include <mimeImpl.h> +#include <notifications/css/style.h> namespace Gentoo { using namespace IceTray::Mime; + static const std::string css(style_css, style_css + style_css_len); static int xmlstrmclosecallback(void * context) { @@ -53,7 +55,12 @@ namespace Gentoo { xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(xmlstrmwritecallback, xmlstrmclosecallback, &strm, NULL); htmlDocContentDumpFormatOutput(buf, result, "utf-8", 0); xmlOutputBufferClose(buf); - return std::make_shared<TextPart>(Headers {}, "text/html", strm.str()); + return std::make_shared<MultiPart>(Headers {}, "related", Parts { + std::make_shared<TextPart>(Headers {}, "text/html", strm.str()), + std::make_shared<TextPart>(Headers { + { "Content-Id", "<style.css@gentoobrowse.randomdan.homeip.net>" }, + }, "text/css", css), + }); } IceTray::Mime::BasicPartPtr XsltStreamSerializer::getText(xmlDoc * result) diff --git a/gentoobrowse-api/unittests/mockDefs.cpp b/gentoobrowse-api/unittests/mockDefs.cpp index 1c93246..485426b 100644 --- a/gentoobrowse-api/unittests/mockDefs.cpp +++ b/gentoobrowse-api/unittests/mockDefs.cpp @@ -4,7 +4,6 @@ #include <tidy.h> #include <fstream> #include <mockMailServer.h> -#include <mimeImpl.h> #include <icecube.h> Service::Service() : @@ -50,22 +49,40 @@ TestClient::TestClient() : BOOST_REQUIRE(u); } -void -TestClient::lintable_test_files(std::string_view name, IceTray::Mail::EmailPtr e) +std::pair<IceTray::Mime::TextPart *, IceTray::Mime::TextPart *> +TestClient::humanReadableParts(IceTray::Mail::EmailPtr e) { BOOST_REQUIRE(e); - std::ofstream text((binDir / name).replace_extension("txt")); auto body = std::dynamic_pointer_cast<IceTray::Mime::BasicMultiPart>(e->content); BOOST_REQUIRE(body); BOOST_REQUIRE_EQUAL(2, body->parts.size()); - text << std::dynamic_pointer_cast<IceTray::Mime::TextPart>(body->parts[0])->payload; + + auto plainPart = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(body->parts[0]); + BOOST_REQUIRE(plainPart); + + auto htmlRel = std::dynamic_pointer_cast<IceTray::Mime::BasicMultiPart>(body->parts[1]); + BOOST_REQUIRE(htmlRel); + + BOOST_REQUIRE_GE(htmlRel->parts.size(), 1); + auto htmlPart = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(htmlRel->parts[0]); + BOOST_REQUIRE(htmlPart); + + return { plainPart.get(), htmlPart.get() }; +} + +void +TestClient::lintable_test_files(std::string_view name, IceTray::Mail::EmailPtr e) +{ + auto [ plainPart, htmlPart ] = humanReadableParts(e); + + std::ofstream text((binDir / name).replace_extension("txt")); + text << plainPart->payload; TidyDoc tdoc = tidyCreate(); BOOST_REQUIRE_EQUAL(1, tidyOptSetBool(tdoc, TidyIndentContent, yes)); BOOST_REQUIRE_EQUAL(1, tidyOptSetInt(tdoc, TidyWrapLen, 0)); - BOOST_REQUIRE_EQUAL(0, tidyParseString(tdoc, - std::dynamic_pointer_cast<IceTray::Mime::TextPart>(body->parts[1])->payload.c_str())); + BOOST_REQUIRE_EQUAL(0, tidyParseString(tdoc, htmlPart->payload.c_str())); BOOST_REQUIRE_EQUAL(0, tidyCleanAndRepair(tdoc)); BOOST_REQUIRE_EQUAL(0, tidySaveFile(tdoc, (binDir / name).replace_extension(".html").c_str())); BOOST_REQUIRE_EQUAL(0, tidyRunDiagnostics(tdoc)); @@ -77,6 +94,7 @@ TestClient::lintable_test_files(std::string_view name, IceTray::Mail::EmailPtr e fputs("From: dan@randomdan.homeip.net\r\n", eml); fputs("Return-path: <dan@randomdan.homeip.net>\r\n", eml); fputs("Date: Tue, 7 May 2019 19:50:44 +0100\r\n", eml); + e->content->write({ eml }, 0); fclose(eml); } diff --git a/gentoobrowse-api/unittests/mockDefs.h b/gentoobrowse-api/unittests/mockDefs.h index 762a589..ee53b0a 100644 --- a/gentoobrowse-api/unittests/mockDefs.h +++ b/gentoobrowse-api/unittests/mockDefs.h @@ -10,6 +10,7 @@ #include <notifications.h> #include <selectcommandUtil.impl.h> #include <boost/test/unit_test.hpp> +#include <mimeImpl.h> class DLL_PUBLIC Service : public IceTray::DryIce, DB::PluginMock<PQ::Mock> { public: @@ -37,6 +38,8 @@ class DLL_PUBLIC TestClient : public IceTray::DryIceClient { Gentoo::UsersPrxPtr u; void lintable_test_files(std::string_view name, IceTray::Mail::EmailPtr e); + std::pair<IceTray::Mime::TextPart *, IceTray::Mime::TextPart *> + humanReadableParts(IceTray::Mail::EmailPtr e); }; #define SQL_REQUIRE_EQUAL(sql, type, expected) BOOST_TEST_CONTEXT(sql) { sqlRequireEqual<type>(db, sql, expected); } diff --git a/gentoobrowse-api/unittests/testNotifications.cpp b/gentoobrowse-api/unittests/testNotifications.cpp index d961412..fb105b8 100644 --- a/gentoobrowse-api/unittests/testNotifications.cpp +++ b/gentoobrowse-api/unittests/testNotifications.cpp @@ -33,7 +33,9 @@ commonAssert(IceTray::Mail::EmailPtr e) BOOST_REQUIRE(plain); BOOST_REQUIRE_EQUAL(plain->mimetype, "text/plain"); BOOST_REQUIRE(!isHtml(plain->payload)); - auto html = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(body->parts[1]); + auto htmlRel = std::dynamic_pointer_cast<IceTray::Mime::BasicMultiPart>(body->parts[1]); + BOOST_REQUIRE(htmlRel); + auto html = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(htmlRel->parts[0]); BOOST_REQUIRE(html); BOOST_REQUIRE_EQUAL(html->mimetype, "text/html"); BOOST_REQUIRE(isHtml(html->payload)); @@ -62,10 +64,8 @@ BOOST_AUTO_TEST_CASE( testSignup ) BOOST_REQUIRE_EQUAL(e->to.address, "test@user.com"); commonAssert(e); lintable_test_files("signup", e); - auto body = std::dynamic_pointer_cast<IceTray::Mime::BasicMultiPart>(e->content); - BOOST_REQUIRE(body); - for (auto p : body->parts) { - auto text = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(p); + auto [ plainPart, htmlPart ] = humanReadableParts(e); + for (auto text : { plainPart, htmlPart }) { BOOST_REQUIRE(text); BOOST_REQUIRE(text->payload.find("Welcome to Gentoo Browse") != std::string::npos); BOOST_REQUIRE(text->payload.find("https://gentoobrowse.randomdan.homeip.net/user/verification/some-guid/testuser") != std::string::npos); @@ -102,10 +102,8 @@ BOOST_AUTO_TEST_CASE( testNews ) auto e = n->getNews(u, nc); commonAssert(e); lintable_test_files("news", e); - auto body = std::dynamic_pointer_cast<IceTray::Mime::BasicMultiPart>(e->content); - BOOST_REQUIRE(body); - for (auto p : body->parts) { - auto text = std::dynamic_pointer_cast<IceTray::Mime::TextPart>(p); + auto [ plainPart, htmlPart ] = humanReadableParts(e); + for (auto text : { plainPart, htmlPart }) { BOOST_REQUIRE(text); BOOST_REQUIRE(text->payload.find("Latest news") != std::string::npos); BOOST_REQUIRE(text->payload.find("https://gentoobrowse.randomdan.homeip.net/packages/app-test") != std::string::npos); |