Example #1
0
        public Message GetTodayPartnerCallsForPlace(string id)
        {
            try
            {
                SvcContext ctx = InflateContext(); if (ctx.Invalid)
                {
                    return(ctx.ContextMessage);
                }

                Guid pID   = Guid.ParseExact(id, "N");
                var  calls = pcSvc.GetPlacesGeoDeducTodayPartnerCalls(pID);

                var dto = new List <PartnerCallDto>();

                foreach (var c in calls)
                {
                    //-- Here we use perf cache instead of Include()/join because it's likely the user will have revisited the same place
                    var place = CfCacheIndex.Get(c.PlaceID);
                    if (place != null)
                    {
                        var user    = CfPerfCache.GetClimber(c.UserID);
                        var callDto = new PartnerCallDto(place, c, user);
                        dto.Add(callDto);
                    }
                }

                return(ReturnAsJson(dto));
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
                return(Failed("Partner search failed : " + ex.Message));
            }
        }
        public override void OnException(ExceptionContext context)
        {
            CfTrace.Error(context.Exception);

            if (context.Exception is AccessViolationException)
            {
                context.Result = new ViewResult()
                {
                    ViewName = "Unauthorized"
                };
                (context.Result as ViewResult).ViewBag.Msg = context.Exception.Message;
                context.ExceptionHandled = true;
            }
            else
            {
                var ex = getBaseException(context.Exception);

                var errorDisplayText = ex.Message;
                if (CfIdentity.IsAuthenticated && CfPrincipal.IsGod())
                {
                    errorDisplayText = ex.ToString();
                }

                context.Result = new ViewResult()
                {
                    ViewName = "Error"
                };
                (context.Result as ViewResult).ViewBag.Msg = errorDisplayText;
                context.ExceptionHandled = true;
            }


            base.OnException(context);
        }
Example #3
0
        public override bool OnStart()
        {
            CfTrace.InitializeTraceSource(new Instrumentation.CfTraceSource("Cf.CacheServer"));

            try
            {
                var connectionString = ConfigurationManager.ConnectionStrings["CfCloudStorage"].ConnectionString;
                CfCloudStorage = CloudStorageAccount.Parse(connectionString);

                //System.Diagnostics.Trace.WriteLine("cf.CacheServer Started: "+DateTime.UtcNow.ToString());
                var startTime = DateTime.UtcNow;
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                proc         = WazMemcachedHelpers.StartMemcachedServer("Memcached", 640);
                proc.Exited += new EventHandler(MemcachedServer_Crashed);
                var index = PopuluteCfCacheIndex();

                stopwatch.Stop();

                //System.Diagnostics.Trace.WriteLine(string.Format("cf.CacheServer index [{0}], Ready after {1}ms", index.Count, stopwatch.ElapsedMilliseconds));

                StartServiceHost();                 //Listen for manual cache refreshes
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
            }

            return(base.OnStart());
        }
