428 lines
15 KiB
C#
428 lines
15 KiB
C#
///////////////////////////////////////////////////////////
|
|
// NotificationList.cs
|
|
// Implementation of Class NotificationList
|
|
// CSLA type: Read only collection
|
|
// Created on: 13-Oct-2005
|
|
// Object design: John
|
|
// Coded: John 13-Oct-2005
|
|
///////////////////////////////////////////////////////////
|
|
|
|
using System;
|
|
using System.Data;
|
|
using GZTW.Data;
|
|
using CSLA.Data;
|
|
using CSLA;
|
|
using System.Threading;
|
|
using CSLA.Security;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace GZTW.AyaNova.BLL
|
|
{
|
|
#pragma warning disable 1591
|
|
|
|
/// <summary>
|
|
/// List of notifications formatted for delivery
|
|
/// and screened to be deliverable
|
|
///
|
|
///
|
|
///
|
|
/// Loops through all NotifyEvenRecords
|
|
/// For pending type events, checks to see if within users selected notification window
|
|
/// foreach NotifyEventRecord it adds a NotificationListInfo
|
|
/// for each open delivery window for each subscriber to that event
|
|
/// As it Processes each deliverable notification it formats it to users
|
|
/// locale and preferences for size etc and keeps track of the address and
|
|
/// delivery type.
|
|
///
|
|
///
|
|
/// End result is a list ready to deliver.
|
|
/// As each one is delivered Ok it should be deleted from the NotifyEvent table by the
|
|
/// delivery Process that uses this list.
|
|
///
|
|
/// </summary>
|
|
[Serializable]
|
|
public class NotificationList : ReadOnlyCollectionBase
|
|
{
|
|
|
|
#region Caching
|
|
//Cache notificaiton messages so we can send them out the door faster without the
|
|
//expensive lookup process if they are identical
|
|
//this happens often in a large office, let's say there is a notification about a workorder past it's due date
|
|
//there could be 20 people subscribed to that notification all of whom will get the same message
|
|
//rather than go through the time consuming process of building up the message for each user
|
|
//we can go to the cache and get it after the first time it's built.
|
|
private List<NotifyMessageRequestData> listMessageCache = new List<NotifyMessageRequestData>();
|
|
|
|
//cache subscriptions while processing deliveries
|
|
private Dictionary<Guid, NotifySubscription> listNotifySubscriptionCache = new Dictionary<Guid, NotifySubscription>();
|
|
|
|
|
|
#endregion
|
|
#region Data structure
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Serializable]
|
|
public struct NotificationListInfo
|
|
{
|
|
|
|
//Event identifying info
|
|
internal Guid _RootObjectID;
|
|
internal RootObjectTypes _RootObjectType;
|
|
internal int _EventType;
|
|
internal Guid _AppliesToUserID;
|
|
internal Guid _NotifyEventID;
|
|
|
|
//internal SmartDate _EventDate;
|
|
internal Guid _GuidValue;
|
|
|
|
//Message info
|
|
internal string _Subject;
|
|
internal string _Message;
|
|
internal Guid _DeliverToUserID;
|
|
|
|
//Physical delivery method info
|
|
internal NotifyDeliveryMethods _DeliveryMethod;
|
|
internal string _Address;
|
|
|
|
//Public properties
|
|
public Guid NotifyEventID {get{return _NotifyEventID;}}
|
|
public Guid RootObjectID {get{return _RootObjectID;}}
|
|
public RootObjectTypes RootObjectType {get{return _RootObjectType;}}
|
|
public int EventType {get{return _EventType;}}
|
|
public Guid AppliesToUserID {get{return _AppliesToUserID;}}
|
|
//public SmartDate EventDate {get{return _EventDate;}}
|
|
public Guid GuidValue {get{return _GuidValue;}}
|
|
public NotifyDeliveryMethods DeliveryMethod {get{return _DeliveryMethod;}}
|
|
public string Address {get{return _Address;}}
|
|
public string Message {get{return _Message;}}
|
|
public string Subject {get{return _Subject;}}
|
|
public Guid DeliverToUserID {get{return _DeliverToUserID;}}
|
|
|
|
}//end NotificationListInfo
|
|
#endregion
|
|
|
|
#region Constructor
|
|
private NotifyDeliverySettings _DeliverySettings;
|
|
protected NotificationList()
|
|
{
|
|
//fetch all users delivery settings so it's
|
|
//cached for use below
|
|
_DeliverySettings=NotifyDeliverySettings.GetItems(Guid.Empty);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Business properties and methods
|
|
|
|
/// <summary>
|
|
/// Get item by index
|
|
/// </summary>
|
|
/// <param name="Item"></param>
|
|
public NotificationListInfo this[int Item]
|
|
{
|
|
|
|
get
|
|
{
|
|
return (NotificationListInfo) List[Item];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Static methods
|
|
/// <summary>
|
|
/// Get all available notifications for delivery
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static NotificationList GetList()
|
|
{
|
|
|
|
if(AyaBizUtils.IsGenerator)
|
|
return (NotificationList) DataPortal.Fetch(new Criteria());
|
|
else
|
|
throw new System.Security.SecurityException(
|
|
string.Format(
|
|
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"),
|
|
LocalizedTextTable.GetLocalizedTextDirect("O.Notification")));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region DAL DATA ACCESS
|
|
//removed these as part of case 1386,
|
|
//probably were used for testing but no longer in use
|
|
// int nHitCache = 0;
|
|
// int nMissedCache = 0;
|
|
protected override void DataPortal_Fetch(object Criteria)
|
|
{
|
|
|
|
listMessageCache.Clear();
|
|
listNotifySubscriptionCache.Clear();
|
|
|
|
//Loop through all the events in the table
|
|
SafeDataReader dr = null;
|
|
try
|
|
{
|
|
|
|
|
|
|
|
DBCommandWrapper cm = DBUtil.DB.GetSqlStringCommandWrapper(
|
|
//************************************************************
|
|
"SELECT aNotifyEvent.*, aNotifySubscription.aID " +
|
|
"AS aSUBSCRIPTIONID FROM aNotifyEvent INNER " +
|
|
"JOIN aNotifySubscription ON aNotifyEvent.AAPPLIESTOUSERID " +
|
|
"= aNotifySubscription.aUserID " +
|
|
"AND aNotifyEvent.aRootObjectType = aNotifySubscription.aRootObjectType " +
|
|
"AND aNotifyEvent.aEventType " +
|
|
"= aNotifySubscription.aEventType " +
|
|
" AND ( " +
|
|
" (ANOTIFYEVENT.AGUIDVALUE = ANOTIFYSUBSCRIPTION.AGUIDVALUE) " +
|
|
" or ((ANOTIFYEVENT.AGUIDVALUE IS NULL AND ANOTIFYSUBSCRIPTION.AGUIDVALUE IS NULL )) " +
|
|
" ) "
|
|
|
|
//************************************************************
|
|
);
|
|
|
|
dr=new SafeDataReader(DBUtil.DB.ExecuteReader(cm));
|
|
|
|
while(dr.Read())
|
|
{
|
|
ProcessSubscription(dr);
|
|
|
|
}
|
|
|
|
if(dr!=null) dr.Close();
|
|
|
|
//Now loop through all NON user specific events
|
|
//Outer joining the subscription so that we will get none to many
|
|
//subscribers to a single non-user-specific event
|
|
|
|
DBCommandWrapper cm2 = DBUtil.DB.GetSqlStringCommandWrapper(
|
|
//************************************************************
|
|
"SELECT aNotifyEvent.*, aNotifySubscription.aID " +
|
|
"AS aSUBSCRIPTIONID FROM aNotifyEvent LEFT " +
|
|
"OUTER JOIN aNotifySubscription ON aNotifyEvent.aRootObjectType " +
|
|
"= aNotifySubscription.aRootObjectType " +
|
|
"AND aNotifyEvent.aEventType = aNotifySubscription.aEventType " +
|
|
"AND aNotifyEvent.aGuidValue " +
|
|
"= aNotifySubscription.aGuidValue " +
|
|
"WHERE (aNotifyEvent.AAPPLIESTOUSERID = @GUIDEMPTY) "
|
|
//************************************************************
|
|
);
|
|
cm2.AddInParameter("@GUIDEMPTY",DbType.Guid,Guid.Empty);
|
|
dr=new SafeDataReader(DBUtil.DB.ExecuteReader(cm2));
|
|
|
|
while(dr.Read())
|
|
{
|
|
#if (DEBUG)
|
|
throw new ApplicationException("Non user specific event found in notification list Processor.");
|
|
#else
|
|
ProcessSubscription(dr);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if(dr!=null) dr.Close();
|
|
}
|
|
}
|
|
|
|
|
|
#region Process Subscription Record (add to list)
|
|
|
|
|
|
/// <summary>
|
|
/// Process an event/subscription record
|
|
/// and insert into list
|
|
///
|
|
/// Gets all the info necessary for delivery as well
|
|
/// as for removing the notify event after sucessful delivery
|
|
/// </summary>
|
|
/// <param name="dr"></param>
|
|
private void ProcessSubscription(SafeDataReader dr)
|
|
{
|
|
//Skip records with no matching subscription
|
|
//(this shouldn't happen should it? TODO:Log this)
|
|
if(dr.GetGuid("aSUBSCRIPTIONID")==Guid.Empty)
|
|
return;
|
|
|
|
//Fetch Subscription
|
|
|
|
//TODO: CACHE THIS
|
|
Guid subscriptionID=dr.GetGuid("aSUBSCRIPTIONID");
|
|
//if not in cache then add it
|
|
if (!listNotifySubscriptionCache.ContainsKey(subscriptionID))
|
|
{
|
|
//nMissedCache++;
|
|
listNotifySubscriptionCache[subscriptionID] = NotifySubscription.GetItem(subscriptionID);
|
|
}
|
|
//else
|
|
// nHitCache++;
|
|
|
|
//set from cache
|
|
NotifySubscription ns = listNotifySubscriptionCache[subscriptionID];
|
|
|
|
//Check if a dated notification is now deliverable
|
|
SmartDate EventDate=DBUtil.ToLocal(dr.GetSmartDate("aEventDate"));
|
|
if(!EventDate.IsEmpty)//it's a dated event...
|
|
{
|
|
//Ok, we have an event date, let's see if it's deliverable
|
|
//This method called will account for the two types of dated events
|
|
//ones where the user can set an advance warning date range
|
|
//and the ones where they can't and it's just delivered on that date
|
|
if(!ns.EventDateIsWithinDeliverableRange(EventDate.Date)) return;
|
|
|
|
}
|
|
|
|
foreach(NotifySubscriptionDelivery nsd in ns.Deliveries)
|
|
{
|
|
NotifyDeliverySetting ds=this._DeliverySettings[nsd.NotifyDeliveryMethodID];
|
|
if (ds.EventWindows.InEventWindow(DBUtil.CurrentWorkingDateTime))//case 1163
|
|
{
|
|
//*******************************************
|
|
//Add to list
|
|
NotificationListInfo info=new NotificationListInfo();
|
|
info._NotifyEventID=dr.GetGuid("aID");
|
|
info._Address=ds.Address;
|
|
info._DeliverToUserID=ds.UserID;
|
|
info._AppliesToUserID=dr.GetGuid("AAPPLIESTOUSERID");
|
|
info._DeliveryMethod=ds.DeliveryMethod;
|
|
info._EventType=dr.GetInt16("aEventType");
|
|
info._GuidValue=dr.GetGuid("aGuidValue");
|
|
info._RootObjectID=dr.GetGuid("aRootObjectID");
|
|
info._RootObjectType=(RootObjectTypes)dr.GetInt16("aRootObjectType");
|
|
|
|
//don't allow deliver notifications about new memos via memo
|
|
//or it will cause a chain reaction
|
|
if(info._RootObjectType==RootObjectTypes.Memo &&
|
|
info.EventType == (int)MemoEvent.Created &&
|
|
ds.DeliveryMethod==NotifyDeliveryMethods.Memo)
|
|
continue;//skip out of the loop
|
|
string Language = User.GetUserLanguage(info.DeliverToUserID);
|
|
|
|
//case 1415
|
|
double TimeZoneOffset = User.GetUserTimeZoneOffset(info.DeliverToUserID);
|
|
|
|
//see if there is a message in the cache we can use instead
|
|
NotifyMessage nm = null;
|
|
NotifyMessageRequestData d = new NotifyMessageRequestData(
|
|
info.RootObjectType,
|
|
info.EventType,
|
|
info.RootObjectID,
|
|
Language,
|
|
ds.MaxCharacters,
|
|
ds.MessageFormat,
|
|
info._GuidValue,
|
|
TimeZoneOffset
|
|
);
|
|
|
|
//case 812
|
|
if (d.RootObject == RootObjectTypes.User && d.EventType == 1)
|
|
{
|
|
//case 1375 add ability for subject without schema change
|
|
string sSavedMessage=dr.GetString("ASAVEDMESSAGE");
|
|
|
|
if (sSavedMessage.StartsWith("<SUBJECT>"))
|
|
{
|
|
Match m = AyaBizUtils.rxQuickNotifySubject.Match(sSavedMessage);
|
|
if (m.Success)
|
|
{
|
|
string sSubject=m.Groups["subject"].Value;
|
|
string sBody=m.Groups["body"].Value;
|
|
if (string.IsNullOrEmpty(sSubject)) sSubject = "QuickNotification";
|
|
if (string.IsNullOrEmpty(sBody)) sBody = "";
|
|
nm = new NotifyMessage(sSubject, sBody);
|
|
}
|
|
else
|
|
nm = new NotifyMessage("QuickNotification", sSavedMessage);
|
|
}
|
|
else//no subject or old style
|
|
nm = new NotifyMessage("QuickNotification", sSavedMessage);
|
|
}
|
|
else
|
|
{
|
|
//Get it from the cache if present
|
|
foreach (NotifyMessageRequestData n in listMessageCache)
|
|
{
|
|
if (n.Equals(d))
|
|
{
|
|
//nHitCache++;
|
|
nm = n.Message;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//If not retrieved from cache then
|
|
//retrive and add to cache
|
|
if (nm == null)
|
|
{
|
|
//nMissedCache++;
|
|
try
|
|
{
|
|
nm = NotifyEventUIHelper.GetNotificationMessage(d);
|
|
d.Message = new NotifyMessage(nm.Subject, nm.Message);
|
|
listMessageCache.Add(d);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
//case 1386
|
|
//crack exception if necessary
|
|
while (ex.InnerException != null) ex = ex.InnerException;
|
|
//log and then continue
|
|
NotifyDeliveryLog.LogDelivery(d.RootObject, d.RootObjectID, d.EventType, ds.UserID, false, d.GuidValue, ds.DeliveryMethod, "Error in NotificationList building new notification message. Full error is:\r\n" + ex.Message,DateTime.Now);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
info._Message = nm.Message;
|
|
info._Subject = nm.Subject;
|
|
InnerList.Add(info);
|
|
|
|
//*******************************************
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endregion Process subscription record
|
|
#endregion
|
|
|
|
#region criteria
|
|
/// <summary>
|
|
/// Criteria for identifying existing object
|
|
/// </summary>
|
|
[Serializable]
|
|
private class Criteria
|
|
{
|
|
|
|
|
|
//public Guid UserID;
|
|
|
|
public Criteria(/*Guid _UserID*/)
|
|
{
|
|
//UserID=_UserID;
|
|
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
}//end NotificationList
|
|
#pragma warning restore 1591
|
|
}//end namespace GZTW.AyaNova.BLL |