This commit is contained in:
2021-08-09 14:18:08 +01:00
parent 0d7be69e1e
commit 5e5ef7190b
84 changed files with 2449 additions and 1717 deletions
@@ -52,6 +52,8 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
private class ActivityData_Web : IndexResults.ActivityData
{
public ActivityData_Web(ItemId itemId, DateTime effectiveOn) : base(itemId, effectiveOn) { }
public void SetOrganisation(SysId organisationId, String organisation) { OrganisationId = organisationId; Organisation = organisation; }
public void SetAuthor(SysId userAccountId, String author) { UserAccountIdAuthor = userAccountId; Author = author; }
public void SetCaption(String caption) { Caption = caption; }
public void SetBlurb(String blurb) { Blurb = blurb; }
public void SetSport(SysId sportId, String sportName) { SportId = sportId; SportName = sportName; }
@@ -134,7 +136,7 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
private void PopulateActivityDetails(IndexContext context, List<ActivityData_Web> activities)
{
PopulateUserActivityDetails(context, activities);
PopulateJournalistArticleDetails(context, activities);
PopulateArticleDetails(context, activities);
PopulateOrganisationOpportunitiesDetails(context, activities);
}
@@ -187,34 +189,42 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
}
//-------------------------------------------------------------------
// Journalist Article details.
private void PopulateJournalistArticleDetails(IndexContext context, List<ActivityData_Web> activities)
// Article details.
private void PopulateArticleDetails(IndexContext context, List<ActivityData_Web> activities)
{
// Extract article Ids.
List<SysId> articleIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.JournalistArticle).Select(ItemId => ItemId.ItemId.Id).ToList();
List<SysId> articleIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.Article).Select(ItemId => ItemId.ItemId.Id).ToList();
if (articleIds.IsEmpty()) return;
// Article columns - limit to essential information.
ColumnDfn colId = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Id);
ColumnDfn colHeadline = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Headline);
ColumnDfn colSummary = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Summary);
ColumnDfn colSportId = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.SportIdPrimary);
ColumnDfn colSportName = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Sport_Name);
ColumnDfn colRegionId = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.RegionIdPrimary);
ColumnDfn colRegionName = Internals.ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Region_Name);
List<ColumnDfn> columns = new List<ColumnDfn>() { colId, colHeadline, colSummary, colSportId, colSportName, colRegionId, colRegionName };
ColumnDfn colId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Id);
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.OrganisationId);
ColumnDfn colOrganisation = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Organisation_Name);
ColumnDfn colAuthorId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.UserAccountIdAuthor);
ColumnDfn colAuthor = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Author_DisplayName);
ColumnDfn colHeadline = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Headline);
ColumnDfn colSummary = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Summary);
ColumnDfn colSportId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.SportIdPrimary);
ColumnDfn colSportName = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Sport_Name);
ColumnDfn colRegionId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.RegionIdPrimary);
ColumnDfn colRegionName = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Region_Name);
List<ColumnDfn> columns = new List<ColumnDfn>() { colId, colOrganisationId, colOrganisation, colAuthor, colAuthorId, colHeadline, colSummary, colSportId, colSportName, colRegionId, colRegionName };
// Article filter.
SaxJournalistArticle.Params prmArticle = new SaxJournalistArticle.Params();
SaxArticle.Params prmArticle = new SaxArticle.Params();
prmArticle.IdsIncluded.AddRange(articleIds);
prmArticle.StatusCat = SaxJournalistArticle.StatusCat.ActiveOnly;
prmArticle.StatusCat = SaxArticle.StatusCat.ActiveOnly;
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteJournalistArticleQuery(columns, prmArticle))
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteArticleQuery(columns, prmArticle))
{
while (dbResultSet != null && dbResultSet.NextRecord())
{
NamedValue.Map values = dbResultSet.GetRecordValues();
ItemId itemId = new ItemId((short)Sax.DataItemType.JournalistArticle, new SysId(values.GetLong(colId.DataName)));
ItemId itemId = new ItemId((short)Sax.DataItemType.Article, new SysId(values.GetLong(colId.DataName)));
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
String organisation = values.GetString(colOrganisation.DataName);
SysId authorId = new SysId(values.GetLong(colAuthorId.DataName));
String author = values.GetString(colAuthor.DataName);
String headline = values.GetString(colHeadline.DataName);
String summary = values.GetString(colSummary.DataName);
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
@@ -225,6 +235,9 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
// Populate to corresponding activities.
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(itemId)))
{
activity.SetOrganisation(organisationId, organisation);
activity.SetAuthor(authorId, author);
activity.SetCaption(headline);
activity.SetCaption(headline);
activity.SetBlurb(summary);
activity.SetSport(sportId, sportName);
@@ -244,6 +257,8 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
// Opportunity columns - limit to essential information.
ColumnDfn colId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Id);
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.OrganisationId);
ColumnDfn colOrganisation= Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Organisation_Name);
ColumnDfn colPosition = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Position);
ColumnDfn colOutline = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Outline);
ColumnDfn colSportId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.SportIdPrimary);
@@ -263,8 +278,10 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
{
NamedValue.Map values = dbResultSet.GetRecordValues();
ItemId itemId = new ItemId((short)Sax.DataItemType.OrganisationOpportunity, new SysId(values.GetLong(colId.DataName)));
String headline = values.GetString(colPosition.DataName);
String summary = values.GetString(colOutline.DataName);
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
String organisation = values.GetString(colOrganisation.DataName);
String position = values.GetString(colPosition.DataName);
String outline = values.GetString(colOutline.DataName);
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
String sportName = values.GetString(colSportName.DataName);
SysId regionId = new SysId(values.GetLong(colRegionId.DataName));
@@ -273,8 +290,9 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
// Populate to corresponding activities.
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(itemId)))
{
activity.SetCaption(headline);
activity.SetBlurb(summary);
activity.SetOrganisation(organisationId, organisation);
activity.SetCaption(position);
activity.SetBlurb(outline);
activity.SetSport(sportId, sportName);
activity.SetRegion(regionId, regionName);
}
@@ -63,7 +63,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
protected SaxApplication_Web App { get { return SaxApplication_Web.WebApp; } }
public SaxAppConfig AppConfig { get { return App.AppConfig; } }
public SaxSessionContext SessionContext { get { return App.SessionContext; } }
protected SaxLocaliser Localiser { get; }
public SaxLocaliser Localiser { get; }
/// <summary>
/// Indicate whether session data should be stored by action.
/// <para>Any action that might modify the session data must store it.</para>
@@ -202,7 +202,16 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
//-------------------------------------------------------------------
// Parameters.
//-------------------------------------------------------------------
public String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key)
// Online Request Password encryption parameters (key & IV) are defined in
// the base Controller so that they can be shared with the Adnin application.
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
// IV Must be regenerated if key is changed.
protected static String Base64Key_RequestPassword_Online { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
//private static String Base64IV_RequestPassword_Generated_Online { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword_Online);
protected static String Base64IV_RequestPassword_Online { get; } = "1VAWYTW6d72n/6HDNhbqow==";
//-------------------------------------------------------------------
public static String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key)
{
String fn = nameof(ControllerBase) + ".EncryptParameters";
try
@@ -219,7 +228,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
// Serialise parameters as if in a URL query string - so that they can be deserialised in DecryptParameters() below.
string queryString = String.Join("&", paramKeys.Select(a => a + "=" + HttpUtility.UrlEncode(parametersToEncrypt[a])));
String encrypted = SacsEncryptionHelper.Encrypt(queryString, base64IV, base64Key);
if (DebugMode)
if (SacsSystem.DebugMode)
{
SaLogger.Debug(fn + " Encrypted: " + encrypted);
NameValueCollection decryptedParams = DecryptParameters(encrypted, base64IV, base64Key);
@@ -229,10 +238,10 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
return "";
}
public NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
{
String fn = nameof(ControllerBase) + ".DecryptParameters";
if (DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tIV: " + base64IV + "\n\tKey: " + base64Key);
if (SacsSystem.DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tIV: " + base64IV + "\n\tKey: " + base64Key);
try
{
String queryString = SacsEncryptionHelper.Decrypt(encrypted, base64IV, base64Key);
@@ -368,13 +377,19 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
}
//-------------------------------------------------------------------
// Response data.
// Null values are ignored by JSON serialisation.
// - See Saxonite.Net.Core.Web.Base.App.SaxStartup.ConfigureServices()
// - Ref. config.services.AddMvc(...).AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
//-------------------------------------------------------------------
// Base response data - for simple responses.
public class AjaxResponse_Base
{
// Response status.
public bool Success { get; set; } = false;
public bool Error { get; set; } = false;
public bool SessionExpired { get; protected set; } = false;
public bool GoHome { get; protected set; } = false;
public bool? Success { get; set; } = null;
public bool? Error { get; set; } = null;
public bool? SessionExpired { get; protected set; } = null;
public bool? GoHome { get; protected set; } = null;
public AjaxResponse_Base SetSessionExpired(String title, String text)
{
SessionExpired = true;
@@ -415,7 +430,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
}
//---------------------------------------------------------------
// Item data.
/// <summary>Item data - Common properties for data items.</summary>
public class ItemData_Base
{
// Common item properties.
@@ -437,6 +452,15 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
/// <summary>Updated on date - formatted per locale</summary>
public String UpdatedOnFmt { get; set; }
}
/// <summary>
/// Item data with just Id and name.
/// <para>- Id is String to allow for obfuscated values.</para>
/// </summary>
public class ItemIdName
{
public String Id { get; set; }
public String Name { get; set; }
}
//---------------------------------------------------------------
// Form data.
@@ -453,7 +477,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
public String Error { get; set; }
}
private readonly Dictionary<String, FormControlValue> controlValues = new Dictionary<String, FormControlValue>();
public List<FormControlValue> ControlValues { get { return controlValues.Values.ToList(); } }
public List<FormControlValue> ControlValues { get { return controlValues.Count > 0 ? controlValues.Values.ToList() : null; } }
public void SetControlValue(String controlName, String value, String error = null)
{
if (controlValues.ContainsKey(controlName))
@@ -500,7 +524,6 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
public String Message { get; set; }
}
public NotificationData Notification { get; private set; }
public bool HasNotification { get { return Notification != null; } }
public AjaxResponse_Data SetNotification(String title, String message)
{
Notification = new NotificationData() { Title = title, Message = message };
@@ -191,12 +191,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
if (AccountMgr.UpdateUserAccount(organisationMember.UserAccount, DbUpdateInfo))
{
// Send activation email.
SaEmailData emailData = new SaEmailData();
emailData.Config = EmailConfig;
emailData.AddressesTo.Add(organisationMember.UserAccount.EmailAddress);
emailData.Subject = Localiser["user.activate.email.subject"];
PopulateAccountActivatedEmailBody(emailData, organisationMember.UserAccount);
if (EmailConsole.SendEmail(emailData))
if (SendAccountActivatedEmail(this, organisationMember.UserAccount))
SaLogger.Info(fn + " User Activation email sent to " + organisationMember.UserAccount.EmailAddress, true);
else SaLogger.Warn(fn + " Failed to send User Activation email to " + organisationMember.UserAccount.EmailAddress);
}
@@ -218,18 +213,33 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
}
//-------------------------------------------------------------------
private void PopulateAccountActivatedEmailBody(SaEmailData emailData, SaxUserAccount userAccount)
/// <summary>
/// Generate the User Activation email.
/// <para>NB URL must be to the Online application.</para>
/// <para>NB Encryption must be done with the Online logic.</para>
/// </summary>
public static bool SendAccountActivatedEmail (SaxController_Admin controller, SaxUserAccount userAccount)
{
SaEmailData emailData = new SaEmailData();
emailData.Config = controller.EmailConfig;
emailData.AddressesTo.Add(userAccount.EmailAddress);
emailData.Subject = controller.Localiser["user.activate.email.subject"];
PopulateAccountActivatedEmailBody(controller, emailData, userAccount);
return controller.EmailConsole.SendEmail(emailData);
}
private static void PopulateAccountActivatedEmailBody(SaxController_Admin controller, SaEmailData emailData, SaxUserAccount userAccount)
{
// Will need to handle culture (language/country) as and when introduced.
emailData.MessageBody = SaxResourceHelper.GetTextResource(SaxResourceHelper.TextResource.Email_Security_AccountActivated_Html);
emailData.HtmlBody = true;
// Replace dynamic tags.
EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
controller.EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
// Replace dynamic tag for link back to change password page.
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, "", AppConfig.URL.Online.Root));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(controller, userAccount.Id, userAccount.EmailAddress, "", true));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.SignIn]", controller.AppConfig.URL.Online.Root + "Security/SignIn");
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(controller).ToString());
}
//-------------------------------------------------------------------
@@ -146,7 +146,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
NamedValue.Map values = resultSet.GetRecordValues();
OrganisationData_List organisationData = new OrganisationData_List()
{
Id = values.GetString(colId.DataName),
Id = values.GetLong(colId.DataName).ToString(),
Name = values.GetString(colName.DataName),
TypeCode = values.GetString(colOrganisationType.DataName),
TypeDesc = OrganisationTypeCodes.GetDescForCode(values.GetString(colOrganisationType.DataName)),
@@ -337,13 +337,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account is not 'Admin'");
else
{
// Send password request email.
SaEmailData emailData = new SaEmailData();
emailData.Config = EmailConfig;
emailData.AddressesTo.Add(model.EmailAddress);
emailData.Subject = Localiser["security.caption.request.password"];
PopulateRequestPasswordEmailBody(emailData, userAccount);
if (EmailConsole.SendEmail(emailData))
if (SendRequestPasswordEmail(this, userAccount, false))
SaLogger.Info(fn + " Password request email sent to " + model.EmailAddress, true);
else SaLogger.Warn(fn + " Failed to send password request email to " + model.EmailAddress);
}
@@ -354,18 +348,28 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
return Json(responseData);
}
private void PopulateRequestPasswordEmailBody(SaEmailData emailData, SaxUserAccount userAccount)
public static bool SendRequestPasswordEmail(SaxController_Admin controller, SaxUserAccount userAccount, bool onlineContext)
{
// Send password request email.
SaEmailData emailData = new SaEmailData();
emailData.Config = controller.EmailConfig;
emailData.AddressesTo.Add(userAccount.EmailAddress);
emailData.Subject = controller.Localiser["security.caption.request.password"];
PopulateRequestPasswordEmailBody(controller, emailData, userAccount, onlineContext);
return controller.EmailConsole.SendEmail(emailData);
}
private static void PopulateRequestPasswordEmailBody(SaxController_Admin controller, SaEmailData emailData, SaxUserAccount userAccount, bool onlineContext)
{
// Will need to handle culture (language/country) as and when introduced.
emailData.MessageBody = SaxResourceHelper.GetTextResource(SaxResourceHelper.TextResource.Email_Security_RequestPassword_Html);
emailData.HtmlBody = true;
// Replace dynamic tags.
EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
controller.EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
// Replace dynamic tag for link back to change password page.
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, "", GetRedirectLocation(RedirectLocation.WebAppBase)));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", GenerateRequestPasswordLink(controller, userAccount.Id, userAccount.EmailAddress, "", onlineContext));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", GetRequestPasswordEmailLinkExpiresMinutes(controller).ToString());
}
//-------------------------------------------------------------------
@@ -377,11 +381,20 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
private static String ParamName_Token { get; } = "tok";
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
// IV Must be regenerated if key is changed.
private static String Base64Key_RequestPassword { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
private static String Base64IV_RequestPassword_Generated { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword);
private static String Base64IV_RequestPassword { get; } = "1VAWYTW6d72n/6HDNhbqow==";
internal static String GenerateRequestPasswordLink(SaxController_Admin controller, SysId userAccountId, String emailAddress, String requestPasswordToken, String baseUrl)
private static String Base64Key_RequestPassword_Admin { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
//private static String Base64IV_RequestPassword_Generated { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword);
private static String Base64IV_RequestPassword_Admin { get; } = "1VAWYTW6d72n/6HDNhbqow==";
/// <summary>
/// Generate Request Password link.
/// <para>NB For an Online application request (from teh ASdmin system), must ensure that the URL and encryption parameters are switched.</para>
/// </summary>
internal static String GenerateRequestPasswordLink(SaxController_Admin controller, SysId userAccountId, String emailAddress, String requestPasswordToken, bool onlineContext)
{
// Base URL.
String baseUrl = onlineContext ? controller.AppConfig.URL.Online.Root : controller.GetRedirectLocation(RedirectLocation.WebAppBase);
String requestPassword_Base64Key = onlineContext ? Base64Key_RequestPassword_Online : Base64Key_RequestPassword_Admin;
String requestPassword_ase64IV = onlineContext ? Base64IV_RequestPassword_Online : Base64IV_RequestPassword_Admin;
NameValueCollection parameters = new NameValueCollection();
parameters.Add(ParamName_UserAccountId, SysId.ToString(userAccountId));
parameters.Add(ParamName_EmailAddress, emailAddress);
@@ -389,7 +402,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
parameters.Add(ParamName_Token, requestPasswordToken);
String link =
baseUrl + "Security/ChangePassword?" +
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(controller.EncryptParameters(parameters, Base64IV_RequestPassword, Base64Key_RequestPassword));
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(EncryptParameters(parameters, requestPassword_ase64IV, requestPassword_Base64Key));
return link;
}
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Admin controller)
@@ -442,7 +455,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
RequestPasswordParams requestPasswordParams = new RequestPasswordParams();
if (!StringUtil.IsEmpty(encryptedParams))
{
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RequestPassword, Base64Key_RequestPassword);
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RequestPassword_Admin, Base64Key_RequestPassword_Admin);
requestPasswordParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_UserAccountId)));
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
requestPasswordParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
@@ -19,18 +19,15 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
{
//-------------------------------------------------------------------
// User data.
private class UserData_List
private class UserData_List : AjaxResponse_Data.ItemData_Base
{
public String Id { get; set; }
public String EmailAddress { get; set; }
public String DisplayName { get; set; }
public String Title { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public int UserRoleCount { get; set; }
public bool SystemAdmin { get; set; }
public String StatusCode { get; set; }
public String StatusDesc { get; set; }
public bool? SystemAdmin { get; set; } = null;
}
private class UserData_Full : UserData_List
{
@@ -45,6 +42,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
data.FirstName = user.FirstName;
data.LastName = user.LastName;
data.UserRoleCount = userRoles?.GetUserRolesByStatus(SaStatus.Active).Count ?? 0;
data.SystemAdmin = (userRoles != null && userRoles.Exists(item => item.UserRole == Sax.UserRole.SystemAdmin) ? true : (bool?)null);
data.StatusCode = user.StatusCode;
data.StatusDesc = user.StatusDesc;
}
@@ -95,9 +93,10 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
String messageTitle = Localiser["user.caption.users"];
AjaxResponse_UserList responseData = new AjaxResponse_UserList(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Reference data - user roles.
foreach (TypeCodeDesc userRole in UserRoleCodes)
@@ -187,9 +186,10 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
String messageTitle = Localiser["user.caption.user"];
AjaxResponse_User responseData = new AjaxResponse_User(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Identify item.
SysId userAccountId = model.UserAccountId.ToSysId();
@@ -222,9 +222,10 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
AjaxResponse_User responseData = new AjaxResponse_User(model);
StoreSessionData = false;
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Identify user.
if (StringUtil.IsEmpty(model.UserEmailAddress))
@@ -259,9 +260,10 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
String messageTitle = Localiser["user.caption.user"];
AjaxResponse_User responseData = new AjaxResponse_User(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate item properties.
model.ValidateUserData(responseData);
@@ -367,6 +369,72 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
return Json(responseData);
}
//-------------------------------------------------------------------
// Send User Emails ajax request.
//-------------------------------------------------------------------
[HttpPost]
[Route("User/Ajax/SendEmails")]
public IActionResult Ajax_SendEmails(Model_User model)
{
String fn = GetType().Name + ".Ajax_SendEmails";
String messageTitle = Localiser["label.emails"];
AjaxResponse_User responseData = new AjaxResponse_User(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Retrieve user.
SysId userAccountId = model.UserAccountId.ToSysId();
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userAccountId);
if (userAccount == null)
{
SaLogger.Warn(fn + " Failed to retrieve user for Id: '" + model.UserAccountId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// User roles.
List<SaxUserRole> userRoles = GetUserRoles(userAccount.Id, SaxUserRole.StatusCat.Any);
bool systemAdmin = userRoles.Exists(item => item.UserRole == Sax.UserRole.SystemAdmin);
// Email types to send.
bool sendAcountActivationOnline = StringUtil.ToBool(model.UserEmailAcountActivationOnline);
bool sendRequestPasswordOnline = StringUtil.ToBool(model.UserEmailRequestPasswordOnline);
bool sendRequestPasswordAdmin = StringUtil.ToBool(model.UserEmailRequestPasswordAdmin);
if (!sendAcountActivationOnline && !sendRequestPasswordOnline && !sendRequestPasswordAdmin)
return Json(responseData.SetMessage(messageTitle, Localiser["msg.validation.select.option"]));
if (sendRequestPasswordAdmin && !systemAdmin)
return Json(responseData.SetMessage(messageTitle, Localiser["user.msg.not.system.admin"]));
// Send emails.
int emailsSentCount = 0;
if (sendAcountActivationOnline)
{
if (!OrganisationController.SendAccountActivatedEmail(this, userAccount))
return Json(responseData.SetMessage(messageTitle, "Failed to send Online Accoutn Activation email."));
emailsSentCount++;
}
if (sendRequestPasswordOnline)
{
if (!SecurityController.SendRequestPasswordEmail(this, userAccount, true))
return Json(responseData.SetMessage(messageTitle, "Failed to send Online Request Password email."));
emailsSentCount++;
}
if (sendRequestPasswordAdmin)
{
if (!SecurityController.SendRequestPasswordEmail(this, userAccount, false))
return Json(responseData.SetMessage(messageTitle, "Failed to send Admin Request Password email."));
emailsSentCount++;
}
// Construct response.
PopulateUserResponseData(responseData.user, userAccount, userRoles.GetUserRolesByStatus(SaStatus.Active));
responseData.SetNotification(messageTitle, "Emails sent: " + emailsSentCount);
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
@@ -1,6 +1,7 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Core.Web.Base.App;
@@ -57,6 +58,10 @@ namespace Saxonite.Net.Core.Web.Admin.Models
}
public String UserStatusCode { get; set; }
public SaStatus UserStatus { get { return SacsSystem.GetStatusForCode(UserStatusCode); } }
// User emails.
public String UserEmailAcountActivationOnline { get; set; }
public String UserEmailRequestPasswordOnline { get; set; }
public String UserEmailRequestPasswordAdmin { get; set; }
//-------------------------------------------------------------------
// Validation.
@@ -73,6 +78,8 @@ namespace Saxonite.Net.Core.Web.Admin.Models
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(UserEmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(UserEmailAddress))
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.invalid.value"]);
else
{
// Check for duplicate email address.
@@ -201,6 +201,12 @@
<data name="label.email.address" xml:space="preserve">
<value>Email address</value>
</data>
<data name="label.email.types" xml:space="preserve">
<value>Email types</value>
</data>
<data name="label.emails" xml:space="preserve">
<value>Emails</value>
</data>
<data name="label.filename" xml:space="preserve">
<value>Filename</value>
</data>
@@ -390,6 +396,9 @@
<data name="msg.validation.maximum.length" xml:space="preserve">
<value>Value must not exceed {0} characters</value>
</data>
<data name="msg.validation.select.option" xml:space="preserve">
<value>At least one option must be selected.</value>
</data>
<data name="organisation.activate.intro" xml:space="preserve">
<value>On activation, the Organisation will become visible on the platform and authorised members will be able to post content associated with the organisation.</value>
</data>
@@ -522,6 +531,9 @@
<data name="user.activate.email.subject" xml:space="preserve">
<value>Account Activation</value>
</data>
<data name="user.caption.select.user.emails" xml:space="preserve">
<value>Select User Emails</value>
</data>
<data name="user.caption.select.user.roles" xml:space="preserve">
<value>Select User Roles</value>
</data>
@@ -537,4 +549,19 @@
<data name="user.caption.users" xml:space="preserve">
<value>Users</value>
</data>
<data name="user.email.account.activation.online" xml:space="preserve">
<value>Account activation - Online</value>
</data>
<data name="user.email.request.password.admin" xml:space="preserve">
<value>Request password - Admin</value>
</data>
<data name="user.email.request.password.online" xml:space="preserve">
<value>Request password - Online</value>
</data>
<data name="user.emails.intro" xml:space="preserve">
<value>Select the types of email to be sent.</value>
</data>
<data name="user.msg.not.system.admin" xml:space="preserve">
<value>User is not system admin.</value>
</data>
</root>
@@ -181,7 +181,7 @@
@* Footer *@
<footer id="sax-page-footer" class="border-top footer text-muted">
<div class="container">
@(Model.CopyrightNotice) - @Localiser["company.name"] @(Model.InstanceVersion) - <a asp-area="" asp-controller="Home" asp-action="">Home</a>
@(Model.CopyrightNotice) - @Localiser["company.name"] @(Model.InstanceVersion)
</div>
</footer>
+50 -5
View File
@@ -5,41 +5,80 @@
ViewData["Title"] = "Users";
}
<div class="">
<div class="sax-panel Users">
<script type="text/javascript">
sax.lbl.refresh = '@(Localiser.GetJavascriptText("label.refresh"))';
sax.lbl.create = '@(Localiser.GetJavascriptText("label.create"))';
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
sax.lbl.emails= '@(Localiser.GetJavascriptText("label.emails"))';
</script>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserFilter", @class = "sax-form", @onSubmit = "return false;" }))
{
@* Filter Panel *@
<div class="sax-panel-filter">
@* Header - Page caption, paging controls, actions. *@
<div class="sax-header row">
<div class="col"><div class="sax-caption">@Localiser["user.caption.users"]</div></div>
<div class="fixed row">
<div>
<div class="col">
<partial name="~/Views/Common/ResultsPaging.cshtml" />
</div>
<div class="sax-action sax-results-refresh"><img src="~/img/action/refresh24.png" alt="@(Localiser["label.refresh"])" title="@(Localiser["label.refresh"])" /></div>
<div class="sax-action sax-item-create"><img src="~/img/action/add24.png" alt="@(Localiser["label.create"])" title="@(Localiser["label.create"])" /></div>
<div class="fixed">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="sax-content">
<div class="row">
@* User filter - email, name etc. *@
<div class="col-sm-5 sax-label text-left text-sm-right">@Localiser["user.caption.user"]</div>
<div class="col-sm-7">@Html.TextBoxFor(model => model.Filter.User, new { @id = "ifFilterUser", @class = "FilterUser", @maxlength = "32" })</div>
</div>
</div>
@* Filter element templates *@
<div class="sax-panel-item-template">
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu UserFilter">
<li class="sax-dropdown-item sax-action"><div class="sax-label">XXX</div></li>
</ul>
</div>
</div>
}
@* Results Panel *@
<div class="sax-panel-results">
<div class="sax-panel-messages"></div>
<div class="sax-panel-item-list"></div>
@* Element templates *@
<div class="sax-panel-item-template">
@* User item template *@
<div class="sax-panel-item User">
<div class="sax-header row">
<div class="col">
@* User email *@
<div class="sax-caption"><div class="sax-action UserEmailAddress"></div></div>
</div>
<div class="fixed sax-actions">
<div class="sax-action sax-item-update"><img src="~/img/action/edit24.png" alt="@(Localiser["label.update"])" title="@(Localiser["label.update"])" /></div>
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
<div class="sax-content">
@@ -54,6 +93,12 @@
</div>
</div>
</div>
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu User">
<li class="sax-dropdown-item sax-action"><div class="sax-label">XXX</div></li>
</ul>
</div>
</div>
@@ -8,6 +8,7 @@
sax.dlg.title.createUser = '@Localiser.GetJavascriptText("user.caption.user.create")';
sax.dlg.title.updateUser = '@Localiser.GetJavascriptText("user.caption.user.update")';
sax.dlg.title.selectUserRoles = '@Localiser.GetJavascriptText("user.caption.select.user.roles")';
sax.dlg.title.selectUserEmails = '@Localiser.GetJavascriptText("user.caption.select.user.emails")';
sax.data.userRoleCodeDelim = '@Model.UserRoleCodeDelim';
</script>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserId", @class = "sax-form" }))
@@ -31,6 +32,7 @@
<div class="sax-message"></div>
</div>
/* Title */
<div class="sax-form-control UserTitle">
<div class="sax-label">
<label for="cbUserTitle"><span><span class="required"></span> @Localiser["label.title"]</span></label>
@@ -89,6 +91,57 @@
}
<partial name="~/Views/Common/SelectCode.cshtml" />
</div>
<partial name="~/Views/Common/SelectCode.cshtml" />
<div id="dlgUserEmails" class="sax-dialog" title="">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserEmails", @class = "sax-form", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.UserAccountId, new { @class = "UserAccountId" })
<div class="sax-para">@Localiser["user.emails.intro"]</div>
@* User email *@
<div class="sax-form-control UserEmailAddress">
<div class="sax-label">
<label><span>@Localiser["label.email.address"]</span></label>
</div>
<div class="sax-control">
<input type="text" class="UserEmailAddress sax-input" readonly="readonly" />
</div>
<div class="sax-message"></div>
</div>
@* User display name *@
<div class="sax-form-control UserDisplayName">
<div class="sax-label">
<label ><span>@Localiser["label.name"]</span></label>
</div>
<div class="sax-control">
<input type="text" class="UserDisplayName sax-input" readonly="readonly" />
</div>
<div class="sax-message"></div>
</div>
@* User emails *@
<div class="sax-form-control UserEmailTypes">
<div class="sax-label">
<label for="chkUserEmailRequestPasswordAdmin"><span>@Localiser["label.email.types"]</span></label>
</div>
<div class="sax-control">
<div class="AcountActivationOnlineOption">
<input type="checkbox" id="chkUserEmailAcountActivationOnline" class="UserEmailAcountActivationOnline" name="UserEmailAcountActivationOnline" value="1" />&nbsp;<span onclick="$('#chkUserEmailAcountActivationOnline').click()">@Localiser["user.email.account.activation.online"]</span>
</div>
<div class="RequestPasswordOnlineOption">
<input type="checkbox" id="chkUserEmailRequestPasswordOnline" class="UserEmailRequestPasswordOnline" name="UserEmailRequestPasswordOnline" value="1" />&nbsp;<span onclick="$('#chkUserEmailRequestPasswordOnline').click()">@Localiser["user.email.request.password.online"]</span>
</div>
<div class="RequestPasswordAdminOption">
<input type="checkbox" id="chkUserEmailRequestPasswordAdmin" class="UserEmailRequestPasswordAdmin" name="UserEmailRequestPasswordAdmin" value="1" />&nbsp;<span onclick="$('#chkUserEmailRequestPasswordAdmin').click()">@Localiser["user.email.request.password.admin"]</span>
</div>
</div>
<div class="sax-message"></div>
</div>
}
</div>
+11 -3
View File
@@ -77,7 +77,7 @@ html
body
{
/* Margin bottom by footer height */
margin-bottom: 60px;
margin-bottom: 40px;
}
.footer
@@ -88,8 +88,8 @@ body
padding: 0 2%;
white-space: nowrap;
/* Set the fixed height of the footer here */
height: 60px;
line-height: 60px; /* Vertically center the text there */
height: 40px;
line-height: 38px; /* Vertically center the text there */
}
/* Header */
@@ -122,6 +122,14 @@ button.accept-policy
line-height: inherit;
}
/* Footer */
#sax-page-footer div,
#sax-page-footer a
{
font-size:0.75rem;
}
/* Information */
.sax-para
+1 -1
View File
@@ -23,7 +23,7 @@
}
sax.handleDbSchemaResponse = function (response)
{
sax.debug('handleDbSchemaResponse', response);
//sax.debug('handleDbSchemaResponse', response);
delete sax.awaitingRefreshResponse;
var $results = $('.sax-panel-results.DbSchema');
var $msgs = $('.sax-panel-messages', $results).hide().empty();
+10 -10
View File
@@ -263,16 +263,16 @@
var $hdr = $('.heading', $not).css({ 'background-color': 'rgba(247,217,0,0.7)' });
$('.title', $not).html(title);
$('.message', $not).html(msg);
var $bdy = $('.sax-page-body');
sax.debug(sax.topMargin($bdy));
var $bdy = $('#sax-page-body');
//sax.debug(sax.topMargin($bdy));
var fbr = $bdy[0].getBoundingClientRect();
var fn = function () { $hdr.delay(2000).animate({ backgroundColor: '#f0f0f0' }, 1000); };
var fn = function () { $hdr.delay(1500).animate({ backgroundColor: '#f0f0f0' }, 500); };
$not.css({ 'top': Math.max(0, fbr.top - sax.topMargin($bdy)), 'right': $win.width() - fbr.right }).slideDown(500, fn);
sax.toNotification = setTimeout(sax.hideNotification, 6000);
sax.toNotification = setTimeout(sax.hideNotification, 4000);
}
sax.hideNotification = function ()
{
wwin.clearTimeout(sax.toNotification);
win.clearTimeout(sax.toNotification);
$('#sax-notification').slideUp(500);
}
sax.doPleaseWait = function ()
@@ -360,7 +360,7 @@
}
sax.doKeepLoggedIn = function ()
{
sax.debug('KeepLoggedIn Calling');
//sax.debug('KeepLoggedIn Calling');
var onKeepLoggedIn = function (response)
{
sax.debug('KeepLoggedIn Responded', response);
@@ -370,19 +370,19 @@
}
sax.configureSessionRefresh = function ()
{
sax.debug('SessionRefresh Configuring');
//sax.debug('SessionRefresh Configuring');
$(document).on('mousedown mousemove touchstart scroll keydown', sax.triggeRefreshSession);
}
sax.triggeRefreshSession = function ()
{
sax.session = sax.session || { refresh: {} };
//sax.session = sax.session || { refresh: {} };
let ssr = sax.session.refresh;
win.clearTimeout(ssr.timeout);
ssr.timeout = setTimeout(function () { sax.refreshSession(); }, 150000);
}
sax.refreshSession = function ()
{
sax.debug('sax.refreshSession');
//sax.debug('sax.refreshSession');
sax.doKeepLoggedIn();
}
@@ -400,7 +400,7 @@
}
sax.setControlError = function (sel, error)
{
sax.debug(sel, error);
//sax.debug(sel, error);
var $ctrl = $(sel).closest('.sax-form-control').addClass('sax-error');
$('.sax-message', $ctrl).text(error);
}
@@ -151,7 +151,7 @@
}
sax.onUpdateItem = function (response)
{
sax.debug('onUpdateItem', response);
//sax.debug('onUpdateItem', response);
let $frm = sax.$frm.member;
$('.UserOrganisationId,input[type="text"],textarea,select', $frm).val('');
if (!response.success) return;
@@ -85,7 +85,7 @@
}
sax.onParentRegionSelected = function (rgn)
{
sax.debug('onParentRegionSelected', rgn);
//sax.debug('onParentRegionSelected', rgn);
let $frm = sax.$frm.region;
$('.RegionIdParent', $frm).val(rgn.id);
$('.ParentRegion', $frm).val(rgn.name);
@@ -115,7 +115,7 @@
}
sax.onUpdateItem = function (response)
{
sax.debug('onUpdateItem', response);
//sax.debug('onUpdateItem', response);
let $frm = sax.$frm.region;
$('.RegionId,input[type="text"],textarea,select', $frm).val('');
if (!response.success) return;
@@ -15,7 +15,7 @@
}
sax.onSignin = function (response)
{
sax.debug(response);
//sax.debug(response);
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
sax.goToPage('');
@@ -31,7 +31,7 @@
}
so.fn.doRefreshResults = function (response)
{
sax.debug('so.doRefreshResults', response);
//sax.debug('so.doRefreshResults', response);
sax.refreshPaging(response, '#frmSelectOrganisationFilter', so.fn.refreshOrganisations);
if (!response.success) return;
let $results = $('.sax-selection-results.Organisations', so.$dlg).empty().hide();
@@ -22,7 +22,7 @@
}
sax.doRefreshResults = function (response)
{
sax.debug('doRefreshResults', response);
//sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
var $results = $('.sax-panel-results');
@@ -0,0 +1,19 @@
/*
* Admin - System Logs page scripts.
*/
(function (win, doc, undef)
{
"use strict";
sax.itemIdPrefix = 'Itm_';
//--------------------------------------------------------------
//--------------------------------------------------------------
$(function ()
{
});
}(window, window.document));
/* The End */
+119 -66
View File
@@ -5,20 +5,21 @@
(function (win, doc, undef)
{
"use strict";
let $pnl = sax.$pnl, $frm = sax.$frm, $dlg = sax.$dlg;
sax.itemIdPrefix = 'Itm_';
sax.userAccount = {};
//--------------------------------------------------------------
sax.refreshResults = function (delay)
{
var $results = $('.sax-panel-results');
if (!sax.awaitingRefreshResponse)
{
var $items = $('.sax-panel-item-list', $results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
$('.sax-burger', $pnl.filter).hide();
var $items = $('.sax-panel-item-list', $pnl.results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
}
sax.ajaxRefreshResults = sax.ajaxRefreshResults || { url: sax.url.base + 'User/Ajax/GetList', formId: 'frmUserFilter', callbackFn: sax.doRefreshResults };
sax.doAjaxRequest(sax.ajaxRefreshResults, delay || 50);
sax.ajax.refreshResults = sax.ajax.refreshResults || { url: sax.url.base + 'User/Ajax/GetList', formId: 'frmUserFilter', callbackFn: sax.doRefreshResults };
sax.doAjaxRequest(sax.ajax.refreshResults, delay || 50);
sax.awaitingRefreshResponse = true;
}
sax.doRefreshResults = function (response)
@@ -26,10 +27,8 @@
//sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
var $results = $('.sax-panel-results');
var $msgs = $('.sax-panel-messages', $results).hide().empty();
var $items = $('.sax-panel-item-list', $results).hide().empty();
var $tmpl = $('.sax-panel-item-template .sax-panel-item.User', $results);
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty();
var $items = $('.sax-panel-item-list', $pnl.results).hide().empty();
sax.refreshPaging(response, '#frmUserFilter', sax.refreshResults);
if (!response.success) return;
// Reference data - Roles.
@@ -39,21 +38,19 @@
if (response.defaultStatusCode) sax.data.defaultStatusCode = response.defaultStatusCode;
if (response.statuses)
sax.populateSelectCodeDesc('#cbUserStatus', response.statuses);
// Menu.
var $bgr = $('.sax-burger', $pnl.filter).hide();
var $mnu = $('ul.sax-dropdown-menu', $bgr).empty();
$mnu.append(sax.getFilterMenuOption(sax.lbl.refresh, function () { sax.refreshResults(); }));
$mnu.append(sax.getFilterMenuOption(sax.lbl.create, function () { sax.createItem(); }));
$bgr.toggle(!!$('.sax-dropdown-item', $mnu).length);
// Items.
var items = response.users;
if (!items.length)
return $msgs.append($('<div class="sax-message">' + sax.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
{
let item = items[itemIdx];
let $item = $tmpl.clone();
sax.populateItem($item, item);
$items.append($item);
}
$items.append(sax.populateItem(sax.getItemTemplate(), items[itemIdx]));
$items.fadeIn(50);
// Reference data.
if (response.userRoles && response.userRoles.length)
sax.data.userRoles = response.userRoles;
}
sax.populateItem = function ($item, item)
{
@@ -66,9 +63,44 @@
$('.UserLastName', $item).text(item.lastName);
$('.UserRoleCount', $item).text(item.userRoleCount);
$('.StatusDesc', $item).text(item.statusDesc);
$('.sax-caption .sax-action, .sax-actions .sax-item-update', $item).off('click').on('click', function () { sax.updateItem(item.id) })
$item.off('dblclick').on('dblclick', function () { sax.updateItem(item.id) })
$('.sax-panel-results .sax-panel-messages').hide().empty();
$('.sax-caption .sax-action').toggleClass('sax-action', !item.deleted);
let $mnu = $('ul.sax-dropdown-menu', $item);
if (!item.deleted)
{
$mnu.append(sax.getItemMenuOption(sax.lbl.edit, function () { sax.updateItem(item) }));
$('.sax-header .sax-action.sax-item-update', $item).off('click').on('click', function () { sax.updateItem(item) });
$item.off('dblclick').on('dblclick', function () { sax.updateItem(item) });
$mnu.append(sax.getItemMenuOption(sax.lbl.emails, function () { sax.userEmails(item) }));
}
$('.sax-burger', $item).toggle(!!$('.sax-dropdown-item', $mnu).length);
$('.sax-panel-messages', $pnl.results).hide().empty();
return $item;
}
//--------------------------------------------------------------
sax.getFilterDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.UserFilter li.sax-dropdown-item', $pnl.filter).clone();
}
sax.getItemTemplate = function ()
{
return $('.sax-panel-item-template .sax-panel-item.User', $pnl.results).clone();
}
sax.getItemDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.User li.sax-dropdown-item', $pnl.results).clone();
}
sax.getFilterMenuOption = function (lbl, fn)
{
return sax.getMenuOption(sax.getFilterDropdownTemplate(), lbl, fn);
}
sax.getItemMenuOption = function (lbl, fn)
{
return sax.getMenuOption(sax.getItemDropdownTemplate(), lbl, fn);
}
sax.getMenuOption = function ($opt, lbl, fn)
{
return $opt.find('div.sax-label').text(lbl).end().on('click', fn);
}
//--------------------------------------------------------------
@@ -104,91 +136,112 @@
//--------------------------------------------------------------
sax.createItem = function ()
{
let $frm = sax.$frm.user;
$('.UserAccountId,.UserRoleCodes,input[type="text"],textarea,select', $frm).val('');
$('.UserStatus', $frm).val(sax.data.defaultStatusCode);
let frm = $frm.user;
$('.UserAccountId,.UserRoleCodes,input[type="text"],textarea,select', frm).val('');
$('.UserStatus', frm).val(sax.data.defaultStatusCode);
sax.clearControlErrors();
sax.userAccount = { userRoleCodes: [] };
sax.$dlg.user.dialog('option', 'title', sax.dlg.title.createUser);
sax.openDialog(sax.$dlg.user, 600, 600);
}
sax.doCreateItem = function ()
{
sax.storeItem();
$dlg.user.dialog('option', 'title', sax.dlg.title.createUser);
sax.openDialog($dlg.user, 600, 600);
}
//--------------------------------------------------------------
sax.updateItem = function (id)
sax.updateItem = function (item)
{
$('.UserAccountId', sax.$frm.userId).val(id);
sax.ajaxUpdateItem = sax.ajaxUpdateItem || { url: sax.url.base + 'User/Ajax/GetItem', formId: 'frmUserId', callbackFn: sax.onUpdateItem };
sax.doAjaxRequest(sax.ajaxUpdateItem, 50);
$('.UserAccountId', $frm.userId).val(item.id);
sax.ajax.updateItem = sax.ajax.updateItem || { url: sax.url.base + 'User/Ajax/GetItem', formId: 'frmUserId', callbackFn: sax.onUpdateItem };
sax.doAjaxRequest(sax.ajax.updateItem, 50);
}
sax.onUpdateItem = function (response)
{
//sax.debug('onUpdateItem', response);
let $frm = sax.$frm.user;
$('.UserAccountId,input[type="text"],textarea,select', $frm).val('');
let frm = $frm.user;
$('.UserAccountId,input[type="text"],textarea,select', frm).val('');
sax.clearControlErrors();
if (!response.success) return;
let item = sax.userAccount = response.user;
$('.UserAccountId', $frm).val(item.id);
$('.UserEmailAddress', $frm).val(item.emailAddress);
$('.UserTitle', $frm).val(item.title);
$('.UserFirstName', $frm).val(item.firstName);
$('.UserLastName', $frm).val(item.lastName);
$('.UserRoles', $frm).val(sax.getSelectedUserRoleDescs().join('\n'));
$('.UserAccountId', frm).val(item.id);
$('.UserEmailAddress', frm).val(item.emailAddress);
$('.UserTitle', frm).val(item.title);
$('.UserFirstName', frm).val(item.firstName);
$('.UserLastName', frm).val(item.lastName);
$('.UserRoles', frm).val(sax.getSelectedUserRoleDescs().join('\n'));
$('#ifUserRoleCodes').val(item.userRoleCodes.join(sax.data.userRoleCodeDelim));
$('.UserStatus', $frm).val(item.statusCode);
sax.$dlg.user.dialog('option', 'title', sax.dlg.title.updateUser);
sax.openDialog(sax.$dlg.user, 600, 600);
}
sax.doUpdateItem = function ()
{
sax.storeItem();
$('.UserStatus', frm).val(item.statusCode);
$dlg.user.dialog('option', 'title', sax.dlg.title.updateUser);
sax.openDialog($dlg.user, 600, 600);
}
//--------------------------------------------------------------
sax.storeItem = function ()
{
sax.ajaxStoreItem = sax.ajaxStoreItem || { url: sax.url.base + 'User/Ajax/StoreItem', formId: 'frmUser', callbackFn: sax.onStoreItem };
sax.doAjaxRequest(sax.ajaxStoreItem, 50);
sax.ajax.storeItem = sax.ajax.storeItem || { url: sax.url.base + 'User/Ajax/StoreItem', formId: 'frmUser', callbackFn: sax.onStoreItem };
sax.doAjaxRequest(sax.ajax.storeItem, 50);
}
sax.onStoreItem = function (response)
{
//sax.debug('onStoreItem', response);
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
sax.$dlg.user.dialog('close');
$dlg.user.dialog('close');
var item = response.user;
var $item = $('#' + sax.itemIdPrefix + item.id);
if (!$item.length)
{
var $results = $('.sax-panel-results');
$item = $('.sax-panel-item-template .sax-panel-item.User', $results).clone();
$('.sax-panel-item-list', $results).prepend($item).show();
$item = sax.getItemTemplate();
$('.sax-panel-item-list', $pnl.results).prepend($item).show();
}
sax.populateItem($item, item)
$item.replaceWith(sax.populateItem(sax.getItemTemplate(), item));
}
//--------------------------------------------------------------
sax.userEmails = function (item)
{
sax.debug('userEmails', item);
let frm = $frm.emailsl
$('.UserAccountId', frm).val(item.id);
$('.UserEmailAddress', frm).val(item.emailAddress);
$('.UserDisplayName', frm).val(item.displayName);
$('.RequestPasswordAdminOption', frm).toggle(item.systemAdmin);
$('input[type="checkbox"]', frm).prop('checked', false);
$dlg.emails.dialog('option', { 'title': sax.dlg.title.selectUserEmails });
sax.openDialog($dlg.emails, 600, 600);
}
sax.sendUserEmails = function ()
{
sax.ajax.sendEmails = sax.ajax.sendEmails || { url: sax.url.base + 'User/Ajax/SendEmails', formId: 'frmUserEmails', callbackFn: sax.onUserEmails };
sax.doAjaxRequest(sax.ajax.sendEmails, 50);
}
sax.onUserEmails = function (response)
{
if (!response || !response.success) return;
$dlg.emails.dialog('close');
}
//--------------------------------------------------------------
$(function ()
{
$('.sax-action.sax-item-create').on('click', function () { sax.createItem(); });
$('.sax-action.sax-results-refresh').on('click', function () { sax.refreshResults(); });
$('.sax-input').on('input', function () { sax.clearControlError(this); });
$('.sax-select').on('click', function () { sax.clearControlError(this); });
$pnl.filter = $('.sax-panel-filter');
$pnl.results = $('.sax-panel-results');
sax.$frm.filter = $('#frmUserFilter');
$('.FilterUser', sax.$frm.filter).on('input', function () { sax.refreshResults(250); });
sax.$frm.userId = $('#frmUserId');
sax.$frm.user = $('#frmUser');
$frm.filter = $('#frmUserFilter');
$('.FilterUser', $frm.filter).on('input', function () { sax.refreshResults(250); });
$frm.userId = $('#frmUserId');
$frm.user = $('#frmUser');
$('.sax-input, .sax-textarea', $frm.user).on('input', function () { sax.clearControlError(this); });
$('.sax-select', $frm.user).on('change', function () { sax.clearControlError(this); });
$frm.emails = $('#frmUserEmails');
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.doCreateItem(); };
opt.buttons[sax.dlg.btn.ok] = function () { sax.storeItem(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); };
sax.$dlg.user = $('#dlgUser').dialog(opt);
$dlg.user = $('#dlgUser').dialog(opt);
opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.sendUserEmails(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); };
$dlg.emails = $('#dlgUserEmails').dialog(opt);
setTimeout(sax.refreshResults, 250);
});
@@ -159,6 +159,18 @@
<data name="activity.caption.activity" xml:space="preserve">
<value>Activity</value>
</data>
<data name="article.caption.article" xml:space="preserve">
<value>Article</value>
</data>
<data name="article.caption.article.create" xml:space="preserve">
<value>Create Article</value>
</data>
<data name="article.caption.article.update" xml:space="preserve">
<value>Update Article</value>
</data>
<data name="article.caption.articles" xml:space="preserve">
<value>Articles</value>
</data>
<data name="company.name" xml:space="preserve">
<value>Solum Forti</value>
</data>
@@ -198,18 +210,6 @@
<data name="home.organisation.request.para2" xml:space="preserve">
<value>Sign-up now with a few details and we'll let you know when you can login and get going.</value>
</data>
<data name="journalist.caption.article" xml:space="preserve">
<value>Article</value>
</data>
<data name="journalist.caption.article.create" xml:space="preserve">
<value>Create Article</value>
</data>
<data name="journalist.caption.article.update" xml:space="preserve">
<value>Update Article</value>
</data>
<data name="journalist.caption.articles" xml:space="preserve">
<value>Articles</value>
</data>
<data name="label.account" xml:space="preserve">
<value>My Account</value>
</data>
@@ -88,10 +88,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["account.caption.profile.contact"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Retrieve user details.
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionData.User.UserAccountId);
@@ -140,10 +139,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["account.caption.profile.contact"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate number of images.
if (model.AccountContactImage.IsEmpty())
@@ -229,10 +227,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["account.caption.profile.contact"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate data.
model.ValidateContactDetails(responseData);
@@ -55,6 +55,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Query organisations that user is a member of.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
@@ -75,10 +75,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["account.caption.profile.sports"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Item filter.
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
@@ -153,10 +152,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_ProfileSport responseData = new AjaxResponse_ProfileSport(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Identify item.
SysId userSportId = model.UserSportId.ToSysId();
@@ -197,10 +195,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_ProfileSport responseData = new AjaxResponse_ProfileSport(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate item properties.
model.ValidateProfileSportData(responseData);
@@ -11,6 +11,7 @@ using Saxonite.Net.Core.Web.Online.Models;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Net.Standard.Base.Mgr;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -49,16 +50,16 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
/// <summary>Article activity info. </summary>
private class ActivityResponseData_Article
{
public ActivityResponseData_Article(SaxController_Online controller, SaxModel_Online model, SaxJournalistArticle article)
public ActivityResponseData_Article(SaxController_Online controller, SaxModel_Online model, SaxArticle article)
{
Author = model.GetUserAccountDisplayName(article.UserAccountIdJournalist);
Author = model.GetUserAccountDisplayName(article.UserAccountIdAuthor);
Headline = article.Headline;
Summary = article.Summary;
Sport = model.GetSportCaption(article.SportIdPrimary);
Region = model.GetRegionCaption(article.RegionIdPrimary);
PublishedOnFmt = model.Localiser.FormatDate(article.PublishedAt);
SaxJournalistArticle.ContentData content = SaxJournalistArticle.ExtractContent(article.BodyData);
foreach (SaxJournalistArticle.ContentData.SegmentData segment in content.Segments)
SaxArticle.ContentData content = SaxArticle.ExtractContent(article.BodyData);
foreach (SaxArticle.ContentData.SegmentData segment in content.Segments)
Content.Segments.Add(new ContentData.SegmentData(controller, segment));
}
public String Organisation { get; set; }
@@ -72,7 +73,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
{
public class SegmentData
{
public SegmentData(SaxController_Online controller, SaxJournalistArticle.ContentData.SegmentData segment)
public SegmentData(SaxController_Online controller, SaxArticle.ContentData.SegmentData segment)
{
if (segment.Body.IsValid())
{
@@ -82,7 +83,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
else if (segment.Image.IsValid())
{
Image = new ImageData();
Image.Link = JournalistController.GetArticleImageLink(controller, segment.Image.ItemImageId);
Image.Link = ArticleController.GetArticleImageLink(controller, segment.Image.ItemImageId);
}
}
public class BodyData
@@ -140,10 +141,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_ActivityList responseData = new AjaxResponse_ActivityList();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
SaxSessionData_Online sessionData = SessionData_Online;
// User context.
@@ -167,12 +167,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
activityItemIds.Add(itemData.ItemId);
ActivityResponseData activityData = new ActivityResponseData();
activityData.ItemType = itemData.ItemId.Type;
if (itemData.ItemId.Type == (int)Sax.DataItemType.JournalistArticle)
if (itemData.ItemId.Type == (int)Sax.DataItemType.Article)
activityData.ItemTypeClass = "Article";
else if (itemData.ItemId.Type == (int)Sax.DataItemType.OrganisationOpportunity)
activityData.ItemTypeClass = "Opportunity";
// ToDo Mask activity index Id with cross-reference stored in session data.
activityData.ItemIdx = SysId.ToLong(itemData.ItemId.Id);
activityData.Organisation = itemData.Organisation;
activityData.Author = itemData.Author;
activityData.Caption = itemData.Caption;
activityData.Blurb = itemData.Blurb;
activityData.Sport = Localiser.GetSportName(itemData.SportId, itemData.SportName);
@@ -211,10 +213,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_ActivityInfo responseData = new AjaxResponse_ActivityInfo();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
SaxSessionData_Online sessionData = SessionData_Online;
// Identify activity.
@@ -222,18 +223,18 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
SysId itemId = model.ActivityIdx.ToSysId();
if (itemType <= 0 || !SysId.IsValid(itemId))
{
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + getLogSuffix());
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + GetLogSuffix());
return Json(responseData);
}
// Retrieve activity details.
if (itemType == Sax.DataItemType.JournalistArticle)
if (itemType == Sax.DataItemType.Article)
{
// Journalist article.
SaxJournalistArticle article = ActivityMgr.GetJournalistArticleById(itemId);
// Article.
SaxArticle article = ActivityMgr.GetArticleById(itemId);
if (article == null)
{
SaLogger.Warn(fn + " Article not found for Activity Id: " + itemId.ToString() + "." + getLogSuffix());
SaLogger.Warn(fn + " Article not found for Activity Id: " + itemId.ToString() + "." + GetLogSuffix());
return Json(responseData);
}
responseData.Article = new ActivityResponseData_Article(this, model, article);
@@ -244,7 +245,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(itemId);
if (opportunity == null)
{
SaLogger.Warn(fn + " Opportunity not found for Activity Id: " + itemId.ToString() + "." + getLogSuffix());
SaLogger.Warn(fn + " Opportunity not found for Activity Id: " + itemId.ToString() + "." + GetLogSuffix());
return Json(responseData);
}
responseData.Opportunity = new ActivityResponseData_Opportunity(model, opportunity);
@@ -253,7 +254,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Record activty viewing.
if (!ActivityConsole.RecordUserActivityViewed(SessionData.User.UserAccountId, new ItemId((short)itemType, itemId), DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to record Activity Viewing: " + ActivityConsole.ErrorStateMessage + "." + getLogSuffix());
SaLogger.Warn(fn + " Failed to record Activity Viewing: " + ActivityConsole.ErrorStateMessage + "." + GetLogSuffix());
return Json(responseData);
}
@@ -280,10 +281,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_ActivityReaction responseData = new AjaxResponse_ActivityReaction();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
SaxSessionData_Online sessionData = SessionData_Online;
// Identify activity.
@@ -291,14 +291,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
SysId itemId = model.ActivityIdx.ToSysId();
if (itemType <= 0 || !SysId.IsValid(itemId))
{
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + getLogSuffix());
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + GetLogSuffix());
return Json(responseData);
}
// Record activity reaction.
if (!ActivityConsole.RecordUserActivityReaction(SessionData.User.UserAccountId, new ItemId((short)itemType, itemId), model.GetActivityReaction(), DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to record Activity Reaction: " + ActivityConsole.ErrorStateMessage + "." + getLogSuffix());
SaLogger.Warn(fn + " Failed to record Activity Reaction: " + ActivityConsole.ErrorStateMessage + "." + GetLogSuffix());
return Json(responseData);
}
@@ -11,6 +11,7 @@ using Saxonite.Net.Core.Web.Online.Models;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Net.Standard.Base.Mgr;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -21,12 +22,12 @@ using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Online.Controllers
{
//=======================================================================
// Online Journalist Controller - Ajax actions.
// Online Article Controller - Ajax actions.
//=======================================================================
partial class JournalistController
partial class ArticleController
{
//-------------------------------------------------------------------
// Journalist Article Content data.
// Article Content data.
private class ArticleContentData
{
public List<ArticleContentSegmentData> Segments { get; } = new List<ArticleContentSegmentData>();
@@ -48,10 +49,11 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
//-------------------------------------------------------------------
// Journalist Article data.
// Article data.
private class ArticleData_List
{
public String Id { get; set; }
public String OrganisationId { get; set; }
public String Headline { get; set; }
public String Summary { get; set; }
public String RegionCaptionPrimary { get; set; }
@@ -70,9 +72,10 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
public String PublishedOn_Calendar { get; set; }
public ArticleContentData Content { get; } = new ArticleContentData();
}
private void PopulateArticleResponseData(Model_Journalist model, SaxJournalistArticle article, ArticleData_List data)
private void PopulateArticleResponseData(Model_Article model, SaxArticle article, ArticleData_List data)
{
data.Id = SysId.ToString(article.Id);
data.OrganisationId = SysId.ToString(article.OrganisationId);
data.Headline = article.Headline;
data.Summary = article.Summary;
data.RegionCaptionPrimary = model.GetRegionCaption(article.RegionIdPrimary);
@@ -82,7 +85,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
data.StatusCode = article.StatusCode;
data.StatusDesc = article.StatusDesc;
}
private void PopulateArticleResponseData(Model_Journalist model, SaxJournalistArticle article, ArticleData_Full data)
private void PopulateArticleResponseData(Model_Article model, SaxArticle article, ArticleData_Full data)
{
PopulateArticleResponseData(model, article, data as ArticleData_List);
data.RegionIdPrimary = SysId.ToString(article.RegionIdPrimary);
@@ -92,7 +95,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
data.PublishedOn_Calendar = model.FormatDateForForm(article.PublishedAt);
// Article content.
SaxJournalistArticle.ContentData articleContent = SaxJournalistArticle.ExtractContent(article.BodyData);
SaxArticle.ContentData articleContent = SaxArticle.ExtractContent(article.BodyData);
foreach (var contentSegment in articleContent.Segments)
{
var segmentData = new ArticleContentSegmentData();
@@ -114,48 +117,83 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
//-------------------------------------------------------------------
// Get Article List ajax request.
//-------------------------------------------------------------------
private class OrganisationData : AjaxResponse_Data.ItemIdName { }
private class AjaxResponse_ArticleList : AjaxResponse_Data
{
// Construction.
public AjaxResponse_ArticleList(SaxModel_Online model) : base(model) { }
// Article list.
public List<ArticleData_List> Articles { get; } = new List<ArticleData_List>();
/// <summary>Organisations that the user has rights to author articles for.</summary>
public List<OrganisationData> Organisations { get; set; }
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Journalist/Ajax/GetArticleList")]
public IActionResult Ajax_GetArticleList(Model_Journalist model)
[Route("Article/Ajax/GetList")]
[Route("Article/Ajax/GetArticles")]
public IActionResult Ajax_GetArticleList(Model_Article model)
{
String fn = GetType().Name + ".Ajax_GetArticleList";
String messageTitle = Localiser["journalist.caption.articles"];
String messageTitle = Localiser["article.caption.articles"];
AjaxResponse_ArticleList responseData = new AjaxResponse_ArticleList(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
if (!UserIsJournalist) return GetAjaxResult_GoHome(responseData);
SaxSessionData_Online sessionData = SessionData_Online;
SysId userAccountId = SessionData.User.UserAccountId;
RefreshModel(model);
// Organisations that the user has rights to author articles for.
foreach (SaxAccountMgr.OrganisationIdName organisation in AccountMgr.GetOrganisationsForUserRole(userAccountId, Sax.OrganisationRole.ArticleAdmin))
{
if (responseData.Organisations == null) responseData.Organisations = new List<OrganisationData>();
OrganisationData organisationData = new OrganisationData()
{
Id = model.EncryptId(organisation.Id),
Name = organisation.Name
};
responseData.Organisations.Add(organisationData);
}
// User must either be a journalist or allowed to author organisation articles.
if (!UserIsJournalist && responseData.Organisations == null) return GetAjaxResult_GoHome(responseData);
if (UserIsJournalist && responseData.Organisations != null)
{
OrganisationData organisationData = new OrganisationData()
{
Id = "",
Name = "No Organisation - Journalist Articles"
};
responseData.Organisations.Insert(0, organisationData);
}
// Filter organisation.
SysId organisationIdFilter = model.ExtractSysId(model.Filter.OrganisationId);
// Item filter.
SaxJournalistArticle.Params prmArticle = new SaxJournalistArticle.Params();
prmArticle.UserAccountIdsJournalistIncluded.Add(sessionData.User.UserAccountId);
SaxArticle.Params prmArticle = new SaxArticle.Params();
prmArticle.UserAccountIdsAuthorIncluded.Add(sessionData.User.UserAccountId);
if (SysId.IsValid(organisationIdFilter))
prmArticle.OrganisationIdsIncluded.Add(organisationIdFilter);
prmArticle.ArticleFilter = model.Filter.Article;
prmArticle.StatusCat = SaxJournalistArticle.StatusCat.NotDeleted;
model.Paging.ItemTotal = (ulong)ActivityMgr.GetJournalistArticleCount(prmArticle);
prmArticle.StatusCat = SaxArticle.StatusCat.NotDeleted;
model.Paging.ItemTotal = (ulong)ActivityMgr.GetArticleCount(prmArticle);
model.PopulatePagingTo(prmArticle.ResultsPaging);
// Item columns.
ColumnDfn colId = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Id);
ColumnDfn colHeadline = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Headline);
ColumnDfn colSummary = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Summary);
ColumnDfn colRegionIdPrimary = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.RegionIdPrimary);
ColumnDfn colSportIdPrimary = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.SportIdPrimary);
ColumnDfn colPublishedOn = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.PublishedAt_Date);
ColumnDfn colStatus = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Status);
ColumnDfn colCreatedOn = ActivityMgr.GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.CreateOn_Date);
ColumnDfn colId = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Id);
ColumnDfn colOrganisationId = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.OrganisationId);
ColumnDfn colHeadline = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Headline);
ColumnDfn colSummary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Summary);
ColumnDfn colRegionIdPrimary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.RegionIdPrimary);
ColumnDfn colSportIdPrimary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.SportIdPrimary);
ColumnDfn colPublishedOn = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.PublishedAt_Date);
ColumnDfn colStatus = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Status);
ColumnDfn colCreatedOn = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.CreateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId, colHeadline, colSummary,
colId, colOrganisationId, colHeadline, colSummary,
colRegionIdPrimary, colSportIdPrimary, colPublishedOn,
colStatus, colCreatedOn
};
@@ -165,7 +203,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
prmArticle.SortColumns.Add(colCreatedOn);
// Query items.
using (DbResultSet resultSet = ActivityMgr.ExecuteJournalistArticleQuery(columns, prmArticle))
using (DbResultSet resultSet = ActivityMgr.ExecuteArticleQuery(columns, prmArticle))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
@@ -173,6 +211,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
ArticleData_List articleData = new ArticleData_List()
{
Id = values.GetString(colId.DataName),
OrganisationId = values.GetString(colOrganisationId.DataName),
Headline = values.GetString(colHeadline.DataName),
Summary = values.GetString(colSummary.DataName),
RegionCaptionPrimary = model.GetRegionCaption(values.GetString(colRegionIdPrimary.DataName).ToSysId()),
@@ -206,20 +245,20 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Journalist/Ajax/GetArticle")]
public IActionResult Ajax_GetArticle(Model_Journalist model)
[Route("Article/Ajax/Get")]
[Route("Article/Ajax/GetItem")]
[Route("Article/Ajax/GetArticle")]
public IActionResult Ajax_GetArticle(Model_Article model)
{
String fn = GetType().Name + ".Ajax_GetArticle";
String messageTitle = Localiser["journalist.caption.article"];
String messageTitle = Localiser["article.caption.article"];
AjaxResponse_Article responseData = new AjaxResponse_Article(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!UserIsJournalist)
return GetAjaxResult_GoHome(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
SysId userAccountId = SessionData.User.UserAccountId;
RefreshModel(model);
// Identify item.
SysId articleId = model.ArticleId.ToSysId();
@@ -227,16 +266,21 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SaxJournalistArticle article = ActivityMgr.GetJournalistArticleById(articleId);
SaxArticle article = ActivityMgr.GetArticleById(articleId);
if (article == null)
{
SaLogger.Warn(fn + " Failed to retrieve Journalist Article for Id: '" + model.ArticleId + "'");
SaLogger.Warn(fn + " Failed to retrieve Article for Id: '" + model.ArticleId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
if (!article.UserAccountIdAuthor.Equals(userAccountId))
{
SaLogger.Warn(fn + " Inconsistent Article Author. Expected: " + userAccountId + ". Found: " + article.UserAccountIdAuthor);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Delete upload images.
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.JournalistArticle, articleId));
prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.Article, articleId));
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.ArticleUpload);
prmItemImage.StatusCat = SaxItemImage.StatusCat.NotDeleted;
foreach (SaxItemImage itemImage in ItemDataMgr.GetItemImageList(prmItemImage))
@@ -254,7 +298,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
//-------------------------------------------------------------------
// Journalist - Upload Article Image.
// Article - Upload Image.
//-------------------------------------------------------------------
private class AjaxResponse_UploadArticleImage : AjaxResponse_Data
{
@@ -266,17 +310,18 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
// Ajax request.
[HttpPost]
[Route("Journalist/Ajax/UploadArticleImage")]
public IActionResult UploadArticleImage(Model_Journalist model)
[Route("Article/Ajax/UploadImage")]
public IActionResult UploadArticleImage(Model_Article model)
{
String fn = GetType().Name + ".UploadArticleImage";
AjaxResponse_UploadArticleImage responseData = new AjaxResponse_UploadArticleImage(model);
String messageTitle = Localiser["journalist.caption.article"];
String messageTitle = Localiser["article.caption.article"];
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
SaxSessionData_Online sessionData = SessionData_Online;
RefreshModel(model);
// Validate number of images.
if (model.ArticleImage.IsEmpty())
@@ -307,7 +352,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Image belongs to the article.
// If the article doesn't yet exist, it will need to be uploaded to the user first and later transferred.
SysId articleId = model.ArticleId.ToSysId();
ItemId articleItemId = new ItemId((short)Sax.DataItemType.JournalistArticle, articleId);
ItemId articleItemId = new ItemId((short)Sax.DataItemType.Article, articleId);
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, sessionData.User.UserAccountId);
ItemId imageItemId = SysId.IsValid(articleId) ? articleItemId : userItemId;
@@ -369,35 +414,59 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
public static String GetArticleImageLink(SaxController_Online controller, SysId itemImageId)
{
String imageLink = "Image/Journalist/Article?";
String imageLink = "Image/Article?";
NameValueCollection parameters = new NameValueCollection();
parameters.Add(ImageController.ParamName_ItemImageId, SysId.ToString(itemImageId));
return imageLink + ImageController.ParamName_JournalistArticleImageEncrypted + "=" + SaxController_Online.EncryptOnlineParams(controller, parameters);
return imageLink + ImageController.ParamName_ArticleImageEncrypted + "=" + SaxController_Online.EncryptOnlineParams(controller, parameters);
}
//-------------------------------------------------------------------
// Store Article ajax request.
//-------------------------------------------------------------------
[HttpPost]
[Route("Journalist/Ajax/StoreArticle")]
public IActionResult Ajax_StoreArticle(Model_Journalist model)
[Route("Article/Ajax/Store")]
[Route("Article/Ajax/StoreItem")]
[Route("Article/Ajax/StoreArticle")]
public IActionResult Ajax_StoreArticle(Model_Article model)
{
String fn = GetType().Name + ".Ajax_StoreArticle";
String messageTitle = Localiser["journalist.caption.article"];
String messageTitle = Localiser["article.caption.article"];
AjaxResponse_Article responseData = new AjaxResponse_Article(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
if (!UserIsJournalist) return GetAjaxResult_GoHome(responseData);
SaxSessionData_Online sessionData = SessionData_Online;
RefreshModel(model);
// Validate item properties.
model.ValidateArticleData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Validate Article against Id against 'Exists' flag.
// Validate User & Organisation.
SysId userAccountId = SessionData.User.UserAccountId;
SysId organisationId = model.ExtractSysId(model.ArticleOrganisationId);
if (SysId.IsValid(organisationId))
{
// Organisation specified - User must have Article Admin role.
if (!AccountMgr.UserHasOrganisationRole(userAccountId, organisationId, Sax.OrganisationRole.ArticleAdmin))
{
SaLogger.Warn(fn + " User does not have Article Admin role for organisation." + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
else
{
// Organisation not specified - User must be a Journalist.
if (!UserIsJournalist)
{
SaLogger.Warn(fn + " User is not a Journalist for non-organisation article." + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
// Validate item Id against 'Exists' flag.
SysId articleId = model.ArticleId.ToSysId();
bool articleExists = StringUtil.ToBool(model.ArticleExists);
if (articleExists && !SysId.IsValid(articleId))
@@ -412,16 +481,30 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
// Retrieve existing item.
SaxJournalistArticle article = ActivityMgr.GetJournalistArticleById(articleId);
SaxArticle article = ActivityMgr.GetArticleById(articleId);
if (article == null && SysId.IsValid(articleId))
{
SaLogger.Warn(fn + " Failed to retrieve article for Id: '" + model.ArticleId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
if (article != null)
{
// Validate existing article.
if (SysId.ToLong(article.UserAccountIdAuthor) != SysId.ToLong(userAccountId))
{
SaLogger.Warn(fn + " Inconsistent Article Author." + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
if (SysId.ToLong(article.OrganisationId) != SysId.ToLong(organisationId))
{
SaLogger.Warn(fn + " Inconsistent Article Organisation." + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
// Create new item if required.
if (article == null)
article = ActivityMgr.CreateJournalistArticle(sessionData.User.UserAccountId);
article = ActivityMgr.CreateArticle(sessionData.User.UserAccountId, organisationId);
// Populate item properties.
if (model.ArticleRegionId != null)
@@ -451,7 +534,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// If Article doesn't yet exist, create it now so that images can be assigned.
if (!SysId.IsValid(article.Id))
{
if (!ActivityMgr.InsertJournalistArticle(article, DbUpdateInfo))
if (!ActivityMgr.InsertArticle(article, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert article: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
@@ -461,7 +544,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Content.
if (model.ArticleContentSegmentBodies != null)
{
SaxJournalistArticle.ContentData articleContent = new SaxJournalistArticle.ContentData();
SaxArticle.ContentData articleContent = new SaxArticle.ContentData();
for (int segmentIdx = 0; segmentIdx < model.ArticleContentSegmentBodies.Count; segmentIdx++)
{
String segmentBody = model.ArticleContentSegmentBodies[segmentIdx];
@@ -505,11 +588,11 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
SaLogger.Warn(fn + " Failed to identify article image. ItemImageId: " + itemImageId.ToInt() + ". SessionIdx: " + sessionData.SessionIdx + ". ImageIdx: " + imageIdx + ".");
}
}
article.BodyData = SaxJournalistArticle.GetContentData(articleContent);
article.BodyData = SaxArticle.GetContentData(articleContent);
}
// Update the Article.
if (!ActivityMgr.UpdateJournalistArticle(article, DbUpdateInfo))
if (!ActivityMgr.UpdateArticle(article, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update article [Id:" + SysId.ToString(article.Id) + "]: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
@@ -1,7 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.Net.Standard.Base.Bus;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Online.Models;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Mgr;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,11 +16,11 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
//=======================================================================
// Online Journalist Controller.
//=======================================================================
public partial class JournalistController : SaxController_Online
public partial class ArticleController : SaxController_Online
{
//-------------------------------------------------------------------
// Construction.
public JournalistController(SaxLocaliser localiser, ILogger<HomeController> logger) :
public ArticleController(SaxLocaliser localiser, ILogger<HomeController> logger) :
base(localiser, logger)
{
}
@@ -26,25 +30,24 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
public IActionResult Index()
{
// Validate session.
if (!ValidUserSession || !UserIsJournalist)
if (!ValidUserSession)
return RedirectToAction("", "");
// No 'Index' view as yet - default to 'Articles' view.
//Model_Journalist model = new Model_Journalist(Localiser);
//return View(model);
return RedirectToAction("Articles", "Journalist");
}
//-------------------------------------------------------------------
[HttpGet]
public IActionResult Articles()
{
// Validate session.
if (!ValidUserSession || !UserIsJournalist)
// User must either be a Journalist or have Article Admin rights with at least one organisation.
List<SaxAccountMgr.OrganisationIdName> organisations = AccountMgr.GetOrganisationsForUserRole(SessionData.User.UserAccountId, Sax.OrganisationRole.ArticleAdmin);
if (organisations.Count < 1 && !UserIsJournalist)
return RedirectToAction("", "");
// Paging.
Model_Journalist model = new Model_Journalist(Localiser);
// Model.
Model_Article model = new Model_Article(Localiser);
model.UserCanAuthorOrganisationArticles = organisations.Count > 0;
model.UserCanAuthorJournalistArticles = UserIsJournalist;
if (organisations.Count > 0)
{
// Default filter to first organisation.
model.Filter.OrganisationId = model.EncryptId(organisations[0].Id);
model.Filter.OrganisationCaption = organisations[0].Name;
}
model.Paging.PageNo = 1;
model.Paging.PageLength = 6;
@@ -92,10 +92,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String fn = GetType().Name + ".GetAccountContactImage";
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return Forbid();
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return Forbid();
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, userAccountId);
// Retrieve account contact images.
@@ -120,28 +118,29 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
//-------------------------------------------------------------------
// Journalist Article image
// Article image
//-------------------------------------------------------------------
public static String ParamName_JournalistArticleImageEncrypted { get; } = "jaie";
public static String ParamName_ArticleImageEncrypted { get; } = "aie";
public static String ParamName_ItemImageId { get; } = "iii";
/// <summary>
/// Get the specified Journalist Article Image.
/// Get the specified Article Image.
/// <para>Method parameter name (aie) must match name of encrypted parameter.</para>
/// <para>Encrypted parameters:</para>
/// <para>- iii: item Image Id.</para>
/// </summary>
[HttpGet]
[Route("Image/Journalist/Article")]
public IActionResult GetJournalistArticleImage(String jaie)
[Route("Image/Article")]
public IActionResult GetArticleImage(String aie)
{
String fn = GetType().Name + ".GetJournalistArticleImage";
String fn = GetType().Name + ".GetArticleImage";
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return Forbid();
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, SessionData.User.UserAccountId);
// EXtract encrypted parameters.
NameValueCollection parameters = ExtractOnlineParams(jaie);
// Extract encrypted parameters.
NameValueCollection parameters = ExtractOnlineParams(aie);
if (parameters.Count<1) return Forbid();
// Item Image.
@@ -102,6 +102,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Organisation.
SysId organisationId = model.Filter.OrganisationId.ToSysId();
@@ -167,7 +168,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
NamedValue.Map values = resultSet.GetRecordValues();
MemberData_List memberData = new MemberData_List()
{
Id = values.GetString(colId.DataName),
Id = values.GetLong(colId.DataName).ToString(),
UserAccountId = values.GetString(colUserAccountId.DataName),
EmailAddress = values.GetString(colEmailAddress.DataName),
DisplayName = AccountMgr.GetUserOrganisationDataValue(colDisplayName, values).ToString(),
@@ -222,6 +223,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Identify item.
SysId memberId = model.MemberId.ToSysId();
@@ -295,6 +297,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate item properties.
model.ValidateMemberData(responseData);
@@ -519,6 +522,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
@@ -609,6 +613,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Replace dynamic tag for link back to change password page.
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, ""));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.SignIn]", GetRedirectLocation(RedirectLocation.WebAppBase) + "Security/SignIn");
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
}
@@ -633,6 +638,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
@@ -92,10 +92,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_OpportunityList responseData = new AjaxResponse_OpportunityList(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Organisation.
SysId organisationId = model.Filter.OrganisationId.ToSysId();
@@ -170,7 +169,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
NamedValue.Map values = resultSet.GetRecordValues();
OpportunityData_List opportunityData = new OpportunityData_List()
{
Id = values.GetString(colId.DataName),
Id = values.GetLong(colId.DataName).ToString(),
TypeCode = values.GetString(colOpportunityTypeCode.DataName),
TypeDesc = Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(values.GetString(colOpportunityTypeCode.DataName))),
Position = values.GetString(colPosition.DataName),
@@ -218,10 +217,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_Opportunity responseData = new AjaxResponse_Opportunity(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Identify item.
SysId opportunityId = model.OpportunityId.ToSysId();
@@ -271,10 +269,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_Opportunity responseData = new AjaxResponse_Opportunity(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Validate item properties.
model.ValidateOpportunityData(responseData);
@@ -41,8 +41,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_RequestOrganisation responseData = new AjaxResponse_RequestOrganisation(model);
// Validate session and referrer. User does not need to be logged in.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
SaxSessionData_Online sessionData = SessionData_Online;
if (!model.ValidateOrganisationRequestData(responseData))
@@ -52,13 +51,13 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
SaxRegion regionCountry = Internals.GetRegion(model.OrganisationRegionIdCountry.ToSysId());
if (SysId.IsValid(model.OrganisationRegionIdCountry.ToSysId()) && regionCountry == null)
{
SaLogger.Warn(fn + " Country region not found. Id: " + model.OrganisationRegionIdCountry + ". " + getLogSuffix());
SaLogger.Warn(fn + " Country region not found. Id: " + model.OrganisationRegionIdCountry + ". " + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
SaxRegion regionProvince = Internals.GetRegion(model.OrganisationAddressRegionIdProvince.ToSysId());
if (SysId.IsValid(model.OrganisationAddressRegionIdProvince.ToSysId()) && regionProvince == null)
{
SaLogger.Warn(fn + " Province region not found. Id: " + model.OrganisationAddressRegionIdProvince + ". " + getLogSuffix());
SaLogger.Warn(fn + " Province region not found. Id: " + model.OrganisationAddressRegionIdProvince + ". " + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
@@ -71,7 +70,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// hence 'System' error response and nothing more specific.
if (!StringUtil.IsEmpty(model.ContactEmailAddress))
{
SaLogger.Warn(fn + " Contact Email supplied when user logged in. " + getLogSuffix());
SaLogger.Warn(fn + " Contact Email supplied when user logged in. " + GetLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve user account.
@@ -52,10 +52,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_OrganisationList responseData = new AjaxResponse_OrganisationList(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Query columns.
ColumnDfn colOrganisationId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Id);
@@ -126,10 +125,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_MemberOrganisationList responseData = new AjaxResponse_MemberOrganisationList(model);
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Query columns.
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
@@ -43,8 +43,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_SportList responseData = new AjaxResponse_SportList();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// User doesn't have to be logged in, eg. to register organisation.
//if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
@@ -75,9 +74,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_RegionList responseData = new AjaxResponse_RegionList();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
// User doesn't have to be logged in, eg. to register organisation.
if (!ValidReferer) return Forbid();
// User doesn't have to be logged in to query regions, eg. for organisation request.
//if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Populate regions.
@@ -258,7 +258,13 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
//-------------------------------------------------------------------
// Logging.
//-------------------------------------------------------------------
protected String getLogSuffix()
/// <summary>
/// Log suffix:
/// <para>- User's email address.</para>
/// <para>- Prefixed with space.</para>
/// </summary>
/// <returns></returns>
protected String GetLogSuffix()
{
List<String> logSuffix = new List<string>();
SaxSessionData_Online sessionData = SessionData_Online;
@@ -43,8 +43,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["signin.caption"];
// Validate referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// Validate Sign-in data.
model.ValidateSignInData(responseData);
@@ -81,10 +80,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
AjaxResponse_KeepLoggedIn responseData = new AjaxResponse_KeepLoggedIn();
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return Json(responseData.SetGoHome());
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return Json(responseData.SetGoHome());
RefreshModel(model);
if (!AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
return Json(responseData);
@@ -155,10 +153,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["signin.caption.signout"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
RefreshModel(model);
// Retrieve user account - in case sign-out needs to be recorded.
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionData_Online.User.UserAccountId);
@@ -194,8 +191,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
public ActionResult Ajax_ScorePassword(Model_Security model)
{
// Validate referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// No need to store the session data for this request.
StoreSessionData = false;
@@ -225,8 +221,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["security.caption.change.password"];
// Validate referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// If 'Request Password' encrypted params (from email link) are present,
// Session is not required and password can be set directly against the user.
@@ -324,8 +319,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["security.caption.request.password"];
// Validate referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// Validate data.
model.ValidateRequestPasswordData(responseData);
@@ -378,11 +372,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
private static String ParamName_EmailAddress { get; } = "ema";
private static String ParamName_ExpiresAt { get; } = "exp";
private static String ParamName_Token { get; } = "tok";
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
// IV Must be regenerated if key is changed.
private static String Base64Key_RequestPassword { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
private static String Base64IV_RequestPassword_Generated { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword);
private static String Base64IV_RequestPassword { get; } = "1VAWYTW6d72n/6HDNhbqow==";
// Request Password encryption parameters (key & IV) are defined in the base Controller
// so that they can be shared with the Adnin application.
internal static String GenerateRequestPasswordLink(SaxController_Online controller, SysId userAccountId, String emailAddress, String requestPasswordToken)
{
NameValueCollection parameters = new NameValueCollection();
@@ -392,7 +383,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
parameters.Add(ParamName_Token, requestPasswordToken);
String link =
controller.GetRedirectLocation(RedirectLocation.WebAppBase) + "Security/ChangePassword?" +
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(controller.EncryptParameters(parameters, Base64IV_RequestPassword, Base64Key_RequestPassword));
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(EncryptParameters(parameters, Base64IV_RequestPassword_Online, Base64Key_RequestPassword_Online));
return link;
}
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Online controller)
@@ -445,7 +436,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
RequestPasswordParams requestPasswordParams = new RequestPasswordParams();
if (!StringUtil.IsEmpty(encryptedParams))
{
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RequestPassword, Base64Key_RequestPassword);
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RequestPassword_Online, Base64Key_RequestPassword_Online);
requestPasswordParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_UserAccountId)));
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
requestPasswordParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
@@ -15,29 +15,45 @@ using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Online.Models
{
//=======================================================================
public class Model_Journalist : SaxModel_Online
public class Model_Article : SaxModel_Online
{
//-------------------------------------------------------------------
// Construction.
public Model_Journalist(SaxLocaliser localiser) :
public Model_Article(SaxLocaliser localiser) :
base(localiser)
{
AdditionalFiles_CSS.Add("css/sax-jrn-art.css");
AdditionalFiles_JS.Add("js/sax-jrn-art.js");
AdditionalFiles_CSS.Add("css/sax-art.css");
AdditionalFiles_JS.Add("js/sax-art.js");
}
//-------------------------------------------------------------------
// List configuration.
public class FilterData
{
public String OrganisationId { get; set; }
public String OrganisationCaption { get; set; }
public String Article { get; set; }
}
public FilterData Filter { get; } = new FilterData();
/// <summary>
/// User has rights to author articles for at least one organisation.
/// <para>- Output only - not returned with form data.</para>
/// <para>- Only populated for initial page construction.</para>
/// </summary>
public bool UserCanAuthorOrganisationArticles { get; set; }
/// <summary>
/// User has rights to author articles as a journalist.
/// <para>- Output only - not returned with form data.</para>
/// <para>- Only populated for initial page construction.</para>
/// </summary>
public bool UserCanAuthorJournalistArticles { get; set; }
//-------------------------------------------------------------------
// Article properties.
public String ArticleId { get; set; }
public String ArticleExists { get; set; }
// Organisation.
public String ArticleOrganisationId { get; set; }
// Sport.
public String ArticleSportId { get; set; }
public String ArticleSportCaption { get; set; }
@@ -75,8 +91,8 @@ namespace Saxonite.Net.Core.Web.Online.Models
responseData.SetControlValue(nameof(ArticleHeadline), ArticleHeadline);
if (StringUtil.IsEmpty(ArticleHeadline))
responseData.SetControlError(nameof(ArticleHeadline), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(ArticleHeadline) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline))
responseData.SetControlError(nameof(ArticleHeadline), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline)]);
else if (StringUtil.GetLength(ArticleHeadline) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline))
responseData.SetControlError(nameof(ArticleHeadline), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline)]);
}
// Article summary.
@@ -85,8 +101,8 @@ namespace Saxonite.Net.Core.Web.Online.Models
responseData.SetControlValue(nameof(ArticleSummary), ArticleSummary);
if (StringUtil.IsEmpty(ArticleSummary))
responseData.SetControlError(nameof(ArticleSummary), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(ArticleSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary))
responseData.SetControlError(nameof(ArticleSummary), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary)]);
else if (StringUtil.GetLength(ArticleSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary))
responseData.SetControlError(nameof(ArticleSummary), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary)]);
}
// Article sport.
@@ -123,7 +139,7 @@ namespace Saxonite.Net.Core.Web.Online.Models
{
if (StringUtil.IsEmpty(ArticleStatusCode))
responseData.SetControlError(nameof(ArticleStatusCode), Localiser["msg.validation.mandatory.value"]);
else if (!SaxJournalistArticle.ValidStatuses.Contains(ArticleStatus))
else if (!SaxArticle.ValidStatuses.Contains(ArticleStatus))
responseData.SetControlError(nameof(ArticleStatusCode), Localiser["msg.validation.invalid.value"]);
}
@@ -1,11 +1,16 @@
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Core.Web.Base.Models;
using Saxonite.Net.Core.Web.Online.App;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Threading.Tasks;
@@ -16,10 +21,9 @@ namespace Saxonite.Net.Core.Web.Online.Models
{
//-------------------------------------------------------------------
// Data members.
private bool userCanManageOrganisationMembers = false;
private bool userCanManageOrganisationMembersChecked = false;
private bool userCanManageOrganisationOpportunities = false;
private bool userCanManageOrganisationOpportunitiesChecked = false;
private bool? userCanManageOrganisationMembers = null;
private bool? userCanManageOrganisationArticles = null;
private bool? userCanManageOrganisationOpportunities = null;
//-------------------------------------------------------------------
// Protected construction.
@@ -30,14 +34,19 @@ namespace Saxonite.Net.Core.Web.Online.Models
//-------------------------------------------------------------------
// Session.
//-------------------------------------------------------------------
public SaxSessionData_Online SessionData_Online { get { return SessionData as SaxSessionData_Online; } }
// Menu options.
public bool MembersAllowed { get { return UserCanManageOrganisationMembers; } }
public bool ArticlesAllowed { get { return UserIsJournalist || UserCanManageOrganisationArticles; } }
public bool OpportunitiesAllowed { get { return UserCanManageOrganisationOpportunities; } }
// Security profile.
public bool UserIsJournalist { get { return SessionData != null && SessionData.User != null && SessionData.User.IsJournalist; } }
public bool UserCanManageOrganisationMembers
{
get
{
if (!userCanManageOrganisationMembersChecked && ValidUserSession)
if (userCanManageOrganisationMembers == null && ValidUserSession)
{
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
@@ -45,16 +54,31 @@ namespace Saxonite.Net.Core.Web.Online.Models
prmUserOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.OpportunityAdmin);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
userCanManageOrganisationMembers = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
userCanManageOrganisationMembersChecked = true;
}
return userCanManageOrganisationMembers;
return userCanManageOrganisationMembers == true ? true : false;
}
}
public bool UserCanManageOrganisationArticles
{
get
{
if (userCanManageOrganisationArticles == null && ValidUserSession)
{
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.OrganisationMembersOnly = true;
prmUserOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.ArticleAdmin);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
userCanManageOrganisationArticles = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
}
return userCanManageOrganisationArticles == true ? true : false;
}
}
public bool UserCanManageOrganisationOpportunities
{
get
{
if (!userCanManageOrganisationOpportunitiesChecked && ValidUserSession)
if (userCanManageOrganisationOpportunities == null && ValidUserSession)
{
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
@@ -62,12 +86,57 @@ namespace Saxonite.Net.Core.Web.Online.Models
prmUserOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.OpportunityAdmin);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
userCanManageOrganisationOpportunities = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
userCanManageOrganisationOpportunitiesChecked = true;
}
return userCanManageOrganisationOpportunities;
return userCanManageOrganisationOpportunities == true ? true : false;
}
}
//-------------------------------------------------------------------
// Item Id Obfuscation.
//-------------------------------------------------------------------
public SysId ExtractSysId(String idx)
{
String fn = GetType().Name + ".ExtractSysId";
if (StringUtil.IsEmpty(idx)) return null;
// Numeric values are assumed to be unencrypted Ids.
if (StringUtil.IsNumeric(idx))
return idx.ToSysId();
try
{
// Attempt to decrypt.
SysId id = DecryptId(idx);
if (SysId.IsValid(id))
return id;
}
catch (Exception exc)
{
SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc));
}
return null;
}
//-------------------------------------------------------------------
// Id encryption.
// To obfuscate Id values that are sent to and from the browser.
// NB IV value can be reset evert time the application restarts.
public static String Base64Key_IdObfuscation = SacsEncryptionHelper.EncodePlainKey("|SaxOnIte.Onl1n3-iD+0bfuscAtion|", SacsEncryptionHelper.KeyLength);
public static String Base64IV_IdObfuscation = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_IdObfuscation);
public static String ParamName_IdObfuscation_Id { get; } = "iob";
public String EncryptId(SysId id)
{
NameValueCollection idObfuscationParams = new NameValueCollection();
idObfuscationParams.Add(ParamName_IdObfuscation_Id, SysId.ToString(id));
return SaxController_Base.EncryptParameters(idObfuscationParams, Base64IV_IdObfuscation, Base64Key_IdObfuscation);
}
public SysId DecryptId(String encryptedParams)
{
NameValueCollection idObfuscationParams = SaxController_Base.DecryptParameters(encryptedParams, Base64IV_IdObfuscation, Base64Key_IdObfuscation);
return idObfuscationParams.Get(ParamName_IdObfuscation_Id).ToSysId();
}
//-------------------------------------------------------------------
// Reference Data.
//-------------------------------------------------------------------
@@ -1,4 +1,4 @@
@model Model_Journalist
@model Model_Article
@inject SaxLocaliser Localiser
@{
ViewData["Title"] = "Journalist - Articles";
@@ -10,7 +10,7 @@
{
<div class="sax-panel-filter">
<div class="sax-header row">
<div class="col"><div class="sax-caption">@Localiser["journalist.caption.articles"]</div></div>
<div class="col"><div class="sax-caption">@Localiser["article.caption.articles"]</div></div>
<div class="fixed row">
<div>
<partial name="~/Views/Common/ResultsPaging.cshtml" />
@@ -20,6 +20,17 @@
</div>
</div>
<div class="sax-content">
@if (Model.UserCanAuthorOrganisationArticles)
{
<div class="sax-control row OrganisationFilter">
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
<div class="col-sm-8 row">
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" readonly="readonly" value="@(Model.Filter.OrganisationCaption)" /></div>
<div class="fixed"><button class="sax-button" onclick="sax.selectFilterOrganisation()">@Localiser["label.select"]</button></div>
</div>
</div>
}
<div class="row">
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
<div class="col-sm-8"><input type="search" name="Filter.Article" id="ifArticleFilter" class="ArticleFilter sax-input" maxlength="64" /></div>
@@ -59,5 +70,6 @@
</div>
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
<partial name="Panel-ArticleDialog.cshtml" />
@@ -1,12 +1,12 @@
@model Model_Journalist
@model Model_Article
@inject SaxLocaliser Localiser
@{
/* Articles - Article dialog panel */
}
<script type="text/javascript">
sax.dlg.title.createArticle = '@Localiser.GetJavascriptText("journalist.caption.article.create")';
sax.dlg.title.updateArticle = '@Localiser.GetJavascriptText("journalist.caption.article.update")';
sax.dlg.title.createArticle = '@Localiser.GetJavascriptText("article.caption.article.create")';
sax.dlg.title.updateArticle = '@Localiser.GetJavascriptText("article.caption.article.update")';
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
</script>
@@ -20,18 +20,35 @@
{
@Html.HiddenFor(model => model.ArticleId, new { @id = "ifArticleId", @class = "ArticleId" })
@Html.HiddenFor(model => model.ArticleExists, new { @id = "ifArticleExists", @class = "ArticleExists" })
@Html.HiddenFor(model => model.ArticleOrganisationId, new { @id = "ifArticleOrganisationId", @class = "ArticleOrganisationId" })
<div class="sax-article ArticleHeader">
<div class="sax-article-panel sax-article-header">
@* Organisation *@
<div class="sax-form-control ArticleOrganisation">
<div class="row">
<div class="col-sm-4">
<div class="sax-label right pt4 pr8">
<label for="ifArticleOrganisation"><span>@Localiser["label.organisation"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sax-control">
<input type="text" id="ifArticleOrganisation" class="ArticleOrganisation sax-input" readonly="readonly" />
</div>
</div>
</div>
</div>
@* Article headline *@
<div class="sax-form-control ArticleHeadline">
<div class="sax-label">
<label for="ifArticleHeadline"><span><span class="required">*</span> @Localiser["label.headline"]</span></label>
<label for="ifArticleHeadline"><span>@Localiser["label.headline"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control">
@Html.TextBoxFor(model => model.ArticleHeadline, new { @id = "ifArticleHeadline", @class = "ArticleHeadline sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline) })
@Html.TextBoxFor(model => model.ArticleHeadline, new { @id = "ifArticleHeadline", @class = "ArticleHeadline sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline) })
</div>
<div class="sax-message"></div>
</div>
@@ -39,10 +56,10 @@
@* Article summary *@
<div class="sax-form-control ArticleSummary">
<div class="sax-label">
<label for="ifArticleSummary"><span><span class="required">*</span> @Localiser["label.summary"]</span></label>
<label for="ifArticleSummary"><span>@Localiser["label.summary"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control">
@Html.TextAreaFor(model => model.ArticleSummary, new { @id = "ifArticleSummary", @class = "ArticleSummary sax-textarea", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary) })
@Html.TextAreaFor(model => model.ArticleSummary, new { @id = "ifArticleSummary", @class = "ArticleSummary sax-textarea", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary) })
</div>
<div class="sax-message"></div>
</div>
@@ -50,7 +67,7 @@
@* Sport *@
<div class="sax-form-control ArticleSportId">
<div class="sax-label">
<label for="ifArticleSportId"><span><span class="required">*</span> @Localiser["label.sport"]</span></label>
<label for="ifArticleSportId"><span>@Localiser["label.sport"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control row">
@Html.HiddenFor(model => model.ArticleSportId, new { @id = "ifArticleSportId", @class = "ArticleSportId" })
@@ -63,7 +80,7 @@
@* Region *@
<div class="sax-form-control ArticleRegionId">
<div class="sax-label">
<label for="ifArticleRegionId"><span><span class="required">*</span> @Localiser["label.region"]</span></label>
<label for="ifArticleRegionId"><span>@Localiser["label.region"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control row">
@Html.HiddenFor(model => model.ArticleRegionId, new { @id = "ifArticleRegionId", @class = "ArticleRegionId" })
@@ -107,7 +124,7 @@
<div class="sax-panel-file-drop row">
<div class="col">Drop image here</div>
<div class="fixed">
<img id="" class="ContactImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" />
<img class="ContactImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" />
</div>
</div>
@* Segment details *@
@@ -138,7 +155,7 @@
<div id="dlgSelectArticleImage" class="sax-dialog">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectArticleImage", @class = "sax-form", @onSubmit = "return false;" }))
{
<input type="hidden" id="" class="SegmentIdx" />
<input type="hidden" class="SegmentIdx" />
<div class="spacer4"></div>
<div class="sax-form-control ArticleImage">
<div class="row">
@@ -150,7 +167,7 @@
<div class="spacer2"></div>
<div class="row">
<div class="col"><div class="UploadMessage"></div></div>
<div class="fixed"><img id="" class="ArticleImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" /></div>
<div class="fixed"><img class="ArticleImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" /></div>
</div>
<div class="spacer2"></div>
}
@@ -22,7 +22,7 @@
<input type="hidden" class="FilterPageNo" name="DataPageNo" value="0" />
<div class="row">
<div class="col-sm-5 sax-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-sm-7"><input type="search" id="" class="sax-input FilterOrganisation" name="Filter.Organisation" maxlength="32" autocomplete="off" /></div>
<div class="col-sm-7"><input type="search" class="sax-input FilterOrganisation" name="Filter.Organisation" maxlength="32" autocomplete="off" /></div>
</div>
}
@@ -55,7 +55,12 @@ else
<div class="sax-panel-item Activity">
<div class="sax-header row">
<div class="col">
<div class="sax-caption"><div class="sax-action ActivityCaption"></div></div>
<div class="sax-caption">
<div class="row">
<div class="col"><div class="sax-action ActivityCaption"></div></div>
<div class="col right"><div class="sax-action ActivityOrganisation"></div></div>
</div>
</div>
</div>
<div class="fixed sax-actions">
</div>
@@ -21,7 +21,7 @@
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
<div class="col-sm-8 row">
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" value="@(Model.Filter.OrganisationCaption)" /></div>
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" readonly="readonly" value="@(Model.Filter.OrganisationCaption)" /></div>
<div class="fixed"><button class="sax-button" onclick="sax.selectFilterOrganisation()">@Localiser["label.select"]</button></div>
</div>
</div>
@@ -64,6 +64,6 @@
</div>
<partial name="Panel-OpportunityDialog.cshtml" />
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
<partial name="Panel-OpportunityDialog.cshtml" />
@@ -129,15 +129,15 @@
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Account/Profile');">@Localiser["account.caption.profile"]</div>
@if (Model.UserIsJournalist)
@if (Model.ArticlesAllowed)
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Journalist/Articles');">@Localiser["journalist.caption.articles"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Article/Index');">@Localiser["article.caption.articles"]</div>
}
@if (Model.UserCanManageOrganisationMembers)
@if (Model.MembersAllowed)
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation/Members');">@Localiser["label.members"]</div>
}
@if (Model.UserCanManageOrganisationOpportunities)
@if (Model.OpportunitiesAllowed)
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation/Opportunities');">@Localiser["label.opportunities"]</div>
}
@@ -273,7 +273,7 @@
}
sax.onRefreshProfileOrganisationsInfo = function (response)
{
sax.debug('onRefreshProfileOrganisationsInfo', response);
//sax.debug('onRefreshProfileOrganisationsInfo', response);
if (!response || !response.success) return;
var $section = $('.sax-panel-section.ProfileOrganisations');
$('.sax-message', $section).stop(true, false).fadeOut(200).empty();
@@ -1,5 +1,5 @@
/*
* Journalist - Articles page scripts.
* Article page scripts.
*/
(function (win, doc, undef)
@@ -8,18 +8,18 @@
sax.itemIdPrefix = 'Itm_';
sax.segIdPrefix = 'Seg_';
sax.classFileDrag = 'sax-file-drag';
let $pnl = sax.$pnl, $frm = sax.$frm;
let ac = sax.articleContent = sax.articleContent || {};
//--------------------------------------------------------------
sax.refreshResults = function (delay)
{
var $results = $('.sax-panel-results');
if (!sax.awaitingRefreshResponse)
{
var $items = $('.sax-panel-item-list', $results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
var $items = $('.sax-panel-item-list', $pnl.results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
}
sax.ajaxRefreshResults = sax.ajaxRefreshResults || { url: sax.url.base + 'Journalist/Ajax/GetArticleList', formId: 'frmArticleFilter', callbackFn: sax.doRefreshResults };
sax.ajaxRefreshResults = sax.ajaxRefreshResults || { url: sax.url.base + 'Article/Ajax/GetList', formId: 'frmArticleFilter', callbackFn: sax.doRefreshResults };
sax.doAjaxRequest(sax.ajaxRefreshResults, delay || 50);
sax.awaitingRefreshResponse = true;
}
@@ -28,11 +28,11 @@
//sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
var $results = $('.sax-panel-results');
var $msgs = $('.sax-panel-messages', $results).hide().empty();
var $items = $('.sax-panel-item-list', $results).hide().empty();
var $tmpl = $('.sax-panel-item-template .sax-panel-item', $results);
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty();
var $items = $('.sax-panel-item-list', $pnl.results).hide().empty();
var $tmpl = $('.sax-panel-item-template .sax-panel-item', $pnl.results);
if (!response.success) return;
sax.data.articleOrganisations = response.organisations;
sax.refreshPaging(response);
var items = response.articles;
if (!items.length)
@@ -60,7 +60,26 @@
$('.ArticleStatusDesc', $item).text(item.statusDesc);
$('.sax-caption .sax-action, .sax-actions .sax-action.sax-item-update', $item).off('click').on('click', function () { sax.updateItem(item.id) })
$item.off('dblclick').on('dblclick', function () { sax.updateItem(item.id) })
$('.sax-panel-results .sax-panel-messages').hide().empty();
$('.sax-panel-messages', $pnl.results).hide().empty();
}
//--------------------------------------------------------------
sax.selectFilterOrganisation = function ()
{
if (!sax.data.articleOrganisations || !sax.data.articleOrganisations.length) return;
sax.showSelectOrganisation();
}
sax.showSelectOrganisation = function ()
{
//sax.debug('sax.selectFilterOrganisation', sax.data.articleOrganisations);
sax.selectOrganisation.fn.selectOrganisation({ caption: sax.dlg.title.selectOrganisation, items: sax.data.articleOrganisations, fnCallback: sax.onOrganisationSelected });
}
sax.onOrganisationSelected = function (id, name)
{
//sax.debug('sax.onOrganisationSelected', id, name);
$('#frmArticleFilter #ifFilterOrganisationId, #frmArticle #ifArticleOrganisationId').val(id);
$('#frmArticleFilter #ifFilterOrganisation').val(name);
sax.refreshResults(50);
}
//--------------------------------------------------------------
@@ -245,13 +264,13 @@
if (file.type != 'image/jpg' && file.type != 'image/jpeg' && file.type != 'image/png') return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileTypeInvalid.format(sax.getFileType(file)));
$(".UploadMessage", context).text(sax.msg.uploadingFile.format(file.name));
$('img.ArticleImageUploadProgress', context).fadeIn(200);
sax.clearControlError(sax.$pnl.contactImageDrag);
sax.clearControlError();
sax.data.contactImageUploadContext = context;
sax.ajax.uploadArticleImage = sax.ajax.uploadArticleImage || { url: sax.url.base + 'Journalist/Ajax/UploadArticleImage', callbackFn: sax.handleArticleImageUploadResponse, noWaitIcon: true };
sax.ajax.uploadArticleImage = sax.ajax.uploadArticleImage || { url: sax.url.base + 'Article/Ajax/UploadImage', callbackFn: sax.handleArticleImageUploadResponse, noWaitIcon: true };
sax.ajax.uploadArticleImage.formData = new FormData();
sax.ajax.uploadArticleImage.formData.append("__RequestVerificationToken", $('#frmNavigate input[name="__RequestVerificationToken"]').val());
sax.ajax.uploadArticleImage.formData.append("ArticleId", $('#ifArticleId', sax.$frm.article).val());
sax.ajax.uploadArticleImage.formData.append("ArticleId", $('#ifArticleId', $frm.article).val());
sax.ajax.uploadArticleImage.formData.append("ArticleImage", file);
sax.doAjaxRequest(sax.ajax.uploadArticleImage, 50);
}
@@ -275,9 +294,21 @@
sax.createItem = function ()
{
sax.clearItem();
let orgId = $('#ifFilterOrganisationId', $frm.filter).val();
$('#ifArticleOrganisationId', $frm.article).val(orgId);
$('#ifArticleOrganisation', $frm.article).val($('#ifFilterOrganisation', $frm.filter).val());
$('.sax-form-control.ArticleOrganisation', $frm.article).toggle(!!orgId);
sax.populateArticleContent({});
sax.openArticleDialog(sax.dlg.title.createArticle);
}
sax.clearItem = function ()
{
let frm = $frm.article;
$('#ifArticleId,#ifArticleExists,#ifArticleOrganisationId,#ifArticleRegionId,#ifArticleSportId,input[type="text"],textarea,select', frm).val('');
$('#chkArticlePublish', frm).prop("checked", false);
$('.sax-input.sax-calendar.ArticlePublishOn', frm).datepicker('setDate', 'today');
sax.clearControlErrors();
}
sax.openArticleDialog = function (title)
{
sax.clearControlErrors();
@@ -285,24 +316,12 @@
sax.$dlg.article.dialog('option', 'title', title);
sax.openDialog(sax.$dlg.article, 600, 800);
}
sax.clearItem = function ()
{
let $frm = sax.$frm.article;
$('#ifArticleId,#ifArticleExists,#ifArticleRegionId,#ifArticleSportId,input[type="text"],textarea,select', $frm).val('');
$('#chkArticlePublish', $frm).prop("checked", false);
$('.sax-input.sax-calendar.ArticlePublishOn', $frm).datepicker('setDate', 'today');
sax.clearControlErrors();
}
sax.doCreateItem = function ()
{
sax.storeItem();
}
//--------------------------------------------------------------
sax.updateItem = function (id)
{
$('.ArticleId', sax.$frm.articleId).val(id);
sax.ajaxUpdateItem = sax.ajaxUpdateItem || { url: sax.url.base + 'Journalist/Ajax/GetArticle', formId: 'frmArticleId', callbackFn: sax.onUpdateItem };
$('.ArticleId', $frm.articleId).val(id);
sax.ajaxUpdateItem = sax.ajaxUpdateItem || { url: sax.url.base + 'Article/Ajax/GetItem', formId: 'frmArticleId', callbackFn: sax.onUpdateItem };
sax.doAjaxRequest(sax.ajaxUpdateItem, 50);
}
sax.onUpdateItem = function (response)
@@ -310,28 +329,24 @@
//sax.debug('onUpdateItem', response);
sax.clearItem();
if (!response.success) return;
let $frm = sax.$frm.article;
let frm = $frm.article;
let item = response.article;
$('#ifArticleId', $frm).val(item.id);
$('#ifArticleExists', $frm).val(1);
$('#ifArticleHeadline', $frm).val(item.headline);
$('#ifArticleSummary', $frm).val(item.summary);
$('#ifArticleRegionId', $frm).val(item.regionIdPrimary);
$('#ifArticleRegionCaption', $frm).val(item.regionCaptionPrimary);
$('#ifArticleSportId', $frm).val(item.sportIdPrimary);
$('#ifArticleSportCaption', $frm).val(item.sportCaptionPrimary);
$('#ifArticleId', frm).val(item.id);
$('#ifArticleExists', frm).val(1);
$('#ifArticleHeadline', frm).val(item.headline);
$('#ifArticleSummary', frm).val(item.summary);
$('#ifArticleRegionId', frm).val(item.regionIdPrimary);
$('#ifArticleRegionCaption', frm).val(item.regionCaptionPrimary);
$('#ifArticleSportId', frm).val(item.sportIdPrimary);
$('#ifArticleSportCaption', frm).val(item.sportCaptionPrimary);
if (item.published)
$('span.ArticlePublishedOn', $frm).text(item.publishedOnFmt);
$('div.ArticlePublish', $frm).toggle(!item.published);
$('div.ArticlePublished', $frm).toggle(!!item.published);
$('#cbArticleStatusCode', $frm).val(item.statusCode);
$('span.ArticlePublishedOn', frm).text(item.publishedOnFmt);
$('div.ArticlePublish', frm).toggle(!item.published);
$('div.ArticlePublished', frm).toggle(!!item.published);
$('#cbArticleStatusCode', frm).val(item.statusCode);
sax.populateArticleContent(item.content);
sax.openArticleDialog(sax.dlg.title.updateArticle);
}
sax.doUpdateItem = function ()
{
sax.storeItem();
}
//--------------------------------------------------------------
sax.switchArticleHeader = function ()
@@ -368,7 +383,7 @@
//--------------------------------------------------------------
sax.storeItem = function ()
{
sax.ajaxStoreItem = sax.ajaxStoreItem || { url: sax.url.base + 'Journalist/Ajax/StoreArticle', formId: 'frmArticle', callbackFn: sax.onStoreItem };
sax.ajaxStoreItem = sax.ajaxStoreItem || { url: sax.url.base + 'Article/Ajax/StoreItem', formId: 'frmArticle', callbackFn: sax.onStoreItem };
sax.doAjaxRequest(sax.ajaxStoreItem, 50);
}
sax.onStoreItem = function (response)
@@ -382,9 +397,8 @@
var $item = $('#' + sax.itemIdPrefix + item.id);
if (!$item.length)
{
var $results = $('.sax-panel-results');
$item = $('.sax-panel-item-template .sax-panel-item', $results).clone();
$('.sax-panel-item-list', $results).prepend($item).show();
$item = $('.sax-panel-item-template .sax-panel-item', $pnl.results).clone();
$('.sax-panel-item-list', $pnl.results).prepend($item).show();
}
sax.populateItem($item, item)
}
@@ -392,20 +406,23 @@
//--------------------------------------------------------------
$(function ()
{
sax.$frm.filter = $('#frmArticleFilter');
$('.sax-panel-filter .sax-action.sax-item-create').on('click', function () { sax.createItem(); });
$('.sax-panel-filter .sax-action.sax-results-refresh').on('click', function () { sax.refreshResults(); });
$('.ArticleFilter', sax.$frm.filter).on('input', function () { sax.refreshResults(250); }).on('keypress', function (event)
$pnl.filter = $('.sax-panel-filter');
$pnl.results= $('.sax-panel-results');
$frm.filter = $('#frmArticleFilter');
$('.sax-action.sax-item-create', $pnl.filter).on('click', function () { sax.createItem(); });
$('.sax-action.sax-results-refresh', $pnl.filter).on('click', function () { sax.refreshResults(); });
$('.ArticleFilter', $frm.filter).on('input', function () { sax.refreshResults(250); }).on('keypress', function (event)
{
if (event.keyCode == 13) setTimeout(sax.refreshResults, 50);
});
sax.$frm.articleId = $('#frmArticleId');
sax.$frm.article = $('#frmArticle');
$('.sax-input', sax.$frm.article).on('input', function () { sax.clearControlError(this); });
$frm.articleId = $('#frmArticleId');
$frm.article = $('#frmArticle');
$('.sax-input', $frm.article).on('input', function () { sax.clearControlError(this); });
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.cancel] = { text: sax.dlg.btn.cancel, class: "floatr", click: function () { $(this).dialog('close'); } };
opt.buttons[sax.dlg.btn.ok] = { text: sax.dlg.btn.ok, class: "floatr", click: function () { sax.doCreateItem(); } };
opt.buttons[sax.dlg.btn.ok] = { text: sax.dlg.btn.ok, class: "floatr", click: function () { sax.storeItem(); } };
opt.buttons['Header'] = { text: 'Header', class: "floatl", click: function () { sax.switchArticleHeader(); } };
opt.buttons['Content'] = { text: 'Content', class: "floatl", click: function () { sax.switchArticleContent(); } };
sax.$dlg.article = $('#dlgArticle').dialog(opt);
+3 -1
View File
@@ -44,9 +44,11 @@
}
sax.populateItem = function ($item, item)
{
//sax.debug('populateItem', item);
sax.debug('populateItem', item);
if (!item) return;
$item.prop('id', sax.itemIdPrefix + item.itemIdx).addClass(item.itemTypeClass).toggleClass('sax-activity-reaction-' + item.reaction, !!item.reaction);
$('.ActivityOrganisation', $item).text(item.organisation);
$('.ActivityAuthor', $item).text(item.author);
$('.ActivityCaption', $item).text(item.caption);
$('.ActivityBlurb', $item).text(item.blurb);
$('.ActivitySport', $item).text(item.sport);
@@ -35,7 +35,7 @@
}
sax.doRefreshResults = function (response)
{
sax.debug('doRefreshResults', response);
//sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
let $mnu = $('.sax-burger ul.sax-dropdown-menu', sax.$pnl.filter).empty();
@@ -201,7 +201,7 @@
}
sax.updateMemberRoles = function (memberRoleCodes)
{
sax.debug('updateMemberRoles', memberRoleCodes);
//sax.debug('updateMemberRoles', memberRoleCodes);
let $frm = sax.$frm.member;
sax.member.roleCodes = memberRoleCodes;
$('.MemberRoleCodes',$frm).val(memberRoleCodes.join(sax.data.memberRoleCodeDelim));
@@ -230,7 +230,7 @@
}
sax.onStoreItem = function (response)
{
sax.debug('onStoreItem', response);
//sax.debug('onStoreItem', response);
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
let $frm = sax.$frm.member;
@@ -26,7 +26,7 @@
}
or.fn.handleRequestOrganisationResponse = function (response)
{
sax.debug('or.handleRequestOrganisationResponse', response);
//sax.debug('or.handleRequestOrganisationResponse', response);
if (!response) return;
sax.refreshControlValues(response.controlValues, or.$frm);
if (!response.success) return;
@@ -6,7 +6,7 @@
{
"use strict";
let so = sax.selectOrganisation;
so.data = {}; so.fn = {}; so.itemIdPrefix = 'Org_';
so.data = {}; so.fn = {};
//--------------------------------------------------------------
/*
@@ -52,7 +52,8 @@
{
let item = items[itemIdx];
if (!so.fn.matchesFilter(item)) continue;
let $item = $tmpl.clone().prop('id', so.itemIdPrefix + item.id).on('click', function () { so.fn.onClickOrganisation(item); }).on('dblclick', function () { so.fn.onDblClickOrganisation(item); });
let $item = $tmpl.clone();
$item.on('click', function () { so.fn.onClickOrganisation(item, $item); }).on('dblclick', function () { so.fn.onDblClickOrganisation(item, $item); });
$('.Name', $item).text(item.name);
so.$results.append($item);
}
@@ -69,16 +70,16 @@
}
return true;
}
so.fn.onClickOrganisation = function (item)
so.fn.onClickOrganisation = function (item, $item)
{
//sax.debug('onClickOrganisation', item);
//sax.debug('onClickOrganisation', item, $item);
so.data.item = item;
$('.sax-panel-item.Organisation', so.$dlg).removeClass('sel');
$('.sax-panel-item.Organisation#' + so.itemIdPrefix + item.id, so.$dlg).addClass('sel');
$item.addClass('sel');
}
so.fn.onDblClickOrganisation = function (item)
so.fn.onDblClickOrganisation = function (item, $item)
{
//sax.debug('onDblClickCode', item);
//sax.debug('onDblClickCode', item, $item);
so.data.item = item;
so.fn.confirmSelection();
}
@@ -99,7 +100,6 @@
delete so.data.item;
}
//--------------------------------------------------------------
so.fn.init = function ()
{
@@ -33,7 +33,7 @@
{
if (!response || !response.success) return;
sr.regions = response.regions;
sax.debug(sr.cfg);
//sax.debug(sr.cfg);
sr.fn.showSelectRegion();
}
sr.fn.showSelectRegion = function ()
+5 -1
View File
@@ -18,7 +18,7 @@ namespace Saxonite.Net.Standard.Base.App
//-------------------------------------------------------------------
public static class Version
{
private static String version { get; } = "1.1.3.0";
private static String version { get; } = "1.1.4.0";
// Retrieve version.
public static String GetFullVersion () { return version; }
public static String GetAppVersion ()
@@ -40,6 +40,10 @@ namespace Saxonite.Net.Standard.Base.App
//-------------------------------------------------------------------
// Version history.
//-------------------------------------------------------------------
// 1.1.4 9-Aug-2021 Organisation Articles.
// - Journalist Article renamed Article and Organisation Id added.
// - Online Organisation Articles.
// - Admin Send Emails for User.
// 1.1.3 23-Jul-2021 Online Members.
// - Online Members.
// - Admin organisation activation.
+3 -3
View File
@@ -145,7 +145,7 @@ namespace Saxonite.Net.Standard.Base.App
// Activty data.
ActivityIndex = 200,
UserActivity = 202,
JournalistArticle = 210,
Article = 210,
OrganisationOpportunity = 220,
OrganisationEvent = 225,
// Item link components.
@@ -234,9 +234,9 @@ namespace Saxonite.Net.Standard.Base.App
Avatar = 100,
/// <summary>User's profile image, uploaded awaiting confirmation.</summary>
AvatarUpload = 101,
/// <summary>Journalist Article image.</summary>
/// <summary>Article image.</summary>
Article = 200,
/// <summary>Journalist Article image uploaded, awaiting confirmation.</summary>
/// <summary>Article image uploaded, awaiting confirmation.</summary>
ArticleUpload = 201,
}
+68 -66
View File
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Base.App
{
@@ -18,10 +18,10 @@ namespace Saxonite.Base.App
{
Unknown = 0,
ActivityIndex,
Article,
ItemAddress,
ItemImage,
ItemSport,
JournalistArticle,
Organisation,
OrganisationOpportunity,
Region,
@@ -53,6 +53,24 @@ namespace Saxonite.Base.App
ActivityIndex_UpdateOn,
ActivityIndex_UpdateBy,
ActivityIndex_UpdateHost,
Article_Id,
Article_UserAccountIdAuthor,
Article_OrganisationId,
Article_SportIdPrimary,
Article_RegionIdPrimary,
Article_Headline,
Article_Summary,
Article_BodyData,
Article_PublishedAt,
Article_Notes,
Article_Flags,
Article_Status,
Article_CreateOn,
Article_CreateBy,
Article_CreateHost,
Article_UpdateOn,
Article_UpdateBy,
Article_UpdateHost,
ItemAddress_Id,
ItemAddress_ItemType,
ItemAddress_ItemId,
@@ -121,23 +139,6 @@ namespace Saxonite.Base.App
ItemSport_UpdateOn,
ItemSport_UpdateBy,
ItemSport_UpdateHost,
JournalistArticle_Id,
JournalistArticle_UserAccountIdJournalist,
JournalistArticle_SportIdPrimary,
JournalistArticle_RegionIdPrimary,
JournalistArticle_Headline,
JournalistArticle_Summary,
JournalistArticle_BodyData,
JournalistArticle_PublishedAt,
JournalistArticle_Notes,
JournalistArticle_Flags,
JournalistArticle_Status,
JournalistArticle_CreateOn,
JournalistArticle_CreateBy,
JournalistArticle_CreateHost,
JournalistArticle_UpdateOn,
JournalistArticle_UpdateBy,
JournalistArticle_UpdateHost,
Organisation_Id,
Organisation_Name,
Organisation_OrganisationType,
@@ -305,7 +306,7 @@ namespace Saxonite.Base.App
//-------------------------------------------------------------------
// Data members.
private static readonly int tableCount = 15;
private static readonly int columnCount = 261;
private static readonly int columnCount = 262;
private static ulong maxTextLen = 0;
//-------------------------------------------------------------------
@@ -452,10 +453,10 @@ namespace Saxonite.Base.App
private static readonly String[] tables =
{
"ActivityIndex",
"Article",
"ItemAddress",
"ItemImage",
"ItemSport",
"JournalistArticle",
"Organisation",
"OrganisationOpportunity",
"Region",
@@ -506,32 +507,18 @@ namespace Saxonite.Base.App
new ColumnDfn(1,"UpdateOn",9,93,false,23),
new ColumnDfn(1,"UpdateBy",4,4,false,10),
new ColumnDfn(1,"UpdateHost",0,12,false,100),
new ColumnDfn(2,"Id",5,-5,true,19),
new ColumnDfn(2,"ItemType",3,5,false,5),
new ColumnDfn(2,"ItemId",4,4,false,10),
new ColumnDfn(2,"AddressType",3,5,false,5),
new ColumnDfn(2,"Caption",0,-9,false,200),
new ColumnDfn(2,"Line1",0,-9,false,200),
new ColumnDfn(2,"Line2",0,-9,false,200),
new ColumnDfn(2,"Line3",0,-9,false,200),
new ColumnDfn(2,"Town",0,-9,false,100),
new ColumnDfn(2,"Province",0,-9,false,100),
new ColumnDfn(2,"RegionIdProvince",4,4,false,10),
new ColumnDfn(2,"Country",0,-9,false,100),
new ColumnDfn(2,"RegionIdCountry",4,4,false,10),
new ColumnDfn(2,"PostalCode",0,-9,false,32),
new ColumnDfn(2,"PhoneMain",0,-9,false,100),
new ColumnDfn(2,"LocationSource",0,12,false,100),
new ColumnDfn(2,"LocationStoredAt",9,93,false,16),
new ColumnDfn(2,"LocationUpdateRequired",1,-7,false,1),
new ColumnDfn(2,"LocationData",0,-9,false,4000),
new ColumnDfn(2,"LocationFormattedAddress",0,-9,false,4000),
new ColumnDfn(2,"LocationLatitude",8,3,false,9),
new ColumnDfn(2,"LocationLongitude",8,3,false,9),
new ColumnDfn(2,"LocationAltitude",8,3,false,9),
new ColumnDfn(2,"Id",4,4,true,10),
new ColumnDfn(2,"UserAccountIdAuthor",4,4,false,10),
new ColumnDfn(2,"OrganisationId",4,4,false,10),
new ColumnDfn(2,"SportIdPrimary",4,4,false,10),
new ColumnDfn(2,"RegionIdPrimary",4,4,false,10),
new ColumnDfn(2,"Headline",0,-9,false,200),
new ColumnDfn(2,"Summary",0,-9,false,2000),
new ColumnDfn(2,"BodyData",0,-9,false,0),
new ColumnDfn(2,"PublishedAt",9,93,false,16),
new ColumnDfn(2,"Notes",0,-9,false,2000),
new ColumnDfn(2,"Flags",3,5,false,5),
new ColumnDfn(2,"Status",0,1,false,3),
new ColumnDfn(2,"Status",0,12,false,3),
new ColumnDfn(2,"CreateOn",9,93,false,23),
new ColumnDfn(2,"CreateBy",4,4,false,10),
new ColumnDfn(2,"CreateHost",0,12,false,100),
@@ -541,30 +528,48 @@ namespace Saxonite.Base.App
new ColumnDfn(3,"Id",5,-5,true,19),
new ColumnDfn(3,"ItemType",3,5,false,5),
new ColumnDfn(3,"ItemId",4,4,false,10),
new ColumnDfn(3,"ImageType",3,5,false,5),
new ColumnDfn(3,"ImageSeq",2,-6,false,3),
new ColumnDfn(3,"SessionUid",5,-5,false,19),
new ColumnDfn(3,"ImageUid",4,4,false,10),
new ColumnDfn(3,"Filename",0,-9,false,1024),
new ColumnDfn(3,"Mime",0,12,false,64),
new ColumnDfn(3,"ContentType",0,12,false,128),
new ColumnDfn(3,"Width",4,4,false,10),
new ColumnDfn(3,"Height",4,4,false,10),
new ColumnDfn(3,"ImageData",10,-3,false,0),
new ColumnDfn(3,"AddressType",3,5,false,5),
new ColumnDfn(3,"Caption",0,-9,false,200),
new ColumnDfn(3,"Line1",0,-9,false,200),
new ColumnDfn(3,"Line2",0,-9,false,200),
new ColumnDfn(3,"Line3",0,-9,false,200),
new ColumnDfn(3,"Town",0,-9,false,100),
new ColumnDfn(3,"Province",0,-9,false,100),
new ColumnDfn(3,"RegionIdProvince",4,4,false,10),
new ColumnDfn(3,"Country",0,-9,false,100),
new ColumnDfn(3,"RegionIdCountry",4,4,false,10),
new ColumnDfn(3,"PostalCode",0,-9,false,32),
new ColumnDfn(3,"PhoneMain",0,-9,false,100),
new ColumnDfn(3,"LocationSource",0,12,false,100),
new ColumnDfn(3,"LocationStoredAt",9,93,false,16),
new ColumnDfn(3,"LocationUpdateRequired",1,-7,false,1),
new ColumnDfn(3,"LocationData",0,-9,false,4000),
new ColumnDfn(3,"LocationFormattedAddress",0,-9,false,4000),
new ColumnDfn(3,"LocationLatitude",8,3,false,9),
new ColumnDfn(3,"LocationLongitude",8,3,false,9),
new ColumnDfn(3,"LocationAltitude",8,3,false,9),
new ColumnDfn(3,"Notes",0,-9,false,2000),
new ColumnDfn(3,"Flags",3,5,false,5),
new ColumnDfn(3,"Status",0,12,false,3),
new ColumnDfn(3,"Status",0,1,false,3),
new ColumnDfn(3,"CreateOn",9,93,false,23),
new ColumnDfn(3,"CreateBy",4,4,false,10),
new ColumnDfn(3,"CreateHost",0,12,false,100),
new ColumnDfn(3,"UpdateOn",9,93,false,23),
new ColumnDfn(3,"UpdateBy",4,4,false,10),
new ColumnDfn(3,"UpdateHost",0,12,false,100),
new ColumnDfn(4,"Id",4,4,true,10),
new ColumnDfn(4,"Id",5,-5,true,19),
new ColumnDfn(4,"ItemType",3,5,false,5),
new ColumnDfn(4,"ItemId",4,4,false,10),
new ColumnDfn(4,"SportId",4,4,false,10),
new ColumnDfn(4,"ItemSportData",0,-9,false,0),
new ColumnDfn(4,"ImageType",3,5,false,5),
new ColumnDfn(4,"ImageSeq",2,-6,false,3),
new ColumnDfn(4,"SessionUid",5,-5,false,19),
new ColumnDfn(4,"ImageUid",4,4,false,10),
new ColumnDfn(4,"Filename",0,-9,false,1024),
new ColumnDfn(4,"Mime",0,12,false,64),
new ColumnDfn(4,"ContentType",0,12,false,128),
new ColumnDfn(4,"Width",4,4,false,10),
new ColumnDfn(4,"Height",4,4,false,10),
new ColumnDfn(4,"ImageData",10,-3,false,0),
new ColumnDfn(4,"Notes",0,-9,false,2000),
new ColumnDfn(4,"Flags",3,5,false,5),
new ColumnDfn(4,"Status",0,12,false,3),
@@ -575,13 +580,10 @@ namespace Saxonite.Base.App
new ColumnDfn(4,"UpdateBy",4,4,false,10),
new ColumnDfn(4,"UpdateHost",0,12,false,100),
new ColumnDfn(5,"Id",4,4,true,10),
new ColumnDfn(5,"UserAccountIdJournalist",4,4,false,10),
new ColumnDfn(5,"SportIdPrimary",4,4,false,10),
new ColumnDfn(5,"RegionIdPrimary",4,4,false,10),
new ColumnDfn(5,"Headline",0,-9,false,200),
new ColumnDfn(5,"Summary",0,-9,false,2000),
new ColumnDfn(5,"BodyData",0,-9,false,0),
new ColumnDfn(5,"PublishedAt",9,93,false,16),
new ColumnDfn(5,"ItemType",3,5,false,5),
new ColumnDfn(5,"ItemId",4,4,false,10),
new ColumnDfn(5,"SportId",4,4,false,10),
new ColumnDfn(5,"ItemSportData",0,-9,false,0),
new ColumnDfn(5,"Notes",0,-9,false,2000),
new ColumnDfn(5,"Flags",3,5,false,5),
new ColumnDfn(5,"Status",0,12,false,3),
@@ -52,7 +52,7 @@ namespace Saxonite.Net.Standard.Base.App
// Activty data.
dataItemTypeCodes.Add(Sax.DataItemType.ActivityIndex, "ActivityIndex", "Activity Index");
dataItemTypeCodes.Add(Sax.DataItemType.UserActivity, "UserActivity", "User Activity");
dataItemTypeCodes.Add(Sax.DataItemType.JournalistArticle, "JournalistArticle", "Journalist Article");
dataItemTypeCodes.Add(Sax.DataItemType.Article, "Article", "Article");
dataItemTypeCodes.Add(Sax.DataItemType.OrganisationOpportunity, "OrganisationOpportunity", "Organisation Opportunity");
dataItemTypeCodes.Add(Sax.DataItemType.OrganisationEvent, "OrganisationEvent", "Organisation Event");
// Item link components.
@@ -29,7 +29,7 @@ namespace Saxonite.Net.Standard.Base.Bus
UserActivity_ViewedAtLast,
UserActivity_Reaction,
UserActivity_ReactedAtLast,
// Journalist Article.
// Article.
Article_Headline,
Article_Summary,
// Organisation opportunity.
@@ -11,9 +11,9 @@ using System.Xml.Linq;
namespace Saxonite.Net.Standard.Base.Bus
{
//=======================================================================
// Journalist Article - Content data.
// Article - Content data.
//=======================================================================
partial class SaxJournalistArticle
partial class SaxArticle
{
//-------------------------------------------------------------------
// Definitions.
@@ -8,9 +8,9 @@ using System.Text;
namespace Saxonite.Net.Standard.Base.Bus
{
//=======================================================================
// Journalist Article.
// Article.
//=======================================================================
public abstract partial class SaxJournalistArticle : SacsHierarchyItem
public abstract partial class SaxArticle : SacsHierarchyItem
{
//-------------------------------------------------------------------
// Columns.
@@ -18,12 +18,15 @@ namespace Saxonite.Net.Standard.Base.Bus
{
Pos,
Id,
// Journalist.
UserAccountIdJournalist,
Journalist_DisplayName,
Journalist_Title,
Journalist_FirstName,
Journalist_LastName,
// Author.
UserAccountIdAuthor,
Author_DisplayName,
Author_Title,
Author_FirstName,
Author_LastName,
// Organisation.
OrganisationId,
Organisation_Name,
// Sport.
SportIdPrimary,
Sport_Name,
@@ -50,7 +53,8 @@ namespace Saxonite.Net.Standard.Base.Bus
/// <summary>Properties other than common.</summary>
public class DataProperties
{
public SysId UserAccountIdJournalist { get; set; }
public SysId UserAccountIdAuthor { get; set; }
public SysId OrganisationId { get; set; }
public String Headline { get; set; } = String.Empty;
public String Summary { get; set; } = String.Empty;
public SysId SportIdPrimary { get; set; }
@@ -71,10 +75,15 @@ namespace Saxonite.Net.Standard.Base.Bus
Status = DefaultStatus;
}
// Properties.
public SysId UserAccountIdJournalist
public SysId UserAccountIdAuthor
{
get { return data.UserAccountIdJournalist; }
set { CheckChanged(data.UserAccountIdJournalist, value); data.UserAccountIdJournalist = value; }
get { return data.UserAccountIdAuthor; }
set { CheckChanged(data.UserAccountIdAuthor, value); data.UserAccountIdAuthor = value; }
}
public SysId OrganisationId
{
get { return data.OrganisationId; }
set { CheckChanged(data.OrganisationId, value); data.OrganisationId = value; }
}
public SysId SportIdPrimary
{
@@ -109,7 +118,8 @@ namespace Saxonite.Net.Standard.Base.Bus
// Population.
internal void PopulateFrom(Data data)
{
UserAccountIdJournalist = data.UserAccountIdJournalist;
UserAccountIdAuthor = data.UserAccountIdAuthor;
OrganisationId = data.OrganisationId;
SportIdPrimary = data.SportIdPrimary;
RegionIdPrimary = data.RegionIdPrimary;
Headline = data.Headline;
@@ -131,7 +141,8 @@ namespace Saxonite.Net.Standard.Base.Bus
public new class ErrField : SacsHierarchyItem.ErrField
{
// Identifies the field that has invalid data.
public ValidValue UserAccountIdJournalist { get; set; } = ValidValue.Valid;
public ValidValue UserAccountIdAuthor { get; set; } = ValidValue.Valid;
public ValidValue OrganisationId { get; set; } = ValidValue.Valid;
public ValidValue SportIdPrimary { get; set; } = ValidValue.Valid;
public ValidValue RegionIdPrimary { get; set; } = ValidValue.Valid;
public ValidValue Headline { get; set; } = ValidValue.Valid;
@@ -146,10 +157,11 @@ namespace Saxonite.Net.Standard.Base.Bus
//-------------------------------------------------------------------
// Construction.
protected SaxJournalistArticle(SysId id, SysId UserAccountIdJournalist) : base(id)
protected SaxArticle(SysId id, SysId UserAccountIdAuthor, SysId organisationId) : base(id)
{
base.SetData(data);
this.UserAccountIdJournalist = UserAccountIdJournalist;
this.UserAccountIdAuthor = UserAccountIdAuthor;
this.OrganisationId = organisationId;
Status = DefaultStatus;
}
@@ -175,7 +187,7 @@ namespace Saxonite.Net.Standard.Base.Bus
// Utilities.
public ItemId GetItemId()
{
return new ItemId((short)Sax.DataItemType.JournalistArticle, Id);
return new ItemId((short)Sax.DataItemType.Article, Id);
}
//-------------------------------------------------------------------
@@ -187,14 +199,21 @@ namespace Saxonite.Net.Standard.Base.Bus
// Properties that cannot be changed if previously specified.
if (SysId.IsValid(Id) && SysId.ToInt(Id) != SysId.ToInt(data.Id))
throw new NotSupportedException(fn + " Id cannot be changed");
if (SysId.IsValid(UserAccountIdJournalist) && SysId.ToInt(UserAccountIdJournalist) != SysId.ToInt(data.UserAccountIdJournalist))
throw new NotSupportedException(fn + " UserAccountIdJournalist cannot be changed");
if (SysId.IsValid(UserAccountIdAuthor) && SysId.ToInt(UserAccountIdAuthor) != SysId.ToInt(data.UserAccountIdAuthor))
throw new NotSupportedException(fn + " UserAccountIdAuthor cannot be changed");
if (SysId.IsValid(OrganisationId) && SysId.ToInt(OrganisationId) != SysId.ToInt(data.OrganisationId))
throw new NotSupportedException(fn + " OrganisationId cannot be changed");
this.data.PopulateFrom(data);
}
public SysId UserAccountIdJournalist
public SysId UserAccountIdAuthor
{
get { return data.UserAccountIdJournalist; }
protected set { data.UserAccountIdJournalist = value; }
get { return data.UserAccountIdAuthor; }
protected set { data.UserAccountIdAuthor = value; }
}
public SysId OrganisationId
{
get { return data.OrganisationId; }
protected set { data.OrganisationId = value; }
}
public String Headline
{
@@ -254,7 +273,8 @@ namespace Saxonite.Net.Standard.Base.Bus
// List filtering.
public List<SysId> IdsIncluded { get; } = new List<SysId>();
public List<SysId> IdsExcluded { get; } = new List<SysId>();
public List<SysId> UserAccountIdsJournalistIncluded { get; } = new List<SysId>();
public List<SysId> UserAccountIdsAuthorIncluded { get; } = new List<SysId>();
public List<SysId> OrganisationIdsIncluded { get; } = new List<SysId>();
public List<SysId> SportIdsIncluded { get; set; } = new List<SysId>();
public List<SysId> RegionIdsIncluded { get; } = new List<SysId>();
public String HeadlinePartial { get; set; }
@@ -270,7 +290,7 @@ namespace Saxonite.Net.Standard.Base.Bus
}
//=======================================================================
// Item list extension methods.
public static class SaxJournalistArticleList
public static class SaxAuthorArticleList
{
}
@@ -58,6 +58,10 @@ namespace Saxonite.Net.Standard.Base.Consoles
}
public ItemId ItemId { get; }
public DateTime EffectiveOn { get; }
public SysId OrganisationId { get; set; }
public String Organisation { get; set; }
public SysId UserAccountIdAuthor { get; set; }
public String Author { get; set; }
public String Caption { get; protected set; }
public String Blurb { get; protected set; }
public SysId SportId { get; protected set; }
@@ -78,7 +82,7 @@ namespace Saxonite.Net.Standard.Base.Consoles
private SaxInternals internals = null;
private readonly List<Sax.DataItemType> validActivityItemTypes = new List<Sax.DataItemType>()
{
Sax.DataItemType.JournalistArticle,
Sax.DataItemType.Article,
Sax.DataItemType.OrganisationOpportunity,
};
@@ -111,9 +115,9 @@ namespace Saxonite.Net.Standard.Base.Consoles
// Store Activity Index for Specific activities.
//-------------------------------------------------------------------
/// <summary>
/// Store the Activity Index for a Journalist Article.
/// Store the Activity Index for an Article.
/// </summary>
public bool StoreActivityIndex(SaxJournalistArticle article, DbUpdateInfo dbUpdateInfo)
public bool StoreActivityIndex(SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
@@ -139,7 +143,7 @@ namespace Saxonite.Net.Standard.Base.Consoles
}
return ClearActivityIndex(article.GetItemId(), dbUpdateInfo);
}
public bool ClearActivityIndex(SaxJournalistArticle article, DbUpdateInfo dbUpdateInfo)
public bool ClearActivityIndex(SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
return ClearActivityIndex(article.GetItemId(), dbUpdateInfo);
}
@@ -2,6 +2,7 @@
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Standard.Base.Bus;
@@ -80,10 +81,18 @@ namespace Saxonite.Net.Standard.Base.Mgr
ClearErrorState();
// Email address.
if (errField.EmailAddress != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.EmailAddress, "email", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress), true))
if (errField.EmailAddress != SacsHierarchyItem.ValidValue.Ignore)
{
errField.EmailAddress = SacsHierarchyItem.ValidValue.Invalid;
return false;
if (!IsValidValue(data.EmailAddress, "email", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress), true))
{
errField.EmailAddress = SacsHierarchyItem.ValidValue.Invalid;
return false;
}
if (!SacsDataValidationHelper.IsValidEmailAddress(data.EmailAddress))
{
errField.EmailAddress = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("Invalid email address");
}
}
// Title.
if (errField.Title != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Title, "Title", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.UserAccount_Title)))
@@ -2,6 +2,7 @@
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
@@ -32,6 +33,7 @@ namespace Saxonite.Net.Standard.Base.Mgr
prmUserOrganisation.StatusCat = statusCat;
return GetUserOrganisationCount(prmUserOrganisation) > 0;
}
/// <summary>
/// Does the user have the specified role with the organisation.
/// </summary>
@@ -40,6 +42,7 @@ namespace Saxonite.Net.Standard.Base.Mgr
if (!SysId.IsValid(userAccountId) || !SysId.IsValid(organisationId) || organisationRole <= 0) return false;
return GetOrganisationRolesForUser(userAccountId, organisationId, statusCat).Contains(organisationRole);
}
/// <summary>
/// Retrieve the roles that a user has with the organisation.
/// </summary>
@@ -57,6 +60,53 @@ namespace Saxonite.Net.Standard.Base.Mgr
return organisationRoles;
}
public class OrganisationIdName
{
public SysId Id { get; internal set; }
public String Name { get; internal set; }
}
/// <summary>
/// Get list of organisation Ids that the user has the specified role with.
/// </summary>
public List<OrganisationIdName> GetOrganisationsForUserRole(SysId userAccountId, Sax.OrganisationRole organisationRole, SaxUserOrganisation.StatusCat statusCat = SaxUserOrganisation.StatusCat.ActiveOnly)
{
List<OrganisationIdName> organisationsData = new List<OrganisationIdName>();
String organisationRoleCode = Internals.OrganisationRoleCodes.GetCodeForType(organisationRole);
if (!SysId.IsValid(userAccountId) || StringUtil.IsEmpty(organisationRoleCode)) return organisationsData;
// Columns.
ColumnDfn colOrganisationId = GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
ColumnDfn colOrganisationName = GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
// Filter.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(userAccountId);
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
prmUserOrganisation.OrganisationMembersOnly = true;
prmUserOrganisation.OrganisationRoles.Add(organisationRole);
prmUserOrganisation.StatusCat = statusCat;
prmUserOrganisation.SortColumns.Add(colOrganisationName);
// Query.
using (DbResultSet resultSet = ExecuteUserOrganisationQuery(new List<ColumnDfn>() { colOrganisationId, colOrganisationName }, prmUserOrganisation))
{
while (resultSet != null && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
String organisationName = values.GetString(colOrganisationName.DataName);
if (SysId.IsValid(organisationId) && !StringUtil.IsEmpty(organisationName))
{
OrganisationIdName organisationData = new OrganisationIdName()
{
Id = organisationId,
Name = organisationName
};
organisationsData.Add(organisationData);
}
}
}
return organisationsData;
}
//-------------------------------------------------------------------
// Create item.
public abstract SaxUserOrganisation CreateUserOrganisation(SysId userAccountId, SysId OrganisationId);
@@ -15,56 +15,56 @@ namespace Saxonite.Net.Standard.Base.Mgr
partial class SaxActivityMgr
{
//*******************************************************************
// Activity Mgr - Journalist Article
// Activity Mgr - Article
//*******************************************************************
// Utilities.
//-------------------------------------------------------------------
// Create item.
public abstract SaxJournalistArticle CreateJournalistArticle(SysId userAccountIdJournalist);
public abstract SaxArticle CreateArticle(SysId userAccountIdAuthor, SysId organisationId);
//-------------------------------------------------------------------
// Item exists.
public bool JournalistArticleExistsById(SysId id)
public bool ArticleExistsById(SysId id)
{
ClearErrorState();
if (!SysId.IsValid(id)) return false;
SaxJournalistArticle.Params prmJournalistArticle = new SaxJournalistArticle.Params();
prmJournalistArticle.IdsIncluded.Add(id);
prmJournalistArticle.StatusCat = SaxJournalistArticle.StatusCat.Any;
return GetJournalistArticleCount(prmJournalistArticle) == 1;
SaxArticle.Params prmArticle = new SaxArticle.Params();
prmArticle.IdsIncluded.Add(id);
prmArticle.StatusCat = SaxArticle.StatusCat.Any;
return GetArticleCount(prmArticle) == 1;
}
//-------------------------------------------------------------------
// Retrieve individual items.
public abstract SaxJournalistArticle GetJournalistArticle(SaxJournalistArticle.Params prmJournalistArticle);
public SaxJournalistArticle GetJournalistArticleById(SysId id)
public abstract SaxArticle GetArticle(SaxArticle.Params prmArticle);
public SaxArticle GetArticleById(SysId id)
{
ClearErrorState();
if (!SysId.IsValid(id)) return null;
SaxJournalistArticle.Params prmJournalistArticle = new SaxJournalistArticle.Params();
prmJournalistArticle.IdsIncluded.Add(id);
prmJournalistArticle.StatusCat = SaxJournalistArticle.StatusCat.Any;
return GetJournalistArticle(prmJournalistArticle);
SaxArticle.Params prmArticle = new SaxArticle.Params();
prmArticle.IdsIncluded.Add(id);
prmArticle.StatusCat = SaxArticle.StatusCat.Any;
return GetArticle(prmArticle);
}
//-------------------------------------------------------------------
// Validate item data.
public bool IsValidJournalistArticle(SaxJournalistArticle journalistArticle)
public bool IsValidArticle(SaxArticle article)
{
ClearErrorState();
if (journalistArticle == null) return SetErrorState(ErrorMessage.ItemNotSpecified);
return IsValidJournalistArticleData(journalistArticle.GetData(), new SaxJournalistArticle.ErrField());
if (article == null) return SetErrorState(ErrorMessage.ItemNotSpecified);
return IsValidArticleData(article.GetData(), new SaxArticle.ErrField());
}
public virtual bool IsValidJournalistArticleData(SaxJournalistArticle.Data data, SaxJournalistArticle.ErrField errField)
public virtual bool IsValidArticleData(SaxArticle.Data data, SaxArticle.ErrField errField)
{
ClearErrorState();
// User Account - Journalist.
if (errField.UserAccountIdJournalist != SacsHierarchyItem.ValidValue.Ignore && !SysId.IsValid(data.UserAccountIdJournalist))
// User Account - Author.
if (errField.UserAccountIdAuthor != SacsHierarchyItem.ValidValue.Ignore && !SysId.IsValid(data.UserAccountIdAuthor))
{
errField.UserAccountIdJournalist = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("User must be specified");
errField.UserAccountIdAuthor = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("Author must be specified");
}
// Primary Sport.
if (errField.SportIdPrimary != SacsHierarchyItem.ValidValue.Ignore && !SysId.IsValid(data.SportIdPrimary))
@@ -80,32 +80,32 @@ namespace Saxonite.Net.Standard.Base.Mgr
}
// Headline.
if (errField.Headline != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Headline, "headline", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline), true))
if (errField.Headline != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Headline, "headline", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.Article_Headline), true))
{
errField.Headline = SacsHierarchyItem.ValidValue.Invalid;
return false;
}
// Summary.
if (errField.Summary != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Summary, "summary", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary), true))
if (errField.Summary != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Summary, "summary", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.Article_Summary), true))
{
errField.Summary = SacsHierarchyItem.ValidValue.Invalid;
return false;
}
// Common properties.
if (errField.Notes != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Notes, "notes", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Notes)))
if (errField.Notes != SacsHierarchyItem.ValidValue.Ignore && !IsValidValue(data.Notes, "notes", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.Article_Notes)))
{
errField.Notes = SacsHierarchyItem.ValidValue.Invalid;
return false;
}
if (errField.Status != SacsHierarchyItem.ValidValue.Ignore)
{
if (!IsValidValue(data.StatusCode, "status", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status), true, true))
if (!IsValidValue(data.StatusCode, "status", (long)SaxDbDfn_Core.GetColTextLen(SaxDbDfn_Core.ColumnIdx.Article_Status), true, true))
{
errField.Status = SacsHierarchyItem.ValidValue.Invalid;
return false;
}
if (!SaxJournalistArticle.ValidStatuses.Contains(data.Status))
if (!SaxArticle.ValidStatuses.Contains(data.Status))
{
errField.Status = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState(ErrorMessage.InvalidStatus);
@@ -117,17 +117,41 @@ namespace Saxonite.Net.Standard.Base.Mgr
if (!data.IsStatusDeleted)
{
// User Account - Journalist.
if (errField.UserAccountIdJournalist != SacsHierarchyItem.ValidValue.Ignore && SysId.IsValid(data.UserAccountIdJournalist))
// User Account - Author.
if (errField.UserAccountIdAuthor != SacsHierarchyItem.ValidValue.Ignore && SysId.IsValid(data.UserAccountIdAuthor))
{
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
prmUserAccount.IdsIncluded.Add(data.UserAccountIdJournalist);
prmUserAccount.ActiveRoles.Add(App.Sax.UserRole.Journalist);
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.NotDeleted;
if (AccountMgr.GetUserAccountCount(prmUserAccount) < 1)
if (SysId.IsValid(data.OrganisationId))
{
errField.UserAccountIdJournalist = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("User must be active Journalist");
// Validate user.
if (!AccountMgr.UserAccountExistsById(data.UserAccountIdAuthor))
{
errField.UserAccountIdAuthor = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("Invalid Author specified");
}
}
else
{
// Organisation not specified - user must be a journalist.
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
prmUserAccount.IdsIncluded.Add(data.UserAccountIdAuthor);
prmUserAccount.ActiveRoles.Add(App.Sax.UserRole.Journalist);
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.NotDeleted;
if (AccountMgr.GetUserAccountCount(prmUserAccount) < 1)
{
errField.UserAccountIdAuthor = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("User must be active Journalist");
}
}
}
// Organisation.
if (errField.OrganisationId != SacsHierarchyItem.ValidValue.Ignore && SysId.IsValid(data.OrganisationId))
{
// Validate organisation.
if (!AccountMgr.OrganisationExistsById(data.OrganisationId))
{
errField.OrganisationId = SacsHierarchyItem.ValidValue.Invalid;
return SetErrorState("Invalid Organisation specified");
}
}
@@ -163,48 +187,48 @@ namespace Saxonite.Net.Standard.Base.Mgr
}
//-------------------------------------------------------------------
// JournalistArticle database interface.
public abstract bool InsertJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo);
public abstract bool UpdateJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo);
public virtual bool JournalistArticleCanBeDeleted(SaxJournalistArticle journalistArticle)
// Article database interface.
public abstract bool InsertArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo);
public abstract bool UpdateArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo);
public virtual bool ArticleCanBeDeleted(SaxArticle article)
{
ClearErrorState();
return true;
}
public abstract bool DeleteJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo);
public abstract bool DeleteArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo);
//-------------------------------------------------------------------
// JournalistArticle list:
public abstract ColumnDfn GetJournalistArticleColumnDfn(SaxJournalistArticle.Column columnId, String caption = "", int width = 0);
public abstract List<String> GetJournalistArticleQueryFilter(SaxJournalistArticle.Params prmJournalistArticle);
public abstract long GetJournalistArticleCount(SaxJournalistArticle.Params prmJournalistArticle);
public abstract List<SaxJournalistArticle> GetJournalistArticleList(SaxJournalistArticle.Params prmJournalistArticle);
public abstract DbResultSet ExecuteJournalistArticleQuery(List<ColumnDfn> columns, SaxJournalistArticle.Params prmJournalistArticle);
// Article list:
public abstract ColumnDfn GetArticleColumnDfn(SaxArticle.Column columnId, String caption = "", int width = 0);
public abstract List<String> GetArticleQueryFilter(SaxArticle.Params prmArticle);
public abstract long GetArticleCount(SaxArticle.Params prmArticle);
public abstract List<SaxArticle> GetArticleList(SaxArticle.Params prmArticle);
public abstract DbResultSet ExecuteArticleQuery(List<ColumnDfn> columns, SaxArticle.Params prmArticle);
//-------------------------------------------------------------------
/// <summary>
/// Extract and format result set data value where specific handling is required.
/// <para>Where response is an invalid data value, format value using column.FormatValue(values).</para>
/// </summary>
public virtual DataValue GetJournalistArticleDataValue(ColumnDfn column, NamedValue.Map values)
public virtual DataValue GetArticleDataValue(ColumnDfn column, NamedValue.Map values)
{
DataValue value = new DataValue();
switch ((SaxJournalistArticle.Column)column.Id)
switch ((SaxArticle.Column)column.Id)
{
//-----------------------------------------------------------
// Journalist display name.
case SaxJournalistArticle.Column.Journalist_DisplayName:
// Author display name.
case SaxArticle.Column.Author_DisplayName:
{
String userTitle = values.GetValue(GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Journalist_Title).DataName).ToString();
String userFirstName = values.GetValue(GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Journalist_FirstName).DataName).ToString();
String userLastName = values.GetValue(GetJournalistArticleColumnDfn(SaxJournalistArticle.Column.Journalist_LastName).DataName).ToString();
String userTitle = values.GetValue(GetArticleColumnDfn(SaxArticle.Column.Author_Title).DataName).ToString();
String userFirstName = values.GetValue(GetArticleColumnDfn(SaxArticle.Column.Author_FirstName).DataName).ToString();
String userLastName = values.GetValue(GetArticleColumnDfn(SaxArticle.Column.Author_LastName).DataName).ToString();
value = new DataValue(SaxUserAccount.GetDisplayName(userTitle, userFirstName, userLastName));
}
break;
//-----------------------------------------------------------
// Summary - limit to 200 chars.
case SaxJournalistArticle.Column.Summary:
case SaxArticle.Column.Summary:
{
value = new DataValue(SacsHierarchyItem.FormatForDisplay(values.GetValue(column.DataName).ToString(), 200));
}
@@ -212,7 +236,7 @@ namespace Saxonite.Net.Standard.Base.Mgr
//-----------------------------------------------------------
// Notes - limit to 200 chars.
case SaxJournalistArticle.Column.Notes:
case SaxArticle.Column.Notes:
{
value = new DataValue(SacsHierarchyItem.FormatForDisplay(values.GetValue(column.DataName).ToString(), 200));
}
@@ -220,15 +244,15 @@ namespace Saxonite.Net.Standard.Base.Mgr
//-----------------------------------------------------------
// Status.
case SaxJournalistArticle.Column.Status_Desc:
case SaxJournalistArticle.Column.Status_Ind:
case SaxArticle.Column.Status_Desc:
case SaxArticle.Column.Status_Ind:
{
String statusCode = values.GetValue(column.DataName).ToString();
SaStatus status = SacsSystem.GetStatusForCode(statusCode);
if (column.Id == (int)SaxJournalistArticle.Column.Status_Desc)
if (column.Id == (int)SaxArticle.Column.Status_Desc)
value = new DataValue(SacsSystem.GetStatusDesc(status));
else if (column.Id == (int)SaxJournalistArticle.Column.Status_Ind)
value = new DataValue(SaxJournalistArticle.GetStatusTriState(status));
else if (column.Id == (int)SaxArticle.Column.Status_Ind)
value = new DataValue(SaxArticle.GetStatusTriState(status));
}
break;
@@ -16,6 +16,7 @@
<div class="sax-para">Follow <span style="font-weight:bold;"><a href="[#Link.RequestPassword]">this link</a></span> to set a password against your account.</div>
<div class="sax-para">Once that's been done you'll be able to sign-in and participate on the platform.</div>
<div class="sax-para">The link will expire in [#Link.ExpiresMinutes] minutes.</div>
<div class="sax-para">Alternatively, go the the <a href="[#Link.SignIn]">Sign-in</a> page and submit a 'Request Password' from there.</div>
<div class="sax-para">Thank you.</div>
</div>
</div>
@@ -8,7 +8,7 @@ using System.Text;
namespace Saxonite.Net.Standard.Dbas.Bus
{
//=======================================================================
public class SaxJournalistArticle_Dbas : SaxJournalistArticle
public class SaxArticle_Dbas : SaxArticle
{
//-------------------------------------------------------------------
// Data members.
@@ -16,8 +16,8 @@ namespace Saxonite.Net.Standard.Dbas.Bus
//-------------------------------------------------------------------
// Construction.
public SaxJournalistArticle_Dbas(ISacsDatabase database, SysId id, SysId userAccountIdJournalist, UInt16 flags) :
base(id, userAccountIdJournalist)
public SaxArticle_Dbas(ISacsDatabase database, SysId id, SysId userAccountIdAuthor, SysId organisationId, UInt16 flags) :
base(id, userAccountIdAuthor, organisationId)
{
this.database = database;
Flags = flags;
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,18 +9,19 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
internal class JournalistArticle_Db : SaxDbDataItem
internal class Article_Db : SaxDbDataItem
{
//-------------------------------------------------------------------
// Column definitions.
public class ColumnsData
{
public ColumnDataInt32 _Id { get; } = new ColumnDataInt32("Id", true);
public ColumnDataInt32 _UserAccountIdJournalist { get; } = new ColumnDataInt32("UserAccountIdJournalist");
public ColumnDataInt32 _UserAccountIdAuthor { get; } = new ColumnDataInt32("UserAccountIdAuthor");
public ColumnDataInt32 _OrganisationId { get; } = new ColumnDataInt32("OrganisationId");
public ColumnDataInt32 _SportIdPrimary { get; } = new ColumnDataInt32("SportIdPrimary");
public ColumnDataInt32 _RegionIdPrimary { get; } = new ColumnDataInt32("RegionIdPrimary");
public ColumnDataString _Headline { get; } = new ColumnDataString("Headline");
@@ -43,7 +44,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal
protected static List<String> fields { get; } = new List<String>()
{
"Id",
"UserAccountIdJournalist",
"UserAccountIdAuthor",
"OrganisationId",
"SportIdPrimary",
"RegionIdPrimary",
"Headline",
@@ -77,14 +79,14 @@ namespace Saxonite.Net.Standard.Dbas.Internal
//-------------------------------------------------------------------
// Construction.
internal JournalistArticle_Db (IDatabaseInfo dbInfo) : base(dbInfo)
internal Article_Db (IDatabaseInfo dbInfo) : base(dbInfo)
{
}
//-------------------------------------------------------------------
// Properties.
public override String SchemaName { get; } = "dbo";
public override String TableName { get; } = "JournalistArticle";
public override String TableName { get; } = "Article";
public String TableNameFmt { get { return (!String.IsNullOrEmpty(SchemaName) ? "[" + SchemaName + "]." : "") + "[" + TableName + "]"; } }
public static List<String> Fields { get { return new List<String>(fields); } }
public static List<String> FieldsId { get { return new List<String>(fieldsId); } }
@@ -92,7 +94,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal
// Columns.
public ColumnsData Cols { get; } = new ColumnsData();
public Int32 _Id { get { return Cols._Id.Value; } set { Cols._Id.Value = value; } }
public Int32 _UserAccountIdJournalist { get { return Cols._UserAccountIdJournalist.Value; } set { Cols._UserAccountIdJournalist.Value = value; } }
public Int32 _UserAccountIdAuthor { get { return Cols._UserAccountIdAuthor.Value; } set { Cols._UserAccountIdAuthor.Value = value; } }
public Int32 _OrganisationId { get { return Cols._OrganisationId.Value; } set { Cols._OrganisationId.Value = value; } }
public Int32 _SportIdPrimary { get { return Cols._SportIdPrimary.Value; } set { Cols._SportIdPrimary.Value = value; } }
public Int32 _RegionIdPrimary { get { return Cols._RegionIdPrimary.Value; } set { Cols._RegionIdPrimary.Value = value; } }
public String _Headline { get { return Cols._Headline.Value; } set { Cols._Headline.Value = value; } }
@@ -130,7 +133,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal
public override void PopulateFrom (DbDataReader dbDataReader)
{
_Id = GetFieldInt32(dbDataReader, "Id", _Id);
_UserAccountIdJournalist = GetFieldInt32(dbDataReader, "UserAccountIdJournalist", _UserAccountIdJournalist);
_UserAccountIdAuthor = GetFieldInt32(dbDataReader, "UserAccountIdAuthor", _UserAccountIdAuthor);
_OrganisationId = GetFieldInt32(dbDataReader, "OrganisationId", _OrganisationId);
_SportIdPrimary = GetFieldInt32(dbDataReader, "SportIdPrimary", _SportIdPrimary);
_RegionIdPrimary = GetFieldInt32(dbDataReader, "RegionIdPrimary", _RegionIdPrimary);
_Headline = GetFieldString(dbDataReader, "Headline", _Headline);
@@ -167,7 +171,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal
Log(GetType().Name + ".ExecuteInsertCommand", dbCommand.CommandText);
// Populate parameters.
dbCommand.Parameters.Clear();
if (columnNames.ContainsCI("UserAccountIdJournalist")) AddCommandParameter(dbCommand, "@UserAccountIdJournalist", _UserAccountIdJournalist);
if (columnNames.ContainsCI("UserAccountIdAuthor")) AddCommandParameter(dbCommand, "@UserAccountIdAuthor", _UserAccountIdAuthor);
if (columnNames.ContainsCI("OrganisationId")) AddCommandParameter(dbCommand, "@OrganisationId", _OrganisationId);
if (columnNames.ContainsCI("SportIdPrimary")) AddCommandParameter(dbCommand, "@SportIdPrimary", _SportIdPrimary);
if (columnNames.ContainsCI("RegionIdPrimary")) AddCommandParameter(dbCommand, "@RegionIdPrimary", _RegionIdPrimary);
if (columnNames.ContainsCI("Headline")) AddCommandParameter(dbCommand, "@Headline", _Headline);
@@ -219,7 +224,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal
Log(GetType().Name + ".ExecuteUpdateCommand", dbCommand.CommandText);
// Populate parameters.
dbCommand.Parameters.Clear();
if (columnNames.ContainsCI("UserAccountIdJournalist")) AddCommandParameter(dbCommand, "@UserAccountIdJournalist", _UserAccountIdJournalist);
if (columnNames.ContainsCI("UserAccountIdAuthor")) AddCommandParameter(dbCommand, "@UserAccountIdAuthor", _UserAccountIdAuthor);
if (columnNames.ContainsCI("OrganisationId")) AddCommandParameter(dbCommand, "@OrganisationId", _OrganisationId);
if (columnNames.ContainsCI("SportIdPrimary")) AddCommandParameter(dbCommand, "@SportIdPrimary", _SportIdPrimary);
if (columnNames.ContainsCI("RegionIdPrimary")) AddCommandParameter(dbCommand, "@RegionIdPrimary", _RegionIdPrimary);
if (columnNames.ContainsCI("Headline")) AddCommandParameter(dbCommand, "@Headline", _Headline);
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -9,7 +9,7 @@ using System.Data.Common;
using System.Linq;
//---------------------------------------------------------------------------
// Code generated by Sarand Database Utilities Wed 14-Jul-2021 14:06:01
// Code generated by Sarand Database Utilities Fri 6-Aug-2021 19:02:06
//---------------------------------------------------------------------------
namespace Saxonite.Net.Standard.Dbas.Internal
{
@@ -241,7 +241,7 @@ namespace Saxonite.Net.Standard.Dbas.Mgr
public static String aliasActivityIndex { get; } = "ActIdx";
public static String aliasActivityIndex_UserActivity { get; } = "ActIdx_UsrAct";
private static String prefixActivityIndex_UserActivity { get; } = aliasActivityIndex_UserActivity + "_";
public static String aliasActivityIndex_Article { get; } = "ActIdx_JrnArt";
public static String aliasActivityIndex_Article { get; } = "ActIdx_Art";
private static String prefixActivityIndex_Article { get; } = aliasActivityIndex_Article + "_";
public static String aliasActivityIndex_Opportunity { get; } = "ActIdx_OrgOpp";
private static String prefixActivityIndex_Opportunity { get; } = aliasActivityIndex_Opportunity + "_";
@@ -318,11 +318,11 @@ namespace Saxonite.Net.Standard.Dbas.Mgr
//-----------------------------------------------------------
// Article.
case SaxActivityIndex.Column.Article_Headline:
SetActivityIndexColDfn(columnDfn, "Headline", 160, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline, ColumnAlignment.Left, DataValue.DataType.String, aliasActivityIndex_Article, prefixActivityIndex_Article);
SetActivityIndexColDfn(columnDfn, "Headline", 160, SaxDbDfn_Core.ColumnIdx.Article_Headline, ColumnAlignment.Left, DataValue.DataType.String, aliasActivityIndex_Article, prefixActivityIndex_Article);
columnDfn.ReadOnly = true;
break;
case SaxActivityIndex.Column.Article_Summary:
SetActivityIndexColDfn(columnDfn, "Summary", 240, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary, ColumnAlignment.Left, DataValue.DataType.String, aliasActivityIndex_Article, prefixActivityIndex_Article);
SetActivityIndexColDfn(columnDfn, "Summary", 240, SaxDbDfn_Core.ColumnIdx.Article_Summary, ColumnAlignment.Left, DataValue.DataType.String, aliasActivityIndex_Article, prefixActivityIndex_Article);
columnDfn.ReadOnly = true;
break;
@@ -596,13 +596,13 @@ namespace Saxonite.Net.Standard.Dbas.Mgr
if (columns.HasId(SaxActivityIndex.Column.Article_Headline) || columns.HasId(SaxActivityIndex.Column.Article_Summary))
{
DbQueryJoin joinArticle = new DbQueryJoin(DbJoinType.LeftOuter);
joinArticle.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.JournalistArticle), aliasActivityIndex_Article);
joinArticle.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemType, aliasActivityIndex) + "=" + ((int)Sax.DataItemType.JournalistArticle).ToString());
joinArticle.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, aliasActivityIndex_Article) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemId, aliasActivityIndex));
joinArticle.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Article), aliasActivityIndex_Article);
joinArticle.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemType, aliasActivityIndex) + "=" + ((int)Sax.DataItemType.Article).ToString());
joinArticle.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Id, aliasActivityIndex_Article) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemId, aliasActivityIndex));
query.Joins.Add(joinArticle);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline);
cols.Add(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary);
cols.Add(SaxDbDfn_Core.ColumnIdx.Article_Headline);
cols.Add(SaxDbDfn_Core.ColumnIdx.Article_Summary);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasActivityIndex_Article), prefixActivityIndex_Article + SaxDbDfn_Core.GetColumnName(col, false));
}
@@ -0,0 +1,692 @@
using Sarand.Net.Standard.Dbas.Data;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Saxonite.Base.App;
using Saxonite.Net.Standard.Dbas.Bus;
using Saxonite.Net.Standard.Dbas.Internal;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Sarand.Net.Standard.Base.Utils;
using System.Linq;
namespace Saxonite.Net.Standard.Dbas.Mgr
{
//=======================================================================
partial class SaxActivityMgr_Dbas
{
//*******************************************************************
// Activity Mgr - Article
//*******************************************************************
// Utilities.
private List<StringPair> GetLogProperties(SaxArticle article)
{
return new List<StringPair>()
{
new StringPair("Id", SysId.ToString(article.Id)),
new StringPair("UserAccountIdAuthor", SysId.ToString(article.UserAccountIdAuthor)),
new StringPair("OrganisationId", SysId.ToString(article.OrganisationId)),
new StringPair("Headline", StringUtil.Left(article.Headline,32)),
new StringPair("Status", article.StatusCode)
};
}
//-------------------------------------------------------------------
// Create item.
public override SaxArticle CreateArticle(SysId userAccountIdAuthor, SysId organisationId)
{
ClearErrorState();
return new SaxArticle_Dbas(CoreDatabase, null, userAccountIdAuthor, organisationId, 0);
}
private SaxArticle_Dbas CreateArticle(Article_Db dbArticle)
{
ClearErrorState();
SaxArticle_Dbas article = new SaxArticle_Dbas(CoreDatabase, new SysId(dbArticle._Id), new SysId(dbArticle._UserAccountIdAuthor), new SysId(dbArticle._OrganisationId), (UInt16)dbArticle._Flags);
PopulateFrom(dbArticle, article);
return article;
}
//-------------------------------------------------------------------
// Get item.
public override SaxArticle GetArticle(SaxArticle.Params prm)
{
ClearErrorState();
return GetArticle(GetArticleQueryFilter(prm).Concat(" And ", "(", ")"));
}
private SaxArticle GetArticle(String filter)
{
ClearErrorState();
long count = GetArticleCount(filter);
if (count == 0) return null;
if (count != 1)
{
SetErrorState("Multiple items found");
return null;
}
SaxArticle article = null;
// Query data.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
Article_Db dbArticle = new Article_Db(CoreDbInfo);
dbArticle.PopulateFrom(dbCommand, aliasArticle, filter);
article = CreateArticle(dbArticle);
}
catch (Exception exc)
{
SetErrorState("Database query exception");
SaLogger.Warn(GetType().Name + ".GetArticle\n\tQuery: " + dbCommand.CommandText + "\n\t" + ExceptionUtil.GetLogMessage(exc));
}
}
return article;
}
//-------------------------------------------------------------------
// Validate item.
public override bool IsValidArticleData(SaxArticle.Data data, SaxArticle.ErrField errField)
{
ClearErrorState();
if (!base.IsValidArticleData(data, errField)) return false;
return true;
}
//-------------------------------------------------------------------
// Insert item.
public override bool InsertArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".InsertArticle";
ClearErrorState();
if (!IsValidArticle(article)) return false;
if (SysId.IsValid(article.Id)) return SetErrorState(ErrorMessage.ValiditemId);
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
Article_Db dbArticle = new Article_Db(CoreDbInfo);
PopulateTo(dbArticle, article, dbUpdateInfo);
if (Article_Db.FieldsNonId.Contains("Id"))
{
// Generate next Id.
// ToDo dbArticle._Id = CoreDatabase.GetNextIdFromTable("Article");
}
dbArticle.ExecuteInsertCommand(dbCommand);
article.Id = new SysId(dbArticle._Id);
article.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Inserted. " + GetLogProperties(article).Concat(": ").Concat("", "\n\t"));
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
}
//-------------------------------------------------------------------
// Update item.
public override bool UpdateArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".UpdateArticle";
ClearErrorState();
if (!IsValidArticle(article)) return false;
if (!SysId.IsValid(article.Id)) return SetErrorState(ErrorMessage.InvalidItemId);
if (!article.Changed)
{
if (DebugMode) SaLogger.Debug(fn + " Data not changed. " + GetLogProperties(article).Concat(": ").Concat("", "\n\t"));
return true;
}
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
// Retrieve item.
dbConnection.Open();
Article_Db dbArticle = new Article_Db(CoreDbInfo);
dbArticle.PopulateFrom(dbCommand, aliasArticle, "Id=" + SysId.ToString(article.Id));
// ToDo SaxUpdateLogItemMonitor_Article updateLogMonitor = new SaxUpdateLogItemMonitor_Article(SessionContext, CreateArticle(dbArticle), dbUpdateInfo);
// Update item.
PopulateTo(dbArticle, article, dbUpdateInfo);
dbArticle.ExecuteUpdateCommand(dbCommand);
article.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Updated. " + GetLogProperties(article).Concat(": ").Concat("", "\n\t"));
// Record updates.
// ToDo updateLogMonitor.RecordUpdatedValues(article);
// ToDo updateLogMonitor.LogUpdates();
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
}
//-------------------------------------------------------------------
// Delete item.
public override bool ArticleCanBeDeleted(SaxArticle article)
{
ClearErrorState();
if (!base.ArticleCanBeDeleted(article)) return false;
return true;
}
public override bool DeleteArticle(SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".DeleteArticle";
ClearErrorState();
if (!ArticleCanBeDeleted(article)) return false;
// Articles are logically deleted by changing the status.
article.Status = SaStatus.Deleted;
return UpdateArticle(article, dbUpdateInfo);
/*
* Physical deletion.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
// Retrieve item.
dbConnection.Open();
Article_Db dbArticle = new Article_Db(CoreDbInfo);
dbArticle.PopulateFrom(dbCommand, aliasArticle, "Id=" + article.Id.ToString());
// Delete item.
dbCommand.CommandType = System.Data.CommandType.Text;
dbCommand.CommandText = "DELETE FROM " + SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Article) + " WHERE Id=" + SysId.ToString(article.Id) + ";";
dbCommand.ExecuteNonQuery();
article.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Deleted. " + GetLogProperties(article).Concat(": ").Concat("", "\n\t"));
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
*/
}
//-------------------------------------------------------------------
// Copy data properties to and from database.
private void PopulateTo(Article_Db dbArticle, SaxArticle article, DbUpdateInfo dbUpdateInfo)
{
dbArticle._Id = SysId.ToInt(article.Id);
dbArticle._UserAccountIdAuthor = SysId.ToInt(article.UserAccountIdAuthor);
dbArticle._OrganisationId = SysId.ToInt(article.OrganisationId);
dbArticle._SportIdPrimary = SysId.ToInt(article.SportIdPrimary);
dbArticle._RegionIdPrimary = SysId.ToInt(article.RegionIdPrimary);
dbArticle._Headline = article.Headline;
dbArticle._Summary = article.Summary;
dbArticle._BodyData = article.BodyData;
dbArticle._PublishedAt = article.PublishedAt;
dbArticle._Notes = article.Notes;
dbArticle._Status = SacsSystem.GetStatusCode(article.Status);
dbArticle._Flags = (short)article.Flags;
if (!SysId.IsValid(article.Id))
{
dbArticle._CreateOn = DateTime.Now;
dbArticle._CreateBy = dbUpdateInfo.UserId.ToInt();
dbArticle._CreateHost = dbUpdateInfo.Host;
}
dbArticle._UpdateOn = DateTime.Now;
dbArticle._UpdateBy = dbUpdateInfo.UserId.ToInt();
dbArticle._UpdateHost = dbUpdateInfo.Host;
}
private void PopulateFrom(Article_Db dbArticle, SaxArticle article)
{
//article.Id = new SysId(dbArticle._Id);
//article.UserAccountIdAuthor = new SysId(dbArticle._UserAccountIdAuthor);
//article.OrganisationId = new SysId(dbArticle._OrganisationId);
article.SportIdPrimary = new SysId(dbArticle._SportIdPrimary);
article.RegionIdPrimary = new SysId(dbArticle._RegionIdPrimary);
article.Headline = dbArticle._Headline;
article.Summary = dbArticle._Summary;
article.BodyData = dbArticle._BodyData;
article.PublishedAt = dbArticle._PublishedAt;
article.Notes = dbArticle._Notes;
article.Status = SacsSystem.GetStatusForCode(dbArticle._Status);
article.SetCreateStamp(dbArticle._CreateOn, new SysId(dbArticle._CreateBy), dbArticle._CreateHost);
article.SetUpdateStamp(dbArticle._UpdateOn, new SysId(dbArticle._UpdateBy), dbArticle._UpdateHost);
article.AcceptChanges();
}
//-------------------------------------------------------------------
// Item column definitions.
private static readonly String aliasArticle = "Art";
private static readonly String aliasArticle_Author = "Art_Auth";
private static readonly String prefixArticle_Author = "Art_Jrn_";
private static readonly String aliasArticle_Organisation = "Art_Org";
private static readonly String prefixArticle_Organisation = "Art_Org_";
private static readonly String aliasArticle_Sport = "Art_Spt";
private static readonly String prefixArticle_Sport = "Art_Spt_";
private static readonly String aliasArticle_Region = "Art_Rgn";
private static readonly String prefixArticle_Region = "Art_Rgn_";
private void SetArticleColDfn
(ColumnDfn col, String caption, int width, SaxDbDfn_Core.ColumnIdx dbCol,
ColumnAlignment align = ColumnAlignment.Default, DataValue.DataType dataType = DataValue.DataType.String,
String alias = "", String prefix = "")
{
if (String.IsNullOrEmpty(alias) && SaxDbDfn_Core.GetTableForColumn(dbCol) == SaxDbDfn_Core.TableIdx.Article)
alias = aliasArticle;
col.Set(caption, width, (int)dbCol, prefix + SaxDbDfn_Core.GetColumnName(dbCol, false), SaxDbDfn_Core.GetColumnNameQual(dbCol, alias), dataType, align);
if (dataType == DataValue.DataType.String && dbCol != SaxDbDfn_Core.ColumnIdx.Unknown)
col.MaxLength = (int)SaxDbDfn_Core.GetColTextLen(dbCol);
}
public override ColumnDfn GetArticleColumnDfn(SaxArticle.Column columnId, string caption = "", int width = 0)
{
ColumnDfn columnDfn = new ColumnDfn((int)columnId, caption, width);
switch (columnId)
{
//-----------------------------------------------------------
case SaxArticle.Column.Pos:
SetArticleColDfn(columnDfn, "Pos", 60, SaxDbDfn_Core.ColumnIdx.Unknown, ColumnAlignment.Right);
columnDfn.SortMode = ColumnDfn.ColumnSortMode.Off;
columnDfn.ReadOnly = true;
columnDfn.Resizable = false;
break;
case SaxArticle.Column.Id:
SetArticleColDfn(columnDfn, "Id", 80, SaxDbDfn_Core.ColumnIdx.Article_Id, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Organisation.
case SaxArticle.Column.OrganisationId:
SetArticleColDfn(columnDfn, "Organisation Id", 80, SaxDbDfn_Core.ColumnIdx.Article_OrganisationId, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Organisation_Name:
SetArticleColDfn(columnDfn, "Organisation", 120, SaxDbDfn_Core.ColumnIdx.Organisation_Name, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Organisation, prefixArticle_Organisation);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Author.
case SaxArticle.Column.UserAccountIdAuthor:
SetArticleColDfn(columnDfn, "Author Id", 80, SaxDbDfn_Core.ColumnIdx.Article_UserAccountIdAuthor, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Author_DisplayName:
SetArticleColDfn(columnDfn, "Author", 120, SaxDbDfn_Core.ColumnIdx.Unknown);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Author_Title:
SetArticleColDfn(columnDfn, "Author title", 80, SaxDbDfn_Core.ColumnIdx.UserAccount_Title, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Author, prefixArticle_Author);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Author_FirstName:
SetArticleColDfn(columnDfn, "Author first name", 100, SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Author, prefixArticle_Author);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Author_LastName:
SetArticleColDfn(columnDfn, "Author last name", 100, SaxDbDfn_Core.ColumnIdx.UserAccount_LastName, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Author, prefixArticle_Author);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Sport.
case SaxArticle.Column.SportIdPrimary:
SetArticleColDfn(columnDfn, "Sport Id", 80, SaxDbDfn_Core.ColumnIdx.Article_SportIdPrimary, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Sport_Name:
SetArticleColDfn(columnDfn, "Sport", 100, SaxDbDfn_Core.ColumnIdx.Sport_Name, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Sport, prefixArticle_Sport);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Region.
case SaxArticle.Column.RegionIdPrimary:
SetArticleColDfn(columnDfn, "Region Id", 80, SaxDbDfn_Core.ColumnIdx.Article_RegionIdPrimary, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.Region_Name:
SetArticleColDfn(columnDfn, "Region", 100, SaxDbDfn_Core.ColumnIdx.Region_Name, ColumnAlignment.Left, DataValue.DataType.String, aliasArticle_Region, prefixArticle_Region);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Article.
case SaxArticle.Column.Headline:
SetArticleColDfn(columnDfn, "Headline", 200, SaxDbDfn_Core.ColumnIdx.Article_Headline);
break;
case SaxArticle.Column.Summary:
SetArticleColDfn(columnDfn, "Summary", 200, SaxDbDfn_Core.ColumnIdx.Article_Summary);
break;
case SaxArticle.Column.PublishedAt_Date:
SetArticleColDfn(columnDfn, "Published", 80, SaxDbDfn_Core.ColumnIdx.Article_PublishedAt, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.PublishedAt_DateTime:
SetArticleColDfn(columnDfn, "Published", 100, SaxDbDfn_Core.ColumnIdx.Article_PublishedAt, ColumnAlignment.Center, DataValue.DataType.DateTime);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Derived properties.
//-----------------------------------------------------------
// Common properties.
case SaxArticle.Column.Notes:
SetArticleColDfn(columnDfn, "Notes", 240, SaxDbDfn_Core.ColumnIdx.Article_Notes);
break;
case SaxArticle.Column.Flags:
SetArticleColDfn(columnDfn, "Flags", 60, SaxDbDfn_Core.ColumnIdx.Article_Flags, ColumnAlignment.Center, DataValue.DataType.Long);
break;
case SaxArticle.Column.Status:
SetArticleColDfn(columnDfn, "Status", 80, SaxDbDfn_Core.ColumnIdx.Article_Status, ColumnAlignment.Center);
break;
case SaxArticle.Column.Status_Desc:
SetArticleColDfn(columnDfn, "Status", 90, SaxDbDfn_Core.ColumnIdx.Article_Status, ColumnAlignment.Center);
break;
case SaxArticle.Column.Status_Ind:
SetArticleColDfn(columnDfn, "Status", 80, SaxDbDfn_Core.ColumnIdx.Article_Status, ColumnAlignment.Center, DataValue.DataType.TriState);
columnDfn.TriStateFormat = ColumnTriStateFormat.Lights;
break;
case SaxArticle.Column.CreateOn_Date:
SetArticleColDfn(columnDfn, "Created", 80, SaxDbDfn_Core.ColumnIdx.Article_CreateOn, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
case SaxArticle.Column.UpdateOn_Date:
SetArticleColDfn(columnDfn, "Updated", 80, SaxDbDfn_Core.ColumnIdx.Article_UpdateOn, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
}
if (!String.IsNullOrEmpty(caption))
columnDfn.Caption = caption;
if (width > 0)
columnDfn.Width = width;
return columnDfn;
}
//-------------------------------------------------------------------
// Item query filter.
public override List<string> GetArticleQueryFilter(SaxArticle.Params prm)
{
List<String> filter = new List<String>();
// Item Ids.
String idsIncluded = prm.IdsIncluded.Concat(",");
if (!idsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Id, aliasArticle) + " IN (" + idsIncluded + ")");
String idsExcluded = prm.IdsExcluded.Concat(",");
if (!idsExcluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Id, aliasArticle) + " NOT IN (" + idsExcluded + ")");
// Author User Account.
String userAccountIdsIncluded = prm.UserAccountIdsAuthorIncluded.Concat(",");
if (!userAccountIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_UserAccountIdAuthor, aliasArticle) + " IN (" + userAccountIdsIncluded + ")");
// Organisations.
String organisationIdsIncluded = prm.OrganisationIdsIncluded.Concat(",");
if (!organisationIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_OrganisationId, aliasArticle) + " IN (" + organisationIdsIncluded + ")");
// Sport Ids.
String sportIdsIncluded = prm.SportIdsIncluded.Concat(",");
if (!sportIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_SportIdPrimary, aliasArticle) + " IN (" + sportIdsIncluded + ")");
// Region Ids.
String regionIdsIncluded = prm.RegionIdsIncluded.Concat(",");
if (!regionIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_RegionIdPrimary, aliasArticle) + " IN (" + regionIdsIncluded + ")");
// Headline.
if (!StringUtil.IsEmpty(prm.HeadlinePartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Headline, aliasArticle) + " Like '%" + DbQuery.FormatForLike(prm.HeadlinePartial, true) + "%'");
// Summary.
if (!StringUtil.IsEmpty(prm.SummaryPartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Summary, aliasArticle) + " Like '%" + DbQuery.FormatForLike(prm.SummaryPartial, true) + "%'");
// Article.
if (!StringUtil.IsEmpty(prm.ArticleFilter))
{
// Split filter into words.
List<String> filterWords = prm.ArticleFilter.Split((char[])null).ToList();
filterWords.RemoveDuplicatesCI();
filterWords.RemoveBlanks();
foreach (String filterWord in filterWords)
{
List<String> articleFilter = new List<String>();
articleFilter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Headline, aliasArticle) + " Like '%" + DbQuery.FormatForLike(filterWord, true) + "%'");
articleFilter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Summary, aliasArticle) + " Like '%" + DbQuery.FormatForLike(filterWord, true) + "%'");
filter.Add(articleFilter.Concat(" OR ", "(", ")"));
}
}
// Notes.
if (!StringUtil.IsEmpty(prm.NotesPartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Notes, aliasArticle) + " LIKE '%" + DbQuery.FormatForLike(prm.NotesPartial) + "%'");
// Status.
if (prm.StatusCat != SaxArticle.StatusCat.Any)
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Status, aliasArticle) + GetArticleStatusCatFilterCondition(prm.StatusCat));
if (filter.Count < 1) filter.Add("1=1");
return filter;
}
internal static String GetArticleStatusCatFilterCondition(SaxArticle.StatusCat statusCat)
{
if (statusCat == SaxArticle.StatusCat.ActiveOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Active) + "'";
if (statusCat == SaxArticle.StatusCat.InactiveOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Inactive) + "'";
if (statusCat == SaxArticle.StatusCat.NotDeleted)
return "!='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'";
if (statusCat == SaxArticle.StatusCat.DeletedOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'";
return "";
}
// Item sort columns.
public List<String> GetArticleSortColumns(SaxArticle.Params prm)
{
// Sort sequence:
List<String> sortColumnNames = new List<String>();
foreach (var columnDfn in prm.SortColumns)
{
// Need to ensure correct alias used for Article columns in case of conflict.
String sortCol = String.Empty;
if (SaxDbDfn_Core.GetTableForColumn((SaxDbDfn_Core.ColumnIdx)columnDfn.DbColumn) == SaxDbDfn_Core.TableIdx.Article)
{
sortCol = SaxDbDfn_Core.GetColumnNameQual((SaxDbDfn_Core.ColumnIdx)columnDfn.DbColumn, aliasArticle);
}
else
{
sortCol = columnDfn.DataName;
if (!StringUtil.IsEmpty(columnDfn.SortDataName))
sortCol = columnDfn.SortDataName;
}
if (!sortCol.IsEmpty())
{
DbOrderByNullMode orderByNullMode = DbOrderByNullMode.Default; // eSaOrderByDemoteNulls, eSaOrderByPromoteNulls
sortColumnNames.Add(DbQuery.FormatForOrderBy(sortCol, columnDfn.SortAscending, orderByNullMode).Concat(", "));
}
}
sortColumnNames.RemoveBlanks();
if (sortColumnNames.IsEmpty())
{
// Default sort columns.
sortColumnNames.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Id, aliasArticle) + " ASC");
}
return sortColumnNames;
}
//-------------------------------------------------------------------
// Item count.
private long GetArticleCount(String filter)
{
ClearErrorState();
return CoreDatabase.GetRowCount(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Article) + " As " + aliasArticle, filter);
}
public override long GetArticleCount(SaxArticle.Params prm)
{
ClearErrorState();
return GetArticleCount(GetArticleQueryFilter(prm).Concat(" AND ", "(", ")"));
}
//-------------------------------------------------------------------
// Item list.
public override List<SaxArticle> GetArticleList(SaxArticle.Params prm)
{
List<SaxArticle> userActivitys = new List<SaxArticle>();
DbQuery qry = new DbQuery(CoreDatabase.DbmsType);
qry.Tables.Add(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Article), aliasArticle);
Article_Db dbArticle = new Article_Db(CoreDbInfo);
qry.Columns.AddRange(dbArticle.ExistingColumnNames);
qry.Filters.AddRange(GetArticleQueryFilter(prm));
qry.OrderBy.AddRange(GetArticleSortColumns(prm));
// Query data.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
dbCommand.CommandText = qry.BuildQuery(prm.ResultsPaging);
using (DbDataReader dbDataReader = dbCommand.ExecuteReader())
{
while (dbDataReader.Read())
{
dbArticle = new Article_Db(CoreDbInfo);
dbArticle.PopulateFrom(dbDataReader);
userActivitys.Add(CreateArticle(dbArticle));
}
}
}
catch (Exception exc)
{
SaLogger.Warn(GetType().Name + ".GetArticleList\n\tQuery: " + dbCommand.CommandText + "\n\t" + ExceptionUtil.GetLogMessage(exc));
}
}
return userActivitys;
}
//-------------------------------------------------------------------
// Item query execution.
public override DbResultSet ExecuteArticleQuery(List<ColumnDfn> columns, SaxArticle.Params prm)
{
ClearErrorState();
//---------------------------------------------------------------------
// Construct query.
DbQuery query = new DbQuery(CoreDatabase.DbmsType);
query.Tables.Add(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Article), aliasArticle);
// Add columns as defined in query list.
if (columns.HasId(SaxArticle.Column.Id))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Id, aliasArticle));
bool hasUserAccountCols = (columns.HasId(SaxArticle.Column.Author_DisplayName) || columns.HasId(SaxArticle.Column.Author_Title) || columns.HasId(SaxArticle.Column.Author_FirstName) || columns.HasId(SaxArticle.Column.Author_LastName));
if (columns.HasId(SaxArticle.Column.UserAccountIdAuthor) || hasUserAccountCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_UserAccountIdAuthor, aliasArticle));
bool hasOrganisationCols = (columns.HasId(SaxArticle.Column.Organisation_Name));
if (columns.HasId(SaxArticle.Column.OrganisationId) || hasOrganisationCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_OrganisationId, aliasArticle));
bool hasSportCols = (columns.HasId(SaxArticle.Column.Sport_Name));
if (columns.HasId(SaxArticle.Column.SportIdPrimary) || hasSportCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_SportIdPrimary, aliasArticle));
bool hasRegionCols = (columns.HasId(SaxArticle.Column.Region_Name));
if (columns.HasId(SaxArticle.Column.RegionIdPrimary) || hasRegionCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_RegionIdPrimary, aliasArticle));
if (columns.HasId(SaxArticle.Column.Headline))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Headline, aliasArticle));
if (columns.HasId(SaxArticle.Column.Summary))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Summary, aliasArticle));
if (columns.HasId(SaxArticle.Column.PublishedAt_Date) || columns.HasId(SaxArticle.Column.PublishedAt_DateTime))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_PublishedAt, aliasArticle));
// Common properties.
if (columns.HasId(SaxArticle.Column.Notes))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Notes, aliasArticle));
if (columns.HasId(SaxArticle.Column.Flags))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Flags, aliasArticle));
if (columns.HasId(SaxArticle.Column.Status) || columns.HasId(SaxArticle.Column.Status_Desc) || columns.HasId(SaxArticle.Column.Status_Ind))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_Status, aliasArticle));
if (columns.HasId(SaxArticle.Column.CreateOn_Date))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_CreateOn, aliasArticle));
if (columns.HasId(SaxArticle.Column.UpdateOn_Date))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_UpdateOn, aliasArticle));
//---------------------------------------------------------------------
// User Account.
if (hasUserAccountCols)
{
DbQueryJoin joinUserAccount = new DbQueryJoin(DbJoinType.LeftOuter);
joinUserAccount.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.UserAccount), aliasArticle_Author);
joinUserAccount.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.UserAccount_Id, aliasArticle_Author) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_UserAccountIdAuthor, aliasArticle));
query.Joins.Add(joinUserAccount);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_Title);
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName);
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasArticle_Author), prefixArticle_Author + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Organisation.
if (hasOrganisationCols)
{
DbQueryJoin joinOrganisation = new DbQueryJoin(DbJoinType.LeftOuter);
joinOrganisation.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Organisation), aliasArticle_Organisation);
joinOrganisation.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Organisation_Id, aliasArticle_Organisation) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_OrganisationId, aliasArticle));
query.Joins.Add(joinOrganisation);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.Organisation_Name);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasArticle_Organisation), prefixArticle_Organisation + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Primary Sport.
if (hasSportCols)
{
DbQueryJoin joinSport = new DbQueryJoin(DbJoinType.LeftOuter);
joinSport.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Sport), aliasArticle_Sport);
joinSport.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Sport_Id, aliasArticle_Sport) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_SportIdPrimary, aliasArticle));
query.Joins.Add(joinSport);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.Sport_Name);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasArticle_Sport), prefixArticle_Sport + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Primary Region.
if (hasRegionCols)
{
DbQueryJoin joinRegion = new DbQueryJoin(DbJoinType.LeftOuter);
joinRegion.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Region), aliasArticle_Region);
joinRegion.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Region_Id, aliasArticle_Region) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Article_RegionIdPrimary, aliasArticle));
query.Joins.Add(joinRegion);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.Region_Name);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasArticle_Region), prefixArticle_Region + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Populate filter.
query.Filters.AddRange(GetArticleQueryFilter(prm));
if (prm.IdsIncluded.Count != 1)
{
// Configure sort sequence.
foreach (String sortColumn in GetArticleSortColumns(prm))
query.OrderBy.Add(sortColumn);
}
//---------------------------------------------------------------------
//return new DbResultSet_DataTableReader(db, query.BuildQuery(prm.ResultsPaging));
return DbResultSet_DataReader.ExecuteQuery(CoreDatabase, query.BuildQuery(prm.ResultsPaging));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -1,654 +0,0 @@
using Sarand.Net.Standard.Dbas.Data;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Saxonite.Base.App;
using Saxonite.Net.Standard.Dbas.Bus;
using Saxonite.Net.Standard.Dbas.Internal;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Sarand.Net.Standard.Base.Utils;
using System.Linq;
namespace Saxonite.Net.Standard.Dbas.Mgr
{
//=======================================================================
partial class SaxActivityMgr_Dbas
{
//*******************************************************************
// Activity Mgr - JournalistArticle
//*******************************************************************
// Utilities.
private List<StringPair> GetLogProperties(SaxJournalistArticle journalistArticle)
{
return new List<StringPair>()
{
new StringPair("Id", SysId.ToString(journalistArticle.Id)),
new StringPair("UserAccountIdJournalist", SysId.ToString(journalistArticle.UserAccountIdJournalist)),
new StringPair("Headline", StringUtil.Left(journalistArticle.Headline,32)),
new StringPair("Status", journalistArticle.StatusCode)
};
}
//-------------------------------------------------------------------
// Create item.
public override SaxJournalistArticle CreateJournalistArticle(SysId userAccountIdJournalist)
{
ClearErrorState();
return new SaxJournalistArticle_Dbas(CoreDatabase, null, userAccountIdJournalist, 0);
}
private SaxJournalistArticle_Dbas CreateJournalistArticle(JournalistArticle_Db dbJournalistArticle)
{
ClearErrorState();
SaxJournalistArticle_Dbas journalistArticle = new SaxJournalistArticle_Dbas(CoreDatabase, new SysId(dbJournalistArticle._Id), new SysId(dbJournalistArticle._UserAccountIdJournalist), (UInt16)dbJournalistArticle._Flags);
PopulateFrom(dbJournalistArticle, journalistArticle);
return journalistArticle;
}
//-------------------------------------------------------------------
// Get item.
public override SaxJournalistArticle GetJournalistArticle(SaxJournalistArticle.Params prm)
{
ClearErrorState();
return GetJournalistArticle(GetJournalistArticleQueryFilter(prm).Concat(" And ", "(", ")"));
}
private SaxJournalistArticle GetJournalistArticle(String filter)
{
ClearErrorState();
long count = GetJournalistArticleCount(filter);
if (count == 0) return null;
if (count != 1)
{
SetErrorState("Multiple items found");
return null;
}
SaxJournalistArticle journalistArticle = null;
// Query data.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
JournalistArticle_Db dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
dbJournalistArticle.PopulateFrom(dbCommand, aliasJournalistArticle, filter);
journalistArticle = CreateJournalistArticle(dbJournalistArticle);
}
catch (Exception exc)
{
SetErrorState("Database query exception");
SaLogger.Warn(GetType().Name + ".GetJournalistArticle\n\tQuery: " + dbCommand.CommandText + "\n\t" + ExceptionUtil.GetLogMessage(exc));
}
}
return journalistArticle;
}
//-------------------------------------------------------------------
// Validate item.
public override bool IsValidJournalistArticleData(SaxJournalistArticle.Data data, SaxJournalistArticle.ErrField errField)
{
ClearErrorState();
if (!base.IsValidJournalistArticleData(data, errField)) return false;
return true;
}
//-------------------------------------------------------------------
// Insert item.
public override bool InsertJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".InsertJournalistArticle";
ClearErrorState();
if (!IsValidJournalistArticle(journalistArticle)) return false;
if (SysId.IsValid(journalistArticle.Id)) return SetErrorState(ErrorMessage.ValiditemId);
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
JournalistArticle_Db dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
PopulateTo(dbJournalistArticle, journalistArticle, dbUpdateInfo);
if (JournalistArticle_Db.FieldsNonId.Contains("Id"))
{
// Generate next Id.
// ToDo dbJournalistArticle._Id = CoreDatabase.GetNextIdFromTable("JournalistArticle");
}
dbJournalistArticle.ExecuteInsertCommand(dbCommand);
journalistArticle.Id = new SysId(dbJournalistArticle._Id);
journalistArticle.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Inserted. " + GetLogProperties(journalistArticle).Concat(": ").Concat("", "\n\t"));
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
}
//-------------------------------------------------------------------
// Update item.
public override bool UpdateJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".UpdateJournalistArticle";
ClearErrorState();
if (!IsValidJournalistArticle(journalistArticle)) return false;
if (!SysId.IsValid(journalistArticle.Id)) return SetErrorState(ErrorMessage.InvalidItemId);
if (!journalistArticle.Changed)
{
if (DebugMode) SaLogger.Debug(fn + " Data not changed. " + GetLogProperties(journalistArticle).Concat(": ").Concat("", "\n\t"));
return true;
}
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
// Retrieve item.
dbConnection.Open();
JournalistArticle_Db dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
dbJournalistArticle.PopulateFrom(dbCommand, aliasJournalistArticle, "Id=" + SysId.ToString(journalistArticle.Id));
// ToDo SaxUpdateLogItemMonitor_JournalistArticle updateLogMonitor = new SaxUpdateLogItemMonitor_JournalistArticle(SessionContext, CreateJournalistArticle(dbJournalistArticle), dbUpdateInfo);
// Update item.
PopulateTo(dbJournalistArticle, journalistArticle, dbUpdateInfo);
dbJournalistArticle.ExecuteUpdateCommand(dbCommand);
journalistArticle.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Updated. " + GetLogProperties(journalistArticle).Concat(": ").Concat("", "\n\t"));
// Record updates.
// ToDo updateLogMonitor.RecordUpdatedValues(journalistArticle);
// ToDo updateLogMonitor.LogUpdates();
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
}
//-------------------------------------------------------------------
// Delete item.
public override bool JournalistArticleCanBeDeleted(SaxJournalistArticle journalistArticle)
{
ClearErrorState();
if (!base.JournalistArticleCanBeDeleted(journalistArticle)) return false;
return true;
}
public override bool DeleteJournalistArticle(SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo)
{
String fn = GetType().Name + ".DeleteJournalistArticle";
ClearErrorState();
if (!JournalistArticleCanBeDeleted(journalistArticle)) return false;
// Journalist Articles are logically deleted by changing the status.
journalistArticle.Status = SaStatus.Deleted;
return UpdateJournalistArticle(journalistArticle, dbUpdateInfo);
/*
* Physical deletion.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
// Retrieve item.
dbConnection.Open();
JournalistArticle_Db dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
dbJournalistArticle.PopulateFrom(dbCommand, aliasJournalistArticle, "Id=" + journalistArticle.Id.ToString());
// Delete item.
dbCommand.CommandType = System.Data.CommandType.Text;
dbCommand.CommandText = "DELETE FROM " + SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.JournalistArticle) + " WHERE Id=" + SysId.ToString(journalistArticle.Id) + ";";
dbCommand.ExecuteNonQuery();
journalistArticle.Changed = false;
if (DebugMode) SaLogger.Debug(fn + " Deleted. " + GetLogProperties(journalistArticle).Concat(": ").Concat("", "\n\t"));
}
catch (Exception exc) { SetErrorState(exc.Message); }
}
return !HasErrorState();
*/
}
//-------------------------------------------------------------------
// Copy data properties to and from database.
private void PopulateTo(JournalistArticle_Db dbJournalistArticle, SaxJournalistArticle journalistArticle, DbUpdateInfo dbUpdateInfo)
{
dbJournalistArticle._Id = SysId.ToInt(journalistArticle.Id);
dbJournalistArticle._UserAccountIdJournalist = SysId.ToInt(journalistArticle.UserAccountIdJournalist);
dbJournalistArticle._SportIdPrimary = SysId.ToInt(journalistArticle.SportIdPrimary);
dbJournalistArticle._RegionIdPrimary = SysId.ToInt(journalistArticle.RegionIdPrimary);
dbJournalistArticle._Headline = journalistArticle.Headline;
dbJournalistArticle._Summary = journalistArticle.Summary;
dbJournalistArticle._BodyData = journalistArticle.BodyData;
dbJournalistArticle._PublishedAt = journalistArticle.PublishedAt;
dbJournalistArticle._Notes = journalistArticle.Notes;
dbJournalistArticle._Status = SacsSystem.GetStatusCode(journalistArticle.Status);
dbJournalistArticle._Flags = (short)journalistArticle.Flags;
if (!SysId.IsValid(journalistArticle.Id))
{
dbJournalistArticle._CreateOn = DateTime.Now;
dbJournalistArticle._CreateBy = dbUpdateInfo.UserId.ToInt();
dbJournalistArticle._CreateHost = dbUpdateInfo.Host;
}
dbJournalistArticle._UpdateOn = DateTime.Now;
dbJournalistArticle._UpdateBy = dbUpdateInfo.UserId.ToInt();
dbJournalistArticle._UpdateHost = dbUpdateInfo.Host;
}
private void PopulateFrom(JournalistArticle_Db dbJournalistArticle, SaxJournalistArticle journalistArticle)
{
//journalistArticle.Id = new SysId(dbJournalistArticle._Id);
//journalistArticle.UserAccountIdJournalist = new SysId(dbJournalistArticle._UserAccountIdJournalist);
journalistArticle.SportIdPrimary = new SysId(dbJournalistArticle._SportIdPrimary);
journalistArticle.RegionIdPrimary = new SysId(dbJournalistArticle._RegionIdPrimary);
journalistArticle.Headline = dbJournalistArticle._Headline;
journalistArticle.Summary = dbJournalistArticle._Summary;
journalistArticle.BodyData = dbJournalistArticle._BodyData;
journalistArticle.PublishedAt = dbJournalistArticle._PublishedAt;
journalistArticle.Notes = dbJournalistArticle._Notes;
journalistArticle.Status = SacsSystem.GetStatusForCode(dbJournalistArticle._Status);
journalistArticle.SetCreateStamp(dbJournalistArticle._CreateOn, new SysId(dbJournalistArticle._CreateBy), dbJournalistArticle._CreateHost);
journalistArticle.SetUpdateStamp(dbJournalistArticle._UpdateOn, new SysId(dbJournalistArticle._UpdateBy), dbJournalistArticle._UpdateHost);
journalistArticle.AcceptChanges();
}
//-------------------------------------------------------------------
// Item column definitions.
private static readonly String aliasJournalistArticle = "Sprt";
private static readonly String aliasJournalistArticle_Journalist = "JrnArt_Jrn";
private static readonly String prefixJournalistArticle_Jourlalist = "JrnArt_Jrn_";
private static readonly String aliasJournalistArticle_Sport = "JrnArt_Spt";
private static readonly String prefixJournalistArticle_Sport = "JrnArt_Spt_";
private static readonly String aliasJournalistArticle_Region = "JrnArt_Rgn";
private static readonly String prefixJournalistArticle_Region = "JrnArt_Rgn_";
private void SetJournalistArticleColDfn
(ColumnDfn col, String caption, int width, SaxDbDfn_Core.ColumnIdx dbCol,
ColumnAlignment align = ColumnAlignment.Default, DataValue.DataType dataType = DataValue.DataType.String,
String alias = "", String prefix = "")
{
if (String.IsNullOrEmpty(alias) && SaxDbDfn_Core.GetTableForColumn(dbCol) == SaxDbDfn_Core.TableIdx.JournalistArticle)
alias = aliasJournalistArticle;
col.Set(caption, width, (int)dbCol, prefix + SaxDbDfn_Core.GetColumnName(dbCol, false), SaxDbDfn_Core.GetColumnNameQual(dbCol, alias), dataType, align);
if (dataType == DataValue.DataType.String && dbCol != SaxDbDfn_Core.ColumnIdx.Unknown)
col.MaxLength = (int)SaxDbDfn_Core.GetColTextLen(dbCol);
}
public override ColumnDfn GetJournalistArticleColumnDfn(SaxJournalistArticle.Column columnId, string caption = "", int width = 0)
{
ColumnDfn columnDfn = new ColumnDfn((int)columnId, caption, width);
switch (columnId)
{
//-----------------------------------------------------------
case SaxJournalistArticle.Column.Pos:
SetJournalistArticleColDfn(columnDfn, "Pos", 60, SaxDbDfn_Core.ColumnIdx.Unknown, ColumnAlignment.Right);
columnDfn.SortMode = ColumnDfn.ColumnSortMode.Off;
columnDfn.ReadOnly = true;
columnDfn.Resizable = false;
break;
case SaxJournalistArticle.Column.Id:
SetJournalistArticleColDfn(columnDfn, "Id", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Journalist.
case SaxJournalistArticle.Column.UserAccountIdJournalist:
SetJournalistArticleColDfn(columnDfn, "Journalist Id", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_UserAccountIdJournalist, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Journalist_DisplayName:
SetJournalistArticleColDfn(columnDfn, "Journalist", 120, SaxDbDfn_Core.ColumnIdx.Unknown);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Journalist_Title:
SetJournalistArticleColDfn(columnDfn, "Journalist Title", 80, SaxDbDfn_Core.ColumnIdx.UserAccount_Title, ColumnAlignment.Left, DataValue.DataType.String, aliasJournalistArticle_Journalist, prefixJournalistArticle_Jourlalist);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Journalist_FirstName:
SetJournalistArticleColDfn(columnDfn, "Journalist First Name", 100, SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName, ColumnAlignment.Left, DataValue.DataType.String, aliasJournalistArticle_Journalist, prefixJournalistArticle_Jourlalist);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Journalist_LastName:
SetJournalistArticleColDfn(columnDfn, "Journalist Last Name", 100, SaxDbDfn_Core.ColumnIdx.UserAccount_LastName, ColumnAlignment.Left, DataValue.DataType.String, aliasJournalistArticle_Journalist, prefixJournalistArticle_Jourlalist);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Sport.
case SaxJournalistArticle.Column.SportIdPrimary:
SetJournalistArticleColDfn(columnDfn, "Sport Id", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_SportIdPrimary, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Sport_Name:
SetJournalistArticleColDfn(columnDfn, "Sport", 100, SaxDbDfn_Core.ColumnIdx.Sport_Name, ColumnAlignment.Left, DataValue.DataType.String, aliasJournalistArticle_Sport, prefixJournalistArticle_Sport);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Region.
case SaxJournalistArticle.Column.RegionIdPrimary:
SetJournalistArticleColDfn(columnDfn, "Region Id", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_RegionIdPrimary, ColumnAlignment.Right, DataValue.DataType.Long);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.Region_Name:
SetJournalistArticleColDfn(columnDfn, "Region", 100, SaxDbDfn_Core.ColumnIdx.Region_Name, ColumnAlignment.Left, DataValue.DataType.String, aliasJournalistArticle_Region, prefixJournalistArticle_Region);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Article.
case SaxJournalistArticle.Column.Headline:
SetJournalistArticleColDfn(columnDfn, "Headline", 200, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline);
break;
case SaxJournalistArticle.Column.Summary:
SetJournalistArticleColDfn(columnDfn, "Summary", 200, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary);
break;
case SaxJournalistArticle.Column.PublishedAt_Date:
SetJournalistArticleColDfn(columnDfn, "Published", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_PublishedAt, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.PublishedAt_DateTime:
SetJournalistArticleColDfn(columnDfn, "Published", 100, SaxDbDfn_Core.ColumnIdx.JournalistArticle_PublishedAt, ColumnAlignment.Center, DataValue.DataType.DateTime);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
// Derived properties.
//-----------------------------------------------------------
// Common properties.
case SaxJournalistArticle.Column.Notes:
SetJournalistArticleColDfn(columnDfn, "Notes", 240, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Notes);
break;
case SaxJournalistArticle.Column.Flags:
SetJournalistArticleColDfn(columnDfn, "Flags", 60, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Flags, ColumnAlignment.Center, DataValue.DataType.Long);
break;
case SaxJournalistArticle.Column.Status:
SetJournalistArticleColDfn(columnDfn, "Status", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status, ColumnAlignment.Center);
break;
case SaxJournalistArticle.Column.Status_Desc:
SetJournalistArticleColDfn(columnDfn, "Status", 90, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status, ColumnAlignment.Center);
break;
case SaxJournalistArticle.Column.Status_Ind:
SetJournalistArticleColDfn(columnDfn, "Status", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status, ColumnAlignment.Center, DataValue.DataType.TriState);
columnDfn.TriStateFormat = ColumnTriStateFormat.Lights;
break;
case SaxJournalistArticle.Column.CreateOn_Date:
SetJournalistArticleColDfn(columnDfn, "Created", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_CreateOn, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
case SaxJournalistArticle.Column.UpdateOn_Date:
SetJournalistArticleColDfn(columnDfn, "Updated", 80, SaxDbDfn_Core.ColumnIdx.JournalistArticle_UpdateOn, ColumnAlignment.Center, DataValue.DataType.Date);
columnDfn.ReadOnly = true;
break;
//-----------------------------------------------------------
}
if (!String.IsNullOrEmpty(caption))
columnDfn.Caption = caption;
if (width > 0)
columnDfn.Width = width;
return columnDfn;
}
//-------------------------------------------------------------------
// Item query filter.
public override List<string> GetJournalistArticleQueryFilter(SaxJournalistArticle.Params prm)
{
List<String> filter = new List<String>();
// Item Ids.
String idsIncluded = prm.IdsIncluded.Concat(",");
if (!idsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, aliasJournalistArticle) + " IN (" + idsIncluded + ")");
String idsExcluded = prm.IdsExcluded.Concat(",");
if (!idsExcluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, aliasJournalistArticle) + " NOT IN (" + idsExcluded + ")");
// User Account Ids.
String userAccountIdsIncluded = prm.UserAccountIdsJournalistIncluded.Concat(",");
if (!userAccountIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_UserAccountIdJournalist, aliasJournalistArticle) + " IN (" + userAccountIdsIncluded + ")");
// Sport Ids.
String sportIdsIncluded = prm.SportIdsIncluded.Concat(",");
if (!sportIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_SportIdPrimary, aliasJournalistArticle) + " IN (" + sportIdsIncluded + ")");
// Region Ids.
String regionIdsIncluded = prm.RegionIdsIncluded.Concat(",");
if (!regionIdsIncluded.IsEmpty())
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_RegionIdPrimary, aliasJournalistArticle) + " IN (" + regionIdsIncluded + ")");
// Headline.
if (!StringUtil.IsEmpty(prm.HeadlinePartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline, aliasJournalistArticle) + " Like '%" + DbQuery.FormatForLike(prm.HeadlinePartial, true) + "%'");
// Summary.
if (!StringUtil.IsEmpty(prm.SummaryPartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary, aliasJournalistArticle) + " Like '%" + DbQuery.FormatForLike(prm.SummaryPartial, true) + "%'");
// Article.
if (!StringUtil.IsEmpty(prm.ArticleFilter))
{
// Split filter into words.
List<String> filterWords = prm.ArticleFilter.Split((char[])null).ToList();
filterWords.RemoveDuplicatesCI();
filterWords.RemoveBlanks();
foreach (String filterWord in filterWords)
{
List<String> articleFilter = new List<String>();
articleFilter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline, aliasJournalistArticle) + " Like '%" + DbQuery.FormatForLike(filterWord, true) + "%'");
articleFilter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary, aliasJournalistArticle) + " Like '%" + DbQuery.FormatForLike(filterWord, true) + "%'");
filter.Add(articleFilter.Concat(" OR ", "(", ")"));
}
}
// Notes.
if (!StringUtil.IsEmpty(prm.NotesPartial))
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Notes, aliasJournalistArticle) + " LIKE '%" + DbQuery.FormatForLike(prm.NotesPartial) + "%'");
// Status.
if (prm.StatusCat != SaxJournalistArticle.StatusCat.Any)
filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status, aliasJournalistArticle) + GetJournalistArticleStatusCatFilterCondition(prm.StatusCat));
if (filter.Count < 1) filter.Add("1=1");
return filter;
}
internal static String GetJournalistArticleStatusCatFilterCondition(SaxJournalistArticle.StatusCat statusCat)
{
if (statusCat == SaxJournalistArticle.StatusCat.ActiveOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Active) + "'";
if (statusCat == SaxJournalistArticle.StatusCat.InactiveOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Inactive) + "'";
if (statusCat == SaxJournalistArticle.StatusCat.NotDeleted)
return "!='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'";
if (statusCat == SaxJournalistArticle.StatusCat.DeletedOnly)
return "='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'";
return "";
}
// Item sort columns.
public List<String> GetJournalistArticleSortColumns(SaxJournalistArticle.Params prm)
{
// Sort sequence:
List<String> sortColumnNames = new List<String>();
foreach (var columnDfn in prm.SortColumns)
{
// Need to ensure correct alias used for JournalistArticle columns in case of conflict.
String sortCol = String.Empty;
if (SaxDbDfn_Core.GetTableForColumn((SaxDbDfn_Core.ColumnIdx)columnDfn.DbColumn) == SaxDbDfn_Core.TableIdx.JournalistArticle)
{
sortCol = SaxDbDfn_Core.GetColumnNameQual((SaxDbDfn_Core.ColumnIdx)columnDfn.DbColumn, aliasJournalistArticle);
}
else
{
sortCol = columnDfn.DataName;
if (!StringUtil.IsEmpty(columnDfn.SortDataName))
sortCol = columnDfn.SortDataName;
}
if (!sortCol.IsEmpty())
{
DbOrderByNullMode orderByNullMode = DbOrderByNullMode.Default; // eSaOrderByDemoteNulls, eSaOrderByPromoteNulls
sortColumnNames.Add(DbQuery.FormatForOrderBy(sortCol, columnDfn.SortAscending, orderByNullMode).Concat(", "));
}
}
sortColumnNames.RemoveBlanks();
if (sortColumnNames.IsEmpty())
{
// Default sort columns.
sortColumnNames.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, aliasJournalistArticle) + " ASC");
}
return sortColumnNames;
}
//-------------------------------------------------------------------
// Item count.
private long GetJournalistArticleCount(String filter)
{
ClearErrorState();
return CoreDatabase.GetRowCount(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.JournalistArticle) + " As " + aliasJournalistArticle, filter);
}
public override long GetJournalistArticleCount(SaxJournalistArticle.Params prm)
{
ClearErrorState();
return GetJournalistArticleCount(GetJournalistArticleQueryFilter(prm).Concat(" AND ", "(", ")"));
}
//-------------------------------------------------------------------
// Item list.
public override List<SaxJournalistArticle> GetJournalistArticleList(SaxJournalistArticle.Params prm)
{
List<SaxJournalistArticle> userActivitys = new List<SaxJournalistArticle>();
DbQuery qry = new DbQuery(CoreDatabase.DbmsType);
qry.Tables.Add(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.JournalistArticle), aliasJournalistArticle);
JournalistArticle_Db dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
qry.Columns.AddRange(dbJournalistArticle.ExistingColumnNames);
qry.Filters.AddRange(GetJournalistArticleQueryFilter(prm));
qry.OrderBy.AddRange(GetJournalistArticleSortColumns(prm));
// Query data.
using (var dbConnection = CoreDatabase.CreateConnection())
using (var dbCommand = dbConnection.CreateCommand())
{
try
{
dbConnection.Open();
dbCommand.CommandText = qry.BuildQuery(prm.ResultsPaging);
using (DbDataReader dbDataReader = dbCommand.ExecuteReader())
{
while (dbDataReader.Read())
{
dbJournalistArticle = new JournalistArticle_Db(CoreDbInfo);
dbJournalistArticle.PopulateFrom(dbDataReader);
userActivitys.Add(CreateJournalistArticle(dbJournalistArticle));
}
}
}
catch (Exception exc)
{
SaLogger.Warn(GetType().Name + ".GetJournalistArticleList\n\tQuery: " + dbCommand.CommandText + "\n\t" + ExceptionUtil.GetLogMessage(exc));
}
}
return userActivitys;
}
//-------------------------------------------------------------------
// Item query execution.
public override DbResultSet ExecuteJournalistArticleQuery(List<ColumnDfn> columns, SaxJournalistArticle.Params prm)
{
ClearErrorState();
//---------------------------------------------------------------------
// Construct query.
DbQuery query = new DbQuery(CoreDatabase.DbmsType);
query.Tables.Add(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.JournalistArticle), aliasJournalistArticle);
// Add columns as defined in query list.
if (columns.HasId(SaxJournalistArticle.Column.Id))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Id, aliasJournalistArticle));
bool hasUserAccountCols = (columns.HasId(SaxJournalistArticle.Column.Journalist_DisplayName) || columns.HasId(SaxJournalistArticle.Column.Journalist_Title) || columns.HasId(SaxJournalistArticle.Column.Journalist_FirstName) || columns.HasId(SaxJournalistArticle.Column.Journalist_LastName));
if (columns.HasId(SaxJournalistArticle.Column.UserAccountIdJournalist) || hasUserAccountCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_UserAccountIdJournalist, aliasJournalistArticle));
bool hasSportCols = (columns.HasId(SaxJournalistArticle.Column.Sport_Name));
if (columns.HasId(SaxJournalistArticle.Column.SportIdPrimary) || hasSportCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_SportIdPrimary, aliasJournalistArticle));
bool hasRegionCols = (columns.HasId(SaxJournalistArticle.Column.Region_Name));
if (columns.HasId(SaxJournalistArticle.Column.RegionIdPrimary) || hasRegionCols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_RegionIdPrimary, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.Headline))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Headline, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.Summary))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Summary, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.PublishedAt_Date) || columns.HasId(SaxJournalistArticle.Column.PublishedAt_DateTime))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_PublishedAt, aliasJournalistArticle));
// Common properties.
if (columns.HasId(SaxJournalistArticle.Column.Notes))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Notes, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.Flags))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Flags, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.Status) || columns.HasId(SaxJournalistArticle.Column.Status_Desc) || columns.HasId(SaxJournalistArticle.Column.Status_Ind))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_Status, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.CreateOn_Date))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_CreateOn, aliasJournalistArticle));
if (columns.HasId(SaxJournalistArticle.Column.UpdateOn_Date))
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_UpdateOn, aliasJournalistArticle));
//---------------------------------------------------------------------
// User Account.
if (hasUserAccountCols)
{
DbQueryJoin joinUserAccount = new DbQueryJoin(DbJoinType.LeftOuter);
joinUserAccount.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.UserAccount), aliasJournalistArticle_Journalist);
joinUserAccount.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.UserAccount_Id, aliasJournalistArticle_Journalist) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_UserAccountIdJournalist, aliasJournalistArticle));
query.Joins.Add(joinUserAccount);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_Title);
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName);
cols.Add(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasJournalistArticle_Journalist), prefixJournalistArticle_Jourlalist + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Primary Sport.
if (hasSportCols)
{
DbQueryJoin joinSport = new DbQueryJoin(DbJoinType.LeftOuter);
joinSport.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Sport), aliasJournalistArticle_Sport);
joinSport.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Sport_Id, aliasJournalistArticle_Sport) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_SportIdPrimary, aliasJournalistArticle));
query.Joins.Add(joinSport);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.Sport_Name);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasJournalistArticle_Sport), prefixJournalistArticle_Sport + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Primary Region.
if (hasRegionCols)
{
DbQueryJoin joinRegion = new DbQueryJoin(DbJoinType.LeftOuter);
joinRegion.Table = new StringPair(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.Region), aliasJournalistArticle_Region);
joinRegion.Filters.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.Region_Id, aliasJournalistArticle_Region) + "=" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.JournalistArticle_RegionIdPrimary, aliasJournalistArticle));
query.Joins.Add(joinRegion);
List<SaxDbDfn_Core.ColumnIdx> cols = new List<SaxDbDfn_Core.ColumnIdx>();
cols.Add(SaxDbDfn_Core.ColumnIdx.Region_Name);
foreach (var col in cols)
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(col, aliasJournalistArticle_Region), prefixJournalistArticle_Region + SaxDbDfn_Core.GetColumnName(col, false));
}
//---------------------------------------------------------------------
// Populate filter.
query.Filters.AddRange(GetJournalistArticleQueryFilter(prm));
if (prm.IdsIncluded.Count != 1)
{
// Configure sort sequence.
foreach (String sortColumn in GetJournalistArticleSortColumns(prm))
query.OrderBy.Add(sortColumn);
}
//---------------------------------------------------------------------
//return new DbResultSet_DataTableReader(db, query.BuildQuery(prm.ResultsPaging));
return DbResultSet_DataReader.ExecuteQuery(CoreDatabase, query.BuildQuery(prm.ResultsPaging));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -256,7 +256,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>7</UniqueValues>
<UniqueValues>8</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -343,6 +343,391 @@
</DbDfnIndex>
</Indices>
</DbDfnTable>
<DbDfnTable>
<Schema>dbo</Schema>
<Name>Article</Name>
<Remarks />
<Columns>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>1</Pos>
<Name>Id</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>true</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>2</Pos>
<Name>UserAccountIdAuthor</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>3</Pos>
<Name>OrganisationId</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>Nullable</Nullable>
<IsNullable>true</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>4</Pos>
<Name>SportIdPrimary</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>5</Pos>
<Name>RegionIdPrimary</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>6</Pos>
<Name>Headline</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>200</Size>
<BufferLen>400</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>7</Pos>
<Name>Summary</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>2000</Size>
<BufferLen>4000</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>8</Pos>
<Name>BodyData</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>0</Size>
<BufferLen>0</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>9</Pos>
<Name>PublishedAt</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>smalldatetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>16</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>Nullable</Nullable>
<IsNullable>true</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>10</Pos>
<Name>Notes</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>2000</Size>
<BufferLen>4000</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>11</Pos>
<Name>Flags</Name>
<DataType>SmallInt</DataType>
<DataTypeName />
<DataTypeNative>5</DataTypeNative>
<DataTypeNameNative>smallint</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>5</Size>
<BufferLen>2</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>12</Pos>
<Name>Status</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>3</Size>
<BufferLen>3</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>13</Pos>
<Name>CreateOn</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>datetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>23</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>3</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>14</Pos>
<Name>CreateBy</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>15</Pos>
<Name>CreateHost</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>100</Size>
<BufferLen>100</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>16</Pos>
<Name>UpdateOn</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>datetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>23</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>3</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>17</Pos>
<Name>UpdateBy</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>Article</Table>
<Pos>18</Pos>
<Name>UpdateHost</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>100</Size>
<BufferLen>100</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
</Columns>
<Indices>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>Article</Table>
<Name>PK_Article</Name>
<IndexType>1</IndexType>
<Unique>true</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>2</Pages>
<UniqueValues>9</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>Id</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>Article</Table>
<Name>IDX_Article_Sport_Region_Published</Name>
<IndexType>3</IndexType>
<Unique>false</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>0</Pages>
<UniqueValues>0</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>SportIdPrimary</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
<DbDfnIndexColumn>
<Seq>2</Seq>
<Name>RegionIdPrimary</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
<DbDfnIndexColumn>
<Seq>3</Seq>
<Name>PublishedAt</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>Article</Table>
<Name>IDX_Article_User</Name>
<IndexType>3</IndexType>
<Unique>false</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>0</Pages>
<UniqueValues>0</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>UserAccountIdAuthor</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
</Indices>
</DbDfnTable>
<DbDfnTable>
<Schema>dbo</Schema>
<Name>ItemAddress</Name>
@@ -904,7 +1289,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>2</UniqueValues>
<UniqueValues>3</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -1332,7 +1717,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>7</UniqueValues>
<UniqueValues>9</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -1741,374 +2126,6 @@
</DbDfnIndex>
</Indices>
</DbDfnTable>
<DbDfnTable>
<Schema>dbo</Schema>
<Name>JournalistArticle</Name>
<Remarks />
<Columns>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>1</Pos>
<Name>Id</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>true</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>2</Pos>
<Name>UserAccountIdJournalist</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>3</Pos>
<Name>SportIdPrimary</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>4</Pos>
<Name>RegionIdPrimary</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>5</Pos>
<Name>Headline</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>200</Size>
<BufferLen>400</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>6</Pos>
<Name>Summary</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>2000</Size>
<BufferLen>4000</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>7</Pos>
<Name>BodyData</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>0</Size>
<BufferLen>0</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>8</Pos>
<Name>PublishedAt</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>smalldatetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>16</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>Nullable</Nullable>
<IsNullable>true</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>9</Pos>
<Name>Notes</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>-9</DataTypeNative>
<DataTypeNameNative>nvarchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>2000</Size>
<BufferLen>4000</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>10</Pos>
<Name>Flags</Name>
<DataType>SmallInt</DataType>
<DataTypeName />
<DataTypeNative>5</DataTypeNative>
<DataTypeNameNative>smallint</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>5</Size>
<BufferLen>2</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>11</Pos>
<Name>Status</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>3</Size>
<BufferLen>3</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>12</Pos>
<Name>CreateOn</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>datetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>23</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>3</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>13</Pos>
<Name>CreateBy</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>14</Pos>
<Name>CreateHost</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>100</Size>
<BufferLen>100</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>15</Pos>
<Name>UpdateOn</Name>
<DataType>DateTime</DataType>
<DataTypeName />
<DataTypeNative>93</DataTypeNative>
<DataTypeNameNative>datetime</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>23</Size>
<BufferLen>16</BufferLen>
<DecimalDigits>3</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>16</Pos>
<Name>UpdateBy</Name>
<DataType>Int</DataType>
<DataTypeName />
<DataTypeNative>4</DataTypeNative>
<DataTypeNameNative>int</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>10</Size>
<BufferLen>4</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
<DbDfnColumn>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Pos>17</Pos>
<Name>UpdateHost</Name>
<DataType>VarChar</DataType>
<DataTypeName />
<DataTypeNative>12</DataTypeNative>
<DataTypeNameNative>varchar</DataTypeNameNative>
<IsIdentity>false</IsIdentity>
<Size>100</Size>
<BufferLen>100</BufferLen>
<DecimalDigits>0</DecimalDigits>
<Nullable>NoNulls</Nullable>
<IsNullable>false</IsNullable>
<Remarks />
</DbDfnColumn>
</Columns>
<Indices>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Name>PK_JournalistArticle</Name>
<IndexType>1</IndexType>
<Unique>true</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>8</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>Id</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Name>IDX_JournalistArticle_Sport_Region_Published</Name>
<IndexType>3</IndexType>
<Unique>false</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>0</Pages>
<UniqueValues>0</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>SportIdPrimary</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
<DbDfnIndexColumn>
<Seq>2</Seq>
<Name>RegionIdPrimary</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
<DbDfnIndexColumn>
<Seq>3</Seq>
<Name>PublishedAt</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
<DbDfnIndex>
<Schema>dbo</Schema>
<Table>JournalistArticle</Table>
<Name>IDX_JournalistArticle_User</Name>
<IndexType>3</IndexType>
<Unique>false</Unique>
<Primary>false</Primary>
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>0</Pages>
<UniqueValues>0</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
<Seq>1</Seq>
<Name>UserAccountIdJournalist</Name>
<Ascend>true</Ascend>
</DbDfnIndexColumn>
</Columns>
</DbDfnIndex>
</Indices>
</DbDfnTable>
<DbDfnTable>
<Schema>dbo</Schema>
<Name>Organisation</Name>
@@ -4011,7 +4028,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>7</UniqueValues>
<UniqueValues>8</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -4474,7 +4491,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>10</UniqueValues>
<UniqueValues>11</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -4858,7 +4875,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>8</UniqueValues>
<UniqueValues>10</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>
@@ -5641,7 +5658,7 @@
<Clustered>false</Clustered>
<Nullable>false</Nullable>
<Pages>1</Pages>
<UniqueValues>5</UniqueValues>
<UniqueValues>7</UniqueValues>
<HasColumns>false</HasColumns>
<Columns>
<DbDfnIndexColumn>