Example #4
0
        /// <summary>
        /// Return all geocode results that are within the specified country
        /// </summary>
        /// <param name="country"></param>
        /// <param name="locality"></param>
        /// <returns></returns>
        public List <GeocodeResult> Geocode(Country country, string locality)
        {
            List <GeocodeResult> results;

            //-- Take out special characters from the locality so when we put it in the url our web request works
            var cleanedLocalityString = locality.Replace("&", "and").Replace("#", "").Trim();

            try
            {
                //- Get the results from bing against the country specific store
                results = BingGeocodeCountryRegionQuery(country, cleanedLocalityString);

                if (results.Count == 0)
                {
                    //-- Sometimes if it doesn't work when we make a country specific call if we make a general call to bing we get a result
                    //-- e.g. "The Peak District National Park" in the UK
                    results = BingGeocodeSingleQuery(country, cleanedLocalityString);
                }
                else
                {
                    //-- Double check that bing hasn't give us a stupid default result representing just the country and not the locality
                    if (ResultIsDefaultCountry(country, results))
                    {
                        results = BingGeocodeSingleQuery(country, cleanedLocalityString);
                        if (ResultIsDefaultCountry(country, results))
                        {
                            //-- We don't want to send back a result of country type
                            results.Clear();
                        }
                    }
                    else
                    {
                        //-- Sometimes the result we get from the country specific call sucks and we want to give
                        //-- the user access to the second result as well
                        results.AddRange(BingGeocodeSingleQuery(country, cleanedLocalityString));
                    }
                }

                //-- If after all the goes above we still don't have anything from silly Bing, let's use google
                if (results.Count == 0)
                {
                    results = GooleGeocodeSingleQuery(country, cleanedLocalityString);
                }

                //-- Remove duplicates
                if (results.Count > 1)
                {
                    results = results.Distinct(new GeocodeResultEqualityComparer()).ToList();
                }
            }
            catch (Exception ex)
            {
                ex.Data.Add("locality", cleanedLocalityString);
                CfTrace.Error(ex);
                throw;
            }

            return(results);
        }
        public void Initialize()
        {
            var connectionString = ConfigurationManager.ConnectionStrings["CfCloudStorage"].ConnectionString;

            CfCloudStorage = CloudStorageAccount.Parse(connectionString);
            blobRepo       = new BlobRepository();
            CfTrace.InitializeTraceSource(new Instrumentation.CfTraceSource("Cf.CacheServer"));
        }
Example #6
0
 public ActionResult RequestProxy(string url)
 {
     try
     {
         return(new ProxyResult(new Uri(url)));
     }
     catch (Exception ex)
     {
         CfTrace.Error(ex);
         return(Json(new { Success = false, Error = ex.Message }));
     }
 }
 public ActionResult LatestCommunityMediaStrip()
 {
     try
     {
         var model = mediaSvc.GetLatestMedia(12);
         return(PartialView(model));
     }
     catch (Exception ex)
     {
         CfTrace.Error(ex);
         return(Content("<p>Failed to load recent media. Refresh the page</p>"));
     }
 }
Example #8
0
        protected void Application_Start(object sender, EventArgs e)
        {
            CfTrace.InitializeTraceSource(new Instrumentation.CfTraceSource("Cf.Svc"));
            CfTrace.Current.Information(TraceCode.AppStart, "Cf.Svc Started {0:MMM dd HH.mm.ss}", DateTime.Now);

            //-- Setup caching depending on if we're running in the cloud or not
            //InitializeEnvironmentCacheAndSearchProviders();

            RegisterRoutes();

            Microsoft.IdentityModel.Web.FederatedAuthentication.ServiceConfigurationCreated += new EventHandler
                                                                                               <Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs>(RsaServerfarmSessionCookieTransform.OnServiceConfigurationCreated);

            CfTrace.Current.Information(TraceCode.AppStartEnd, "Cf.Svc Start ended {0:MMM dd HH.mm.ss}", DateTime.Now);
        }
