diff --git a/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs b/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs index 6249d93..e6572f9 100644 --- a/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs +++ b/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs @@ -48,6 +48,10 @@ namespace Saxonite.Net.Core.UnitTests.Web.Admin.App Assert.IsTrue(sessionData.ValidUserSession); Assert.AreNotEqual("", sessionData.User.DisplayName); + int idx = sessionData.NextItemIdx; + idx = sessionData.NextItemIdx; + idx = sessionData.NextItemIdx; + // Serialise session data using same method as base controller. String sessionDataJson = JsonConvert.SerializeObject(sessionData); Assert.AreNotEqual("", sessionDataJson); @@ -61,6 +65,8 @@ namespace Saxonite.Net.Core.UnitTests.Web.Admin.App Assert.IsNotNull(sessionDataDeserialized); // Validate deserialised values. + Assert.AreEqual(sessionData.SessionIdx, sessionDataDeserialized.SessionIdx); + Assert.AreEqual(sessionData.ItemIdx, sessionDataDeserialized.ItemIdx); Assert.AreEqual(App.SessionContext.Index, sessionDataDeserialized.SessionContext.Index); Assert.AreEqual(Sax.Application.Admin, sessionDataDeserialized.SessionContext.Application); Assert.AreEqual(SysId.ToInt(sessionDataDeserialized.User.UserAccountId), SysId.ToInt(sessionDataDeserialized.User.UserAccountId)); diff --git a/SaxoniteCoreUnitTestsOnline/UnitTests/Online/App/SaxSessionData_Online_Tester.cs b/SaxoniteCoreUnitTestsOnline/UnitTests/Online/App/SaxSessionData_Online_Tester.cs index c18acd0..17bbd70 100644 --- a/SaxoniteCoreUnitTestsOnline/UnitTests/Online/App/SaxSessionData_Online_Tester.cs +++ b/SaxoniteCoreUnitTestsOnline/UnitTests/Online/App/SaxSessionData_Online_Tester.cs @@ -77,6 +77,10 @@ namespace Saxonite.Net.Core.UnitTests.Web.Online.App sessionData.Filter.OrganisationIdMember = filterOrganisationIdMember; sessionData.Filter.OrganisationCaptionMember = filterOrganisationCaptionMember; + int idx = sessionData.NextItemIdx; + idx = sessionData.NextItemIdx; + idx = sessionData.NextItemIdx; + // Serialise session data using same method as base controller. String sessionDataJson = JsonConvert.SerializeObject(sessionData); Assert.AreNotEqual("", sessionDataJson); @@ -90,8 +94,13 @@ namespace Saxonite.Net.Core.UnitTests.Web.Online.App Assert.IsNotNull(sessionDataDeserialised); // Validate deserialised values. + Assert.AreEqual(sessionData.SessionIdx, sessionDataDeserialised.SessionIdx); + Assert.AreEqual(sessionData.ItemIdx, sessionDataDeserialised.ItemIdx); + Assert.AreEqual(sessionData.Base64IV_OnlineApp, sessionDataDeserialised.Base64IV_OnlineApp); Assert.AreEqual(App.SessionContext.Index, sessionDataDeserialised.SessionContext.Index); Assert.AreEqual(Sax.Application.Online, sessionDataDeserialised.SessionContext.Application); + + // User details. Assert.AreEqual(SysId.ToInt(sessionDataDeserialised.User.UserAccountId), SysId.ToInt(sessionDataDeserialised.User.UserAccountId)); Assert.AreEqual(SysId.ToInt(sessionData.User.UserAccountId), SysId.ToInt(sessionDataDeserialised.User.UserAccountId)); Assert.AreEqual(sessionData.User.EmailAddress, sessionDataDeserialised.User.EmailAddress); diff --git a/SaxoniteCoreWeb/Base/App/SaxSessionData_Web.cs b/SaxoniteCoreWeb/Base/App/SaxSessionData_Web.cs index 29e7b18..4472a99 100644 --- a/SaxoniteCoreWeb/Base/App/SaxSessionData_Web.cs +++ b/SaxoniteCoreWeb/Base/App/SaxSessionData_Web.cs @@ -10,6 +10,11 @@ namespace Saxonite.Net.Core.Web.Base.App public abstract class SaxSessionData_Web : SaxSessionData { //------------------------------------------------------------------- + // Private construction - for JSON deserialisation. + protected SaxSessionData_Web(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) : + base(sessionIdx, itemIdx, sessionContext) + { + } // Protected construction. protected SaxSessionData_Web(SaxSessionContext sessionContext, SaxUserAccount userAccount, List userRoles) : base(sessionContext, userAccount, userRoles) diff --git a/SaxoniteCoreWebAdmin/Admin/App/SaxSessionData_Admin.cs b/SaxoniteCoreWebAdmin/Admin/App/SaxSessionData_Admin.cs index c1f73d7..ea75943 100644 --- a/SaxoniteCoreWebAdmin/Admin/App/SaxSessionData_Admin.cs +++ b/SaxoniteCoreWebAdmin/Admin/App/SaxSessionData_Admin.cs @@ -15,7 +15,9 @@ namespace Saxonite.Net.Core.Web.Admin.App //------------------------------------------------------------------- // Construction. [JsonConstructor] - private SaxSessionData_Admin(SaxSessionContext sessionContext) : this(sessionContext, null, null) { } + private SaxSessionData_Admin(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) : + base(sessionIdx, itemIdx, sessionContext) + { } /// /// SessionData construction. /// SessionContext and UserAccount must be supplied. @@ -23,8 +25,7 @@ namespace Saxonite.Net.Core.Web.Admin.App /// public SaxSessionData_Admin(SaxSessionContext sessionContext, SaxUserAccount userAccount, List userRoles) : base(sessionContext, userAccount, userRoles) - { - } + { } //------------------------------------------------------------------- // Properties. diff --git a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx index be7962b..026d515 100644 --- a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx +++ b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx @@ -369,6 +369,9 @@ Yes + + Are you sure that this item should be removed? + No matching data has been found. @@ -414,6 +417,9 @@ Uploading {0}. + + Invalid image file uploaded + Only one image can be uploaded. diff --git a/SaxoniteCoreWebOnline/Online/App/SaxSessionData_Online.cs b/SaxoniteCoreWebOnline/Online/App/SaxSessionData_Online.cs index a62de02..622ceb3 100644 --- a/SaxoniteCoreWebOnline/Online/App/SaxSessionData_Online.cs +++ b/SaxoniteCoreWebOnline/Online/App/SaxSessionData_Online.cs @@ -3,7 +3,9 @@ using Newtonsoft.Json.Linq; 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 Saxonite.Net.Core.Web.Base.App; +using Saxonite.Net.Core.Web.Online.Controllers; using Saxonite.Net.Standard.Base.App; using Saxonite.Net.Standard.Base.Bus; using System; @@ -20,7 +22,9 @@ namespace Saxonite.Net.Core.Web.Online.App //------------------------------------------------------------------- // Construction. [JsonConstructor] - private SaxSessionData_Online(SaxSessionContext sessionContext) : this(sessionContext, null, null) { } + private SaxSessionData_Online(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) : + base(sessionIdx, itemIdx, sessionContext) + { } /// /// SessionData construction. /// SessionContext and UserAccount must be supplied. @@ -148,6 +152,10 @@ namespace Saxonite.Net.Core.Web.Online.App } public FilterData Filter { get; private set; } = new FilterData(); + //------------------------------------------------------------------- + // Online application encryption IV value - for consistent encryption during session. + public String Base64IV_OnlineApp { get; private set; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(SaxController_Online.Base64Key_OnlineApp); + //------------------------------------------------------------------- // JSON Deserialisation. [JsonExtensionData] diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs index afebfe0..26d88a6 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs @@ -148,7 +148,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers if (model.AccountContactImage.Count != 1) { SaLogger.Warn(fn + " Invalid number of image files uploaded: " + model.AccountContactImage.Count); - return Json(responseData.SetControlError("AccountContactImage", "Only one image can be uploaded.")); + return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.single"])); } IFormFile file = model.AccountContactImage[0]; @@ -163,7 +163,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers // Validate the image. ImageUtils.ImageConfig imageConfig = ImageUtils.VerifyImageData(imageData); if (!imageConfig.ValidImage) - return Json(responseData.SetControlError("AccountContactImage", "Invalid image file uploaded.")); + return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid"])); // Image belongs to the user's account. ItemId userItemId = GetUserItemId(SessionData.User.UserAccountId); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs index b458a74..891a39e 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ActivityController-Ajax.cs @@ -47,7 +47,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers /// Article activity info. public class ActivityResponseData_Article { - public ActivityResponseData_Article(SaxModel_Online model, SaxJournalistArticle article) + public ActivityResponseData_Article(SaxController_Online controller, SaxModel_Online model, SaxJournalistArticle article) { Headline = article.Headline; Summary = article.Summary; @@ -56,7 +56,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers PublishedOnFmt = model.Localiser.FormatDate(article.PublishedAt); SaxJournalistArticle.ContentData content = SaxJournalistArticle.ExtractContent(article.BodyData); foreach (SaxJournalistArticle.ContentData.SegmentData segment in content.Segments) - Content.Segments.Add(new ContentData.SegmentData(segment)); + Content.Segments.Add(new ContentData.SegmentData(controller, segment)); } public String Headline { get; set; } public String Summary { get; set; } @@ -67,15 +67,29 @@ namespace Saxonite.Net.Core.Web.Online.Controllers { public class SegmentData { - public SegmentData(SaxJournalistArticle.ContentData.SegmentData segment) + public SegmentData(SaxController_Online controller, SaxJournalistArticle.ContentData.SegmentData segment) { - Body.Html = segment.Body.Html; + if (segment.Body.IsValid()) + { + Body = new BodyData(); + Body.Html = segment.Body.Html; + } + else if (segment.Image.IsValid()) + { + Image = new ImageData(); + Image.Link = JournalistController.GetArticleImageLink(controller, segment.Image.ItemImageId); + } } public class BodyData { public String Html { get; set; } } - public BodyData Body { get; } = new BodyData(); + public BodyData Body { get; } + public class ImageData + { + public String Link { get; set; } + } + public ImageData Image { get; } } public List Segments { get; } = new List(); } @@ -214,7 +228,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers SaLogger.Warn(fn + " Article not found for Activity Id: " + itemId.ToString() + "." + getLogSuffix()); return Json(responseData); } - responseData.Article = new ActivityResponseData_Article(model, article); + responseData.Article = new ActivityResponseData_Article(this, model, article); } else if (itemType == Sax.DataItemType.OrganisationOpportunity) { diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Image.cs b/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs similarity index 77% rename from SaxoniteCoreWebOnline/Online/Controllers/AccountController-Image.cs rename to SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs index ec6c3fb..387c2ab 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Image.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ImageController.cs @@ -19,6 +19,7 @@ using System.IO; using System.Drawing; using Sarand.Net.Standard.Base.Core; using Microsoft.Net.Http.Headers; +using System.Collections.Specialized; namespace Saxonite.Net.Core.Web.Online.Controllers { @@ -118,6 +119,42 @@ namespace Saxonite.Net.Core.Web.Online.Controllers return File(itemImage.ImageData, itemImage.ContentType); } + //------------------------------------------------------------------- + // Journalist Article image + //------------------------------------------------------------------- + public static String ParamName_JournalistArticleImageEncrypted { get; } = "jaie"; + public static String ParamName_ItemImageId { get; } = "iii"; + /// + /// Get the specified Journalist Article Image. + /// Encrypted parameters: + /// - iii: item Image Id. + /// + [HttpGet] + [Route("Image/Journalist/Article")] + public IActionResult GetJournalistArticleImage(String jaie) + { + String fn = GetType().Name + ".GetJournalistArticleImage"; + + // 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); + if (parameters.Count<1) return Forbid(); + + // Item Image. + SysId itemImageId = parameters.Get(ParamName_ItemImageId).ToSysId(); + if (!SysId.IsValid(itemImageId)) return Forbid(); + SaxItemImage itemImage = ItemDataMgr.GetItemImageById(itemImageId); + if (itemImage == null) + return NotFound(); + + // Construct response. + return File(itemImage.ImageData, itemImage.ContentType); + } + //------------------------------------------------------------------- } //======================================================================= diff --git a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs index d1779b2..a52732f 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/JournalistController-Ajax.cs @@ -1,15 +1,20 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; 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 Sarand.Net.Standard.Base.Helpers; using Sarand.Net.Standard.Base.Utils; +using Saxonite.Net.Core.Web.Online.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.Consoles; using System; using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; using System.Linq; using System.Threading.Tasks; @@ -28,12 +33,19 @@ namespace Saxonite.Net.Core.Web.Online.Controllers } public class ArticleContentSegmentData { - public ArticleContentSegmentBodyData Body { get; } = new ArticleContentSegmentBodyData(); + public ArticleContentSegmentBodyData Body { get; set; } + public ArticleContentSegmentImageData Image { get; set; } } public class ArticleContentSegmentBodyData { public String Html { get; set; } } + public class ArticleContentSegmentImageData + { + public int ItemImageId { get; set; } + public int ImageIdx { get; set; } + public String ImageLink { get; set; } + } //------------------------------------------------------------------- // Journalist Article data. @@ -80,7 +92,17 @@ namespace Saxonite.Net.Core.Web.Online.Controllers foreach (var contentSegment in articleContent.Segments) { var segmentData = new ArticleContentSegmentData(); - segmentData.Body.Html = contentSegment.Body.Html; + if (contentSegment.Body.IsValid()) + { + segmentData.Body = new ArticleContentSegmentBodyData(); + segmentData.Body.Html = contentSegment.Body.Html; + } + else if (contentSegment.Image.IsValid()) + { + segmentData.Image = new ArticleContentSegmentImageData(); + segmentData.Image.ItemImageId = SysId.ToInt(contentSegment.Image.ItemImageId); + segmentData.Image.ImageLink = GetArticleImageLink(contentSegment.Image.ItemImageId); + } data.Content.Segments.Add(segmentData); } } @@ -102,16 +124,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers AjaxResponse_ArticleList responseData = new AjaxResponse_ArticleList(); // 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); + if (!UserIsJournalist) return GetAjaxResult_GoHome(responseData); + SaxSessionData_Online sessionData = SessionData_Online; // Item filter. SaxJournalistArticle.Params prmArticle = new SaxJournalistArticle.Params(); - prmArticle.UserAccountIdsJournalistIncluded.Add(SessionData.User.UserAccountId); + prmArticle.UserAccountIdsJournalistIncluded.Add(sessionData.User.UserAccountId); prmArticle.ArticleFilter = model.Filter.Article; prmArticle.StatusCat = SaxJournalistArticle.StatusCat.NotDeleted; model.DataItemTotal = (ulong)ActivityMgr.GetJournalistArticleCount(prmArticle); @@ -204,12 +224,144 @@ namespace Saxonite.Net.Core.Web.Online.Controllers return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); } + // Delete upload images. + SaxItemImage.Params prmItemImage = new SaxItemImage.Params(); + prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.JournalistArticle, articleId)); + prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.ArticleUpload); + prmItemImage.StatusCat = SaxItemImage.StatusCat.NotDeleted; + foreach (SaxItemImage itemImage in ItemDataMgr.GetItemImageList(prmItemImage)) + { + itemImage.SessionUid = 0; + itemImage.ImageUid = 0; + itemImage.Status = SaStatus.Deleted; + ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo); + } + // Construct response. PopulateArticleResponseData(model, article, responseData.Article); responseData.Success = true; return Json(responseData); } + //------------------------------------------------------------------- + // Journalist - Upload Article Image. + //------------------------------------------------------------------- + public class AjaxResponse_UploadArticleImage : AjaxResponse_Data + { + public ArticleContentSegmentData Segment { get; set; } + public String UploadMsg { get; set; } + } + // Ajax request. + [HttpPost] + [Route("Journalist/Ajax/UploadArticleImage")] + public IActionResult UploadArticleImage(Model_Journalist model) + { + String fn = GetType().Name + ".UploadArticleImage"; + AjaxResponse_UploadArticleImage responseData = new AjaxResponse_UploadArticleImage(); + String messageTitle = Localiser["journalist.caption.article"]; + + // Validate session and referrer. + if (!ValidReferer) return Forbid(); + if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); + SaxSessionData_Online sessionData = SessionData_Online; + + // Validate number of images. + if (model.ArticleImage.IsEmpty()) + { + SaLogger.Warn(fn + " No image file supplied for upload"); + return Json(responseData); + } + if (model.ArticleImage.Count != 1) + { + SaLogger.Warn(fn + " Invalid number of image files uploaded: " + model.ArticleImage.Count); + return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.single"])); + } + IFormFile file = model.ArticleImage[0]; + + // Image properties. + byte[] imageData = null; + using (MemoryStream fileStream = new MemoryStream()) + { + file.CopyTo(fileStream); + imageData = fileStream.ToArray(); + } + + // Validate the image. + ImageUtils.ImageConfig imageConfig = ImageUtils.VerifyImageData(imageData); + if (!imageConfig.ValidImage) + return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid"])); + + // 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 userItemId = new ItemId((short)Sax.DataItemType.UserAccount, sessionData.User.UserAccountId); + ItemId imageItemId = SysId.IsValid(articleId) ? articleItemId : userItemId; + + // Store uploaded image as 'Upload' - awaiting confirmation that the article details are to be saved. + // NB Reuse any existing deleted article upload image to avoid creating new images unless necessary. + SaxItemImage.Params prmItemImage = new SaxItemImage.Params(); + prmItemImage.ItemIdsIncluded.Add(imageItemId); + prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article); + prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.ArticleUpload); + prmItemImage.StatusCat = SaxItemImage.StatusCat.Deleted; + prmItemImage.ResultsPaging.PageLength = 1; + prmItemImage.ResultsPaging.PageNo = 1; + List itemImages = ItemDataMgr.GetItemImageList(prmItemImage); + SaxItemImage itemImage = !itemImages.IsEmpty() ? itemImages[0] : null; + if (itemImage == null) + itemImage = ItemDataMgr.CreateItemImage(imageItemId, Sax.ImageType.ArticleUpload); + itemImage.ImageType = Sax.ImageType.ArticleUpload; + itemImage.Filename = file.FileName; + itemImage.Mime = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType).ToString().ToLower(); + itemImage.ContentType = file.ContentType; + itemImage.Width = imageConfig.Width; + itemImage.Height = imageConfig.Height; + itemImage.ImageData = imageData; + itemImage.SessionUid = sessionData.SessionIdx; + itemImage.ImageUid = sessionData.NextItemIdx; + itemImage.Status = SaxItemImage.DefaultStatus; + + if (!SysId.IsValid(itemImage.Id)) + { + if (!ItemDataMgr.InsertItemImage(itemImage, DbUpdateInfo)) + { + SaLogger.Warn(fn + " Failed to insert uploaded image - " + ItemDataMgr.ErrorStateMessage); + return Json(responseData.SetControlError("ArticleImage", Localiser["msg.error.item.insert.failed"])); + } + } + else + { + if (!ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo)) + { + SaLogger.Warn(fn + " Failed to update uploaded image - " + ItemDataMgr.ErrorStateMessage); + return Json(responseData.SetControlError("ArticleImage", Localiser["msg.error.item.insert.failed"])); + } + } + + // Segment image info. + responseData.Segment = new ArticleContentSegmentData(); + responseData.Segment.Image = new ArticleContentSegmentImageData(); + responseData.Segment.Image.ImageLink = GetArticleImageLink(itemImage.Id); + responseData.Segment.Image.ImageIdx = itemImage.ImageUid; + + // Complete response. + //responseData.SetNotification(messageTitle, "Image uploaded."); + responseData.Success = true; + return Json(responseData); + } + private String GetArticleImageLink(SysId itemImageId) + { + return GetArticleImageLink(this, itemImageId); + } + public static String GetArticleImageLink(SaxController_Online controller, SysId itemImageId) + { + String imageLink = "Image/Journalist/Article?"; + NameValueCollection parameters = new NameValueCollection(); + parameters.Add(ImageController.ParamName_ItemImageId, SysId.ToString(itemImageId)); + return imageLink + ImageController.ParamName_JournalistArticleImageEncrypted + "=" + SaxController_Online.EncryptOnlineParams(controller, parameters); + } + //------------------------------------------------------------------- // Store Article ajax request. //------------------------------------------------------------------- @@ -222,12 +374,10 @@ namespace Saxonite.Net.Core.Web.Online.Controllers AjaxResponse_Article responseData = new AjaxResponse_Article(); // 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); + if (!UserIsJournalist) return GetAjaxResult_GoHome(responseData); + SaxSessionData_Online sessionData = SessionData_Online; // Validate item properties. model.ValidateArticleData(responseData); @@ -258,7 +408,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers // Create new item if required. if (article == null) - article = ActivityMgr.CreateJournalistArticle(SessionData.User.UserAccountId); + article = ActivityMgr.CreateJournalistArticle(sessionData.User.UserAccountId); // Populate item properties. if (model.ArticleRegionId != null) @@ -272,20 +422,18 @@ namespace Saxonite.Net.Core.Web.Online.Controllers if (model.ArticleStatusCode != null) article.Status = model.ArticleStatus; - // Content. - if (model.ArticleContentSegments != null) - { - SaxJournalistArticle.ContentData articleContent = new SaxJournalistArticle.ContentData(); - foreach (String contentSegment in model.ArticleContentSegments) - { - if (StringUtil.IsEmpty(contentSegment)) continue; - var segment = articleContent.AddSegment(); - segment.Body.Html = contentSegment; - } - article.BodyData = SaxJournalistArticle.GetContentData(articleContent); - } + // Retrieve all article images - before new article is created as uploaded images are assigned to user first. + SaxItemImage.Params prmItemImage = new SaxItemImage.Params(); + if (SysId.IsValid(article.Id)) + prmItemImage.ItemIdsIncluded.Add(article.GetItemId()); + else + prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.UserAccount, sessionData.User.UserAccountId)); + prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article); + prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.ArticleUpload); + prmItemImage.StatusCat = SaxItemImage.StatusCat.NotDeleted; + List itemImages = ItemDataMgr.GetItemImageList(prmItemImage); - // Store item. + // 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)) @@ -294,18 +442,76 @@ namespace Saxonite.Net.Core.Web.Online.Controllers return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ActivityMgr.ErrorStateMessage)); } } - else + + // Content. + if (model.ArticleContentSegmentBodies != null) { - if (!ActivityMgr.UpdateJournalistArticle(article, DbUpdateInfo)) + SaxJournalistArticle.ContentData articleContent = new SaxJournalistArticle.ContentData(); + for (int segmentIdx = 0; segmentIdx < model.ArticleContentSegmentBodies.Count; segmentIdx++) { - 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"] + "\n\n" + ActivityMgr.ErrorStateMessage)); + String segmentBody = model.ArticleContentSegmentBodies[segmentIdx]; + String segmentItemImageId = model.ArticleContentSegmentItemImageIds.Count > segmentIdx ? model.ArticleContentSegmentItemImageIds[segmentIdx] : ""; + String segmentImageIdx = model.ArticleContentSegmentImageIdxs.Count > segmentIdx ? model.ArticleContentSegmentImageIdxs[segmentIdx] : ""; + if (!StringUtil.IsEmpty(segmentBody)) + { + // HTML Body segment. + var segment = articleContent.AddSegment(); + segment.Body.Html = segmentBody; + } + else if (!StringUtil.IsEmpty(segmentItemImageId) || !StringUtil.IsEmpty(segmentImageIdx)) + { + SysId itemImageId = segmentItemImageId.ToSysId(); + int imageIdx = StringUtil.ToInt(segmentImageIdx); + + // Check for new image first. + SaxItemImage itemImage = itemImages.GetItemImageBySessionImage(sessionData.SessionIdx, imageIdx); + if (itemImage == null) + itemImage = itemImages.GetItemImageById(itemImageId); + if (itemImage != null) + { + // Ensure that the image is correctly identified for the Article. + itemImage.ItemId = article.GetItemId(); + itemImage.ImageType = Sax.ImageType.Article; + itemImage.SessionUid = 0; + itemImage.ImageUid = 0; + itemImage.Status = SaxItemImage.DefaultStatus; + if (ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo)) + { + // Assign the image segment to the article. + var segment = articleContent.AddSegment(); + segment.Image.ItemImageId = itemImage.Id; + // Remove the image from the list as it's now been handled. + itemImages.Remove(itemImage); + } + else + SaLogger.Warn(fn + " Failed to update article image: " + ItemDataMgr.ErrorStateMessage); + } + else + SaLogger.Warn(fn + " Failed to identify article image. ItemImageId: " + itemImageId.ToInt() + ". SessionIdx: " + sessionData.SessionIdx + ". ImageIdx: " + imageIdx + "."); + } } + article.BodyData = SaxJournalistArticle.GetContentData(articleContent); + } + + // Update the Article. + if (!ActivityMgr.UpdateJournalistArticle(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"] + "\n\n" + ActivityMgr.ErrorStateMessage)); } // Store Article Activity Index data. ActivityConsole.StoreActivityIndex(article, DbUpdateInfo); + // Delete remaining images as they are no longer required. + foreach (SaxItemImage itemImage in itemImages) + { + itemImage.SessionUid = 0; + itemImage.ImageUid = 0; + itemImage.Status = SaStatus.Deleted; + ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo); + } + // Construct response. PopulateArticleResponseData(model, article, responseData.Article); responseData.Success = true; diff --git a/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs b/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs index fd7431c..ac759a3 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/SaxController_Online.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Threading.Tasks; +using System.Web; namespace Saxonite.Net.Core.Web.Online.Controllers { @@ -236,8 +237,27 @@ namespace Saxonite.Net.Core.Web.Online.Controllers return keepLoggedInParams; } + //------------------------------------------------------------------- + // Parameter encryption, eg. for images. + //------------------------------------------------------------------- + // Encryption key is the same for all users but a different IV value is generated for each session so that the links/parameters cannot be shared. + public static String Base64Key_OnlineApp { get; } = SacsEncryptionHelper.EncodePlainKey("", SacsEncryptionHelper.KeyLength); + protected String EncryptOnlineParams(NameValueCollection parameters) + { + return HttpUtility.UrlEncode(EncryptParameters(parameters, SessionData_Online.Base64IV_OnlineApp, Base64Key_OnlineApp)); + } + public static String EncryptOnlineParams(SaxController_Online controller, NameValueCollection parameters) + { + return controller.EncryptOnlineParams(parameters); + } + protected NameValueCollection ExtractOnlineParams(String encryptedParams) + { + return DecryptParameters(encryptedParams, SessionData_Online.Base64IV_OnlineApp, Base64Key_OnlineApp); + } + //------------------------------------------------------------------- // Logging. + //------------------------------------------------------------------- protected String getLogSuffix() { List logSuffix = new List(); diff --git a/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs b/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs index 8607b88..08f412b 100644 --- a/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs +++ b/SaxoniteCoreWebOnline/Online/Models/Model_Journalist.cs @@ -1,4 +1,5 @@ -using Sarand.Net.Standard.Base.App; +using Microsoft.AspNetCore.Http; +using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; @@ -49,7 +50,11 @@ namespace Saxonite.Net.Core.Web.Online.Models public String ArticleStatusCode { get; set; } public SaStatus ArticleStatus { get { return SacsSystem.GetStatusForCode(ArticleStatusCode); } } // Article content. - public List ArticleContentSegments { get; set; } + public List ArticleContentSegmentBodies { get; set; } + public List ArticleContentSegmentItemImageIds { get; set; } + public List ArticleContentSegmentImageIdxs { get; set; } + // Article images. + public List ArticleImage { get; set; } //------------------------------------------------------------------- // Validation. diff --git a/SaxoniteCoreWebOnline/Views/Account/Profile-Contact.cshtml b/SaxoniteCoreWebOnline/Views/Account/Profile-Contact.cshtml index 8bec208..fa91a36 100644 --- a/SaxoniteCoreWebOnline/Views/Account/Profile-Contact.cshtml +++ b/SaxoniteCoreWebOnline/Views/Account/Profile-Contact.cshtml @@ -191,6 +191,6 @@ } - + diff --git a/SaxoniteCoreWebOnline/Views/Home/Index.cshtml b/SaxoniteCoreWebOnline/Views/Home/Index.cshtml index de77341..8ab23bc 100644 --- a/SaxoniteCoreWebOnline/Views/Home/Index.cshtml +++ b/SaxoniteCoreWebOnline/Views/Home/Index.cshtml @@ -85,6 +85,9 @@ else
+
+ +
diff --git a/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml b/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml index 9382858..3c3ca0f 100644 --- a/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml +++ b/SaxoniteCoreWebOnline/Views/Journalist/Panel-ArticleDialog.cshtml @@ -82,13 +82,30 @@
- -
-
+ @* Inputs with same name for every segment to ensure they are uploaded as a list. *@ + + + + @* Image drop panel *@ +
+
Drop image here
+ +
+
+ @* Segment details *@ +
+ @* Segment body *@ +
+
+ +
+
+ @* Segment actions *@
-
-
+
+
+
@@ -101,6 +118,35 @@ } +
+ @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectArticleImage", @class = "sax-form", @onSubmit = "return false;" })) + { + +
+
+
+
@Localiser["label.image"]
+
+
+
+
+
+
+
+
+
+
+ } +
+ + diff --git a/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml b/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml index ef5b46e..ae9b26d 100644 --- a/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml +++ b/SaxoniteCoreWebOnline/Views/Shared/_Layout.cshtml @@ -74,6 +74,7 @@ sax.lbl.availableCharacters = '@Localiser.GetJavascriptText("label.characters.count", "{0}")'; sax.lbl.noneSelected = '@Localiser.GetJavascriptText("label.selected.none")'; sax.lbl.numberSelected = '@Localiser.GetJavascriptText("label.selected.count", "{0}")'; + sax.msg.itemRemoveConfirm = '@Localiser.GetJavascriptText("msg.confirm.item.remove")'; sax.msg.signOutConfirm = '@Localiser.GetJavascriptText("security.msg.signout.confirm")'; sax.msg.somethingGoneWrong = '@Localiser.GetJavascriptText("msg.something.gone.wrong")'; sax.msg.dataRefreshing = '@Localiser.GetJavascriptText("msg.data.refreshing")'; diff --git a/SaxoniteCoreWebOnline/wwwroot/css/sax-account.css b/SaxoniteCoreWebOnline/wwwroot/css/sax-account.css index dc9f30e..9e2b749 100644 --- a/SaxoniteCoreWebOnline/wwwroot/css/sax-account.css +++ b/SaxoniteCoreWebOnline/wwwroot/css/sax-account.css @@ -89,7 +89,12 @@ border-radius: 4px; } -.sax-profile #pnlContactImageDrop.sax-panel-drop.sax-dragging +.sax-profile #pnlContactImageDrop.sax-panel-drop * +{ + pointer-events: none; +} + +.sax-profile #pnlContactImageDrop.sax-panel-drop.sax-file-drag { border-color: var(--color-profile); } diff --git a/SaxoniteCoreWebOnline/wwwroot/css/sax-home.css b/SaxoniteCoreWebOnline/wwwroot/css/sax-home.css index 5711a05..ddb97da 100644 --- a/SaxoniteCoreWebOnline/wwwroot/css/sax-home.css +++ b/SaxoniteCoreWebOnline/wwwroot/css/sax-home.css @@ -69,6 +69,16 @@ { } +#dlgActivity .sax-panel-item.Article .ArticleContentSegment +{ +} + +#dlgActivity .sax-panel-item.Article .ArticleContentSegmentImage img +{ + max-width:75%; + max-height:400px; +} + .ui-dialog.sax-dialog-activity button.ActivityReaction { min-width: 80px; diff --git a/SaxoniteCoreWebOnline/wwwroot/css/sax-jrn-art.css b/SaxoniteCoreWebOnline/wwwroot/css/sax-jrn-art.css index 602b9b1..4dff8f2 100644 --- a/SaxoniteCoreWebOnline/wwwroot/css/sax-jrn-art.css +++ b/SaxoniteCoreWebOnline/wwwroot/css/sax-jrn-art.css @@ -23,26 +23,26 @@ border-radius: 6px; } -.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment-body { - min-height: 160px; - max-height: 320px; + min-height: 150px; + max-height: 300px; margin: 0; padding: 4px; background-color: #e0efff; border: 2px solid #e0efff; border-radius: 4px; overflow-y: scroll; - z-index:1000; + z-index: 1000; } -.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment:hover .sax-article-segment -/*,.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment:focus*/ +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment:hover .sax-article-segment-body +/*,.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment-body:focus*/ { border: 2px solid #c0d0ff; } -.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment.mce-edit-focus +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment-body.mce-edit-focus { margin-top: 48px; } @@ -52,4 +52,58 @@ z-index: 1000; } +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment.sax-file-drag +{ + border-color: var(--color-article); +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-actions +{ + margin: 2px 0; +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-action +{ + margin: 0 2px; + padding: 2px 2px; + border-radius: 4px; +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-action:hover +{ + background-color: var(--color-article-pale); +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-action img +{ +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-panel-file-drop +{ + display: none; +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment.sax-file-drag .sax-panel-file-drop +{ + display: block; + margin: 4px; + border: 1px dashed var(--color-article); +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment.ArticleImage .sax-article-segment-body +{ + display: none; +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment.ArticleImage .sax-article-segment-image +{ + display: block; +} + +.sax-article.ArticleContent .sax-article-content .sax-panel-item.ArticleSegment .sax-article-segment-image img +{ + max-width: 320px; + max-height: 160px; +} + /* The End */ diff --git a/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-24.png b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-24.png new file mode 100644 index 0000000..1c9c7e3 Binary files /dev/null and b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-24.png differ diff --git a/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-32.png b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-32.png new file mode 100644 index 0000000..b3cc845 Binary files /dev/null and b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-32.png differ diff --git a/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-48.png b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-48.png new file mode 100644 index 0000000..15e066e Binary files /dev/null and b/SaxoniteCoreWebOnline/wwwroot/img/action/image-add-48.png differ diff --git a/SaxoniteCoreWebOnline/wwwroot/js/sax-account.js b/SaxoniteCoreWebOnline/wwwroot/js/sax-account.js index 0d6ab13..55f37e1 100644 --- a/SaxoniteCoreWebOnline/wwwroot/js/sax-account.js +++ b/SaxoniteCoreWebOnline/wwwroot/js/sax-account.js @@ -5,6 +5,7 @@ (function (win, doc, undef) { "use strict"; + sax.classFileDrag = 'sax-file-drag'; sax.profile = { contact: {}, sports: {}, organisations: {} }; //-------------------------------------------------------------- @@ -106,7 +107,7 @@ } sax.onDropContactImageFile = function (file, context) { - //sax.debug('onDropContactImageFile', file); + //sax.debug('onDropContactImageFile', file, context); if (file.size > sax.maxProfileImageSize) return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileSizeMax.format(sax.formatFileSize(sax.maxProfileImageSize))); if (file.type != 'image/jpg' && file.type != 'image/jpeg' && file.type != 'image/png') return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileTypeInvalid.format(sax.getFileType(file))); $(".UploadMessage", context).text(sax.msg.uploadingFile.format(file.name)); @@ -123,7 +124,7 @@ sax.handleContactImageUploadResponse = function (response) { let context = sax.data.contactImageUploadContext; - sax.debug('handleContactImageUploadResponse', response, context); + //sax.debug('handleContactImageUploadResponse', response, context); if (!response) return; var $section = $('.sax-panel-section.ProfileContact'); sax.refreshControlValues(response.controlValues, context); @@ -340,9 +341,9 @@ sax.$pnl.contactImageDrag = $('#pnlContactImageDrop') .on("dragenter", function (evt) { sax.haltEvent(evt); }) - .on("dragover", function (evt) { sax.haltEvent(evt); if (!sax.$pnl.contactImageDrag.hasClass('sax-dragging')) sax.$pnl.contactImageDrag.addClass('sax-dragging'); }) - .on("dragleave", function (evt) { sax.haltEvent(evt); sax.$pnl.contactImageDrag.removeClass('sax-dragging'); }) - .on("drop", function (evt) { sax.haltEvent(evt); sax.$pnl.contactImageDrag.removeClass('sax-dragging'); sax.onDropContactImage(evt); }); + .on("dragover", function (evt) { sax.haltEvent(evt); if (!sax.$pnl.contactImageDrag.hasClass(sax.classFileDrag)) sax.$pnl.contactImageDrag.addClass(sax.classFileDrag); }) + .on("dragleave", function (evt) { sax.haltEvent(evt); sax.$pnl.contactImageDrag.removeClass(sax.classFileDrag); }) + .on("drop", function (evt) { sax.haltEvent(evt); sax.$pnl.contactImageDrag.removeClass(sax.classFileDrag); sax.onDropContactImage(evt); }); $('.sax-panel-section.ProfileSports .sax-action.sax-add').on('click', function (evt) { sax.addProfileSport(); }); var opt = sax.dlgOpts(); diff --git a/SaxoniteCoreWebOnline/wwwroot/js/sax-home.js b/SaxoniteCoreWebOnline/wwwroot/js/sax-home.js index 29ce7a7..5128c77 100644 --- a/SaxoniteCoreWebOnline/wwwroot/js/sax-home.js +++ b/SaxoniteCoreWebOnline/wwwroot/js/sax-home.js @@ -23,7 +23,7 @@ } sax.doRefreshResults = function (response) { - sax.debug('doRefreshResults', response); + //sax.debug('doRefreshResults', response); delete sax.awaitingRefreshResponse; var $results = $('.sax-panel-results'); var $msgs = $('.sax-panel-messages', $results).hide().empty(); @@ -69,7 +69,7 @@ let $frm = $('#frmActivityId'); $('.ActivityType', $frm).val(item.itemType); $('.ActivityIdx', $frm).val(item.itemIdx); - sax.activity = { item:item, $item: $item }; + sax.activity = { item: item, $item: $item }; sax.ajax.activityInfo = sax.ajax.activityInfo || { url: sax.url.base + 'Activity/Ajax/GetInfo', formId: 'frmActivityId', callbackFn: sax.showActivityDetails, noWaitIcon: true }; sax.doAjaxRequest(sax.ajax.activityInfo, 50); } @@ -81,14 +81,24 @@ if (item = response.article) { let $itm = $('.sax-panel-item-template .sax-panel-item.Article').clone(); + let $segs = $('.ArticleContentSegments', $itm); $('.ArticleHeadline', $itm).text(item.headline); $('.ArticleSummary', $itm).text(item.summary).toggle(!!item.summary); let segs = item.content.segments; for (let segIdx = 0; segIdx < segs.length; segIdx++) { let seg = segs[segIdx]; - let $seg = $('.sax-panel-item-template .sax-panel-item.ArticleContentSegment').clone().html(seg.body.html); - $('.ArticleContentSegments', $itm).append($seg); + if (seg.body) + { + let $seg = $('.sax-panel-item-template .sax-panel-item.ArticleContentSegment').clone().html(seg.body.html); + $seg.appendTo($segs); + } + if (seg.image) + { + let $seg = $('.sax-panel-item-template .sax-panel-item.ArticleContentSegmentImage').clone(); + $('img', $seg).prop('src', seg.image.link); + $seg.appendTo($segs); + } } $act.append($itm); } diff --git a/SaxoniteCoreWebOnline/wwwroot/js/sax-jrn-art.js b/SaxoniteCoreWebOnline/wwwroot/js/sax-jrn-art.js index 6b393a9..fafaaeb 100644 --- a/SaxoniteCoreWebOnline/wwwroot/js/sax-jrn-art.js +++ b/SaxoniteCoreWebOnline/wwwroot/js/sax-jrn-art.js @@ -7,6 +7,7 @@ "use strict"; sax.itemIdPrefix = 'Itm_'; sax.segIdPrefix = 'Seg_'; + sax.classFileDrag = 'sax-file-drag'; let ac = sax.articleContent = sax.articleContent || {}; //-------------------------------------------------------------- @@ -68,16 +69,16 @@ } sax.populateArticleContent = function (content) { - sax.debug('populateArticleContent', content); + //sax.debug('populateArticleContent', content); ac.$segList.empty(); ac.segIdx = 0; - let segments = content.segments || [{}]; - if (!segments.length) segments.push({}); + let segments = content.segments || []; + if (!segments.length) segments.push({ body: {}}); for (let segIdx = 0; segIdx < segments.length; segIdx++) sax.addContentSegment(segments[segIdx]); } - sax.addContentSegment = function (seg) + sax.addContentSegment = function (seg, idxAfter, idxBefore) { let idx = ++ac.segIdx; let segId = sax.segmentId(idx); @@ -86,57 +87,90 @@ return; } let $seg = $('.sax-panel-item-template .sax-panel-item.ArticleSegment', ac.$content).clone().prop('id', segId) - let segBody = seg.body || {}; - $('.sax-article-segment', $seg).html(segBody.html); - $('input.ArticleContentSegment', $seg).val(segBody.html); - ac.$segList.append($seg); - $('.sax-action.sax-add', $seg).on('click', function () { sax.addContentSegment({}, idx); }); + if (seg.body) + { + $('.sax-article-segment-body', $seg).html(seg.body.html); + $('input.ArticleContentSegmentBody', $seg).val(seg.body.html); + } + else if (seg.image) + { + $seg.addClass("ArticleImage"); + $('input.ArticleContentSegmentItemImageId', $seg).val(seg.image.itemImageId); + $('input.ArticleContentSegmentImageIdx', $seg).val(seg.image.imageIdx); + $('.sax-article-segment-image', $seg).show().find('img').prop('src', seg.image.imageLink); + $('.sax-action.sax-add-image', $seg).hide(); + } + $('.sax-action.sax-add', $seg).on('click', function () { sax.addContentSegment({ body: {} }, idx); }); + $('.sax-action.sax-add-image', $seg).on('click', function () { sax.selectArticleImage(idx); }); $('.sax-action.sax-up', $seg).on('click', function () { sax.moveUpContentSegment(idx); }); $('.sax-action.sax-down', $seg).on('click', function () { sax.moveDownContentSegment(idx); }); $('.sax-action.sax-delete', $seg).on('click', function () { sax.deleteContentSegment(idx); }); - tinymce.init({ - branding: false, - elementpath: true, - menubar: false, - inline: true, - //skin: 'small', - //icons: 'small', - selector: '#' + segId + ' .sax-article-segment', - setup: function (ed) - { - ed.on('blur', function (e) + let $segAfter = $('#' + sax.segmentId(idxAfter)); + let $segBefore = $('#' + sax.segmentId(idxBefore)); + if ($segAfter.length) $seg.insertAfter($segAfter); + else if ($segBefore.length) $seg.insertBefore($segBefore); + else ac.$segList.append($seg); + + if (seg.body) + { + tinymce.init({ + branding: false, + elementpath: true, + menubar: false, + inline: true, + //skin: 'small', + //icons: 'small', + selector: '#' + segId + ' .sax-article-segment-body', + setup: function (ed) { - let ed = tinymce.get(e.target.id); - let $ed = $('#' + ed.id); - let $seg = $ed.closest('.sax-panel-item.ArticleSegment'); - $(".sax-article-segment p", $seg).each(function (i,el) { if ($.trim($(el).text()) == "") { $(el).remove(); } }); - let $inp = $seg.find('input.ArticleContentSegment').val(ed.getContent()); - sax.debug('blur Id: ' + e.target.id + '. Val: ' + $inp.val()); - }); - }, - /* - plugins: [ - //'link', - 'lists', - //'powerpaste', - //'autolink', - //'tinymcespellchecker' - ], - //powerpaste_word_import: 'clean', - //powerpaste_html_import: 'clean', - */ - toolbar: [ - 'undo redo | bold italic underline | fontselect fontsizeselect', - 'forecolor backcolor | alignleft aligncenter alignright alignfull | numlist bullist outdent indent' - ], - valid_elements: 'p[style],strong,em,span[style],a[href],ul,ol,li', - valid_styles: { '*': 'font-size,font-family,color,text-decoration,text-align' }, - }); + ed.on('focus', function (e) + { + ed.notificationManager.close(); + }); + ed.on('blur', function (e) + { + let ed = tinymce.get(e.target.id); + let $ed = $('#' + ed.id); + let $seg = $ed.closest('.sax-panel-item.ArticleSegment'); + $(".sax-article-segment-body p", $seg).each(function (i, el) { if ($.trim($(el).text()) == "") { $(el).remove(); } }); + let $inp = $seg.find('input.ArticleContentSegmentBody').val(ed.getContent()); + //sax.debug('blur Id: ' + e.target.id + '. Val: ' + $inp.val()); + }); + }, + plugins: [ + //'paste image' + //'link', + //'lists', + //'powerpaste', + //'autolink', + //'tinymcespellchecker' + ], + //paste_block_drop: true, + //powerpaste_block_drop: true, + /* + //powerpaste_word_import: 'clean', + //powerpaste_html_import: 'clean', + */ + toolbar: [ + 'undo redo | bold italic underline | fontselect fontsizeselect', + 'forecolor backcolor | alignleft aligncenter alignright alignfull | numlist bullist outdent indent' + ], + valid_elements: 'p[style],strong,em,span[style],a[href],ul,ol,li', + valid_styles: { '*': 'font-size,font-family,color,background-color,text-decoration,text-align' }, + }); + + $seg.dragCount = 0; + $seg + .on("dragenter", function (evt) { $seg.dragCount++; sax.haltEvent(evt); }) + .on("dragover", function (evt) { sax.haltEvent(evt); if (!$seg.hasClass(sax.classFileDrag)) $seg.addClass(sax.classFileDrag); }) + .on("dragleave", function (evt) { $seg.dragCount--; sax.haltEvent(evt); if (!$seg.dragCount) $seg.removeClass(sax.classFileDrag); }) + .on("drop", function (evt) { sax.haltEvent(evt); $seg.removeClass(sax.classFileDrag); sax.onDropArticleImage(evt, idx, $seg); }); + } } sax.moveUpContentSegment = function (idx) { - sax.debug('moveUpContentSegment(' + idx + ')'); + //sax.debug('moveUpContentSegment(' + idx + ')'); let segId = sax.segmentId(idx); let $segPrev; $('.sax-panel-item.ArticleSegment', ac.$segList).detach().each( @@ -154,7 +188,7 @@ } sax.moveDownContentSegment = function (idx) { - sax.debug('moveDownContentSegment(' + idx + ')'); + //sax.debug('moveDownContentSegment(' + idx + ')'); let segId = sax.segmentId(idx); let $segMove; let $segs = $('.sax-panel-item.ArticleSegment', ac.$segList).detach(); @@ -169,13 +203,71 @@ } ac.$segList.append($seg); if ($segMove) $segMove.insertAfter($seg); + $segMove = null; }); } sax.deleteContentSegment = function (idx) { - sax.debug('deleteContentSegment(' + idx + ')'); + //sax.debug('deleteContentSegment(' + idx + ')'); if ($('.sax-panel-item.ArticleSegment', ac.$segList).length < 2) return; - $('#' + sax.segmentId(idx)).remove(); + sax.confirmItemRemove(function () { $('#' + sax.segmentId(idx)).remove(); }); + } + sax.selectArticleImage = function (idx) + { + let $dlg = sax.$dlg.selectArticleImage.dialog('option', { title: sax.dlg.title.imageUpload }); + $('input.SegmentIdx', $dlg).val(idx); + $('#ifArticleImage', $dlg).val(''); + sax.openDialog($dlg, 560, 240); + } + sax.uploadArticleImage = function () + { + let $dlg = sax.$dlg.selectArticleImage; + let $fileCtrl = $('#ifArticleImage', $dlg); + if (!$fileCtrl.length || !$fileCtrl[0].files.length) + return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileSelect); + let file = $fileCtrl[0].files[0]; + sax.onDropArticleImageFile(file, $('input.SegmentIdx', $dlg).val(), $dlg); + } + sax.onDropArticleImage = function (evt, idx, $seg) + { + //sax.debug('onDropArticleImage'); + let files = evt.originalEvent.dataTransfer.files; + if (files.length < 1) return; + if (files.length > 1) return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadImageSingle); + sax.onDropArticleImageFile(files[0], idx, $('#frmArticle')); + } + sax.onDropArticleImageFile = function (file, idx, context) + { + //sax.debug('onDropArticleImageFile', file, context); + ac.segIdxAddImage = idx; + if (file.size > sax.maxProfileImageSize) return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileSizeMax.format(sax.formatFileSize(sax.maxProfileImageSize))); + if (file.type != 'image/jpg' && file.type != 'image/jpeg' && file.type != 'image/png') return sax.doAlert(sax.dlg.title.imageUpload, sax.msg.uploadFileTypeInvalid.format(sax.getFileType(file))); + $(".UploadMessage", context).text(sax.msg.uploadingFile.format(file.name)); + $('img.ArticleImageUploadProgress', context).fadeIn(200); + sax.clearControlError(sax.$pnl.contactImageDrag); + sax.data.contactImageUploadContext = context; + + sax.ajax.uploadArticleImage = sax.ajax.uploadArticleImage || { url: sax.url.base + 'Journalist/Ajax/UploadArticleImage', callbackFn: sax.handleArticleImageUploadResponse, noWaitIcon: true }; + sax.ajax.uploadArticleImage.formData = new FormData(); + sax.ajax.uploadArticleImage.formData.append("__RequestVerificationToken", $('#frmNavigate input[name="__RequestVerificationToken"]').val()); + sax.ajax.uploadArticleImage.formData.append("ArticleId", $('#ifArticleId', sax.$frm.article).val()); + sax.ajax.uploadArticleImage.formData.append("ArticleImage", file); + sax.doAjaxRequest(sax.ajax.uploadArticleImage, 50); + } + sax.handleArticleImageUploadResponse = function (response) + { + let context = sax.data.contactImageUploadContext; + //sax.debug('handleArticleImageUploadResponse', response, context); + if (!response) return; + sax.refreshControlValues(response.controlValues, context); + $(".UploadMessage", context).empty(); + $('img.ArticleImageUploadProgress', context).hide(); + if (response.success && response.segment) + { + sax.addContentSegment(response.segment, 0, ac.segIdxAddImage); + delete ac.segIdxAddImage; + sax.$dlg.selectArticleImage.dialog('close'); + } } //-------------------------------------------------------------- @@ -313,6 +405,11 @@ ac.$content = $('.sax-article-panel.sax-article-content'); ac.$segList = $('.sax-article-segment-list', ac.$content); + var opt = sax.dlgOpts(); + opt.buttons[sax.dlg.btn.ok] = function () { sax.uploadArticleImage(); }; + opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); }; + sax.$dlg.selectArticleImage = $('#dlgSelectArticleImage').dialog(opt); + setTimeout(sax.refreshResults, 250); }); diff --git a/SaxoniteCoreWebOnline/wwwroot/js/sax-main.js b/SaxoniteCoreWebOnline/wwwroot/js/sax-main.js index 4a9f479..cc06217 100644 --- a/SaxoniteCoreWebOnline/wwwroot/js/sax-main.js +++ b/SaxoniteCoreWebOnline/wwwroot/js/sax-main.js @@ -68,7 +68,7 @@ evt.preventDefault(); evt.stopPropagation(); } - sax.debug = sax.debugMode ? window.console.log.bind(window.console) : function () { }; + sax.debug = sax.debugMode ? win.console.log.bind(win.console) : function () { }; //-------------------------------------------------------------- sax.setOddDataRowClass = function (rowSel, cName) @@ -152,10 +152,11 @@ // Dialogs. sax.openDialog = function ($dlg, width, height) { + let $win = $(win); $dlg.dialog( { - minWidth: null, maxWidth: null, width: Math.min(width || 400, $(window).width() * .90), - minHeight: null, maxHeight: null, height: Math.min(height || 320, $(window).innerHeight() * .90) + minWidth: null, maxWidth: null, width: Math.min(width || 400, $win.width() * .90), + minHeight: null, maxHeight: null, height: Math.min(height || 320, $win.innerHeight() * .96) }).dialog('open'); return $dlg; } @@ -205,6 +206,10 @@ $('#dlgConfirmMsg').html(msg); sax.openDialog(sax.$dlg.confirm); } + sax.confirmItemRemove = function (fn) + { + sax.doConfirm('', sax.msg.itemRemoveConfirm, fn); + } sax.doProgress = function (title, msg, delay) { if (!msg) @@ -235,8 +240,8 @@ // Notifications. sax.showNotification = function (title, msg) { - window.clearTimeout(sax.toNotification); - var $win = $(window); + win.clearTimeout(sax.toNotification); + var $win = $(win); var $not = $('#sax-notification').hide(); if (!$not.length) { @@ -255,7 +260,7 @@ } sax.hideNotification = function () { - window.clearTimeout(sax.toNotification); + win.clearTimeout(sax.toNotification); $('#sax-notification').slideUp(500); } sax.doPleaseWait = function () @@ -272,13 +277,13 @@ // Ajax. sax.doAjaxRequest = function (ajax, delay) { - window.clearTimeout(ajax.timeout); + win.clearTimeout(ajax.timeout); if (!ajax.noWaitIcon) sax.doPleaseWait(); ajax.timeout = setTimeout(function () { sax.execAjaxRequest(ajax); }, Math.max(50, parseInt(delay || 0, 10))); } sax.execAjaxRequest = function (ajax) { - window.clearTimeout(ajax.timeout); + win.clearTimeout(ajax.timeout); if (ajax.request) ajax.request.abort(); var cfgAjax = { @@ -360,7 +365,7 @@ { sax.session = sax.session || { refresh: {} }; let ssr = sax.session.refresh; - window.clearTimeout(ssr.timeout); + win.clearTimeout(ssr.timeout); ssr.timeout = setTimeout(function () { sax.refreshSession(); }, 150000); } sax.refreshSession = function () @@ -383,12 +388,12 @@ } sax.setControlError = function (sel, error) { - var $ctrl = $(sel).closest('.sax-form-control').toggleClass('sax-error',!!error.length); + var $ctrl = $(sel).closest('.sax-form-control').toggleClass('sax-error', !!error.length); $('.sax-message', $ctrl).text(error); } sax.refreshControlValues = function (controlValues, context) { - var $frmCtrls = $('.sax-form-control',context).removeClass('sax-error'); + var $frmCtrls = $('.sax-form-control', context).removeClass('sax-error'); sax.clearControlErrors(); var values = (controlValues || []); var valuesLen = values.length; @@ -461,11 +466,11 @@ if (viewport.is('xs')) $body.addClass('mob'); else if (viewport.current() != 'unrecognized') $body.addClass('dsk'); } - sax.isAutoHeight = function () { return ($(window).width() < 360 || $(window).height() < 560 || sax.isMob()); } + sax.isAutoHeight = function () { return ($(win).width() < 360 || $(win).height() < 560 || sax.isMob()); } sax.onWinResizePage = function () { }; sax.onWinResize = function () { - var winH = $(window).height(); + var winH = $(win).height(); var $pageBody = $('#sax-page-body'); var $hdr = $('#sax-page-header'); var $ftr = $('#sax-page-footer'); diff --git a/SaxoniteStandardBase/Base/App/Sax-Version.cs b/SaxoniteStandardBase/Base/App/Sax-Version.cs index 6aebb30..d64d68f 100644 --- a/SaxoniteStandardBase/Base/App/Sax-Version.cs +++ b/SaxoniteStandardBase/Base/App/Sax-Version.cs @@ -18,7 +18,7 @@ namespace Saxonite.Net.Standard.Base.App //------------------------------------------------------------------- public static class Version { - private static String version { get; } = "1.0.8.1"; + private static String version { get; } = "1.0.9.0"; // Retrieve version. public static String GetFullVersion () { return version; } public static String GetAppVersion () @@ -40,6 +40,8 @@ namespace Saxonite.Net.Standard.Base.App //------------------------------------------------------------------- // Version history. //------------------------------------------------------------------- + // 1.0.9 ?-Jun-2021 Journalist Articles + // - Online Article Images. // 1.0.8 15-Jun-2021 Online Article Content // - Journalist Articles styled content. // - Online home page click through activity for details with reaction. diff --git a/SaxoniteStandardBase/Base/App/Sax.cs b/SaxoniteStandardBase/Base/App/Sax.cs index 0507494..031e629 100644 --- a/SaxoniteStandardBase/Base/App/Sax.cs +++ b/SaxoniteStandardBase/Base/App/Sax.cs @@ -227,8 +227,12 @@ namespace Saxonite.Net.Standard.Base.App Unknown, /// User's profile image. Avatar = 100, - /// User's new profile image awaiting confirmation. + /// User's profile image, uploaded awaiting confirmation. AvatarUpload = 101, + /// Journalist Article image. + Article = 200, + /// Journalist Article image uploaded, awaiting confirmation. + ArticleUpload = 201, } //------------------------------------------------------------------- diff --git a/SaxoniteStandardBase/Base/App/SaxDbDfn_Core.cs b/SaxoniteStandardBase/Base/App/SaxDbDfn_Core.cs index 12c1984..2d3186e 100644 --- a/SaxoniteStandardBase/Base/App/SaxDbDfn_Core.cs +++ b/SaxoniteStandardBase/Base/App/SaxDbDfn_Core.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Linq; //--------------------------------------------------------------------------- -// Code generated by Sarand Database Utilities Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Base.App { @@ -57,6 +57,8 @@ namespace Saxonite.Base.App ItemImage_ItemId, ItemImage_ImageType, ItemImage_ImageSeq, + ItemImage_SessionUid, + ItemImage_ImageUid, ItemImage_Filename, ItemImage_Mime, ItemImage_ContentType, @@ -269,7 +271,7 @@ namespace Saxonite.Base.App //------------------------------------------------------------------- // Data members. private static readonly int tableCount = 14; - private static readonly int columnCount = 226; + private static readonly int columnCount = 228; private static ulong maxTextLen = 0; //------------------------------------------------------------------- @@ -474,6 +476,8 @@ namespace Saxonite.Base.App new ColumnDfn(2,"ItemId",4,4,false,10), new ColumnDfn(2,"ImageType",3,5,false,5), new ColumnDfn(2,"ImageSeq",2,-6,false,3), + new ColumnDfn(2,"SessionUid",5,-5,false,19), + new ColumnDfn(2,"ImageUid",4,4,false,10), new ColumnDfn(2,"Filename",0,-9,false,1024), new ColumnDfn(2,"Mime",0,12,false,64), new ColumnDfn(2,"ContentType",0,12,false,128), diff --git a/SaxoniteStandardBase/Base/App/SaxSessionData.cs b/SaxoniteStandardBase/Base/App/SaxSessionData.cs index f3c0d2d..4067b71 100644 --- a/SaxoniteStandardBase/Base/App/SaxSessionData.cs +++ b/SaxoniteStandardBase/Base/App/SaxSessionData.cs @@ -10,6 +10,7 @@ using System.Text; using System.Diagnostics; using Sarand.Net.Standard.Base.Utils; using Newtonsoft.Json.Converters; +using Sarand.Net.Standard.Base.Helpers; namespace Saxonite.Net.Standard.Base.App { @@ -17,16 +18,15 @@ namespace Saxonite.Net.Standard.Base.App public abstract class SaxSessionData { //------------------------------------------------------------------- - // Protected construction. - protected SaxSessionData() - { - } + private static long sessionIdxRoot = SacsRandomHelper.GetInt32(1000, 1999); //------------------------------------------------------------------- // Construction. - /// Hidden constructor for deserialisation only. - private SaxSessionData(SaxSessionContext sessionContext) + /// Protected constructor for deserialisation only. + protected SaxSessionData(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) { + SessionIdx = sessionIdx; + ItemIdx = itemIdx; SessionContext = sessionContext; userData = CreateUserData(SessionContext, null, null); } @@ -37,12 +37,20 @@ namespace Saxonite.Net.Standard.Base.App ///
protected SaxSessionData(SaxSessionContext sessionContext, SaxUserAccount userAccount, List userRoles) { + SessionIdx = ++sessionIdxRoot; + ItemIdx = 1000; SessionContext = sessionContext; userData = CreateUserData(SessionContext, userAccount, userRoles); } //------------------------------------------------------------------- // Properties. + // Session and Item indexers. + public long SessionIdx { get; } + public int ItemIdx { get; private set; } + [JsonIgnore] + public int NextItemIdx { get { return ++ItemIdx; } } + // Session context. public SaxSessionContext SessionContext { get; } [JsonIgnore] public bool ValidUserSession { get { return SysId.IsValid(User.UserAccountId) && SysId.IsValid(User.UserAccountId); } } diff --git a/SaxoniteStandardBase/Base/App/SaxSystem-Statics.cs b/SaxoniteStandardBase/Base/App/SaxSystem-Statics.cs index 0ac7ea4..1effdcd 100644 --- a/SaxoniteStandardBase/Base/App/SaxSystem-Statics.cs +++ b/SaxoniteStandardBase/Base/App/SaxSystem-Statics.cs @@ -98,6 +98,8 @@ namespace Saxonite.Net.Standard.Base.App // Image types. imageTypeCodes.Add(Sax.ImageType.Avatar, "Avatar", "Avatar"); imageTypeCodes.Add(Sax.ImageType.AvatarUpload, "AvatarUpload", "Avatar - upload"); + imageTypeCodes.Add(Sax.ImageType.Article, "Article", "Article"); + imageTypeCodes.Add(Sax.ImageType.ArticleUpload, "ArticleUpload", "Article - upload"); //--------------------------------------------------------------- // Organisation types. diff --git a/SaxoniteStandardBase/Base/Bus/SaxItemImage.cs b/SaxoniteStandardBase/Base/Bus/SaxItemImage.cs index b547ba7..7b2ab03 100644 --- a/SaxoniteStandardBase/Base/Bus/SaxItemImage.cs +++ b/SaxoniteStandardBase/Base/Bus/SaxItemImage.cs @@ -53,6 +53,8 @@ namespace Saxonite.Net.Standard.Base.Bus public ItemId ItemId { get; set; } public Sax.ImageType ImageType { get; set; } public byte ImageSeq { get; set; } + public long SessionUid { get; set; } + public int ImageUid { get; set; } public String Filename { get; set; } public String Mime { get; set; } public String ContentType { get; set; } @@ -88,6 +90,16 @@ namespace Saxonite.Net.Standard.Base.Bus get { return data.ImageSeq; } set { CheckChanged(data.ImageSeq, value); data.ImageSeq = value; } } + public long SessionUid + { + get { return data.SessionUid; } + set { CheckChanged(data.SessionUid, value); data.SessionUid = value; } + } + public int ImageUid + { + get { return data.ImageUid; } + set { CheckChanged(data.ImageUid, value); data.ImageUid = value; } + } public String Filename { get { return data.Filename; } @@ -124,6 +136,8 @@ namespace Saxonite.Net.Standard.Base.Bus ItemId = data.ItemId; ImageType = data.ImageType; ImageSeq = data.ImageSeq; + SessionUid = data.SessionUid; + ImageUid = data.ImageUid; Filename = data.Filename; Mime = data.Mime; ContentType = data.ContentType; @@ -148,6 +162,8 @@ namespace Saxonite.Net.Standard.Base.Bus public ValidValue ItemId { get; set; } = ValidValue.Valid; public ValidValue ImageType { get; set; } = ValidValue.Valid; public ValidValue ImageSeq { get; set; } = ValidValue.Valid; + public ValidValue SessionUid { get; set; } = ValidValue.Valid; + public ValidValue ImageUid { get; set; } = ValidValue.Valid; public ValidValue Filename { get; set; } = ValidValue.Valid; public ValidValue Mime { get; set; } = ValidValue.Valid; public ValidValue ContentType { get; set; } = ValidValue.Valid; @@ -213,18 +229,28 @@ namespace Saxonite.Net.Standard.Base.Bus public ItemId ItemId { get { return data.ItemId; } - protected set { data.ItemId = value; } + set { data.ItemId = value; } } public Sax.ImageType ImageType { get { return data.ImageType; } - protected set { data.ImageType = value; } + set { data.ImageType = value; } } public byte ImageSeq { get { return data.ImageSeq; } set { data.ImageSeq = value; } } + public long SessionUid + { + get { return data.SessionUid; } + set { data.SessionUid = value; } + } + public int ImageUid + { + get { return data.ImageUid; } + set { data.ImageUid = value; } + } public String Filename { get { return data.Filename; } @@ -273,6 +299,7 @@ namespace Saxonite.Net.Standard.Base.Bus NotDeleted, ActiveOnly, InctiveOnly, + Deleted, } /// /// Item list parameters. @@ -294,6 +321,20 @@ namespace Saxonite.Net.Standard.Base.Bus // Item list extension methods. public static class SaxItemImageList { + //------------------------------------------------------------------- + public static SaxItemImage GetItemImageById(this List values, SysId itemImageId) + { + if (!SysId.IsValid(itemImageId)) return null; + return values.Find(item => item.Id.Equals(itemImageId)); + } + + public static SaxItemImage GetItemImageBySessionImage(this List values, long sessionUid, int imageUid) + { + if (sessionUid < 1 || imageUid < 1) return null; + return values.Find(item => item.SessionUid == sessionUid && item.ImageUid == imageUid); + } + + //------------------------------------------------------------------- } //======================================================================= diff --git a/SaxoniteStandardBase/Base/Bus/SaxJournalistArticle-ContentData.cs b/SaxoniteStandardBase/Base/Bus/SaxJournalistArticle-ContentData.cs index 797d421..4c23efb 100644 --- a/SaxoniteStandardBase/Base/Bus/SaxJournalistArticle-ContentData.cs +++ b/SaxoniteStandardBase/Base/Bus/SaxJournalistArticle-ContentData.cs @@ -21,23 +21,46 @@ namespace Saxonite.Net.Standard.Base.Bus private static readonly String ElementName_Segments = "segments"; private static readonly String ElementName_Segment = "segment"; private static readonly String ElementName_Body = "body"; - private static readonly String ElementName_Html= "html"; + private static readonly String ElementName_Html = "html"; + private static readonly String ElementName_Image = "image"; + private static readonly String ElementName_ImageId = "imageId"; //------------------------------------------------------------------- /// Article content. public class ContentData { + /// + /// Article Content Segment - either body content or image. + /// public class SegmentData { + // Segment body. public class BodyData { + public bool IsValid() + { + if (!StringUtil.IsEmpty(Html)) return true; + return false; + } public String Html { get; set; } = String.Empty; } public BodyData Body { get; } = new BodyData(); + // Segment image. + public class ImageData + { + public bool IsValid() + { + if (SysId.IsValid(ItemImageId)) return true; + return false; + } + public SysId ItemImageId { get; set; } + } + public ImageData Image { get; } = new ImageData(); // Validate. public bool IsValid() { - if (!StringUtil.IsEmpty(Body.Html)) return true; + if (Body.IsValid()) return true; + if (Image.IsValid()) return true; return false; } } @@ -59,6 +82,7 @@ namespace Saxonite.Net.Standard.Base.Bus { String fn = typeof(ContentData).FullName + ".ExtractContent"; ContentData content = new ContentData(); + if (StringUtil.IsEmpty(contentData)) return content; try { @@ -99,6 +123,22 @@ namespace Saxonite.Net.Standard.Base.Bus else SaLogger.Warn(fn + " Unexpected 'Segment' child element: " + segmentChildElementName); } } + else if (segmentChildElementName.EqualsCI(ElementName_Image)) + { + // Content segment image. + XElement imageElement = segmentChildElement; + foreach (XElement imageChildElement in imageElement.GetChildElements()) + { + String imageChildElementName = imageChildElement.GetLocalName(); + if (imageChildElementName.EqualsCI(ElementName_ImageId)) + { + // Content segment image Id. + XElement imageIdElement = imageChildElement; + segment.Image.ItemImageId = imageIdElement.Value.ToSysId(); + } + else SaLogger.Warn(fn + " Unexpected 'Segment' child element: " + segmentChildElementName); + } + } else SaLogger.Warn(fn + " Unexpected 'Segment' child element: " + segmentChildElementName); } // Add this segment to the list. @@ -136,9 +176,20 @@ namespace Saxonite.Net.Standard.Base.Bus { if (!segment.IsValid()) continue; XElement segmentElement = segmentsElement.AppendElement(ElementName_Segment); - XElement bodyElement = segmentElement.AppendElement(ElementName_Body); - if (!StringUtil.IsEmpty(segment.Body.Html)) - bodyElement.AppendElement(ElementName_Html, segment.Body.Html); + if (segment.Body.IsValid()) + { + // Segment Body. + XElement bodyElement = segmentElement.AppendElement(ElementName_Body); + if (!StringUtil.IsEmpty(segment.Body.Html)) + bodyElement.AppendElement(ElementName_Html, segment.Body.Html); + } + else if (segment.Image.IsValid()) + { + // Segment Image. + XElement imageElement = segmentElement.AppendElement(ElementName_Image); + if (SysId.IsValid(segment.Image.ItemImageId)) + imageElement.AppendElement(ElementName_ImageId, SysId.ToString(segment.Image.ItemImageId)); + } } return doc.GetXml(); } diff --git a/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ActivityIndex_Db.cs index 087563c..6096ba5 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ItemImage_Db.cs index 09a022c..db07298 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { @@ -24,6 +24,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal public ColumnDataInt32 _ItemId { get; } = new ColumnDataInt32("ItemId"); public ColumnDataInt16 _ImageType { get; } = new ColumnDataInt16("ImageType"); public ColumnDataByte _ImageSeq { get; } = new ColumnDataByte("ImageSeq"); + public ColumnDataInt64 _SessionUid { get; } = new ColumnDataInt64("SessionUid"); + public ColumnDataInt32 _ImageUid { get; } = new ColumnDataInt32("ImageUid"); public ColumnDataString _Filename { get; } = new ColumnDataString("Filename"); public ColumnDataString _Mime { get; } = new ColumnDataString("Mime"); public ColumnDataString _ContentType { get; } = new ColumnDataString("ContentType"); @@ -50,6 +52,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal "ItemId", "ImageType", "ImageSeq", + "SessionUid", + "ImageUid", "Filename", "Mime", "ContentType", @@ -102,6 +106,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal public Int32 _ItemId { get { return Cols._ItemId.Value; } set { Cols._ItemId.Value = value; } } public Int16 _ImageType { get { return Cols._ImageType.Value; } set { Cols._ImageType.Value = value; } } public Byte _ImageSeq { get { return Cols._ImageSeq.Value; } set { Cols._ImageSeq.Value = value; } } + public Int64 _SessionUid { get { return Cols._SessionUid.Value; } set { Cols._SessionUid.Value = value; } } + public Int32 _ImageUid { get { return Cols._ImageUid.Value; } set { Cols._ImageUid.Value = value; } } public String _Filename { get { return Cols._Filename.Value; } set { Cols._Filename.Value = value; } } public String _Mime { get { return Cols._Mime.Value; } set { Cols._Mime.Value = value; } } public String _ContentType { get { return Cols._ContentType.Value; } set { Cols._ContentType.Value = value; } } @@ -143,6 +149,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal _ItemId = GetFieldInt32(dbDataReader, "ItemId", _ItemId); _ImageType = GetFieldInt16(dbDataReader, "ImageType", _ImageType); _ImageSeq = GetFieldByte(dbDataReader, "ImageSeq", _ImageSeq); + _SessionUid = GetFieldInt64(dbDataReader, "SessionUid", _SessionUid); + _ImageUid = GetFieldInt32(dbDataReader, "ImageUid", _ImageUid); _Filename = GetFieldString(dbDataReader, "Filename", _Filename); _Mime = GetFieldString(dbDataReader, "Mime", _Mime); _ContentType = GetFieldString(dbDataReader, "ContentType", _ContentType); @@ -183,6 +191,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal if (columnNames.ContainsCI("ItemId")) AddCommandParameter(dbCommand, "@ItemId", _ItemId); if (columnNames.ContainsCI("ImageType")) AddCommandParameter(dbCommand, "@ImageType", _ImageType); if (columnNames.ContainsCI("ImageSeq")) AddCommandParameter(dbCommand, "@ImageSeq", _ImageSeq); + if (columnNames.ContainsCI("SessionUid")) AddCommandParameter(dbCommand, "@SessionUid", _SessionUid); + if (columnNames.ContainsCI("ImageUid")) AddCommandParameter(dbCommand, "@ImageUid", _ImageUid); if (columnNames.ContainsCI("Filename")) AddCommandParameter(dbCommand, "@Filename", _Filename); if (columnNames.ContainsCI("Mime")) AddCommandParameter(dbCommand, "@Mime", _Mime); if (columnNames.ContainsCI("ContentType")) AddCommandParameter(dbCommand, "@ContentType", _ContentType); @@ -238,6 +248,8 @@ namespace Saxonite.Net.Standard.Dbas.Internal if (columnNames.ContainsCI("ItemId")) AddCommandParameter(dbCommand, "@ItemId", _ItemId); if (columnNames.ContainsCI("ImageType")) AddCommandParameter(dbCommand, "@ImageType", _ImageType); if (columnNames.ContainsCI("ImageSeq")) AddCommandParameter(dbCommand, "@ImageSeq", _ImageSeq); + if (columnNames.ContainsCI("SessionUid")) AddCommandParameter(dbCommand, "@SessionUid", _SessionUid); + if (columnNames.ContainsCI("ImageUid")) AddCommandParameter(dbCommand, "@ImageUid", _ImageUid); if (columnNames.ContainsCI("Filename")) AddCommandParameter(dbCommand, "@Filename", _Filename); if (columnNames.ContainsCI("Mime")) AddCommandParameter(dbCommand, "@Mime", _Mime); if (columnNames.ContainsCI("ContentType")) AddCommandParameter(dbCommand, "@ContentType", _ContentType); diff --git a/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/ItemSport_Db.cs index 69a4025..b44fee5 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs index 3f559b1..7b347a3 100644 --- a/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs +++ b/SaxoniteStandardDbas/Dbas/Internal/JournalistArticle_Db.cs @@ -9,7 +9,7 @@ using System.Data.Common; using System.Linq; //--------------------------------------------------------------------------- -// Code generated by Sarand Database Utilities Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/OrganisationOpportunity_Db.cs index 8b94cba..9c9b334 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Organisation_Db.cs index 0d33216..f0fb41e 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Region_Db.cs index 7a28e2d..2b52b7e 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/Sport_Db.cs index 3dd0ee5..e57d044 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserAccount_Db.cs index 8445b03..89042fa 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserActivity_Db.cs index ff25408..a8fa07d 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserOrganisation_Db.cs index 4f75c67..a863ec2 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserRole_Db.cs index 8baac34..02bffe4 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserSession_Db.cs index 2777252..13af9b5 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs b/SaxoniteStandardDbas/Dbas/Internal/UserSport_Db.cs index c273cb3..229f99a 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 Fri 18-Jun-2021 11:08:40 +// Code generated by Sarand Database Utilities Tue 22-Jun-2021 08:56:11 //--------------------------------------------------------------------------- namespace Saxonite.Net.Standard.Dbas.Internal { diff --git a/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemImage.cs b/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemImage.cs index 0cfe7e2..f0732d6 100644 --- a/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemImage.cs +++ b/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemImage.cs @@ -29,7 +29,7 @@ namespace Saxonite.Net.Standard.Dbas.Mgr return new List() { new StringPair("Id", SysId.ToString(itemImage.Id)), - new StringPair("ItemId", ItemId.ToString(itemImage.ItemId)), + new StringPair("ItemId", (Sax.DataItemType)itemImage.ItemId.Type + ": " + itemImage.ItemId.Id), new StringPair("ImageType", itemImage.ImageType.ToString()), new StringPair("Status", itemImage.StatusCode) }; @@ -209,6 +209,8 @@ namespace Saxonite.Net.Standard.Dbas.Mgr dbItemImage._ItemId = SysId.ToInt(itemImage.ItemId.Id); dbItemImage._ImageType = (short)itemImage.ImageType; dbItemImage._ImageSeq = itemImage.ImageSeq; + dbItemImage._SessionUid = itemImage.SessionUid; + dbItemImage._ImageUid = itemImage.ImageUid; dbItemImage._Filename = itemImage.Filename; dbItemImage._Mime = itemImage.Mime; dbItemImage._ContentType = itemImage.ContentType; @@ -235,6 +237,8 @@ namespace Saxonite.Net.Standard.Dbas.Mgr //itemImage.ItemId = new ItemId(dbItemImage._ItemType, new SysId(dbItemImage._ItemId); //itemImage.ImageType = (Sax.ImageType)dbItemImage._ImageType; itemImage.ImageSeq = dbItemImage._ImageSeq; + itemImage.SessionUid = dbItemImage._SessionUid; + itemImage.ImageUid = dbItemImage._ImageUid; itemImage.Filename = dbItemImage._Filename; itemImage.Mime = dbItemImage._Mime; itemImage.ContentType = dbItemImage._ContentType; @@ -407,8 +411,12 @@ namespace Saxonite.Net.Standard.Dbas.Mgr // Status. if (prm.StatusCat == SaxItemImage.StatusCat.ActiveOnly) filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ItemImage_Status, aliasItemImage) + "='" + SacsSystem.GetStatusCode(SaStatus.Active) + "'"); + else if (prm.StatusCat == SaxItemImage.StatusCat.InctiveOnly) + filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ItemImage_Status, aliasItemImage) + "='" + SacsSystem.GetStatusCode(SaStatus.Inactive) + "'"); else if (prm.StatusCat == SaxItemImage.StatusCat.NotDeleted) filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ItemImage_Status, aliasItemImage) + "!='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'"); + else if (prm.StatusCat == SaxItemImage.StatusCat.Deleted) + filter.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ItemImage_Status, aliasItemImage) + "='" + SacsSystem.GetStatusCode(SaStatus.Deleted) + "'"); if (filter.Count < 1) filter.Add("1=1"); return filter; diff --git a/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemSport.cs b/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemSport.cs index 01a2bf5..531e36f 100644 --- a/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemSport.cs +++ b/SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemSport.cs @@ -28,7 +28,7 @@ namespace Saxonite.Net.Standard.Dbas.Mgr return new List() { new StringPair("Id",SysId.ToString(itemSport.Id)), - new StringPair("ItemId",ItemId.ToString(itemSport.ItemId)), + new StringPair("ItemId", (Sax.DataItemType)itemSport.ItemId.Type + ": " + itemSport.ItemId.Id), new StringPair("Sport",SysId.ToString(itemSport.SportId)), new StringPair("Status",itemSport.StatusCode) }; diff --git a/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml b/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml index 77ffed6..87e189d 100644 --- a/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml +++ b/SaxoniteStandardDbas/Resources/Database/SaxDbDfn_Core.xml @@ -437,6 +437,40 @@ dbo ItemImage
6 + SessionUid + BigInt + + -5 + bigint + false + 19 + 8 + 0 + NoNulls + false + + + + dbo + ItemImage
+ 7 + ImageUid + Int + + 4 + int + false + 10 + 4 + 0 + NoNulls + false + +
+ + dbo + ItemImage
+ 8 Filename VarChar @@ -453,7 +487,7 @@ dbo ItemImage
- 7 + 9 Mime VarChar @@ -470,7 +504,7 @@ dbo ItemImage
- 8 + 10 ContentType VarChar @@ -487,7 +521,7 @@ dbo ItemImage
- 9 + 11 Width Int @@ -504,7 +538,7 @@ dbo ItemImage
- 10 + 12 Height Int @@ -521,7 +555,7 @@ dbo ItemImage
- 11 + 13 ImageData Binary @@ -538,7 +572,7 @@ dbo ItemImage
- 12 + 14 Notes VarChar @@ -555,7 +589,7 @@ dbo ItemImage
- 13 + 15 Flags SmallInt @@ -572,7 +606,7 @@ dbo ItemImage
- 14 + 16 Status VarChar @@ -589,7 +623,7 @@ dbo ItemImage
- 15 + 17 CreateOn DateTime @@ -606,7 +640,7 @@ dbo ItemImage
- 16 + 18 CreateBy Int @@ -623,7 +657,7 @@ dbo ItemImage
- 17 + 19 CreateHost VarChar @@ -640,7 +674,7 @@ dbo ItemImage
- 18 + 20 UpdateOn DateTime @@ -657,7 +691,7 @@ dbo ItemImage
- 19 + 21 UpdateBy Int @@ -674,7 +708,7 @@ dbo ItemImage
- 20 + 22 UpdateHost VarChar @@ -700,7 +734,7 @@ false false 1 - 2 + 5 false @@ -3816,8 +3850,8 @@ false false false - 0 - 0 + 1 + 8 false