diff --git a/SaxoniteCoreWeb/Base/Consoles/SaxActivityConsole_Web.cs b/SaxoniteCoreWeb/Base/Consoles/SaxActivityConsole_Web.cs index 9b2a20d..a397c19 100644 --- a/SaxoniteCoreWeb/Base/Consoles/SaxActivityConsole_Web.cs +++ b/SaxoniteCoreWeb/Base/Consoles/SaxActivityConsole_Web.cs @@ -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 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 activities) + // Article details. + private void PopulateArticleDetails(IndexContext context, List activities) { // Extract article Ids. - List articleIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.JournalistArticle).Select(ItemId => ItemId.ItemId.Id).ToList(); + List 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 columns = new List() { 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 columns = new List() { 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); } diff --git a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs index 41b2148..56c6809 100644 --- a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs +++ b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs @@ -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; } /// /// Indicate whether session data should be stored by action. /// Any action that might modify the session data must store it. @@ -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. + /// Item data - Common properties for data items. public class ItemData_Base { // Common item properties. @@ -437,6 +452,15 @@ namespace Saxonite.Net.Core.Web.Base.Controllers /// Updated on date - formatted per locale public String UpdatedOnFmt { get; set; } } + /// + /// Item data with just Id and name. + /// - Id is String to allow for obfuscated values. + /// + 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 controlValues = new Dictionary(); - public List ControlValues { get { return controlValues.Values.ToList(); } } + public List 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 }; diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs index d0cbf9e..05b493f 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs @@ -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) + /// + /// Generate the User Activation email. + /// NB URL must be to the Online application. + /// NB Encryption must be done with the Online logic. + /// + 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()); } //------------------------------------------------------------------- diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs index ecbeebb..c1e9947 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs @@ -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)), diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs index da6805b..c17e9b3 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs @@ -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=="; + /// + /// Generate Request Password link. + /// NB For an Online application request (from teh ASdmin system), must ensure that the URL and encryption parameters are switched. + /// + 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)); diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs index e4ffde4..06bc13d 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs @@ -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 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); + } + //------------------------------------------------------------------- } //======================================================================= diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Model_User.cs b/SaxoniteCoreWebAdmin/Admin/Models/Model_User.cs index 9dda3ca..c98d030 100644 --- a/SaxoniteCoreWebAdmin/Admin/Models/Model_User.cs +++ b/SaxoniteCoreWebAdmin/Admin/Models/Model_User.cs @@ -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. diff --git a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx index a970def..c938e0c 100644 --- a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx +++ b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx @@ -201,6 +201,12 @@ Email address + + Email types + + + Emails + Filename @@ -390,6 +396,9 @@ Value must not exceed {0} characters + + At least one option must be selected. + On activation, the Organisation will become visible on the platform and authorised members will be able to post content associated with the organisation. @@ -522,6 +531,9 @@ Account Activation + + Select User Emails + Select User Roles @@ -537,4 +549,19 @@ Users + + Account activation - Online + + + Request password - Admin + + + Request password - Online + + + Select the types of email to be sent. + + + User is not system admin. + \ No newline at end of file diff --git a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml index 5d6bc01..24d8b80 100644 --- a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml @@ -181,7 +181,7 @@ @* Footer *@
- @(Model.CopyrightNotice) - @Localiser["company.name"] @(Model.InstanceVersion) - Home + @(Model.CopyrightNotice) - @Localiser["company.name"] @(Model.InstanceVersion)
diff --git a/SaxoniteCoreWebAdmin/Views/User/Index.cshtml b/SaxoniteCoreWebAdmin/Views/User/Index.cshtml index ffee8d6..5daa135 100644 --- a/SaxoniteCoreWebAdmin/Views/User/Index.cshtml +++ b/SaxoniteCoreWebAdmin/Views/User/Index.cshtml @@ -5,41 +5,80 @@ ViewData["Title"] = "Users"; } -
+
+ + @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserFilter", @class = "sax-form", @onSubmit = "return false;" })) { + + @* Filter Panel *@
+ @* Header - Page caption, paging controls, actions. *@
@Localiser["user.caption.users"]
-
+
-
@(Localiser[
-
@(Localiser[
+
+ @* Burger menu *@ + +
+ @* User filter - email, name etc. *@
@Localiser["user.caption.user"]
@Html.TextBoxFor(model => model.Filter.User, new { @id = "ifFilterUser", @class = "FilterUser", @maxlength = "32" })
+ + @* Filter element templates *@ +
+ @* Burger dropdown item template - ul is ignored *@ +
    +
  • XXX
  • +
+
+
} + @* Results Panel *@
+ + @* Element templates *@
+ + @* User item template *@
+ @* User email *@
-
@(Localiser[
+ @* Burger menu *@ +
@@ -54,6 +93,12 @@
+ + @* Burger dropdown item template - ul is ignored *@ +
    +
  • XXX
  • +
+
diff --git a/SaxoniteCoreWebAdmin/Views/User/Panel-UserDialog.cshtml b/SaxoniteCoreWebAdmin/Views/User/Panel-UserDialog.cshtml index 0380544..b30e105 100644 --- a/SaxoniteCoreWebAdmin/Views/User/Panel-UserDialog.cshtml +++ b/SaxoniteCoreWebAdmin/Views/User/Panel-UserDialog.cshtml @@ -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'; @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserId", @class = "sax-form" })) @@ -31,6 +32,7 @@
+ /* Title */
@@ -89,6 +91,57 @@ } - - +
+ + + +
+ @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserEmails", @class = "sax-form", @onSubmit = "return false;" })) + { + @Html.HiddenFor(model => model.UserAccountId, new { @class = "UserAccountId" }) + +
@Localiser["user.emails.intro"]
+ + @* User email *@ +
+
+ +
+
+ +
+
+
+ + @* User display name *@ +
+
+ +
+
+ +
+
+
+ + @* User emails *@ +
+
+ +
+
+
+  @Localiser["user.email.account.activation.online"] +
+
+  @Localiser["user.email.request.password.online"] +
+
+  @Localiser["user.email.request.password.admin"] +
+
+
+
+ + }
diff --git a/SaxoniteCoreWebAdmin/wwwroot/css/sax-main.css b/SaxoniteCoreWebAdmin/wwwroot/css/sax-main.css index ab9b6b8..08c8bcd 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/css/sax-main.css +++ b/SaxoniteCoreWebAdmin/wwwroot/css/sax-main.css @@ -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 diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-home.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-home.js index f637176..4f92215 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-home.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-home.js @@ -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(); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-main.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-main.js index 824af4a..d88c8c3 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-main.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-main.js @@ -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); } diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-organisationMembers.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-organisationMembers.js index bd4f276..0e7c700 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-organisationMembers.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-organisationMembers.js @@ -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; diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-region.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-region.js index e8056a7..a3da3bd 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-region.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-region.js @@ -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; diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-security.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-security.js index 67d91cf..8bb2c8a 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-security.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-security.js @@ -15,7 +15,7 @@ } sax.onSignin = function (response) { - sax.debug(response); + //sax.debug(response); sax.refreshControlValues(response.controlValues); if (!response.success) return; sax.goToPage(''); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-selectOrganisation.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-selectOrganisation.js index 98d1f6c..fa7b32d 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-selectOrganisation.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-selectOrganisation.js @@ -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(); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-db.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-db.js index c3d9285..a8acc44 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-db.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-db.js @@ -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'); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-logs.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-logs.js new file mode 100644 index 0000000..6a31426 --- /dev/null +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sys-logs.js @@ -0,0 +1,19 @@ +/* + * Admin - System Logs page scripts. + */ + +(function (win, doc, undef) +{ + "use strict"; + sax.itemIdPrefix = 'Itm_'; + + //-------------------------------------------------------------- + + //-------------------------------------------------------------- + $(function () + { + }); + +}(window, window.document)); + +/* The End */ \ No newline at end of file diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-user.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-user.js index 878c073..c57d236 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-user.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-user.js @@ -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($('
' + sax.msg.dataQuerying + '
')).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($('
' + sax.msg.dataQuerying + '
')).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($('
' + sax.msg.dataNoneFound + '
')).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); }); diff --git a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx index 71a12ba..b07f9ba 100644 --- a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx +++ b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx @@ -159,6 +159,18 @@ Activity + + Article + + + Create Article + + + Update Article + + + Articles + Solum Forti @@ -198,18 +210,6 @@ Sign-up now with a few details and we'll let you know when you can login and get going. - - Article - - - Create Article - - - Update Article - - - Articles - My Account diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs index 6cbe16c..6e9341f 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs @@ -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); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Organisations.cs b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Organisations.cs index b70d4eb..1979b58 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Organisations.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Organisations.cs @@ -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(); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Sports.cs b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Sports.cs index a41fbc8..3717eee 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Sports.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Sports.cs @@ -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); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs index 4f1bd86..211ec48 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs @@ -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 /// Article activity info. 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); } diff --git a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs similarity index 73% rename from SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs rename to SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs index c4b3349..c43c84e 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs @@ -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 Segments { get; } = new List(); @@ -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 Articles { get; } = new List(); + /// Organisations that the user has rights to author articles for. + public List 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 = 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 columns = new List() { - 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"])); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController.cs b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController.cs similarity index 50% rename from SaxoniteCoreWebOnline/Online/Controllers/JournalistController.cs rename to SaxoniteCoreWebOnline/Online/Controllers/ArticleController.cs index eb503f0..a3f7140 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController.cs @@ -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 logger) : + public ArticleController(SaxLocaliser localiser, ILogger 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 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; diff --git a/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs b/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs index 387c2ab..ed75166 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs @@ -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"; /// - /// Get the specified Journalist Article Image. + /// Get the specified Article Image. + /// Method parameter name (aie) must match name of encrypted parameter. /// Encrypted parameters: /// - iii: item Image Id. /// [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. diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Members.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Members.cs index 80af8bc..764908a 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Members.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Members.cs @@ -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 disposableItems = new DisposableCollection()) @@ -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 disposableItems = new DisposableCollection()) diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Opportunities.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Opportunities.cs index 4d00314..d582630 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Opportunities.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Opportunities.cs @@ -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); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Request.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Request.cs index 8f265a4..e6ac2bc 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Request.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Request.cs @@ -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. diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax.cs index 14d5221..6faba77 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax.cs @@ -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); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/ReferenceController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/ReferenceController-Ajax.cs index 41a7a8c..1b50a6e 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/ReferenceController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ReferenceController-Ajax.cs @@ -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. diff --git a/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs b/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs index 58c6099..3f065dd 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs @@ -258,7 +258,13 @@ namespace Saxonite.Net.Core.Web.Online.Controllers //------------------------------------------------------------------- // Logging. //------------------------------------------------------------------- - protected String getLogSuffix() + /// + /// Log suffix: + /// - User's email address. + /// - Prefixed with space. + /// + /// + protected String GetLogSuffix() { List logSuffix = new List(); SaxSessionData_Online sessionData = SessionData_Online; diff --git a/SaxoniteCoreWebOnline/Online/Controllers/SecurityController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/SecurityController-Ajax.cs index cafe364..b32bfb2 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/SecurityController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/SecurityController-Ajax.cs @@ -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)); diff --git a/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs b/SaxoniteCoreWebOnline/Online/Models/Model_Article.cs similarity index 80% rename from SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs rename to SaxoniteCoreWebOnline/Online/Models/Model_Article.cs index c49953b..6cd015b 100644 --- a/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs +++ b/SaxoniteCoreWebOnline/Online/Models/Model_Article.cs @@ -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(); + /// + /// User has rights to author articles for at least one organisation. + /// - Output only - not returned with form data. + /// - Only populated for initial page construction. + /// + public bool UserCanAuthorOrganisationArticles { get; set; } + /// + /// User has rights to author articles as a journalist. + /// - Output only - not returned with form data. + /// - Only populated for initial page construction. + /// + 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"]); } diff --git a/SaxoniteCoreWebOnline/Online/Models/SaxModel_Online.cs b/SaxoniteCoreWebOnline/Online/Models/SaxModel_Online.cs index 6f780cf..1534f71 100644 --- a/SaxoniteCoreWebOnline/Online/Models/SaxModel_Online.cs +++ b/SaxoniteCoreWebOnline/Online/Models/SaxModel_Online.cs @@ -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. //------------------------------------------------------------------- diff --git a/SaxoniteCoreWebOnline/Views/Journalist/Articles.cshtml b/SaxoniteCoreWebOnline/Views/Article/Index.cshtml similarity index 73% rename from SaxoniteCoreWebOnline/Views/Journalist/Articles.cshtml rename to SaxoniteCoreWebOnline/Views/Article/Index.cshtml index e19e02b..3042236 100644 --- a/SaxoniteCoreWebOnline/Views/Journalist/Articles.cshtml +++ b/SaxoniteCoreWebOnline/Views/Article/Index.cshtml @@ -1,4 +1,4 @@ -@model Model_Journalist +@model Model_Article @inject SaxLocaliser Localiser @{ ViewData["Title"] = "Journalist - Articles"; @@ -10,7 +10,7 @@ {
-
@Localiser["journalist.caption.articles"]
+
@Localiser["article.caption.articles"]
@@ -20,6 +20,17 @@
+ @if (Model.UserCanAuthorOrganisationArticles) + { +
+
@Localiser["label.organisation"]
+
+ @Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" }) +
+
+
+
+ }
@Localiser["label.search"]
@@ -59,5 +70,6 @@
+ diff --git a/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml b/SaxoniteCoreWebOnline/Views/Article/Panel-ArticleDialog.cshtml similarity index 80% rename from SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml rename to SaxoniteCoreWebOnline/Views/Article/Panel-ArticleDialog.cshtml index 028a36c..66d8925 100644 --- a/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml +++ b/SaxoniteCoreWebOnline/Views/Article/Panel-ArticleDialog.cshtml @@ -1,12 +1,12 @@ -@model Model_Journalist +@model Model_Article @inject SaxLocaliser Localiser @{ /* Articles - Article dialog panel */ } @@ -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" })
+ @* Organisation *@ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ @* Article headline *@
- +
- @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) })
@@ -39,10 +56,10 @@ @* Article summary *@
- +
- @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) })
@@ -50,7 +67,7 @@ @* Sport *@
- +
@Html.HiddenFor(model => model.ArticleSportId, new { @id = "ifArticleSportId", @class = "ArticleSportId" }) @@ -63,7 +80,7 @@ @* Region *@
- +
@Html.HiddenFor(model => model.ArticleRegionId, new { @id = "ifArticleRegionId", @class = "ArticleRegionId" }) @@ -107,7 +124,7 @@
Drop image here
- +
@* Segment details *@ @@ -138,7 +155,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectArticleImage", @class = "sax-form", @onSubmit = "return false;" })) { - +
@@ -150,7 +167,7 @@
-
+
} diff --git a/SaxoniteCoreWebOnline/Views/Common/OrganisationSelect.cshtml b/SaxoniteCoreWebOnline/Views/Common/OrganisationSelect.cshtml index 51b6b48..8ac8f19 100644 --- a/SaxoniteCoreWebOnline/Views/Common/OrganisationSelect.cshtml +++ b/SaxoniteCoreWebOnline/Views/Common/OrganisationSelect.cshtml @@ -22,7 +22,7 @@
@Localiser["label.search"]
-
+
} diff --git a/SaxoniteCoreWebOnline/Views/Home/Index.cshtml b/SaxoniteCoreWebOnline/Views/Home/Index.cshtml index 85ac12d..da9bafb 100644 --- a/SaxoniteCoreWebOnline/Views/Home/Index.cshtml +++ b/SaxoniteCoreWebOnline/Views/Home/Index.cshtml @@ -55,7 +55,12 @@ else
-
+
+
+
+
+
+
diff --git a/SaxoniteCoreWebOnline/Views/Organisation/Opportunities.cshtml b/SaxoniteCoreWebOnline/Views/Organisation/Opportunities.cshtml index 3128b2d..7aba9e7 100644 --- a/SaxoniteCoreWebOnline/Views/Organisation/Opportunities.cshtml +++ b/SaxoniteCoreWebOnline/Views/Organisation/Opportunities.cshtml @@ -21,7 +21,7 @@
@Localiser["label.organisation"]
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" }) -
+
@@ -64,6 +64,6 @@
- + diff --git a/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml b/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml index 9fbe32d..ed6fb43 100644 --- a/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml +++ b/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml @@ -129,15 +129,15 @@
diff --git a/SaxoniteStandardDbas/Dbas/Bus/SaxJournalistArticle_Dbas.cs b/SaxoniteStandardDbas/Dbas/Bus/SaxArticle_Dbas.cs similarity index 79% rename from SaxoniteStandardDbas/Dbas/Bus/SaxJournalistArticle_Dbas.cs rename to SaxoniteStandardDbas/Dbas/Bus/SaxArticle_Dbas.cs index e8a108f..d0a26de 100644 --- a/SaxoniteStandardDbas/Dbas/Bus/SaxJournalistArticle_Dbas.cs +++ b/SaxoniteStandardDbas/Dbas/Bus/SaxArticle_Dbas.cs @@ -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; diff --git a/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs index 4f43d56..513ddba 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Article_Db.cs similarity index 89% rename from SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs rename to SaxoniteStandardDbas/Dbas/Internal/Article_Db.cs index 4693303..e0841a2 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/Article_Db.cs @@ -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 fields { get; } = new List() { "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 Fields { get { return new List(fields); } } public static List FieldsId { get { return new List(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); diff --git a/SaxoniteStandardDbas/Dbas/Internal/ItemAddress_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ItemAddress_Db.cs index 2a18b46..fe20040 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/ItemAddress_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/ItemAddress_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs index 0e9f72b..d650dc4 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs index 227eee6..b935102 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs index f00e1f1..6e7da22 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs index f9d63e7..d1b0e34 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs index c6f4ddd..5afea92 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs index 75678e6..e901ece 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs index 46d64c8..d119bc4 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs index 30bf60d..dc7478f 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs index a37317a..93c9682 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs index e8874b5..e18d2da 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs index 7d0313f..0ccc9ed 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs index 49d93e3..b5ff751 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs @@ -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 { diff --git a/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-ActivityIndex.cs b/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-ActivityIndex.cs index 9ef8900..605aab3 100644 --- a/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-ActivityIndex.cs +++ b/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-ActivityIndex.cs @@ -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 cols = new List(); - 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)); } diff --git a/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-Article.cs b/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-Article.cs new file mode 100644 index 0000000..8bfb017 --- /dev/null +++ b/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-Article.cs @@ -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 GetLogProperties(SaxArticle article) + { + return new List() + { + 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 GetArticleQueryFilter(SaxArticle.Params prm) + { + List filter = new List(); + + // 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 filterWords = prm.ArticleFilter.Split((char[])null).ToList(); + filterWords.RemoveDuplicatesCI(); + filterWords.RemoveBlanks(); + foreach (String filterWord in filterWords) + { + List articleFilter = new List(); + 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 GetArticleSortColumns(SaxArticle.Params prm) + { + // Sort sequence: + List sortColumnNames = new List(); + 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 GetArticleList(SaxArticle.Params prm) + { + List userActivitys = new List(); + 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 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 cols = new List(); + 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 cols = new List(); + 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 cols = new List(); + 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 cols = new List(); + 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)); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-JournalistArticle.cs b/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-JournalistArticle.cs deleted file mode 100644 index bb3514d..0000000 --- a/SaxoniteStandardDbas/Dbas/Mgr/SaxActivityMgr_Dbas-JournalistArticle.cs +++ /dev/null @@ -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 GetLogProperties(SaxJournalistArticle journalistArticle) - { - return new List() - { - 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 GetJournalistArticleQueryFilter(SaxJournalistArticle.Params prm) - { - List filter = new List(); - - // 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 filterWords = prm.ArticleFilter.Split((char[])null).ToList(); - filterWords.RemoveDuplicatesCI(); - filterWords.RemoveBlanks(); - foreach (String filterWord in filterWords) - { - List articleFilter = new List(); - 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 GetJournalistArticleSortColumns(SaxJournalistArticle.Params prm) - { - // Sort sequence: - List sortColumnNames = new List(); - 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 GetJournalistArticleList(SaxJournalistArticle.Params prm) - { - List userActivitys = new List(); - 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 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 cols = new List(); - 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 cols = new List(); - 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 cols = new List(); - 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)); - } - - //------------------------------------------------------------------- - } - //======================================================================= -} diff --git a/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml b/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml index ded9577..42b891c 100644 --- a/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml +++ b/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml @@ -256,7 +256,7 @@ false false 1 - 7 + 8 false @@ -343,6 +343,391 @@ + + dbo + Article + + + + dbo + Article
+ 1 + Id + Int + + 4 + int + true + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 2 + UserAccountIdAuthor + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 3 + OrganisationId + Int + + 4 + int + false + 10 + 4 + 0 + Nullable + true + +
+ + dbo + Article
+ 4 + SportIdPrimary + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 5 + RegionIdPrimary + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 6 + Headline + VarChar + + -9 + nvarchar + false + 200 + 400 + 0 + NoNulls + false + +
+ + dbo + Article
+ 7 + Summary + VarChar + + -9 + nvarchar + false + 2000 + 4000 + 0 + NoNulls + false + +
+ + dbo + Article
+ 8 + BodyData + VarChar + + -9 + nvarchar + false + 0 + 0 + 0 + NoNulls + false + +
+ + dbo + Article
+ 9 + PublishedAt + DateTime + + 93 + smalldatetime + false + 16 + 16 + 0 + Nullable + true + +
+ + dbo + Article
+ 10 + Notes + VarChar + + -9 + nvarchar + false + 2000 + 4000 + 0 + NoNulls + false + +
+ + dbo + Article
+ 11 + Flags + SmallInt + + 5 + smallint + false + 5 + 2 + 0 + NoNulls + false + +
+ + dbo + Article
+ 12 + Status + VarChar + + 12 + varchar + false + 3 + 3 + 0 + NoNulls + false + +
+ + dbo + Article
+ 13 + CreateOn + DateTime + + 93 + datetime + false + 23 + 16 + 3 + NoNulls + false + +
+ + dbo + Article
+ 14 + CreateBy + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 15 + CreateHost + VarChar + + 12 + varchar + false + 100 + 100 + 0 + NoNulls + false + +
+ + dbo + Article
+ 16 + UpdateOn + DateTime + + 93 + datetime + false + 23 + 16 + 3 + NoNulls + false + +
+ + dbo + Article
+ 17 + UpdateBy + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + Article
+ 18 + UpdateHost + VarChar + + 12 + varchar + false + 100 + 100 + 0 + NoNulls + false + +
+
+ + + dbo + Article
+ PK_Article + 1 + true + false + false + false + 2 + 9 + false + + + 1 + Id + true + + +
+ + dbo + Article
+ IDX_Article_Sport_Region_Published + 3 + false + false + false + false + 0 + 0 + false + + + 1 + SportIdPrimary + true + + + 2 + RegionIdPrimary + true + + + 3 + PublishedAt + true + + +
+ + dbo + Article
+ IDX_Article_User + 3 + false + false + false + false + 0 + 0 + false + + + 1 + UserAccountIdAuthor + true + + +
+
+
dbo ItemAddress @@ -904,7 +1289,7 @@ false false 1 - 2 + 3 false @@ -1332,7 +1717,7 @@ false false 1 - 7 + 9 false @@ -1741,374 +2126,6 @@ - - dbo - JournalistArticle - - - - dbo - JournalistArticle
- 1 - Id - Int - - 4 - int - true - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 2 - UserAccountIdJournalist - Int - - 4 - int - false - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 3 - SportIdPrimary - Int - - 4 - int - false - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 4 - RegionIdPrimary - Int - - 4 - int - false - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 5 - Headline - VarChar - - -9 - nvarchar - false - 200 - 400 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 6 - Summary - VarChar - - -9 - nvarchar - false - 2000 - 4000 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 7 - BodyData - VarChar - - -9 - nvarchar - false - 0 - 0 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 8 - PublishedAt - DateTime - - 93 - smalldatetime - false - 16 - 16 - 0 - Nullable - true - -
- - dbo - JournalistArticle
- 9 - Notes - VarChar - - -9 - nvarchar - false - 2000 - 4000 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 10 - Flags - SmallInt - - 5 - smallint - false - 5 - 2 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 11 - Status - VarChar - - 12 - varchar - false - 3 - 3 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 12 - CreateOn - DateTime - - 93 - datetime - false - 23 - 16 - 3 - NoNulls - false - -
- - dbo - JournalistArticle
- 13 - CreateBy - Int - - 4 - int - false - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 14 - CreateHost - VarChar - - 12 - varchar - false - 100 - 100 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 15 - UpdateOn - DateTime - - 93 - datetime - false - 23 - 16 - 3 - NoNulls - false - -
- - dbo - JournalistArticle
- 16 - UpdateBy - Int - - 4 - int - false - 10 - 4 - 0 - NoNulls - false - -
- - dbo - JournalistArticle
- 17 - UpdateHost - VarChar - - 12 - varchar - false - 100 - 100 - 0 - NoNulls - false - -
-
- - - dbo - JournalistArticle
- PK_JournalistArticle - 1 - true - false - false - false - 1 - 8 - false - - - 1 - Id - true - - -
- - dbo - JournalistArticle
- IDX_JournalistArticle_Sport_Region_Published - 3 - false - false - false - false - 0 - 0 - false - - - 1 - SportIdPrimary - true - - - 2 - RegionIdPrimary - true - - - 3 - PublishedAt - true - - -
- - dbo - JournalistArticle
- IDX_JournalistArticle_User - 3 - false - false - false - false - 0 - 0 - false - - - 1 - UserAccountIdJournalist - true - - -
-
-
dbo Organisation @@ -4011,7 +4028,7 @@ false false 1 - 7 + 8 false @@ -4474,7 +4491,7 @@ false false 1 - 10 + 11 false @@ -4858,7 +4875,7 @@ false false 1 - 8 + 10 false @@ -5641,7 +5658,7 @@ false false 1 - 5 + 7 false