Example #9
0
        //void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
        //{
        //    var token = e.SessionToken;
        //}

        //void SessionAuthenticationModule_SessionSessionSecurityTokenCreated(object sender, SessionSecurityTokenCreatedEventArgs e)
        //{
        //    var token = e.SessionToken;
        //}


        //void WSFederationAuthenticationModule_SessionSecurityTokenCreated(object sender, SessionSecurityTokenCreatedEventArgs e)
        //{
        //    e.WriteSessionCookie = true;

        //    e.SessionToken = FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken(
        //        e.SessionToken.ClaimsPrincipal,
        //        e.SessionToken.Context,
        //        DateTime.UtcNow,
        //        DateTime.UtcNow.AddDays(300),
        //        true);

        //    var id = e.SessionToken.Id;
        //}

        void Application_Error(Object sender, EventArgs e)
        {
            try
            {
                string    relativeUrl = HttpContext.Current.Request.RawUrl.ToLower();
                Exception exception   = Server.GetLastError().GetBaseException();

                if (exception.ShouldRecord(relativeUrl) && !HttpContext.Current.Request.Url.OriginalString.StartsWith("http://cf4"))
                {
                    CfTrace.Error(exception);
                }

                Server.ClearError();

                if (SpecialUrls.Cf3Redirect(relativeUrl))
                {
                    Response.Status = "301 Moved Permanently";
                    Response.AddHeader("Location", "http://cf3.climbfind.com" + relativeUrl);
                    Response.Flush();
                    Response.End();
                }
                else if (SpecialUrls.Instance.PermanentlyMoved.ContainsKey(relativeUrl))
                {
                    Response.Status = "301 Moved Permanently";
                    Response.AddHeader("Location", SpecialUrls.Instance.PermanentlyMoved[relativeUrl]);
                    Response.Flush();
                    Response.End();
                }
                else if (SpecialUrls.HasBeenRemoved(relativeUrl))
                {
                    Response.Status      = "410 Gone";
                    Response.ContentType = "text/html";
                    Response.WriteFile(Server.MapPath("~/page-not-found.htm"));
                }
                else if (exception.Message.Contains("The controller for path") || exception.Message.Contains("A public action method"))
                {
                    Response.Status      = "404 Not Found";
                    Response.ContentType = "text/html";
                    Response.WriteFile(Server.MapPath("~/page-not-found.htm"));
                }
            }
            catch (Exception ex)
            {
                Response.Write("<span class='note'>GLOBAL ENDPOINT: PLEASE EMAIL [email protected] IMMEDIATELY IF YOU SEE THIS SCREEN!!!!!!!!!!!!</span>" + ex.ToString());
            }
        }
Example #10
0
        // Create or update a blob.
        // Return true on success, false if already exists, throw exception on error.

        public bool PutMessage(string queueName, CloudQueueMessage message)
        {
            try
            {
                CloudQueue queue = QueueClient.GetQueueReference(queueName);
                queue.AddMessage(message);
                return(true);
            }
            catch (StorageClientException ex)
            {
                CfTrace.Error(ex);

                return(false);

                //-- no throw because if this fails, prefer not to break the app for the user
                //throw;
            }
        }
Example #11
0
 /// <summary>
 ///
 /// </summary>
 public override void Run()
 {
     while (true)
     {
         try
         {
             //var mClient = WazMemcachedHelpers.CreateProtobufferClient(CacheConstants.CacheRole, CacheConstants.CacheEndpoint);
             //ServerStats stats = mClient.Stats();
             //MailMan.SendAppEvent(TraceCode.AppBuildCache, "Hourly cache cache + lucene index", "*****@*****.**", Guid.Empty, "*****@*****.**", false);
             Thread.Sleep(1000 * 3600);                     //-- Sleep for an hour and then refresh the index
             Trace.WriteLine("CacheServer cache refresh", "Information");
             PopuluteCfCacheIndex();
         }
         catch (Exception ex)
         {
             CfTrace.Error(ex);
         }
     }
 }
Example #12
0
        /// <summary>
        ///
        /// </summary>
        private void RebuildLuceneIndex()
        {
            try
            {
                var dir = new Lucene.Net.Store.Azure.AzureDirectory(CfCloudStorage, "SearchCatalog", new Lucene.Net.Store.RAMDirectory());

                //-- The magic code... delete all the blobs before rebuilding the index
                foreach (var b in dir.BlobContainer.ListBlobs())
                {
                    dir.BlobContainer.GetBlobReference(b.Uri.ToString()).Delete();
                }

                new cf.Content.Search.SearchManager().BuildIndex(dir);
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
            }
        }
Example #13
0
        void Application_Error(Object sender, EventArgs e)
        {
            try
            {
                string    relativeUrl = HttpContext.Current.Request.RawUrl;
                Exception exception   = Server.GetLastError().GetBaseException();

                if (exception.ShouldRecord(relativeUrl))
                {
                    CfTrace.Error(exception);
                    Response.Write(exception.ToString());
                }

                Server.ClearError();
            }
            catch (Exception ex)
            {
                //TODO: write to text file
                Response.Write("<span class='note'>GLOBAL ENDPOINT: PLEASE EMAIL [email protected] IMMEDIATELY IF YOU SEE THIS SCREEN!!!!!!!!!!!!</span>" + ex.ToString());
            }
        }
