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