summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2019-06-10 20:48:15 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2019-06-10 20:48:15 +0100
commit94b448a70011b201a354fa7824dc5eb8b457f2ae (patch)
treebdce0862955e3c1af860573e683896551d54f9a1
parentReturn mime basic parts (diff)
downloadgentoobrowse-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.jam3
-rw-r--r--gentoobrowse-api/service/notifications/css/style.css50
-rw-r--r--gentoobrowse-api/service/notifications/xslt/base.xslt53
-rw-r--r--gentoobrowse-api/service/xsltStreamSerializer.cpp9
-rw-r--r--gentoobrowse-api/unittests/mockDefs.cpp32
-rw-r--r--gentoobrowse-api/unittests/mockDefs.h3
-rw-r--r--gentoobrowse-api/unittests/testNotifications.cpp16
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);