1 /**
2 	Copyright: © 2014 rejectedsoftware e.K.
3 	License: Subject to the terms of the GNU GPLv3 license, as written in the included LICENSE.txt file.
4 	Authors: Sönke Ludwig
5 */
6 module dubregistry.notificationcenter;
7 
8 import dubregistry.scheduler;
9 
10 import std.datetime;
11 import std.encoding : sanitize;
12 import std.string : format;
13 import userman.db.controller;
14 import vibe.core.log;
15 import vibe.mail.smtp;
16 import vibe.stream.memory;
17 import vibe.templ.diet;
18 
19 
20 class NotificationCenter {
21 	private {
22 		UserManController m_users;
23 		PersistentScheduler m_scheduler;
24 		string[][string][User.ID] m_deprecations;
25 
26 		enum weeklyDeprecationEventName = "deprecation-warnings";
27 	}
28 
29 	this(UserManController users)
30 	{
31 		m_users = users;
32 		m_scheduler = new PersistentScheduler(Path("notification-schedule.json"));
33 		if (!m_scheduler.existsEvent(weeklyDeprecationEventName))
34 			m_scheduler.scheduleWeeklyEvent(weeklyDeprecationEventName, SysTime(DateTime(2014, 01, 05, 12, 0, 0), UTC()));
35 	}
36 
37 	void startRegularNotifications()
38 	{
39 		m_scheduler.setEventHandler(weeklyDeprecationEventName, &onSendDeprecationWarnings);
40 	}
41 
42 	void notifyNewErrors(User.ID user_id, string package_name, string branch_or_version, string[] errors)
43 	{
44 		auto user = m_users.getUser(user_id);
45 		if (user.email != "sludwig@rejectedsoftware.com") return;
46 
47 		auto settings = m_users.settings;
48 
49 		auto mail = new Mail;
50 		mail.headers["From"] = format("%s <%s>", settings.serviceName, settings.serviceEmail);
51 		mail.headers["To"] = format("%s <%s>", user.fullName, user.email); // FIXME: sanitize/escape user.fullName
52 		mail.headers["Subject"] = format("[%s] Errors in new version %s", package_name, branch_or_version);
53 
54 		auto dst = createMemoryOutputStream();
55 		dst.compileDietFile!("dubregistry.mail.package-version-errors.dt", user, settings, package_name, branch_or_version, errors);
56 		mail.bodyText = cast(string)dst.data;
57 
58 		sendMail(settings.mailSettings, mail);
59 	}
60 
61 	void setDeprecationWarnings(User.ID user_id, string package_name, string[] warnings)
62 	{
63 		auto pd = user_id in m_deprecations;
64 		if (!pd) {
65 			m_deprecations[user_id] = null;
66 			pd = user_id in m_deprecations;
67 		}
68 		if (warnings.length) (*pd)[package_name] = warnings;
69 		else if (package_name in *pd) (*pd).remove(package_name);
70 	}
71 
72 	private void onSendDeprecationWarnings()
73 	{
74 		foreach (uid, deprecations; m_deprecations) {
75 			User user;
76 			try {
77 				user = m_users.getUser(uid);
78 				if (user.email != "sludwig@rejectedsoftware.com") continue;
79 
80 				auto settings = m_users.settings;
81 
82 				auto mail = new Mail;
83 				mail.headers["From"] = format("%s <%s>", settings.serviceName, settings.serviceEmail);
84 				mail.headers["To"] = format("%s <%s>", user.fullName, user.email); // FIXME: sanitize/escape user.fullName
85 				mail.headers["Subject"] = format("Weekly deprecation warnings reminder");
86 
87 				auto dst = createMemoryOutputStream();
88 				dst.compileDietFile!("dubregistry.mail.package-deprecation-warnings.dt", user, settings, deprecations);
89 				mail.bodyText = cast(string)dst.data;
90 
91 				sendMail(settings.mailSettings, mail);
92 			} catch (Exception e) {
93 				logDiagnostic("Failed to send deprecation mail to %s <%s>: %s", user.fullName, user.email, e.msg);
94 				logDebug("Full error: %s", e.toString().sanitize);
95 			}
96 		}
97 	}
98 }