Ejemplo n.º 1
0
 //--- Class Methods ---
 public static NotificationUpdateRecord FromDocument(XDoc doc) {
     var record = new NotificationUpdateRecord(doc["@wikiid"].AsText, doc["@userid"].AsUInt.Value);
     foreach(var page in doc["page"]) {
         record.Add(page["@id"].AsUInt.Value, page["@modified"].AsDate.Value);
     }
     return record;
 }
Ejemplo n.º 2
0
        //--- Class Methods ---
        public static NotificationUpdateRecord FromDocument(XDoc doc)
        {
            var record = new NotificationUpdateRecord(doc["@wikiid"].AsText, doc["@userid"].AsUInt.Value);

            foreach (var page in doc["page"])
            {
                record.Add(page["@id"].AsUInt.Value, page["@modified"].AsDate.Value);
            }
            return(record);
        }
Ejemplo n.º 3
0
 //--- Methods ---
 public void Enqueue(string wikiid, uint userId, uint pageId, DateTime modificationDate) {
     lock(_pending) {
         NotificationUpdateRecord pending;
         string key = wikiid + ":" + userId;
         if(!_pending.TryGetValue(key, out pending)) {
             pending = new NotificationUpdateRecord(wikiid, userId);
             _pending[key] = pending;
             _queue.Enqueue(new Tuplet<DateTime, string>(DateTime.UtcNow.Add(_delay), key));
         }
         pending.Add(pageId, modificationDate);
     }
 }
 //--- Methods ---
 public void Enqueue(string wikiid, uint userId, uint pageId, DateTime modificationDate)
 {
     lock (_pending) {
         NotificationUpdateRecord pending;
         string key = wikiid + ":" + userId;
         if (!_pending.TryGetValue(key, out pending))
         {
             pending       = new NotificationUpdateRecord(wikiid, userId);
             _pending[key] = pending;
             _queue.Enqueue(new Tuplet <DateTime, string>(DateTime.UtcNow.Add(_delay), key));
         }
         pending.Add(pageId, modificationDate);
     }
 }
 private void Dispatch(NotificationUpdateRecord updateRecord, Action completionCallback)
 {
     Coroutine.Invoke(_callback, updateRecord, new Result()).WhenDone(
         r => {
         completionCallback();
         if (r.HasException)
         {
             _log.ErrorExceptionMethodCall(r.Exception, "DispatchFromQueue", string.Format("dispatch for user '{0}' encountered an error", updateRecord.UserId));
         }
         else
         {
             _log.DebugFormat("finished dispatch of update record for user '{0}'", updateRecord.UserId);
         }
     });
 }
        private Yield SendEmail(NotificationUpdateRecord updateRecord, Result result) {
            bool userChanged = false;
            Plug deki = _deki.With("apikey", _apikey).WithCookieJar(Cookies);
            _log.DebugFormat("trying to dispatch email to user {0} for wiki '{1}'", updateRecord.UserId, updateRecord.WikiId);
            bool createUser = false;
            UserInfo userInfo = _subscriptions.GetUser(updateRecord.WikiId, updateRecord.UserId, false);
            if(userInfo == null) {
                createUser = true;
                _log.DebugFormat("user is gone from subscriptions. Trying to re-fetch", updateRecord.UserId, updateRecord.WikiId);
            }
            if(userInfo == null || !userInfo.IsValidated) {

                // need to refetch user info to make sure we have
                DreamMessage userMsg = null;
                yield return deki.At("users", updateRecord.UserId.ToString()).WithHeader("X-Deki-Site", "id=" + updateRecord.WikiId)
                    .Get(new Result<DreamMessage>())
                    .Set(x => userMsg = x);
                if(!userMsg.IsSuccessful) {
                    _log.DebugFormat("unable to fetch user {0}, skipping delivery: {1}", updateRecord.UserId, userMsg.Status);
                    result.Return();
                    yield break;
                }
                var userDoc = userMsg.ToDocument();
                try {
                    userInfo = GetUserInfo(userDoc, updateRecord.WikiId, createUser);
                } catch(UserException e) {
                    _log.DebugFormat("unable to re-validate user {0}, skipping delivery: {1}", updateRecord.UserId, e.Message);
                    result.Return();
                    yield break;
                }
                userInfo.Save();
            }
            SiteInfo siteInfo = _subscriptions.GetSiteInfo(updateRecord.WikiId);
            if(!siteInfo.IsValidated) {

                // lazy loading site information
                Result<DreamMessage> siteResult;
                yield return siteResult = deki.At("site", "settings").WithHeader("X-Deki-Site", "id=" + updateRecord.WikiId).GetAsync();
                DreamMessage site = siteResult.Value;
                if(!site.IsSuccessful) {
                    _log.WarnFormat("unable to fetch site data for deki '{0}', skipping delivery: {1}", updateRecord.WikiId, site.Status);
                    result.Return();
                    yield break;
                }
                XDoc siteDoc = site.ToDocument();
                siteInfo.Sitename = siteDoc["ui/sitename"].AsText;
                siteInfo.EmailFromAddress = siteDoc["page-subscription/from-address"].AsText;
                siteInfo.EmailFormat = siteDoc["page-subscription/email-format"].AsText;
                if(string.IsNullOrEmpty(siteInfo.EmailFromAddress)) {
                    siteInfo.EmailFromAddress = siteDoc["admin/email"].AsText;
                }
                siteInfo.Culture = CultureUtil.GetNonNeutralCulture(siteDoc["ui/language"].AsText) ?? CultureInfo.GetCultureInfo("en-us");
                if(!siteInfo.IsValidated) {
                    _log.WarnFormat("unable to get required data from site settings, cannot send email");
                    if(string.IsNullOrEmpty(siteInfo.Sitename)) {
                        _log.WarnFormat("missing ui/sitename");
                    }
                    if(string.IsNullOrEmpty(siteInfo.EmailFromAddress)) {
                        _log.WarnFormat("missing page-subscription/from-address");
                    }
                    result.Return();
                    yield break;
                }
            }
            CultureInfo culture = CultureUtil.GetNonNeutralCulture(userInfo.Culture, siteInfo.Culture);
            string subject = string.Format("[{0}] {1}", siteInfo.Sitename, _resourceManager.GetString("Notification.Page.email-subject", culture, "Site Modified"));
            XDoc email = new XDoc("email")
                .Attr("configuration", siteInfo.WikiId)
                .Elem("to", userInfo.Email)
                .Elem("from", siteInfo.EmailFromAddress)
                .Elem("subject", subject)
                .Start("pages");
            string header = _resourceManager.GetString("Notification.Page.email-header", culture, "The following pages have changed:");
            StringBuilder plainBody = new StringBuilder();
            plainBody.AppendFormat("{0}\r\n\r\n", header);
            XDoc htmlBody = new XDoc("body")
                .Attr("html", true)
                .Elem("h2", header);
            foreach(Tuplet<uint, DateTime, bool> record in updateRecord.Pages) {

                // TODO (arnec): Need to revalidate that the user is still allowed to see that page
                // TODO (arnec): Should check that the user is still subscribed to this page
                uint pageId = record.Item1;
                email.Elem("pageid", pageId);
                Result<PageChangeData> dataResult;
                yield return dataResult = Coroutine.Invoke(_cache.GetPageData, pageId, userInfo.WikiId, record.Item2, culture, userInfo.Timezone, new Result<PageChangeData>());
                PageChangeData data = dataResult.Value;
                if(data == null) {
                    _log.WarnFormat("Unable to fetch page change data for page {0}", pageId);
                    continue;
                }
                htmlBody.AddAll(data.HtmlBody.Elements);
                plainBody.Append(data.PlainTextBody);
                if(!record.Item3) {
                    continue;
                }
                userInfo.RemoveResource(pageId);
                userChanged = true;
            }
            email.End();
            if(!StringUtil.EqualsInvariantIgnoreCase(siteInfo.EmailFormat, "html")) {
                email.Elem("body", plainBody.ToString());
            }
            if(!StringUtil.EqualsInvariantIgnoreCase(siteInfo.EmailFormat, "plaintext")) {
                email.Add(htmlBody);
            }
            _log.DebugFormat("dispatching email for user '{0}'", userInfo.Id);
            yield return _emailer.WithCookieJar(Cookies).PostAsync(email).Catch();
            if(userChanged) {
                userInfo.Save();
            }
            result.Return();
            yield break;
        }
 private Yield ExpirationCallback(NotificationUpdateRecord record, Result result) {
     expirationResult.Return(record);
     result.Return();
     yield break;
 }
 private Yield SendEmail(NotificationUpdateRecord updateRecord, Result result) {
     yield return Self.WithCookieJar(Cookies).At("__sendnotification").Post(updateRecord.ToDocument(), new Result<DreamMessage>());
     result.Return();
 }
Ejemplo n.º 9
0
 private void Dispatch(NotificationUpdateRecord updateRecord, Action completionCallback) {
     Coroutine.Invoke(_callback, updateRecord, new Result()).WhenDone(
       r => {
           completionCallback();
           if(r.HasException) {
               _log.ErrorExceptionMethodCall(r.Exception, "DispatchFromQueue", string.Format("dispatch for user '{0}' encountered an error", updateRecord.UserId));
           } else {
               _log.DebugFormat("finished dispatch of update record for user '{0}'", updateRecord.UserId);
           }
       });
 }