|  | @@ -4,10 +4,30 @@ using System.Linq;
 | 
	
		
			
				|  |  |  using System.Text;
 | 
	
		
			
				|  |  |  using System.Text.RegularExpressions;
 | 
	
		
			
				|  |  |  using Comal.Classes;
 | 
	
		
			
				|  |  | +using InABox.Clients;
 | 
	
		
			
				|  |  |  using InABox.Core;
 | 
	
		
			
				|  |  | +using InABox.Database;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace Comal.Stores
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +    public class ServerKanbanSubscriberSet : BaseKanbanSubscriberSet
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        public ServerKanbanSubscriberSet(IEnumerable<Guid> kanbanids) : base(kanbanids)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        protected override void DoSave(IEnumerable<KanbanSubscriber> updates)
 | 
	
		
			
				|  |  | +            => DbFactory.Provider.Save(updates);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        protected override void DoDelete(KanbanSubscriber[] deletes)
 | 
	
		
			
				|  |  | +            => DbFactory.Provider.Delete(deletes,"");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        protected override CoreTable DoQuery(Filter<KanbanSubscriber> filter, Columns<KanbanSubscriber> columns)
 | 
	
		
			
				|  |  | +            => DbFactory.Provider.Query(filter, columns);
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      internal class KanbanStore : ScheduleActionStore<Kanban>
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          private void CheckNotifications(Kanban entity)
 | 
	
	
		
			
				|  | @@ -19,7 +39,7 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |                      new Filter<Notification>(x => x.EntityType).IsEqualTo(typeof(Kanban).EntityName()).And(x => x.EntityID).IsEqualTo(entity.ID)
 | 
	
		
			
				|  |  |                          .And(x => x.Closed).IsEqualTo(DateTime.MinValue),
 | 
	
		
			
				|  |  |                      new Columns<Notification>(x => x.ID)
 | 
	
		
			
				|  |  | -                ).Rows.Select(x => x.ToObject<Notification>());
 | 
	
		
			
				|  |  | +                ).Rows.Select(x => x.ToObject<Notification>()).ToArray();
 | 
	
		
			
				|  |  |                  foreach (var notification in notifications)
 | 
	
		
			
				|  |  |                      notification.Closed = entity.Completed;
 | 
	
		
			
				|  |  |                  if (notifications.Any())
 | 
	
	
		
			
				|  | @@ -29,12 +49,12 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void NotifyUsers(Kanban entity)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var Subject = string.Format("Updated Task: {0} (Due: {1:dd MMM yy})", entity.Title, entity.DueDate);        
 | 
	
		
			
				|  |  | +            var Subject = $"Updated Task: {entity.Title} (Due: {entity.DueDate:dd MMM yy})";        
 | 
	
		
			
				|  |  |              var emps = Provider.Query(
 | 
	
		
			
				|  |  |                  new Filter<KanbanSubscriber>(x => x.Kanban.ID).IsEqualTo(entity.ID),
 | 
	
		
			
				|  |  |                  new Columns<KanbanSubscriber>(x => x.Employee.ID, x => x.Employee.UserLink.ID));          
 | 
	
		
			
				|  |  |              var senderrow = emps.Rows.FirstOrDefault(r => r.Get<KanbanSubscriber, Guid>(c => c.Employee.UserLink.ID).Equals(UserGuid));
 | 
	
		
			
				|  |  | -            var senderid = senderrow != null ? senderrow.Get<KanbanSubscriber, Guid>(c => c.Employee.ID) : Guid.Empty;
 | 
	
		
			
				|  |  | +            var senderid = senderrow?.Get<KanbanSubscriber, Guid>(c => c.Employee.ID) ?? Guid.Empty;
 | 
	
		
			
				|  |  |              var notifications = new List<Notification>();
 | 
	
		
			
				|  |  |              foreach (var row in emps.Rows)
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -75,10 +95,8 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private string BuildDescription(Kanban entity)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var notes = entity.Notes != null
 | 
	
		
			
				|  |  | -                ? string.Join("\r\n", entity.Notes)
 | 
	
		
			
				|  |  | -                    .Split(new[] { "===================================\r\n" }, StringSplitOptions.RemoveEmptyEntries)
 | 
	
		
			
				|  |  | -                : new string[] { };
 | 
	
		
			
				|  |  | +            var notes = string.Join("\r\n", entity.Notes)
 | 
	
		
			
				|  |  | +                .Split(new[] { "===================================\r\n" }, StringSplitOptions.RemoveEmptyEntries);
 | 
	
		
			
				|  |  |              var summary = notes.LastOrDefault();
 | 
	
		
			
				|  |  |              if (string.IsNullOrEmpty(summary))
 | 
	
		
			
				|  |  |                  summary = entity.Summary;
 | 
	
	
		
			
				|  | @@ -145,8 +163,8 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |                  return;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              var kanbanForms = Provider.Query(
 | 
	
		
			
				|  |  | -                new Filter<KanbanForm>(x => x.Parent.ID).IsEqualTo(kanban.ID)).Rows.Select(x => x.ToObject<KanbanForm>());
 | 
	
		
			
				|  |  | -            var toDelete = kanbanForms.Where(x => string.IsNullOrWhiteSpace(x.FormData));
 | 
	
		
			
				|  |  | +                new Filter<KanbanForm>(x => x.Parent.ID).IsEqualTo(kanban.ID)).Rows.Select(x => x.ToObject<KanbanForm>()).ToArray();
 | 
	
		
			
				|  |  | +            var toDelete = kanbanForms.Where(x => string.IsNullOrWhiteSpace(x.FormData)).ToArray();
 | 
	
		
			
				|  |  |              Provider.Delete(toDelete, UserID);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var kanbanTypeForms = Provider.Query(
 | 
	
	
		
			
				|  | @@ -157,7 +175,7 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |              foreach(var row in kanbanTypeForms.Rows)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var formID = row.Get<KanbanTypeForm, Guid>(x => x.Form.ID);
 | 
	
		
			
				|  |  | -                if (!(kanbanForms.Any(x => x.Form.ID == formID) && !toDelete.Any(x => x.Form.ID == formID)))
 | 
	
		
			
				|  |  | +                if (!(kanbanForms.Any(x => x.Form.ID == formID) && toDelete.All(x => x.Form.ID != formID)))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      var kanbanForm = new KanbanForm();
 | 
	
		
			
				|  |  |                      kanbanForm.Form.ID = formID;
 | 
	
	
		
			
				|  | @@ -174,6 +192,22 @@ namespace Comal.Stores
 | 
	
		
			
				|  |  |              CheckNotifications(entity);
 | 
	
		
			
				|  |  |              CheckNotificationRequired(entity);
 | 
	
		
			
				|  |  |              CheckKanbanTypeForms(entity);
 | 
	
		
			
				|  |  | +            CheckSubscribers(entity);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void CheckSubscribers(Kanban entity)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (entity.EmployeeLink.HasOriginalValue(x => x.ID) || (entity.ManagerLink.HasOriginalValue(x => x.ID)))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var set = new ServerKanbanSubscriberSet(new Guid[] { entity.ID });
 | 
	
		
			
				|  |  | +                if (entity.EmployeeLink.HasOriginalValue(x => x.ID))
 | 
	
		
			
				|  |  | +                    set.EnsureAssignee(entity.ID,entity.EmployeeLink.ID);
 | 
	
		
			
				|  |  | +                if (entity.ManagerLink.HasOriginalValue(x => x.ID))
 | 
	
		
			
				|  |  | +                    set.EnsureManager(entity.ID,entity.ManagerLink.ID);
 | 
	
		
			
				|  |  | +                set.Save();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |