/// <summary> /// /// </summary> /// <param name="dto"></param> public void ProcessPartnerCallWorkItem(PartnerCallAlertWorkItem dto) { IfNullThrowArgumentExceptionAndClearMsg(dto, "Cannot process PartnerCallAlertWorkItem, dto object is null.", ""); var pc = pcRepo.GetByID(dto.PartnerCallID); IfNullThrowArgumentExceptionAndClearMsg(pc, "Cannot process PartnerCallAlertWorkItem[{0}], PartnerCall is null.", dto.ToJson()); var post = new PostRepository().GetByID(pc.ID); if (post == null) { pcRepo.Delete(pc.ID); return; } //-- If they've deleted the post, let's not send out anything and delete the original call... var place = AppLookups.GetCacheIndexEntry(pc.PlaceID); //if (place == null) //-- Maybe we tried to read when //{ // //} IfNullThrowArgumentExceptionAndClearMsg(place, "Cannot process PartnerCallAlertWorkItem[{0}] for place[{1}], Place is null.", pc.ID, pc.PlaceID); var by = CfPerfCache.GetClimber(pc.UserID); IfNullThrowArgumentExceptionAndClearMsg(by, "Cannot process PartnerCallAlertWorkItem[{0}] for byUser[{1}], User is null.", pc.ID, pc.UserID); PCNWorkItem pcnWi = new PartnerCallNotificationWorkItem() { ID = Guid.NewGuid(), CreatedUtc = DateTime.UtcNow, CountryID = place.CountryID, OnBehalfOfUserID = by.ID, PartnerCallID = pc.ID, PlaceID = pc.PlaceID }; var alerts = new List <Alert>(); var msg = string.Format("<a href='/climber/{0}'>{1}</a> posted a <a href='/partner-call/{2}'>PartnerCall™</a> for <a href='{3}'>{4}</a>", by.ID, by.DisplayName, pc.ID, place.SlugUrl, place.Name); var deduciblePlaces = CfPerfCache.GetGeoDeduciblePlaces(place); var subscriptionsByUsers = pcsRepo.GetSubscriptionsForPlaces(deduciblePlaces.Select(p => p.ID).ToList()) .Where(s => s.UserID != pc.UserID).GroupBy(s => s.UserID); //-- We only want to create one Alert per user for a single partner call foreach (var subsUserSet in subscriptionsByUsers) { try { var subscribedUser = CfPerfCache.GetClimber(subsUserSet.Key); if (subscribedUser == null) { throw new ArgumentException(string.Format("Cannot process partner call subscription alerts for user[{0}] as user is null", subsUserSet.Key)); } var matchingSubs = new List <PCSubscription>(); foreach (var sub in subsUserSet) { if (sub.PlaceID == place.ID || !sub.ExactMatchOnly) //-- Here we make sure we don't include subscription with ExactMatchOnly chosen { //-- Make sure we match on Indoor/Outdoor preferences if ((sub.ForIndoor && pc.ForIndoor) || (sub.ForOutdoor && pc.ForOutdoor)) { matchingSubs.Add(sub); } } } if (matchingSubs.Count > 0) { var alert = new Alert() { ID = Guid.NewGuid(), Utc = DateTime.UtcNow, TypeID = (byte)AlertType.PartnerCall, PostID = pc.ID, UserID = subscribedUser.ID, Message = msg }; alert.ByFeed = true; //-- Here we always put partner calls in the alert feed (unless at a later date we decide to change this). //-- Default notifications bool sendEmail = false; bool sendMobilePush = false; int count = 1; string subscriptionPlaces = string.Empty; foreach (var sub in matchingSubs) { if (sub.EmailRealTime) { sendEmail = true; } if (sub.MobileRealTime) { sendMobilePush = true; } var p = AppLookups.GetCacheIndexEntry(sub.PlaceID); if (count == 1) { subscriptionPlaces = p.Name; } else if (count == matchingSubs.Count) { alert.Message += string.Format(" & {0}", p.Name); } else { alert.Message += string.Format(", {0}", p.Name); } count++; } if (matchingSubs.Count == 1) { alert.Message += ", <i>matching subscription for " + subscriptionPlaces + ".</i>"; } else { alert.Message += ", <i>matching subscriptions for " + subscriptionPlaces + ".</i>"; } if (sendEmail) { MailMan.SendPartnerCallEmail(subscribedUser, by, place, pc, subscriptionPlaces); alert.ByEmail = true; } //if (sendMobilePush) //{ //SendAlertByMobilePush(alert); // alert.ByMobile = true; //} alerts.Add(alert); } } catch (Exception ex) // Here we have a try catch incase it fails for one user we can try and still process the others { CfTrace.Error(ex); } } pcnWi.NotificationsSent = alerts.Count(); pcnWi.ProcessedUtc = DateTime.UtcNow; pcWRepo.Create(pcnWi); //-- We have to check this again to see if they delete the post while we were processing var postagain = new PostRepository().GetByID(pc.ID); if (postagain != null) { new AlertRepository().Create(alerts); } CfTrace.Information(TraceCode.PartnerCallNofiticatonWorkItemProcess, "Processed {4} <a href='/climber/{0}'>{1}'s</a> <a href='/partner-call/{2}'>PartnerCall™</a> for {3}.", by.ID, by.DisplayName, pc.ID, place.Name, alerts.Count); }