summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2017-01-03 21:05:48 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2017-01-03 21:05:48 +0000
commit80cc06c81d6ef331cd18d50818f0512393cf3811 (patch)
treeece641b3bf75a35a122a8ca880e55594945c8dc2
parentAdd fields/members/functions for storing a user's signup date and when they l... (diff)
downloadgentoobrowse-api-80cc06c81d6ef331cd18d50818f0512393cf3811.tar.bz2
gentoobrowse-api-80cc06c81d6ef331cd18d50818f0512393cf3811.tar.xz
gentoobrowse-api-80cc06c81d6ef331cd18d50818f0512393cf3811.zip
Implement sending emails of news ebuilds and signup verification
-rw-r--r--gentoobrowse-api/api/maintenance.ice5
-rw-r--r--gentoobrowse-api/domain/news-models.ice26
-rw-r--r--gentoobrowse-api/service/maintenanceCommon.cpp54
-rw-r--r--gentoobrowse-api/service/maintenanceimpl.h2
-rw-r--r--gentoobrowse-api/service/notifications/notifications.ice8
-rw-r--r--gentoobrowse-api/service/sql/maintenance/getNotificationEbuildLists.sql11
-rw-r--r--gentoobrowse-api/service/usersimpl.cpp18
-rw-r--r--gentoobrowse-api/unittests/Jamfile.jam9
-rw-r--r--gentoobrowse-api/unittests/testNotificationsTriggers.cpp50
-rw-r--r--gentoobrowse-api/unittests/testUsers.cpp6
10 files changed, 177 insertions, 12 deletions
diff --git a/gentoobrowse-api/api/maintenance.ice b/gentoobrowse-api/api/maintenance.ice
index 013acb3..736b913 100644
--- a/gentoobrowse-api/api/maintenance.ice
+++ b/gentoobrowse-api/api/maintenance.ice
@@ -1,3 +1,5 @@
+#include <news-models.ice>
+
module Gentoo {
["cpp:ice_print"]
exception GitError {
@@ -5,10 +7,13 @@ module Gentoo {
int errorClass;
string message;
};
+
interface Maintenance {
idempotent void refreshPackageTree();
idempotent void refreshBugs();
idempotent void refreshChangeLogs() throws GitError;
+ UserNews getUserNews();
+ void sendNotifications();
};
};
diff --git a/gentoobrowse-api/domain/news-models.ice b/gentoobrowse-api/domain/news-models.ice
new file mode 100644
index 0000000..0b7021f
--- /dev/null
+++ b/gentoobrowse-api/domain/news-models.ice
@@ -0,0 +1,26 @@
+#ifndef GENTOO_NEWS_MODELS
+#define GENTOO_NEWS_MODELS
+
+#include <portage-models.ice>
+
+module Gentoo {
+ struct NewsContentTrigger {
+ int userid;
+ IntList ebuildids;
+ IntList packageids;
+ IntList categoryids;
+ };
+
+ sequence<NewsContentTrigger> NewsContentTriggers;
+
+ struct NewsContent {
+ Categories categories;
+ Packages packages;
+ Ebuilds ebuilds;
+ };
+
+ dictionary<int, NewsContent> UserNews;
+};
+
+#endif
+
diff --git a/gentoobrowse-api/service/maintenanceCommon.cpp b/gentoobrowse-api/service/maintenanceCommon.cpp
index 49101ee..8a55087 100644
--- a/gentoobrowse-api/service/maintenanceCommon.cpp
+++ b/gentoobrowse-api/service/maintenanceCommon.cpp
@@ -1,9 +1,11 @@
#include "maintenanceimpl.h"
#include <Ice/ObjectAdapter.h>
#include <Ice/Communicator.h>
-#include <tablepatch.h>
-#include "utils/dbUtils.h"
-#include "sql/maintenance/bugAssociate.sql.h"
+#include <notifications.h>
+#include <portage.h>
+#include <users.h>
+#include <safeMapFind.h>
+#include "sql/maintenance/getNotificationEbuildLists.sql.h"
namespace Gentoo {
namespace Service {
@@ -12,6 +14,52 @@ namespace Gentoo {
{
return c.adapter->getCommunicator()->getProperties();
}
+
+ Gentoo::UserNews
+ Maintenance::getUserNews(const Ice::Current & current)
+ {
+ auto portage = PortagePrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("portage"));
+ portage->ice_ping();
+ auto categories = portage->getAllCategories();
+
+ UserNews un;
+ auto t = fetch<NewsContentTriggers>(sql::maintenance::getNotificationEbuildLists);
+ std::transform(t.begin(), t.end(), std::inserter(un, un.end()), [&categories,&portage](const NewsContentTriggers::value_type & t) {
+ NewsContent nc;
+ std::copy_if(categories.begin(), categories.end(), std::back_inserter(nc.categories), [&t](const Gentoo::CategoryPtr & c) {
+ return AdHoc::containerContains(t.categoryids, c->categoryid);
+ });
+ for (auto pid : t.packageids) {
+ auto par = portage->begin_getPackage(pid);
+ auto vsar = portage->begin_getPackageVersions(pid);
+ nc.packages.push_back(portage->end_getPackage(par));
+ auto vs = portage->end_getPackageVersions(vsar);
+ std::copy_if(vs.begin(), vs.end(), std::back_inserter(nc.ebuilds), [&t](const Gentoo::EbuildPtr & v) {
+ return AdHoc::containerContains(t.ebuildids, v->ebuildid);
+ });
+ }
+ return UserNews::value_type(t.userid, nc);
+ });
+ return un;
+ }
+
+ void
+ Maintenance::sendNotifications(const Ice::Current & current)
+ {
+ auto notifications = NotificationsPrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("notifications"));
+ notifications->ice_ping();
+ auto mailServer = MailServerPrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("mailserver"));
+ mailServer->ice_ping();
+ auto users = UsersPrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("users"));
+ users->ice_ping();
+
+ for (const auto & trigger : getUserNews(current)) {
+ auto user = users->get(trigger.first);
+ auto email = notifications->getNews(user, trigger.second);
+ mailServer->sendEmail(email);
+ users->mailshotsent(user->userid);
+ }
+ }
}
}
diff --git a/gentoobrowse-api/service/maintenanceimpl.h b/gentoobrowse-api/service/maintenanceimpl.h
index c150043..dc6cbbf 100644
--- a/gentoobrowse-api/service/maintenanceimpl.h
+++ b/gentoobrowse-api/service/maintenanceimpl.h
@@ -38,6 +38,8 @@ namespace Gentoo {
void refreshPackageTree(const Ice::Current &) override;
void refreshBugs(const Ice::Current &) override;
void refreshChangeLogs(const Ice::Current &) override;
+ Gentoo::UserNews getUserNews(const Ice::Current &) override;
+ void sendNotifications(const Ice::Current &) override;
private:
void updateFileTypes(DB::Connection *) const;
diff --git a/gentoobrowse-api/service/notifications/notifications.ice b/gentoobrowse-api/service/notifications/notifications.ice
index a60fa28..4a2673f 100644
--- a/gentoobrowse-api/service/notifications/notifications.ice
+++ b/gentoobrowse-api/service/notifications/notifications.ice
@@ -2,7 +2,7 @@
#define GENTOO_NOTIFICATIONS
#include <user-models.ice>
-#include <portage-models.ice>
+#include <news-models.ice>
module Gentoo {
class MimePart {
@@ -29,12 +29,6 @@ module Gentoo {
string message;
};
- struct NewsContent {
- Categories categories;
- Packages packages;
- Ebuilds ebuilds;
- };
-
interface Notifications {
Email getSignup(NewUser user);
Email getNews(User user, NewsContent nc);
diff --git a/gentoobrowse-api/service/sql/maintenance/getNotificationEbuildLists.sql b/gentoobrowse-api/service/sql/maintenance/getNotificationEbuildLists.sql
new file mode 100644
index 0000000..35453fc
--- /dev/null
+++ b/gentoobrowse-api/service/sql/maintenance/getNotificationEbuildLists.sql
@@ -0,0 +1,11 @@
+SELECT u.userid,
+ array_agg(DISTINCT e.ebuildid) ebuildids,
+ array_agg(DISTINCT p.packageid) packageids,
+ array_agg(DISTINCT p.categoryid) categoryids
+FROM gentoobrowse.users u, gentoobrowse.user_packages up, gentoobrowse.ebuilds e, gentoobrowse.packages p
+WHERE u.userid = up.userid
+AND p.packageid = e.packageid
+AND up.trackedsince < e.firstseen
+AND up.packageid = e.packageid
+AND coalesce(u.lastmailshot, u.signedup) < e.firstseen
+GROUP BY u.userid
diff --git a/gentoobrowse-api/service/usersimpl.cpp b/gentoobrowse-api/service/usersimpl.cpp
index c2f45a7..60d0b64 100644
--- a/gentoobrowse-api/service/usersimpl.cpp
+++ b/gentoobrowse-api/service/usersimpl.cpp
@@ -1,4 +1,6 @@
#include "usersimpl.h"
+#include <Ice/ObjectAdapter.h>
+#include <Ice/Communicator.h>
#include <modifycommand.h>
#include <sql/users/authenticate.sql.h>
#include <sql/users/verify.sql.h>
@@ -10,6 +12,7 @@
#include <sql/users/untrack.sql.h>
#include <sql/users/tracked.sql.h>
#include <sql/users/mailshotsent.sql.h>
+#include <notifications.h>
namespace Gentoo {
namespace Service {
@@ -43,9 +46,20 @@ Users::find(const std::string & username, const Ice::Current &)
}
Gentoo::NewUserPtr
-Users::create(const std::string & username, const std::string & password, const std::string & realname, const std::string & email, const Ice::Current &)
+Users::create(const std::string & username, const std::string & password, const std::string & realname, const std::string & email, const Ice::Current & current)
{
- return fetch<Gentoo::NewUserPtr>(sql::users::create, username, password, realname, email);
+ auto notifications = NotificationsPrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("notifications"));
+ notifications->ice_ping();
+ auto mailServer = MailServerPrx::checkedCast(current.adapter->getCommunicator()->stringToProxy("mailserver"));
+ mailServer->ice_ping();
+
+ auto dbc = db->get();
+ DB::TransactionScope tx(dbc.get());
+ auto newUser = fetch<Gentoo::NewUserPtr>(sql::users::create, username, password, realname, email);
+ auto mail = notifications->getSignup(newUser);
+ mailServer->sendEmail(mail);
+
+ return newUser;
}
void
diff --git a/gentoobrowse-api/unittests/Jamfile.jam b/gentoobrowse-api/unittests/Jamfile.jam
index 60ee5e6..ba030eb 100644
--- a/gentoobrowse-api/unittests/Jamfile.jam
+++ b/gentoobrowse-api/unittests/Jamfile.jam
@@ -112,6 +112,15 @@ run
: testNotifications ;
run
+ testNotificationsTriggers.cpp
+ : : :
+ <dependency>../db/schema.sql
+ <define>BOOST_TEST_DYN_LINK
+ <library>testCommon
+ <implicit-dependency>testCommon
+ : testNotificationsTriggers ;
+
+run
testBugs.cpp
: : :
<dependency>../db/schema.sql
diff --git a/gentoobrowse-api/unittests/testNotificationsTriggers.cpp b/gentoobrowse-api/unittests/testNotificationsTriggers.cpp
new file mode 100644
index 0000000..6455627
--- /dev/null
+++ b/gentoobrowse-api/unittests/testNotificationsTriggers.cpp
@@ -0,0 +1,50 @@
+#define BOOST_TEST_MODULE TestNotificationsTriggers
+#include <boost/test/unit_test.hpp>
+
+#include "mockDefs.h"
+
+BOOST_GLOBAL_FIXTURE( Service );
+
+BOOST_FIXTURE_TEST_SUITE(tp, TestClient);
+
+BOOST_AUTO_TEST_CASE( triggers )
+{
+ auto t = m->getUserNews();
+ BOOST_REQUIRE_EQUAL(1, t.size());
+ BOOST_REQUIRE_EQUAL(1, t.begin()->first);
+ BOOST_REQUIRE_EQUAL(2, t.begin()->second.categories.size());
+ std::sort(t.begin()->second.categories.begin(), t.begin()->second.categories.end(), [](auto a, auto b) { return a->categoryid < b->categoryid; });
+ BOOST_REQUIRE_EQUAL(311, t.begin()->second.categories[0]->categoryid);
+ BOOST_REQUIRE_EQUAL(313, t.begin()->second.categories[1]->categoryid);
+ BOOST_REQUIRE_EQUAL(2, t.begin()->second.packages.size());
+ std::sort(t.begin()->second.packages.begin(), t.begin()->second.packages.end(), [](auto a, auto b) { return a->packageid < b->packageid; });
+ BOOST_REQUIRE_EQUAL(49517, t.begin()->second.packages[0]->packageid);
+ BOOST_REQUIRE_EQUAL(54144, t.begin()->second.packages[1]->packageid);
+ BOOST_REQUIRE_EQUAL(7, t.begin()->second.ebuilds.size());
+ std::sort(t.begin()->second.ebuilds.begin(), t.begin()->second.ebuilds.end(), [](auto a, auto b) { return a->ebuildid < b->ebuildid; });
+ BOOST_REQUIRE_EQUAL(657508, t.begin()->second.ebuilds[0]->ebuildid);
+ BOOST_REQUIRE_EQUAL(657509, t.begin()->second.ebuilds[1]->ebuildid);
+ BOOST_REQUIRE_EQUAL(658228, t.begin()->second.ebuilds[2]->ebuildid);
+ BOOST_REQUIRE_EQUAL(658511, t.begin()->second.ebuilds[3]->ebuildid);
+ BOOST_REQUIRE_EQUAL(659908, t.begin()->second.ebuilds[4]->ebuildid);
+ BOOST_REQUIRE_EQUAL(660220, t.begin()->second.ebuilds[5]->ebuildid);
+ BOOST_REQUIRE_EQUAL(680613, t.begin()->second.ebuilds[6]->ebuildid);
+}
+
+BOOST_AUTO_TEST_CASE( send )
+{
+ auto ms = getProxy<Gentoo::MockMailServerPrx>("mailserver");
+ BOOST_REQUIRE(ms);
+
+ BOOST_REQUIRE(!u->get(1)->lastmailshot);
+ m->sendNotifications();
+ BOOST_REQUIRE(u->get(1)->lastmailshot);
+ const auto & es = ms->getSentEmails();
+ BOOST_REQUIRE_EQUAL(1, es.size());
+ BOOST_REQUIRE_EQUAL("Gentoo Browse: Latest updates", es[0]->subject);
+ BOOST_REQUIRE_EQUAL("Dan Goodliffe", es[0]->to.name);
+ BOOST_REQUIRE_EQUAL("Gentoo Browse", es[0]->from.name);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/gentoobrowse-api/unittests/testUsers.cpp b/gentoobrowse-api/unittests/testUsers.cpp
index e515b77..7f9eaee 100644
--- a/gentoobrowse-api/unittests/testUsers.cpp
+++ b/gentoobrowse-api/unittests/testUsers.cpp
@@ -43,7 +43,13 @@ BOOST_AUTO_TEST_CASE( authenticateVerify )
BOOST_AUTO_TEST_CASE( create )
{
+ auto ms = getProxy<Gentoo::MockMailServerPrx>("mailserver");
+ BOOST_REQUIRE(ms);
auto user = u->create("testuser", "testpass", "Test User", "test@user.com");
+ BOOST_REQUIRE_EQUAL(1, ms->getSentEmails().size());
+ BOOST_REQUIRE_EQUAL("Gentoo Browse: Welcome", ms->getSentEmails().front()->subject);
+ BOOST_REQUIRE_EQUAL("test@user.com", ms->getSentEmails().front()->to.address);
+ BOOST_REQUIRE_EQUAL("Test User", ms->getSentEmails().front()->to.name);
BOOST_REQUIRE_EQUAL(3, user->userid);
BOOST_REQUIRE_EQUAL("testuser", user->username);
BOOST_REQUIRE_EQUAL("Test User", user->userrealname);