/// <summary> /// Run the job /// </summary> public void Run(object sender, EventArgs e, object[] parameters) { try { this.m_stateManager.SetState(this, JobStateType.Running); using (AuthenticationContext.EnterSystemContext()) { this.m_tracer.TraceInfo("Will notify users of inactivity..."); int days = parameters.Length > 0 ? (int)parameters[0] : 28; var userRepository = ApplicationServiceContext.Current.GetService <IRepositoryService <SecurityUser> >(); var entityRepository = ApplicationServiceContext.Current.GetService <IRepositoryService <UserEntity> >(); var notificationService = ApplicationServiceContext.Current.GetService <INotificationService>(); var templateService = ApplicationServiceContext.Current.GetService <INotificationTemplateFiller>(); DateTimeOffset cutoff = DateTimeOffset.Now.AddDays(-days); int offset = 0, totalResults = 1; while (offset < totalResults) { this.m_stateManager.SetProgress(this, "Pruning Users", (float)offset / (float)totalResults); List <SecurityUser> actionedUser = new List <SecurityUser>(10); // Users who haven't logged in foreach (var usr in userRepository.Find(o => o.UserClass == ActorTypeKeys.HumanUser && o.LastLoginTime < cutoff, offset, 100, out totalResults)) { // Cancel request? if (this.m_cancelFlag) { break; } double daysSinceLastLogin = 0; if (!usr.LastLoginTime.HasValue) { daysSinceLastLogin = DateTimeOffset.Now.Subtract(usr.CreationTime).TotalDays; } else { daysSinceLastLogin = DateTimeOffset.Now.Subtract(usr.LastLoginTime.Value).TotalDays; } // To which address? String[] to = null; if (usr.EmailConfirmed) { to = new string[] { $"mailto:{usr.Email}" } } ; else if (usr.PhoneNumberConfirmed) { to = new string[] { $"tel:{usr.Email}" } } ; // Template and action string templateId = null; if (daysSinceLastLogin > days + 7) // a week since we notified them, obsolete { actionedUser.Add(usr); this.m_tracer.TraceVerbose("De-activating user {0}...", usr.UserName); userRepository.Obsolete(usr.Key.Value); templateId = "org.santedb.notification.security.user.inactiveRemoved"; } else { templateId = "org.santedb.notification.security.user.inactiveWarned"; } var entity = entityRepository.Find(o => o.SecurityUserKey == usr.Key, 0, 1, out int _).FirstOrDefault(); var lang = entity?.GetPersonLanguages()?.FirstOrDefault(o => o.IsPreferred)?.LanguageCode; var template = templateService.FillTemplate(templateId, lang, new { removalDays = Math.Round((days + 7) - daysSinceLastLogin), removalDate = DateTime.Now.AddDays((days + 7) - daysSinceLastLogin).Date, user = usr, entity = entity }); // Send the notification this.m_tracer.TraceVerbose("Sending {0} notification to {1}...", templateId, usr.UserName); notificationService.Send(to, template.Subject, template.Body); } offset += 100; // Audit that we deleted users if (actionedUser.Count > 0) { AuditUtil.AuditSecurityDeletionAction(actionedUser, true, new String[] { "obsoletionTime" }); } } this.m_stateManager.SetState(this, JobStateType.Completed); } } catch (Exception ex) { this.m_tracer.TraceError("Error pruning inactive users : {0}", ex); this.m_stateManager.SetProgress(this, ex.Message, 0.0f); this.m_stateManager.SetState(this, JobStateType.Aborted); } finally { this.m_cancelFlag = false; } }