Example #14
0
        public override bool OnStart()
        {
            //-- Wait for the cf.CacheServer to load first
            System.Threading.Thread.Sleep(100000);

            try
            {
                CfTrace.InitializeTraceSource(new Instrumentation.CfTraceSource("Cf.AlertsServer"));

                CfCacheIndex.Initialize(new Level2MemcachedCacheIndex());
                CfPerfCache.Initialize(new Level2MemcachedPerfCache());
                // Set the maximum number of concurrent connections
                //ServicePointManager.DefaultConnectionLimit = 12;
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
            }

            return(base.OnStart());
        }
Example #15
0
        public Message History(string id)
        {
            try
            {
                SvcContext ctx = InflateContext(); if (ctx.Invalid)
                {
                    return(ctx.ContextMessage);
                }

                Guid uID;
                if (id == "me")
                {
                    uID = CfIdentity.UserID;
                }
                else
                {
                    uID = Guid.ParseExact(id, "N");
                }

                //-- TODO: rewrite to use $expand and do single database call
                var usersCheckIns = visitsSvc.GetUsersHistory(uID).OrderByDescending(c => c.Utc).Take(15);
                var dto           = new List <VisitDto>();

                foreach (var ci in usersCheckIns)
                {
                    //-- Here we use perf cache instead of Include()/join because it's likely the user will
                    //-- have revisited the same place
                    var loc   = CfPerfCache.GetLocation(ci.LocationID);
                    var ciDto = new VisitDto(ci, loc, "", "");
                    dto.Add(ciDto);
                }

                return(ReturnAsJson(dto));
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
                return(Failed("History query failed : " + ex.Message));
            }
        }
Example #16
0
        protected void Application_Start()
        {
            CfTrace.InitializeTraceSource(new Instrumentation.CfTraceSource("Cf.Web"));

            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RouteRegistrar.RegisterRoutes(RouteTable.Routes);

            //-- Setup caching depending on if we're running in the cloud or not
            if (!RoleEnvironment.IsAvailable)
            {
                CfCacheIndex.Initialize(); CfPerfCache.Initialize();
            }
            else
            {
                CfCacheIndex.Initialize(new Level2MemcachedCacheIndex()); CfPerfCache.Initialize(new Level2MemcachedPerfCache());
            }

            Microsoft.IdentityModel.Web.FederatedAuthentication.ServiceConfigurationCreated += new EventHandler
                                                                                               <Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs>(RsaServerfarmSessionCookieTransform.OnServiceConfigurationCreated);
        }
Example #17
0
        public ActionResult RebuildSearchIndex()
        {
            try
            {
                //-- Refresh our local cache
                AppLookups.RefreshCacheIndex();

                //-- Refresh our remote cache & search index
                //var url = Stgs.RestSvcsUrl + "v0/search/refresh";

                //var requestCookies = HttpContext.Request.Cookies;
                //var authCookies = new HttpCookieCollection();
                //if (requestCookies.AllKeys.Contains("FedAuth")) { authCookies.Add(requestCookies.Get("FedAuth")); }
                //if (requestCookies.AllKeys.Contains("FedAuth1")) { authCookies.Add(requestCookies.Get("FedAuth1")); }

                return(Json(new { Success = true, Msg = "Cache refresh notification sent to server" }));
            }
            catch (Exception ex)
            {
                CfTrace.Error(ex);
                return(Json(new { Success = false, Error = ex.Message }));
            }
        }
