Files
ayanova7/source/bizobjects/AyaLib/GZTW.AyaNova.BLL/NotificationList.cs
2018-06-29 19:47:36 +00:00

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