Example #18
0
        /// <summary>
        /// Delete the specified image
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="fileName"></param>
        public override void DeleteImage(string filePath, string key)
        {
            DeleteObjectRequest request = new DeleteObjectRequest();

            request.WithBucketName("images.climbfind.com" + filePath)
            .WithKey(key);

            using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(Stgs.AWSAccessKey, Stgs.AWSSecretKey, S3Config))
            {
                // simple object put
                using (DeleteObjectResponse response = client.DeleteObject(request))
                {
                    //-- Do a little bit of tracing
                    string headersString        = string.Empty;
                    WebHeaderCollection headers = response.Headers;
                    foreach (string h in headers.Keys)
                    {
                        headersString += string.Format("Response Header: {0}, Value: {1}", h, headers.Get(h));
                    }
                    CfTrace.Information(TraceCode.DeletingImage, headersString);
                }
            }
        }
        public void Dispose()
        {
            lock (WriterLock)
            {
                if (!_disposed)
                {
                    //Never checking for disposing = true because there are
                    //no managed resources to dispose

                    var writer = _writer;

                    if (writer != null)
                    {
                        try
                        {
                            writer.Commit();
                            writer.Close();
                            IndexWriter.Unlock(_directory);
                        }
                        catch (ObjectDisposedException e)
                        {
                            CfTrace.Error(e);
                        }
                        _writer = null;
                    }

                    var analyzer = _analyzer;

                    if (_analyzer != null)
                    {
                        try
                        {
                            analyzer.Close();
                        }
                        catch (ObjectDisposedException e)
                        {
                            CfTrace.Current.Error(e);
                        }
                    }


                    var directory = _directory;
                    if (directory != null)
                    {
                        try
                        {
                            //var lockFactory = directory.GetLockFactory();
                            //foreach (var name in directory.ListAll()) { lockFactory.ClearLock(name); }

                            directory.Close();
                        }
                        catch (ObjectDisposedException e)
                        {
                            CfTrace.Current.Error(e);
                        }
                    }

                    _disposed = true;
                }
            }
            GC.SuppressFinalize(this);
        }
Example #20
0
        /// <summary>
        /// Called from authenticated facebook client 'accounts.climbfind.com' and the mobile app
        /// </summary>
        /// <param name="email"></param>
        /// <param name="fullName"></param>
        /// <param name="password"></param>
        /// <param name="nationality"></param>
        /// <param name="isMale"></param>
        /// <param name="facebookID"></param>
        /// <param name="facebookToken"></param>
        /// <param name="signUpOrigin"></param>
        /// <returns></returns>
        public Profile CreateUser(string email, string fullName, string password, byte nationality, bool isMale, long?facebookID,
                                  string facebookToken, string signUpOrigin)
        {
            try
            {
                bool detailsValid = true; //-- todo, perform some sort of validation on incoming details
                if (detailsValid)
                {
                    MembershipCreateStatus createStatus;
                    var mUser = Membership.CreateUser(email, password, email, null, null, true, null, out createStatus);

                    if (createStatus != MembershipCreateStatus.Success)
                    {
                        throw new MembershipCreateUserException(createStatus);
                    }
                    else
                    {
                        var userID = new Guid(mUser.ProviderUserKey.ToString());

                        var user = CreateProfile(new Profile()
                        {
                            ID            = userID,
                            CountryID     = nationality,
                            Email         = email,
                            FullName      = fullName,
                            IsMale        = isMale,
                            FacebookID    = facebookID,
                            FacebookToken = facebookToken,
                            PrivacyAllowNewConversations = true,
                            PrivacyShowFeed             = true,
                            PrivacyShowHistory          = true,
                            PrivacyPostsDefaultIsPublic = true,
                            PrivacyShowInSearch         = true,
                            PrivacyShowOnPartnerSites   = true
                        });

                        var traceMsg = string.Format("{0} created an account via {1}", fullName, signUpOrigin);
                        if (facebookID.HasValue)
                        {
                            traceMsg += " w fbid: " + facebookID.Value.ToString();
                        }
                        CfTrace.Information(TraceCode.UserCreateAccount, traceMsg);
                        MailMan.SendAppEvent(TraceCode.UserCreateAccount, traceMsg, email, userID, "*****@*****.**", true);

                        try
                        {
                            if (facebookID.HasValue)
                            {
                                var originalImgUrl = string.Format("http://graph.facebook.com/{0}/picture?type=large", facebookID.Value);
                                using (Stream imgStream = new ImageDownloader().DownloadImageAsStream(originalImgUrl))
                                {
                                    //-- Note this function automatically updates the user object in the database
                                    SaveProfileAvatarPicFrom3rdPartSource(imgStream, user);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            CfTrace.Error(ex);
                        }

                        return(user);
                    }
                }
                else
                {
                    throw new Exception("Sign up detail invalid from origin: " + signUpOrigin);
                }
            }
            catch (Exception ex) //-- extra logging / safety as we really don't want this code to screw up and if it does be better know about it!
            {
                if (!ex.Message.Contains("form required for an e-mail address") && !ex.Message.Contains("username is already in use"))
                {
                    CfTrace.Error(ex);
                }
                throw ex;
            }
        }
Example #21
0
        /// <summary>
        /// Used:
        /// 1) In the case when the facebook ID does not match a profile, but the user is signed in to facebook (we check if we can connect the accounts)
        /// 2) When the user logs in with their CF3 email/password to a client (Accounts Server, PG Site, CF4, Mobile App) for the first time
        /// </summary>
        public Profile GetUserByEmailAndCreateCf4ProfileIfNotExists(string email)
        {
            var profile = profileRepo.GetProfileByEmail(email);

            if (profile == null)
            {
                var cf3Profile = new cf.DataAccess.cf3.ClimberProfileDA().GetClimberProfile(email);
                if (cf3Profile != default(Cf3Profile))
                {
                    var    idStr    = cf3Profile.ID.ToString();
                    string userName = idStr.Substring(idStr.Length - 9, 8);

                    profile = new Profile()
                    {
                        ID                           = cf3Profile.ID,
                        CountryID                    = byte.Parse(cf3Profile.Nationality.ToString()),
                        DisplayNameTypeID            = 0,
                        Email                        = email,
                        FullName                     = cf3Profile.FullName,
                        IsMale                       = cf3Profile.IsMale.Value,
                        NickName                     = cf3Profile.NickName,
                        UserName                     = userName,
                        ContactNumber                = cf3Profile.ContractPhoneNumber,
                        PrivacyAllowNewConversations = true,
                        PrivacyShowFeed              = true,
                        PrivacyShowHistory           = true,
                        PrivacyPostsDefaultIsPublic  = true,
                        PrivacyShowInSearch          = true,
                        PrivacyShowOnPartnerSites    = true
                    };

                    profileRepo.Create(profile);

                    var traceMsg = string.Format("{0} upgraded cf3 account", cf3Profile.FullName);
                    CfTrace.Information(TraceCode.UserCreateAccount, traceMsg);
                    MailMan.SendAppEvent(TraceCode.UserCreateAccount, traceMsg, email, cf3Profile.ID, "*****@*****.**", true);

                    try
                    {
                        var originalImgUrl = GetCf3ProfilePicFullSizeUrl(cf3Profile.ID, cf3Profile.ProfilePictureFile);
                        if (!string.IsNullOrWhiteSpace(originalImgUrl))
                        {
                            using (Stream imgStream = new ImageDownloader().DownloadImageAsStream(originalImgUrl))
                            {
                                if (imgStream == null)
                                {
                                    throw new ArgumentException("Cf3 image stream is null for: " + originalImgUrl);
                                }
                                if (profile == null)
                                {
                                    throw new ArgumentException("Profile is null...");
                                }

                                //-- Note this function automatically updates the user object in the database
                                SaveProfileAvatarPicFrom3rdPartSource(imgStream, profile);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        CfTrace.Error(ex);
                    }
                }
            }

            return(profile);
        }
        /// <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&trade;</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&trade;</a> for {3}.",
                                by.ID, by.DisplayName, pc.ID, place.Name, alerts.Count);
        }