diff --git a/OpenContent/BuildScripts/ModulePackage.targets b/OpenContent/BuildScripts/ModulePackage.targets
index 9af64e1c..38fb28ef 100644
--- a/OpenContent/BuildScripts/ModulePackage.targets
+++ b/OpenContent/BuildScripts/ModulePackage.targets
@@ -8,6 +8,7 @@
$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs
+ $(MSBuildProjectDirectory)\..\appveyor.yml
@@ -23,8 +24,9 @@
-
-
+
+
+
diff --git a/OpenContent/Components/Datasource/DefaultDataItem.cs b/OpenContent/Components/Datasource/DefaultDataItem.cs
index af7aac3b..c058e3da 100644
--- a/OpenContent/Components/Datasource/DefaultDataItem.cs
+++ b/OpenContent/Components/Datasource/DefaultDataItem.cs
@@ -5,14 +5,29 @@ namespace Satrabel.OpenContent.Components.Datasource
{
public class DefaultDataItem : IDataItem
{
+ [Obsolete("Please use constructor with parameters 12/10/2021")]
public DefaultDataItem()
{
}
+ public DefaultDataItem(string id)
+ {
+ Id = id;
+ Key = id;
+ }
+
+ public DefaultDataItem(string id, string key)
+ {
+ Id = id;
+ Key = key;
+ }
public DefaultDataItem(JToken json)
{
+ Id = null;
+ Key = null;
Data = json;
}
+
public string Id { get; set; }
public string Key { get; set; }
public string Collection { get; set; }
@@ -23,6 +38,5 @@ public DefaultDataItem(JToken json)
public int LastModifiedByUserId { get; set; }
public DateTime LastModifiedOnDate { get; set; }
public object Item { get; set; }
-
}
}
\ No newline at end of file
diff --git a/OpenContent/Components/Datasource/DnnPortalSettingsDataSource.cs b/OpenContent/Components/Datasource/DnnPortalSettingsDataSource.cs
index 8e9feaef..2e2d13ff 100644
--- a/OpenContent/Components/Datasource/DnnPortalSettingsDataSource.cs
+++ b/OpenContent/Components/Datasource/DnnPortalSettingsDataSource.cs
@@ -33,9 +33,8 @@ public override IDataItem Get(DataSourceContext context, string id)
}
private static IDataItem ToData(PortalSettingInfoBase setting)
{
- var item = new DefaultDataItem()
+ var item = new DefaultDataItem(setting.Id())
{
- Id = setting.Id(),
Title = $"{setting.SettingName}",
Data = JObject.FromObject(new
{
diff --git a/OpenContent/Components/Datasource/DnnTabsDataSource.cs b/OpenContent/Components/Datasource/DnnTabsDataSource.cs
index efd00b77..af3262c1 100644
--- a/OpenContent/Components/Datasource/DnnTabsDataSource.cs
+++ b/OpenContent/Components/Datasource/DnnTabsDataSource.cs
@@ -41,9 +41,8 @@ public override IDataItems GetAll(DataSourceContext context, Select selectQuery)
var dataList = new List();
foreach (var tab in tabs)
{
- var item = new DefaultDataItem()
+ var item = new DefaultDataItem(tab.TabID.ToString())
{
- Id = tab.TabID.ToString(),
Title = tab.TabName,
Data = JObject.FromObject(new
{
diff --git a/OpenContent/Components/Datasource/DnnUsersDataSource.cs b/OpenContent/Components/Datasource/DnnUsersDataSource.cs
index 347af26a..fa78126c 100644
--- a/OpenContent/Components/Datasource/DnnUsersDataSource.cs
+++ b/OpenContent/Components/Datasource/DnnUsersDataSource.cs
@@ -40,9 +40,8 @@ public override IDataItem Get(DataSourceContext context, string id)
}
private static IDataItem ToData(UserInfo user)
{
- var item = new DefaultDataItem()
+ var item = new DefaultDataItem(user.UserID.ToString())
{
- Id = user.UserID.ToString(),
Title = user.DisplayName,
Data = JObject.FromObject(new
{
diff --git a/OpenContent/Components/Datasource/OpenContentDataSource.cs b/OpenContent/Components/Datasource/OpenContentDataSource.cs
index 48a8b72b..d399ec6c 100644
--- a/OpenContent/Components/Datasource/OpenContentDataSource.cs
+++ b/OpenContent/Components/Datasource/OpenContentDataSource.cs
@@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using DotNetNuke.Entities.Modules;
+using DotNetNuke.Entities.Portals;
using Satrabel.OpenContent.Components.Datasource.Search;
using Satrabel.OpenContent.Components.Logging;
using Satrabel.OpenContent.Components.Form;
@@ -165,7 +167,7 @@ public virtual IDataItem GetData(DataSourceContext context, string scope, string
var json = dc.GetData(scopeStorage, key);
if (json != null)
{
- var dataItem = new DefaultDataItem
+ var dataItem = new DefaultDataItem("")
{
Data = json.Json.ToJObject("GetContent " + scope + "/" + key),
CreatedByUserId = json.CreatedByUserId,
@@ -304,8 +306,9 @@ public virtual void Update(DataSourceContext context, IDataItem item, JToken dat
ctrl.UpdateContent(content);
if (context.Index)
{
+ var module = OpenContentModuleConfig.Create(ModuleController.Instance.GetModule(context.ModuleId, -1, false), new PortalSettings(context.PortalId));
var indexConfig = OpenContentUtils.GetIndexConfig(new FolderUri(context.TemplateFolder), context.Collection);
- content.HydrateDefaultFields(indexConfig);
+ content.HydrateDefaultFields(indexConfig, module.Settings?.Manifest?.UsePublishTime ?? false);
LuceneController.Instance.Update(content, indexConfig);
LuceneController.Instance.Commit();
}
@@ -353,7 +356,7 @@ public virtual JToken Action(DataSourceContext context, string action, IDataItem
{
if (action == "FormSubmit")
{
- if (data["form"]["approvalEnabled"] != null && data["form"]["approvalEnabled"].Value() == true )
+ if (data["form"]["approvalEnabled"] != null && data["form"]["approvalEnabled"].Value() == true)
{
data["form"]["approved"] = false;
}
@@ -373,7 +376,7 @@ public virtual JToken Action(DataSourceContext context, string action, IDataItem
ctrl.AddContent(content);
//Index the content item
-
+
if (context.Index)
{
var indexConfig = OpenContentUtils.GetIndexConfig(new FolderUri(context.TemplateFolder), "Submissions");
@@ -463,10 +466,8 @@ private static int GetTabId(DataSourceContext context)
private static DefaultDataItem CreateDefaultDataItem(OpenContentInfo content)
{
- return new DefaultDataItem
+ return new DefaultDataItem(content.Id)
{
- Id = content.Id,
- Key= content.Key,
Collection = content.Collection,
Title = content.Title,
Data = content.JsonAsJToken,
diff --git a/OpenContent/Components/Datasource/RestApiDataSource.cs b/OpenContent/Components/Datasource/RestApiDataSource.cs
new file mode 100644
index 00000000..248ba274
--- /dev/null
+++ b/OpenContent/Components/Datasource/RestApiDataSource.cs
@@ -0,0 +1,260 @@
+using DotNetNuke.Services.Mail;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Satrabel.OpenContent.Components;
+using Satrabel.OpenContent.Components.Datasource;
+using Satrabel.OpenContent.Components.Datasource.Search;
+using Satrabel.OpenContent.Components.Form;
+using Satrabel.OpenContent.Components.Handlebars;
+using Satrabel.OpenContent.Components.Logging;
+using Satrabel.OpenContent.Components.Lucene;
+using Satrabel.OpenContent.Components.Lucene.Config;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Mail;
+using System.Web;
+
+namespace Satrabel.OpenContent.Components.Datasource
+{
+ public class RestApiDataSource : OpenContentDataSource
+ {
+
+ public override string Name
+ {
+ get
+ {
+ return "Satrabel.RestApi";
+ }
+ }
+ public override IDataItems GetAll(DataSourceContext context)
+ {
+ JArray items = new JArray();
+
+ var url = context.Config["listUrl"].ToString();
+
+ using (var client = new HttpClient())
+ {
+ var response = client.GetAsync(url).GetAwaiter().GetResult(); ;
+ response.EnsureSuccessStatusCode();
+ var responseBody = response.Content.ReadAsStringAsync();
+ var content = responseBody.GetAwaiter().GetResult();
+ items = JArray.Parse(content);
+ }
+ var dataList = items
+ .Select(content => CreateDefaultDataItem(content));
+
+ return new DefaultDataItems()
+ {
+ Items = dataList,
+ Total = dataList.Count()
+ };
+ }
+
+ public override IDataItems GetAll(DataSourceContext context, Select selectQuery)
+ {
+ if (selectQuery == null)
+ {
+ return GetAll(context);
+ }
+ else
+ {
+ string query = context.Config["listUrl"].ToString();
+ foreach (var f in selectQuery.Filter.FilterRules)
+ {
+ if (f.Value != null)
+ {
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += f.Field + "=" + f.Value.AsString;
+ }
+ }
+
+ foreach (var g in selectQuery.Filter.FilterGroups)
+ {
+ foreach (var f in g.FilterRules)
+ {
+ if (f.Value != null)
+ {
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += f.Field + "=" + f.Value.AsString;
+ }
+ }
+ }
+
+ foreach (var f in selectQuery.Query.FilterRules)
+ {
+ if (f.Value != null)
+ {
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += f.Field + "=" + f.Value.AsString;
+ }
+ else if (f.MultiValue != null)
+
+ {
+ foreach (var val in f.MultiValue)
+ {
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += f.Field + "=" + val.AsString;
+ }
+
+ }
+ }
+
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += "PageIndex=" + selectQuery.PageIndex;
+
+ if (!query.Contains('?'))
+ query += "?";
+ else
+ query += "&";
+
+ query += "PageSize=" + selectQuery.PageSize;
+
+ JArray items = new JArray();
+
+ //var url = context.Config["listUrl"].ToString()+query;
+
+ var url = query;
+
+ using (var client = new HttpClient())
+ {
+ var response = client.GetAsync(url).GetAwaiter().GetResult(); ;
+ response.EnsureSuccessStatusCode();
+ var responseBody = response.Content.ReadAsStringAsync();
+ var content = responseBody.GetAwaiter().GetResult();
+ items = JArray.Parse(content);
+ }
+ var dataList = items
+ .Select(content => CreateDefaultDataItem(content));
+
+ return new DefaultDataItems()
+ {
+ Items = dataList,
+ Total = dataList.Count()
+ };
+
+
+ //var ruleCategory = selectQuery.Filter.FilterRules.FirstOrDefault(f => f.Field == "Category");
+ //if (ruleCategory != null)
+ //{
+ // string category = ruleCategory.Value.AsString;
+
+ //}
+ }
+ }
+
+ public override IDataItem Get(DataSourceContext context, string id)
+ {
+ JObject item = new JObject();
+ var url = context.Config["detailUrl"].ToString();
+
+ using (var client = new HttpClient())
+ {
+ var response = client.GetAsync(string.Format(url, id)).GetAwaiter().GetResult(); ;
+ response.EnsureSuccessStatusCode();
+ var responseBody = response.Content.ReadAsStringAsync();
+ var content = responseBody.GetAwaiter().GetResult();
+ item = JObject.Parse(content);
+ }
+
+ if (item == null)
+ {
+ App.Services.Logger.Warn($"Item not shown because no content item found. Id [{id}]. url : [{url}], Id: [{id}]");
+ LogContext.Log(context.ActiveModuleId, "Get DataItem", "Result", "not item found with id " + id);
+ }
+ else
+ {
+ var dataItem = CreateDefaultDataItem(item);
+ if (LogContext.IsLogActive)
+ {
+ LogContext.Log(context.ActiveModuleId, "Get DataItem", "Result", dataItem.Data);
+ }
+ return dataItem;
+ }
+ return null;
+ }
+
+ ///
+ /// Gets additional/related data of a datasource.
+ ///
+ /// The context.
+ /// The Scope. (portal, tab, module, tabmodule)
+ /// The unique key in the scope
+ ///
+ public override IDataItem GetData(DataSourceContext context, string scope, string key)
+ {
+ if (context.Config[key + "Url"] == null)
+ {
+ return base.GetData(context, scope, key);
+ }
+
+ JToken item = new JArray();
+ var url = context.Config[key + "Url"].ToString();
+
+ using (var client = new HttpClient())
+ {
+ var response = client.GetAsync(string.Format(url, key)).GetAwaiter().GetResult(); ;
+ response.EnsureSuccessStatusCode();
+ var responseBody = response.Content.ReadAsStringAsync();
+ var content = responseBody.GetAwaiter().GetResult();
+ item = JToken.Parse(content);
+ }
+ if (item != null)
+ {
+ var dataItem = new DefaultDataItem()
+ {
+ Data = item,
+ CreatedByUserId = 1,
+ Item = null
+ };
+ if (LogContext.IsLogActive)
+ {
+ LogContext.Log(context.ActiveModuleId, "Get Data", key, dataItem.Data);
+ }
+ return dataItem;
+ }
+ return null;
+ }
+ private static DefaultDataItem CreateDefaultDataItem(JToken content)
+ {
+ return new DefaultDataItem
+ {
+ Id = content["id"].ToString(),
+ Key = content["id"].ToString(),
+ Collection = "Items",
+ Title = content["title"]?.ToString(),
+ Data = content,
+ CreatedByUserId = 1,
+ LastModifiedByUserId = 1,
+ LastModifiedOnDate = DateTime.Now,
+ CreatedOnDate = DateTime.Now,
+ Item = null
+ };
+ }
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/OpenContent/Components/DnnEntitiesAPIController.cs b/OpenContent/Components/DnnEntitiesAPIController.cs
index b469e76b..7c3be3d7 100644
--- a/OpenContent/Components/DnnEntitiesAPIController.cs
+++ b/OpenContent/Components/DnnEntitiesAPIController.cs
@@ -152,7 +152,7 @@ public HttpResponseMessage ImagesLookupExt(string q, string folder, string itemK
{
var module = OpenContentModuleConfig.Create(ActiveModule, PortalSettings);
var folderManager = FolderManager.Instance;
- string imageFolder = "OpenContent/Files/" + ActiveModule.ModuleID;
+ string imageFolder = "OpenContent/Files/" + module.DataModule.ModuleId;
if (module.Settings.Manifest.DeleteFiles)
{
if (!string.IsNullOrEmpty(itemKey))
@@ -451,6 +451,7 @@ public HttpResponseMessage Files(string q, string d)
[HttpPost]
public HttpResponseMessage CropImage(CropResizeDTO cropData)
{
+ var module = OpenContentModuleConfig.Create(ActiveModule, PortalSettings);
FilesStatus fs = null;
try
{
@@ -473,7 +474,7 @@ public HttpResponseMessage CropImage(CropResizeDTO cropData)
}
rawImageUrl = rawImageUrl.Replace(PortalSettings.HomeDirectory, "");
var file = fileManager.GetFile(ActiveModule.PortalID, rawImageUrl);
- string cropfolder = "OpenContent/Cropped/" + ActiveModule.ModuleID;
+ string cropfolder = "OpenContent/Cropped/" + module.DataModule.ModuleId;
if (!string.IsNullOrEmpty(cropData.itemKey))
{
cropfolder += "/" + cropData.itemKey;
@@ -560,6 +561,7 @@ public HttpResponseMessage CropImage(CropResizeDTO cropData)
[HttpPost]
public HttpResponseMessage CropImages(CroppersDTO cropData)
{
+ var module = OpenContentModuleConfig.Create(ActiveModule, PortalSettings);
try
{
var res = new CroppersResultDTO();
@@ -574,7 +576,7 @@ public HttpResponseMessage CropImages(CroppersDTO cropData)
var file = fileManager.GetFile(ActiveModule.PortalID, rawImageUrl);
if (file != null)
{
- string cropfolder = "OpenContent/Files/" + ActiveModule.ModuleID;
+ string cropfolder = "OpenContent/Files/" + module.DataModule.ModuleId;
if (!string.IsNullOrEmpty(cropData.cropfolder))
{
cropfolder = cropData.cropfolder;
@@ -675,6 +677,7 @@ private CropResizeResultDTO CropFile(IFileInfo file, string newFilename, CropDTO
[HttpPost]
public HttpResponseMessage DownloadFile(FileDTO req)
{
+ var module = OpenContentModuleConfig.Create(ActiveModule, PortalSettings);
try
{
var folderManager = FolderManager.Instance;
@@ -686,7 +689,7 @@ public HttpResponseMessage DownloadFile(FileDTO req)
}
RawImageUrl = RawImageUrl.Replace(PortalSettings.HomeDirectory, "");
var file = fileManager.GetFile(ActiveModule.PortalID, RawImageUrl);
- string uploadfolder = "OpenContent/Files/" + ActiveModule.ModuleID;
+ string uploadfolder = "OpenContent/Files/" + module.DataModule.ModuleId;
if (!string.IsNullOrEmpty(req.uploadfolder))
{
uploadfolder = req.uploadfolder;
diff --git a/OpenContent/Components/FeatureController.cs b/OpenContent/Components/FeatureController.cs
index 192d1e82..46b4a5a6 100644
--- a/OpenContent/Components/FeatureController.cs
+++ b/OpenContent/Components/FeatureController.cs
@@ -28,11 +28,14 @@
using DotNetNuke.Common.Internal;
using DotNetNuke.Services.Search.Controllers;
using Satrabel.OpenContent.Components.Datasource;
+using Satrabel.OpenContent.Components.Datasource.Search;
using Satrabel.OpenContent.Components.Dnn;
using Satrabel.OpenContent.Components.Handlebars;
using Satrabel.OpenContent.Components.Json;
using Satrabel.OpenContent.Components.Lucene;
+using Satrabel.OpenContent.Components.Lucene.Config;
using Satrabel.OpenContent.Components.TemplateHelpers;
+using PortalInfo = DotNetNuke.Entities.Portals.PortalInfo;
namespace Satrabel.OpenContent.Components
{
@@ -47,7 +50,7 @@ public string ExportModule(int moduleId)
var tabModules = ModuleController.Instance.GetTabModulesByModule(moduleId);
Hashtable moduleSettings = tabModules.Any() ? tabModules.First().ModuleSettings : new Hashtable();
-
+
var items = ctrl.GetContents(moduleId);
xml += "";
foreach (var item in items)
@@ -66,7 +69,7 @@ public string ExportModule(int moduleId)
xml += "" + XmlUtils.XMLEncode(moduleSetting.Value.ToString()) + "";
xml += "";
}
-
+
xml += "";
return xml;
}
@@ -113,7 +116,7 @@ public void ImportModule(int moduleId, string content, string version, int userI
}
}
module = OpenContentModuleConfig.Create(moduleId, Null.NullInteger, PortalSettings.Current);
-
+
LuceneUtils.ReIndexModuleData(module);
}
@@ -163,6 +166,9 @@ public override IList GetModifiedSearchDocuments(ModuleInfo modI
{
App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{modInfo.CultureCode} - NOT - No content found");
}
+
+ var ps = new PortalSettings(modInfo.PortalID);
+
foreach (IDataItem content in contentList.Items)
{
if (content == null)
@@ -173,29 +179,38 @@ public override IList GetModifiedSearchDocuments(ModuleInfo modI
&& content.LastModifiedOnDate.ToUniversalTime() < DateTime.UtcNow)
{
SearchDocument searchDoc;
+
+ var portalLocales = DnnLanguageUtils.GetPortalLocales(modInfo.PortalID);
+
if (DnnLanguageUtils.IsMultiLingualPortal(modInfo.PortalID))
{
- // first process the default language module
- var culture = modInfo.CultureCode;
- var localizedData = GetLocalizedContent(content.Data, culture);
- searchDoc = CreateSearchDocument(modInfo, module.Settings, localizedData, content.Id, culture, content.Title, content.LastModifiedOnDate.ToUniversalTime());
- searchDocuments.Add(searchDoc);
- App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{culture} - OK! {searchDoc.Title} ({modInfo.TabID}) of {content.LastModifiedOnDate.ToUniversalTime()}");
-
- // now do the same with any linked localized instances of this module
- if (modInfo.LocalizedModules != null)
- foreach (var localizedModule in modInfo.LocalizedModules)
- {
- culture = localizedModule.Value.CultureCode;
- localizedData = GetLocalizedContent(content.Data, culture);
- searchDoc = CreateSearchDocument(modInfo, module.Settings, localizedData, content.Id, culture, content.Title, content.LastModifiedOnDate.ToUniversalTime());
- searchDocuments.Add(searchDoc);
- App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{culture} - OK! {searchDoc.Title} ({modInfo.TabID}) of {content.LastModifiedOnDate.ToUniversalTime()}");
- }
+ if (string.IsNullOrEmpty(modInfo.CultureCode))
+ {
+ // it's a neutral language module according to DNN, which means we will need to add the neutral language content too
+ var culture = ps.DefaultLanguage;
+ var localizedData = GetLocalizedContent(content.Data, culture);
+ // pass "" as culture to indicate we're indexing the neutral language here
+ searchDoc = CreateSearchDocument(ps, modInfo, module.Settings, localizedData, content.Id, "", content.Title, content.LastModifiedOnDate.ToUniversalTime());
+ searchDocuments.Add(searchDoc);
+ App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{culture} - OK! {searchDoc.Title} ({modInfo.TabID}) of {content.LastModifiedOnDate.ToUniversalTime()}");
+ }
+ // now start creating the docs for specific cultures
+ foreach (var portalLocale in portalLocales.Keys)
+ {
+ var localizedData = GetLocalizedContent(content.Data, portalLocale);
+ searchDoc = CreateSearchDocument(ps, modInfo, module.Settings, localizedData, content.Id, portalLocale, content.Title, content.LastModifiedOnDate.ToUniversalTime());
+ searchDocuments.Add(searchDoc);
+ App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{portalLocale} - OK! {searchDoc.Title} ({modInfo.TabID}) of {content.LastModifiedOnDate.ToUniversalTime()}");
+ }
}
else
{
- searchDoc = CreateSearchDocument(modInfo, module.Settings, content.Data, content.Id, "", content.Title, content.LastModifiedOnDate.ToUniversalTime());
+ // to make ML-Templates be correctly indexed by DNN, we need to use GetLocalizedContent with the default culture
+ // for sites with only one culture
+ var culture = portalLocales.First().Key ?? "";
+ var localizedData = string.IsNullOrEmpty(culture) ? content.Data : GetLocalizedContent(content.Data, culture);
+ // we are intentionally still passing "" as culture to tell DNN it's the neutral language content
+ searchDoc = CreateSearchDocument(ps, modInfo, module.Settings, localizedData, content.Id, "", content.Title, content.LastModifiedOnDate.ToUniversalTime());
searchDocuments.Add(searchDoc);
App.Services.Logger.Trace($"Indexing content {modInfo.ModuleID}|{modInfo.CultureCode} - OK! {searchDoc.Title} ({modInfo.TabID}) of {content.LastModifiedOnDate.ToUniversalTime()}");
}
@@ -217,11 +232,10 @@ private static JToken GetLocalizedContent(JToken contentData, string culture)
return retval;
}
- private static SearchDocument CreateSearchDocument(ModuleInfo modInfo, OpenContentSettings settings, JToken contentData, string itemId, string culture, string dataItemTitle, DateTime time)
+ private static SearchDocument CreateSearchDocument(PortalSettings ps, ModuleInfo modInfo, OpenContentSettings settings, JToken contentData, string itemId, string culture, string dataItemTitle, DateTime time)
{
// existance of settings.Template.Main has already been checked: we wouldn't be here if it doesn't exist
// but still, we don't want to count on that too much
- var ps = new PortalSettings(modInfo.PortalID);
ps.PortalAlias = PortalAliasController.Instance.GetPortalAlias(ps.DefaultPortalAlias);
string url = null;
@@ -235,6 +249,14 @@ private static SearchDocument CreateSearchDocument(ModuleInfo modInfo, OpenConte
// With a signle template we don't want to identify the content by id.
url = TestableGlobals.Instance.NavigateURL(modInfo.TabID, ps, "");
}
+ // chek if we have a dnnSearchUrl field
+ // if we have, we use the OpenContent url as default
+ if (!string.IsNullOrEmpty(settings.Template?.Main?.DnnSearchUrl))
+ {
+ var dicForHbs = JsonUtils.JsonToDictionary(contentData.ToString());
+ var hbEngine = new HandlebarsEngine();
+ url = hbEngine.ExecuteWithoutFaillure(settings.Template.Main.DnnSearchUrl, dicForHbs, url);
+ }
// instanciate the search document
var retval = new SearchDocument
@@ -411,6 +433,44 @@ public string UpgradeModule(string version)
{
LuceneUtils.IndexAll();
}
+ else if (version == "04.07.00")
+ {
+ // Given the changed behavior with time int publishedEndDate, we need to Update the lucene index for all items.
+ foreach (PortalInfo portal in PortalController.Instance.GetPortals())
+ {
+ var portalId = portal.PortalID;
+ IEnumerable modules = (new ModuleController()).GetModules(portalId).Cast();
+ modules = modules.Where(m => m.ModuleDefinition.DefinitionName == App.Config.Opencontent && m.IsDeleted == false && !m.OpenContentSettings().IsOtherModule);
+ foreach (var module in modules)
+ {
+ try
+ {
+ var ocConfig = OpenContentModuleConfig.Create(module, new PortalSettings(portalId));
+ var dsContext = OpenContentUtils.CreateDataContext(ocConfig);
+ var indexConfig = OpenContentUtils.GetIndexConfig(new FolderUri(dsContext.TemplateFolder), dsContext.Collection);
+ if (dsContext.Index)
+ {
+ if (indexConfig.HasField(App.Config.FieldNamePublishEndDate))
+ {
+ IDataSource ds = DataSourceManager.GetDataSource(ocConfig.Settings.Manifest.DataSource);
+ foreach (var dataItem in ds.GetAll(dsContext, new Select()).Items)
+ {
+ var content = (OpenContentInfo)dataItem.Item;
+ content.HydrateDefaultFields(indexConfig, ocConfig.Settings?.Manifest?.UsePublishTime ?? false);
+ LuceneController.Instance.Update(content, indexConfig);
+ }
+ LuceneController.Instance.Commit();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ App.Services.Logger.Error("Error during upgrade to 4.7.0: reindex all modules to fix.", e);
+ }
+ }
+ }
+
+ }
return version + res;
}
diff --git a/OpenContent/Components/FileUploadController.cs b/OpenContent/Components/FileUploadController.cs
index 6741bbd1..67beb64c 100644
--- a/OpenContent/Components/FileUploadController.cs
+++ b/OpenContent/Components/FileUploadController.cs
@@ -60,6 +60,7 @@ public HttpResponseMessage UploadFile()
catch (Exception exc)
{
Logger.Error(exc);
+ throw;
}
return IframeSafeJson(statuses);
}
@@ -78,6 +79,7 @@ public HttpResponseMessage UploadEasyImage()
catch (Exception exc)
{
Logger.Error(exc);
+ throw;
}
return new HttpResponseMessage
{
diff --git a/OpenContent/Components/Handlebars/HandlebarsEngine.cs b/OpenContent/Components/Handlebars/HandlebarsEngine.cs
index d8b33401..c2de5ee0 100644
--- a/OpenContent/Components/Handlebars/HandlebarsEngine.cs
+++ b/OpenContent/Components/Handlebars/HandlebarsEngine.cs
@@ -424,9 +424,20 @@ private static void RegisterEachPublishedHelper(HandlebarsDotNet.IHandlebars hbs
try
{
DateTime publishstartdate = DateTime.Parse(item.publishstartdate, null, System.Globalization.DateTimeStyles.RoundtripKind);
- if (publishstartdate.Date >= DateTime.Today)
+ // check if we need to compare the time
+ if (publishstartdate.TimeOfDay.TotalMilliseconds > 0)
{
- show = false;
+ if (publishstartdate >= DateTime.Now)
+ {
+ show = false;
+ }
+ }
+ else
+ {
+ if (publishstartdate.Date >= DateTime.Today)
+ {
+ show = false;
+ }
}
}
catch (Exception)
@@ -435,9 +446,20 @@ private static void RegisterEachPublishedHelper(HandlebarsDotNet.IHandlebars hbs
try
{
DateTime publishenddate = DateTime.Parse(item.publishenddate, null, System.Globalization.DateTimeStyles.RoundtripKind);
- if (publishenddate.Date <= DateTime.Today)
+ // check if we need to compare the time
+ if (publishenddate.TimeOfDay.TotalMilliseconds > 0)
{
- show = false;
+ if (publishenddate <= DateTime.Now)
+ {
+ show = false;
+ }
+ }
+ else
+ {
+ if (publishenddate.Date <= DateTime.Today)
+ {
+ show = false;
+ }
}
}
catch (Exception)
@@ -584,6 +606,16 @@ private static void RegisterImageUrlHelper(HandlebarsDotNet.IHandlebars hbs)
writer.WriteSafeString(imageUrl);
}
});
+ hbs.RegisterHelper("imageediturl", (writer, context, parameters) =>
+ {
+ if (parameters.Length == 1) //{{imageediturl ImageId}}
+ {
+ string imageId = parameters[0].ToString();
+ ImageUri imageObject = ImageUriFactory.CreateImageUri(imageId);
+ var imageUrl = imageObject == null ? string.Empty : imageObject.EditUrl();
+ writer.WriteSafeString(imageUrl);
+ }
+ });
}
private static void RegisterEmailHelper(HandlebarsDotNet.IHandlebars hbs)
@@ -1124,7 +1156,7 @@ private static void RegisterContainsHelper(IHandlebars hbs)
{
var arg1 = arguments[0].ToString();
var arg2 = arguments[1].ToString();
- res = arg2.Contains(arg1);
+ res = arg1.Contains(arg2);
}
if (res)
diff --git a/OpenContent/Components/Lucene/Mapping/JsonObjectMapper.cs b/OpenContent/Components/Lucene/Mapping/JsonObjectMapper.cs
index 1f394ba5..5aadb416 100644
--- a/OpenContent/Components/Lucene/Mapping/JsonObjectMapper.cs
+++ b/OpenContent/Components/Lucene/Mapping/JsonObjectMapper.cs
@@ -69,185 +69,194 @@ public void AddJsonToDocument(JToken json, Document doc, FieldConfig config)
///
private static void Add(Document doc, string prefix, JToken token, FieldConfig fieldconfig)
{
- if (token is JObject)
+ try
{
- AddProperties(doc, prefix, token as JObject, fieldconfig);
- }
- else if (token is JArray)
- {
- var itemsConfig = fieldconfig?.Items;
- if (fieldconfig != null && fieldconfig.Index && itemsConfig == null)
+ if (token is JObject)
{
- throw new Exception($"Error indexing Array field {prefix}. No 'Items' section defined in index.json. Please fix your index.json.");
+ AddProperties(doc, prefix, token as JObject, fieldconfig);
}
- AddArray(doc, prefix, token as JArray, itemsConfig);
- }
- else if (token is JValue)
- {
- JValue value = token as JValue;
- bool index = false;
- bool sort = false;
- if (fieldconfig != null)
+ else if (token is JArray)
{
- index = fieldconfig.Index;
- sort = fieldconfig.Sort;
- if (fieldconfig.IndexType == "datetime" && value.Type == JTokenType.String)
+ var itemsConfig = fieldconfig?.Items;
+ if (fieldconfig != null && fieldconfig.Index && itemsConfig == null)
{
- DateTime d;
- if (DateTime.TryParse(value.Value.ToString(), null, System.Globalization.DateTimeStyles.RoundtripKind, out d))
- {
- value = new JValue(d);
- }
+ throw new Exception($"Error indexing Array field {prefix}. No 'Items' section defined in index.json. Please fix your index.json.");
}
+ AddArray(doc, prefix, token as JArray, itemsConfig);
}
-
- switch (value.Type) //todo: simple date gets detected as string
+ else if (token is JValue)
{
- case JTokenType.Boolean:
- if (index || sort)
+ JValue value = token as JValue;
+ bool index = false;
+ bool sort = false;
+ if (fieldconfig != null)
+ {
+ index = fieldconfig.Index;
+ sort = fieldconfig.Sort;
+ if (fieldconfig.IndexType == "datetime" && value.Type == JTokenType.String)
{
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetIntValue((bool)value.Value ? 1 : 0));
+ DateTime d;
+ if (DateTime.TryParse(value.Value.ToString(), null, System.Globalization.DateTimeStyles.RoundtripKind, out d))
+ {
+ value = new JValue(d);
+ }
}
- break;
+ }
- case JTokenType.Date:
- if (index || sort)
- {
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetLongValue(((DateTime)value.Value).Ticks));
+ switch (value.Type) //todo: simple date gets detected as string
+ {
+ case JTokenType.Boolean:
+ if (index || sort)
+ {
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetIntValue((bool)value.Value ? 1 : 0));
+ }
+ break;
+
+ case JTokenType.Date:
+ if (index || sort)
+ {
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetLongValue(((DateTime)value.Value).Ticks));
- //doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ //doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND), Field.Store.NO, Field.Index.NOT_ANALYZED));
- /*
- if (field != null ){
- if (field.IndexType == "datetime")
+ /*
+ if (field != null ){
+ if (field.IndexType == "datetime")
+ {
+ doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
+ else if (field.IndexType == "date")
+ {
+ doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.DAY), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
+ else if (field.IndexType == "time")
+ {
+ doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND).Substring(8), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
+ }
+ else
{
doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND), Field.Store.NO, Field.Index.NOT_ANALYZED));
}
- else if (field.IndexType == "date")
+ */
+ }
+ break;
+
+ case JTokenType.Float:
+ if (index || sort)
+ {
+ if (value.Value is float)
{
- doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.DAY), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)value.Value));
}
- else if (field.IndexType == "time")
+ else
{
- doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND).Substring(8), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)Convert.ToDouble(value.Value)));
}
}
- else
- {
- doc.Add(new Field(prefix, DateTools.DateToString((DateTime)value.Value, DateTools.Resolution.SECOND), Field.Store.NO, Field.Index.NOT_ANALYZED));
- }
- */
- }
- break;
+ break;
- case JTokenType.Float:
- if (index || sort)
- {
- if (value.Value is float)
+ case JTokenType.Guid:
+ if (index || sort)
{
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)value.Value));
+ doc.Add(new Field(prefix, value.Value.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED));
}
- else
+ break;
+
+ case JTokenType.Integer:
+ if (index || sort)
{
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)Convert.ToDouble(value.Value)));
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)Convert.ToInt64(value.Value)));
}
- }
- break;
+ break;
- case JTokenType.Guid:
- if (index || sort)
- {
- doc.Add(new Field(prefix, value.Value.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED));
- }
- break;
-
- case JTokenType.Integer:
- if (index || sort)
- {
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetFloatValue((float)Convert.ToInt64(value.Value)));
- }
- break;
-
- case JTokenType.Null:
- break;
+ case JTokenType.Null:
+ break;
- case JTokenType.String:
+ case JTokenType.String:
+ if (value.Value == null)
+ break;
- if (fieldconfig != null && fieldconfig.IndexType == "key")
- {
- doc.Add(new Field(prefix, QueryParser.Escape(value.Value.ToString()), Field.Store.NO, Field.Index.NOT_ANALYZED));
- }
- else if (fieldconfig != null && fieldconfig.IndexType == "html")
- {
- if (index)
+ if (fieldconfig != null && fieldconfig.IndexType == "key")
{
- doc.Add(new Field(prefix, CleanHtml(value.Value.ToString(), true), Field.Store.NO, Field.Index.ANALYZED));
+ doc.Add(new Field(prefix, QueryParser.Escape(value.Value.ToString()), Field.Store.NO, Field.Index.NOT_ANALYZED));
}
- if (sort)
+ else if (fieldconfig != null && fieldconfig.IndexType == "html")
{
- doc.Add(new Field("@" + prefix, CleanHtml(Truncate(value.Value.ToString(), 100), true), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ if (index)
+ {
+ doc.Add(new Field(prefix, CleanHtml(value.Value.ToString(), true), Field.Store.NO, Field.Index.ANALYZED));
+ }
+ if (sort)
+ {
+ doc.Add(new Field("@" + prefix, CleanHtml(Truncate(value.Value.ToString(), 100), true), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
}
- }
- else if (fieldconfig != null && fieldconfig.IndexType == "file")
- {
- var val = value.Value.ToString();
- if (!string.IsNullOrEmpty(val))
+ else if (fieldconfig != null && fieldconfig.IndexType == "file")
{
- var fileIndexer = FileIndexerManager.GetFileIndexer(val);
- if (fileIndexer != null)
+ var val = value.Value.ToString();
+ if (!string.IsNullOrEmpty(val))
{
- var content = fileIndexer.GetContent(val);
- if (index)
+ var fileIndexer = FileIndexerManager.GetFileIndexer(val);
+ if (fileIndexer != null)
{
- doc.Add(new Field(prefix, content, Field.Store.NO, Field.Index.ANALYZED));
- }
- if (sort)
- {
- doc.Add(new Field("@" + prefix, Truncate(content, 100), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ var content = fileIndexer.GetContent(val);
+ if (index)
+ {
+ doc.Add(new Field(prefix, content, Field.Store.NO, Field.Index.ANALYZED));
+ }
+ if (sort)
+ {
+ doc.Add(new Field("@" + prefix, Truncate(content, 100), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
}
}
}
- }
- else
- {
-
- var val = SelectQueryDefinition.RemoveDiacritics(value.Value.ToString());
- val = val.Replace('-', ' '); // concider '-' as a space
- val = val.Replace(',', ' '); // concider ',' as a space
- //var val = LuceneUtils.CleanupText(value.Value.ToString());
- if (index)
+ else
{
- doc.Add(new Field(prefix, val, Field.Store.NO, Field.Index.ANALYZED));
+ var val = SelectQueryDefinition.RemoveDiacritics(value.Value.ToString());
+ val = val.Replace('-', ' '); // concider '-' as a space
+ val = val.Replace(',', ' '); // concider ',' as a space
+ //var val = LuceneUtils.CleanupText(value.Value.ToString());
+ if (index)
+ {
+ doc.Add(new Field(prefix, val, Field.Store.NO, Field.Index.ANALYZED));
+ }
+ if (sort)
+ {
+ doc.Add(new Field("@" + prefix, Truncate(val, 100), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ }
}
- if (sort)
+ break;
+
+ case JTokenType.TimeSpan:
+ if (index || sort)
{
- doc.Add(new Field("@" + prefix, Truncate(val, 100), Field.Store.NO, Field.Index.NOT_ANALYZED));
+ doc.Add(new NumericField(prefix, Field.Store.NO, true).SetLongValue(((TimeSpan)value.Value).Ticks));
}
- }
- break;
+ break;
- case JTokenType.TimeSpan:
- if (index || sort)
- {
- doc.Add(new NumericField(prefix, Field.Store.NO, true).SetLongValue(((TimeSpan)value.Value).Ticks));
- }
- break;
-
- case JTokenType.Uri:
- if (index || sort)
- {
- doc.Add(new Field(prefix, value.Value.ToString(), Field.Store.NO, Field.Index.ANALYZED));
- }
- break;
+ case JTokenType.Uri:
+ if (index || sort)
+ {
+ doc.Add(new Field(prefix, value.Value.ToString(), Field.Store.NO, Field.Index.ANALYZED));
+ }
+ break;
- default:
- Debug.Fail("Unsupported JValue type: " + value.Type);
- break;
+ default:
+ Debug.Fail("Unsupported JValue type: " + value.Type);
+ break;
+ }
+ }
+ else
+ {
+ Debug.Fail("Unsupported JToken: " + token);
}
}
- else
+ catch (Exception e)
{
- Debug.Fail("Unsupported JToken: " + token);
+ if(Debugger.IsAttached) Debugger.Break();
+ throw;
}
}
diff --git a/OpenContent/Components/Manifest/Manifest.cs b/OpenContent/Components/Manifest/Manifest.cs
index a8d90792..98cb5729 100644
--- a/OpenContent/Components/Manifest/Manifest.cs
+++ b/OpenContent/Components/Manifest/Manifest.cs
@@ -75,7 +75,9 @@ public Dictionary AdditionalDataDefinition
[JsonProperty(PropertyName = "deleteFiles")]
public bool DeleteFiles { get; set; }
-
+ [JsonProperty(PropertyName = "usePublishTime")]
+ public bool UsePublishTime { get; set; }
+
public bool HasTemplates => (Templates != null);
public FolderUri ManifestDir { get; set; }
diff --git a/OpenContent/Components/Manifest/TemplateFiles.cs b/OpenContent/Components/Manifest/TemplateFiles.cs
index ab3e346a..519001c3 100644
--- a/OpenContent/Components/Manifest/TemplateFiles.cs
+++ b/OpenContent/Components/Manifest/TemplateFiles.cs
@@ -63,6 +63,15 @@ public TemplateFiles()
[JsonProperty(PropertyName = "dnnSearchText")]
public string DnnSearchText { get; set; }
+ ///
+ /// Gets or sets a value specifying the url to use for the indexed document in [DNN search].
+ ///
+ ///
+ /// You can use a Handlebars template.
+ ///
+ [JsonProperty(PropertyName = "dnnSearchUrl")]
+ public string DnnSearchUrl { get; set; }
+
[JsonProperty(PropertyName = "model")]
public Dictionary Model { get; set; }
}
diff --git a/OpenContent/Components/OpenContentAPIController.cs b/OpenContent/Components/OpenContentAPIController.cs
index dc9b862a..4dfdf4c4 100644
--- a/OpenContent/Components/OpenContentAPIController.cs
+++ b/OpenContent/Components/OpenContentAPIController.cs
@@ -96,10 +96,10 @@ public HttpResponseMessage Edit(string id)
}
json["options"]["form"]["buttons"] = newButtons;
}
- string itemKey;
+ string itemKey;
if (dsItem == null)
{
- itemKey= ObjectId.NewObjectId().ToString();
+ itemKey = ObjectId.NewObjectId().ToString();
}
else
{
diff --git a/OpenContent/Components/OpenContentInfo.cs b/OpenContent/Components/OpenContentInfo.cs
index d539702b..e5b6feba 100644
--- a/OpenContent/Components/OpenContentInfo.cs
+++ b/OpenContent/Components/OpenContentInfo.cs
@@ -37,8 +37,13 @@ public OpenContentInfo(string json)
}
public int ContentId { get; set; }
+
+ ///
+ /// OpenContent item Key, unique across all modules. Typically populated with ObjectId.NewObjectId().ToString()
+ ///
[ColumnName("DocumentKey")]
public string Key { get; internal set; }
+
[IgnoreColumn]
public string Id
{
@@ -73,7 +78,14 @@ public JToken JsonAsJToken
{
if (_jsonAsJToken == null && !string.IsNullOrEmpty(this.Json))
{
- _jsonAsJToken = JToken.Parse(this.Json);
+ try
+ {
+ _jsonAsJToken = JToken.Parse(this.Json);
+ }
+ catch (Exception e)
+ {
+ throw new Exception($"Failed to parse json from moduleId:{ModuleId}, contentId:{ContentId}", e);
+ }
}
// JsonAsJToken is modified (to remove other cultures)
return _jsonAsJToken?.DeepClone();
diff --git a/OpenContent/Components/Querying/QueryBuilder.cs b/OpenContent/Components/Querying/QueryBuilder.cs
index e5ab9c7d..a67d25a9 100644
--- a/OpenContent/Components/Querying/QueryBuilder.cs
+++ b/OpenContent/Components/Querying/QueryBuilder.cs
@@ -271,23 +271,23 @@ private void AddWorkflowFilter(FilterGroup filter)
if (_indexConfig?.Fields != null && _indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishStartDate))
{
//DateTime startDate = DateTime.MinValue;
- //DateTime endDate = DateTime.Today;
+ //DateTime endDate = DateTime.Now;
filter.AddRule(new FilterRule()
{
Field = App.Config.FieldNamePublishStartDate,
- Value = new DateTimeRuleValue(DateTime.Today),
+ Value = new DateTimeRuleValue(DateTime.Now),
FieldOperator = OperatorEnum.LESS_THEN_OR_EQUALS,
FieldType = FieldTypeEnum.DATETIME
});
}
if (_indexConfig?.Fields != null && _indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishEndDate))
{
- //DateTime startDate = DateTime.Today;
+ //DateTime startDate = DateTime.Now;
//DateTime endDate = DateTime.MaxValue;
filter.AddRule(new FilterRule()
{
Field = App.Config.FieldNamePublishEndDate,
- Value = new DateTimeRuleValue(DateTime.Today),
+ Value = new DateTimeRuleValue(DateTime.Now),
FieldOperator = OperatorEnum.GREATER_THEN_OR_EQUALS,
FieldType = FieldTypeEnum.DATETIME
});
diff --git a/OpenContent/Components/Render/ModelFactoryBase.cs b/OpenContent/Components/Render/ModelFactoryBase.cs
index ca46ebf9..78033339 100644
--- a/OpenContent/Components/Render/ModelFactoryBase.cs
+++ b/OpenContent/Components/Render/ModelFactoryBase.cs
@@ -296,8 +296,7 @@ protected void ExtendModel(JObject model, bool onlyData, bool onlyMainData, stri
context["ModuleId"] = _module.ViewModule.ModuleId;
context["GoogleApiKey"] = App.Services.CreateGlobalSettingsRepository(_portalId).GetGoogleApiKey();
context["ModuleTitle"] = _module.ViewModule.ModuleTitle;
- var editIsAllowed = !_manifest.DisableEdit && !_templateManifest.DisableEdit && IsEditAllowed(-1);
- context["IsEditable"] = editIsAllowed; //allowed to edit the item or list (meaning allow Add)
+
context["IsEditMode"] = IsEditMode;
context["PortalId"] = _portalId;
context["MainUrl"] = _module.GetUrl(_detailTabId, GetCurrentCultureCode());
@@ -305,8 +304,13 @@ protected void ExtendModel(JObject model, bool onlyData, bool onlyMainData, stri
context["HTTPAlias"] = _module.HostName;
context["PortalName"] = _module.PortalName;
context["TemplatePath"] = _module.Settings.TemplateDir.UrlFolder;
- context["TemplateName"] = (String.IsNullOrEmpty(_manifest.Title) ? Path.GetFileName(_templateManifest.MainTemplateUri().FolderPath) : _manifest.Title) +" - "+ (string.IsNullOrEmpty(_templateManifest.Title) ? _templateManifest.Key.ShortKey : _templateManifest.Title);
- //context["TemplateName"] = _templateManifest.MainTemplateUri().UrlFilePath ;
+ if (_templateManifest != null)
+ {
+ var editIsAllowed = !_manifest.DisableEdit && !_templateManifest.DisableEdit && IsEditAllowed(-1);
+ context["IsEditable"] = editIsAllowed; //allowed to edit the item or list (meaning allow Add)
+ context["TemplateName"] = (String.IsNullOrEmpty(_manifest.Title) ? Path.GetFileName(_templateManifest.MainTemplateUri().FolderPath) : _manifest.Title) + " - " + (string.IsNullOrEmpty(_templateManifest.Title) ? _templateManifest.Key.ShortKey : _templateManifest.Title);
+ //context["TemplateName"] = _templateManifest.MainTemplateUri().UrlFilePath ;
+ }
}
}
@@ -540,7 +544,8 @@ private JToken GenerateObject(string id, int tabId, int moduleId, bool onlyData)
var context = new JObject();
json["Context"] = context;
context["Id"] = dataItem.Id;
- context["DetailUrl"] = GenerateDetailUrl(dataItem, json, module.Settings.Manifest, GetCurrentCultureCode(), tabId > 0 ? tabId : _detailTabId);
+ //context["DetailUrl"] = GenerateDetailUrl(dataItem, json, module.Settings.Manifest, GetCurrentCultureCode(), tabId > 0 ? tabId : _detailTabId);
+ context["DetailUrl"] = GenerateDetailUrl(dataItem, json, module.Settings.Manifest, GetCurrentCultureCode(), _detailTabId);
}
return json;
}
@@ -562,7 +567,7 @@ protected string GenerateDetailUrl(IDataItem item, JObject dyn, Manifest.Manifes
url = hbEngine.Execute(manifest.DetailUrl, dynForHBS);
url = HttpUtility.HtmlDecode(url);
}
- return _module.GetUrl(_detailTabId, cultureCode, url.CleanupUrl(), "id=" + item.Id);
+ return _module.GetUrl(detailTabId, cultureCode, url.CleanupUrl(), "id=" + item.Id);
}
}
}
\ No newline at end of file
diff --git a/OpenContent/Components/Render/ModelFactoryMultiple.cs b/OpenContent/Components/Render/ModelFactoryMultiple.cs
index c4410bd7..0a3e132d 100644
--- a/OpenContent/Components/Render/ModelFactoryMultiple.cs
+++ b/OpenContent/Components/Render/ModelFactoryMultiple.cs
@@ -103,8 +103,11 @@ public override JToken GetModelAsJson(bool onlyData = false, bool onlyMainData =
}
else
{
- var editStatus = !_manifest.DisableEdit && !_templateManifest.DisableEdit && IsEditAllowed(item.CreatedByUserId);
- context["IsEditable"] = editStatus;
+ if (_templateManifest != null)
+ {
+ var editStatus = !_manifest.DisableEdit && !_templateManifest.DisableEdit && IsEditAllowed(item.CreatedByUserId);
+ context["IsEditable"] = editStatus;
+ }
if (HasEditPermissions(item.CreatedByUserId))
{
context["EditUrl"] = _module.EditUrl("id", item.Id, _module.ViewModule.ModuleId);
diff --git a/OpenContent/Components/Render/RenderEngine.cs b/OpenContent/Components/Render/RenderEngine.cs
index f65c305d..78e265e6 100644
--- a/OpenContent/Components/Render/RenderEngine.cs
+++ b/OpenContent/Components/Render/RenderEngine.cs
@@ -366,7 +366,7 @@ private void GetDetailData(RenderInfo info, OpenContentModuleConfig module)
{
var indexConfig = OpenContentUtils.GetIndexConfig(info.Template);
string raison;
- if (!OpenContentUtils.HaveViewPermissions(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
+ if (!OpenContentUtils.IsViewAllowed(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
{
App.Services.Logger.Error($"Error accessing {HttpContext.Current?.Request?.Url?.AbsoluteUri}. Referrer {HttpContext.Current?.Request?.UrlReferrer?.AbsoluteUri}");
if (module.ViewModule.HasEditRightsOnModule())
diff --git a/OpenContent/Components/Rest/RestController.cs b/OpenContent/Components/Rest/RestController.cs
index b107a38b..910eb29c 100644
--- a/OpenContent/Components/Rest/RestController.cs
+++ b/OpenContent/Components/Rest/RestController.cs
@@ -54,7 +54,7 @@ public HttpResponseMessage Get(string entity, string id)
var mf = new ModelFactorySingle(dsItem, module, collection);
string raison = "";
- if (!OpenContentUtils.HaveViewPermissions(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
+ if (!OpenContentUtils.IsViewAllowed(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
{
Exceptions.ProcessHttpException(new HttpException(404, "No detail view permissions for id=" + id + " (" + raison + ")"));
//throw new UnauthorizedAccessException("No detail view permissions for id " + info.DetailItemId);
diff --git a/OpenContent/Components/Rest/V2/RestController.cs b/OpenContent/Components/Rest/V2/RestController.cs
index 15849a8d..d290f09d 100644
--- a/OpenContent/Components/Rest/V2/RestController.cs
+++ b/OpenContent/Components/Rest/V2/RestController.cs
@@ -55,7 +55,7 @@ public HttpResponseMessage Get(string entity, string id)
var mf = new ModelFactorySingle(dsItem, module, collection);
string raison = "";
- if (!OpenContentUtils.HaveViewPermissions(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
+ if (!OpenContentUtils.IsViewAllowed(dsItem, module.UserRoles.FromDnnRoles(), indexConfig, out raison))
{
Exceptions.ProcessHttpException(new HttpException(404, "No detail view permissions for id=" + id + " (" + raison + ")"));
//throw new UnauthorizedAccessException("No detail view permissions for id " + info.DetailItemId);
diff --git a/OpenContent/Components/Utils/OpenContentUtils.cs b/OpenContent/Components/Utils/OpenContentUtils.cs
index a8be462b..e7ce1595 100644
--- a/OpenContent/Components/Utils/OpenContentUtils.cs
+++ b/OpenContent/Components/Utils/OpenContentUtils.cs
@@ -25,7 +25,7 @@ namespace Satrabel.OpenContent.Components
{
public static class OpenContentUtils
{
- public static void HydrateDefaultFields(this OpenContentInfo content, FieldConfig indexConfig)
+ public static void HydrateDefaultFields(this OpenContentInfo content, FieldConfig indexConfig, bool usePublishTime = false)
{
if (indexConfig.HasField(App.Config.FieldNamePublishStartDate)
&& content.JsonAsJToken != null && content.JsonAsJToken[App.Config.FieldNamePublishStartDate] == null)
@@ -33,9 +33,26 @@ public static void HydrateDefaultFields(this OpenContentInfo content, FieldConfi
content.JsonAsJToken[App.Config.FieldNamePublishStartDate] = DateTime.MinValue;
}
if (indexConfig.HasField(App.Config.FieldNamePublishEndDate)
- && content.JsonAsJToken != null && content.JsonAsJToken[App.Config.FieldNamePublishEndDate] == null)
+ && content.JsonAsJToken != null)
{
- content.JsonAsJToken[App.Config.FieldNamePublishEndDate] = DateTime.MaxValue;
+ if (content.JsonAsJToken[App.Config.FieldNamePublishEndDate] == null)
+ {
+ content.JsonAsJToken[App.Config.FieldNamePublishEndDate] = DateTime.MaxValue;
+ }
+ else
+ {
+ // if the enddata has no time,
+ // and we don't need to usePublishTime
+ // we add 23:59:59.999 as a time
+ var t = content.JsonAsJToken[App.Config.FieldNamePublishEndDate].Value();
+ if (!usePublishTime && t.TimeOfDay.TotalMilliseconds == 0)
+ {
+ var contentJToken = content.JsonAsJToken;
+ contentJToken[App.Config.FieldNamePublishEndDate] = t.AddDays(1).AddMilliseconds(-1);
+ content.JsonAsJToken = contentJToken;
+ }
+ }
+
}
if (indexConfig.HasField(App.Config.FieldNamePublishStatus)
&& content.JsonAsJToken != null && content.JsonAsJToken[App.Config.FieldNamePublishStatus] == null)
@@ -63,7 +80,7 @@ public static string GetSkinTemplateFolder(PortalSettings portalSettings, string
public static string GetHostTemplateFolder(PortalSettings portalSettings, string moduleSubDir)
{
var hostPath = "~/Portals/_Default/";
-
+
return hostPath + moduleSubDir + "/Templates/";
}
@@ -220,7 +237,7 @@ public static List ListOfTemplatesFiles(PortalSettings portalSettings,
//if (!string.IsNullOrEmpty(portalSettings.ActiveTab.SkinPath))
{
basePath = HostingEnvironment.MapPath(GetSkinTemplateFolder(portalSettings, moduleSubDir));
-
+
dirs = GetDirs(selectedTemplate, otherModuleTemplate, advanced, basePath, dirs, lst, "Skin");
}
// Host
@@ -266,22 +283,25 @@ private static string[] GetDirs(TemplateManifest selectedTemplate, FileUri other
if (manifest != null && manifest.HasTemplates)
{
manifestTemplateFound = true;
- foreach (var template in manifest.Templates)
+ if (advanced || !manifest.Advanced)
{
- FileUri templateUri = new FileUri(manifestFileUri.FolderPath, template.Key);
- string templateName = Path.GetDirectoryName(manifestFile).Substring(basePath.Length).Replace("\\", " / ");
- if (!String.IsNullOrEmpty(template.Value.Title))
+ foreach (var template in manifest.Templates)
{
- if (advanced)
- templateName = templateName + " - " + template.Value.Title;
+ FileUri templateUri = new FileUri(manifestFileUri.FolderPath, template.Key);
+ string templateName = Path.GetDirectoryName(manifestFile).Substring(basePath.Length).Replace("\\", " / ");
+ if (!String.IsNullOrEmpty(template.Value.Title))
+ {
+ if (advanced)
+ templateName = templateName + " - " + template.Value.Title;
+ }
+ var item = new ListItem((templateCat == "Site" ? "" : templateCat + " : ") + templateName, templateUri.FilePath);
+ if (selectedTemplate != null && templateUri.FilePath.ToLowerInvariant() == selectedTemplate.Key.ToString().ToLowerInvariant())
+ {
+ item.Selected = true;
+ }
+ lst.Add(item);
+ if (!advanced) break;
}
- var item = new ListItem((templateCat == "Site" ? "" : templateCat + " : ") + templateName, templateUri.FilePath);
- if (selectedTemplate != null && templateUri.FilePath.ToLowerInvariant() == selectedTemplate.Key.ToString().ToLowerInvariant())
- {
- item.Selected = true;
- }
- lst.Add(item);
- if (!advanced) break;
}
}
}
@@ -622,81 +642,140 @@ internal static bool FormExist(FolderUri folder)
return false;
}
- internal static bool HaveViewPermissions(IDataItem dsItem, IList userRoles, FieldConfig indexConfig, out string raison)
+ internal static bool IsViewAllowed(IDataItem dsItem, IList userRoles, FieldConfig indexConfig, out string raison)
{
raison = "";
if (dsItem?.Data == null) return true;
- bool permissions = true;
//publish status , dates
- if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishStatus))
- {
- permissions = dsItem.Data[App.Config.FieldNamePublishStatus] != null &&
- dsItem.Data[App.Config.FieldNamePublishStatus].ToString() == "published";
- if (!permissions) raison = App.Config.FieldNamePublishStatus + $" being {dsItem.Data[App.Config.FieldNamePublishStatus]}";
- }
- if (permissions && indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishStartDate))
+ var isAllowed = IsPublished(dsItem, indexConfig, out raison);
+ // user and roles
+ if (isAllowed) isAllowed = HaveViewPermissions(dsItem, userRoles, indexConfig, out raison);
+
+ return isAllowed;
+ }
+ ///
+ /// Check the user's permissions to view the item. NOTE: as of 2021-05-22 use IsViewAllowed to also check publish status and date.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static bool HaveViewPermissions(IDataItem dsItem, IList userRoles, FieldConfig indexConfig, out string reason)
+ {
+ reason = "";
+ if (dsItem?.Data == null) return true;
+
+ bool permissions = true;
+
+ // Roles
+ string fieldName = "";
+ if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey("userrole"))
{
- permissions = dsItem.Data[App.Config.FieldNamePublishStartDate] != null &&
- dsItem.Data[App.Config.FieldNamePublishStartDate].Type == JTokenType.Date &&
- ((DateTime)dsItem.Data[App.Config.FieldNamePublishStartDate]) <= DateTime.Today;
- if (!permissions) raison = App.Config.FieldNamePublishStartDate + $" being {dsItem.Data[App.Config.FieldNamePublishStartDate]}";
+ fieldName = "userrole";
}
- if (permissions && indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishEndDate))
+ else if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey("userroles"))
{
- permissions = dsItem.Data[App.Config.FieldNamePublishEndDate] != null &&
- dsItem.Data[App.Config.FieldNamePublishEndDate].Type == JTokenType.Date &&
- ((DateTime)dsItem.Data[App.Config.FieldNamePublishEndDate]) >= DateTime.Today;
- if (!permissions) raison = App.Config.FieldNamePublishEndDate + $" being {dsItem.Data[App.Config.FieldNamePublishEndDate]}";
+ fieldName = "userroles";
}
- if (permissions)
+ if (!String.IsNullOrEmpty(fieldName))
{
- // Roles
- string fieldName = "";
- if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey("userrole"))
+ permissions = false;
+ string[] dataRoles = { };
+ if (dsItem.Data[fieldName] != null)
{
- fieldName = "userrole";
+ if (dsItem.Data[fieldName].Type == JTokenType.Array)
+ {
+ dataRoles = ((JArray)dsItem.Data[fieldName]).Select(d => d.ToString()).ToArray();
+ }
+ else
+ {
+ dataRoles = new string[] { dsItem.Data[fieldName].ToString() };
+ }
}
- else if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey("userroles"))
+ if (dataRoles.Contains("AllUsers"))
{
- fieldName = "userroles";
+ permissions = true;
}
- if (!String.IsNullOrEmpty(fieldName))
+ else
{
- permissions = false;
- string[] dataRoles = { };
- if (dsItem.Data[fieldName] != null)
+ var roles = userRoles;
+ if (roles.Any())
{
- if (dsItem.Data[fieldName].Type == JTokenType.Array)
- {
- dataRoles = ((JArray)dsItem.Data[fieldName]).Select(d => d.ToString()).ToArray();
- }
- else
- {
- dataRoles = new string[] { dsItem.Data[fieldName].ToString() };
- }
+ permissions = roles.Any(r => dataRoles.Contains(r.RoleId.ToString()));
}
- if (dataRoles.Contains("AllUsers"))
+ else
{
- permissions = true;
+ permissions = dataRoles.Contains("Unauthenticated");
+ }
+ }
+ if (!permissions) reason = fieldName;
+ }
+ return permissions;
+
+ }
+
+ internal static bool IsPublished(IDataItem dsItem, FieldConfig indexConfig, out string reason)
+ {
+ reason = "";
+ if (dsItem?.Data == null) return true;
+
+ bool isPublished = true;
+ if (indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishStatus))
+ {
+ isPublished = dsItem.Data[App.Config.FieldNamePublishStatus] != null &&
+ dsItem.Data[App.Config.FieldNamePublishStatus].ToString() == "published";
+ if (!isPublished) reason = App.Config.FieldNamePublishStatus + $" being {dsItem.Data[App.Config.FieldNamePublishStatus]}";
+ }
+ if (isPublished && indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishStartDate))
+ {
+ if (dsItem.Data[App.Config.FieldNamePublishStartDate] != null && dsItem.Data[App.Config.FieldNamePublishStartDate].Type == JTokenType.Date)
+ {
+ var compareDate = (DateTime)dsItem.Data[App.Config.FieldNamePublishStartDate];
+ // do we need to compare time?
+ if (compareDate.TimeOfDay.TotalMilliseconds > 0)
+ {
+ isPublished = compareDate <= DateTime.Now;
}
else
{
- var roles = userRoles;
- if (roles.Any())
- {
- permissions = roles.Any(r => dataRoles.Contains(r.RoleId.ToString()));
- }
- else
- {
- permissions = dataRoles.Contains("Unauthenticated");
- }
+ isPublished = compareDate <= DateTime.Today;
}
- if (!permissions) raison = fieldName;
}
+ else
+ {
+ // not a date
+ isPublished = false;
+ }
+
+ if (!isPublished) reason = App.Config.FieldNamePublishStartDate + $" being {dsItem.Data[App.Config.FieldNamePublishStartDate]}";
+ }
+ if (isPublished && indexConfig?.Fields != null && indexConfig.Fields.ContainsKey(App.Config.FieldNamePublishEndDate))
+ {
+ if (dsItem.Data[App.Config.FieldNamePublishEndDate] != null && dsItem.Data[App.Config.FieldNamePublishEndDate].Type == JTokenType.Date)
+ {
+ var compareDate = (DateTime)dsItem.Data[App.Config.FieldNamePublishEndDate];
+ // do we need to compare time?
+ if (compareDate.TimeOfDay.TotalMilliseconds > 0)
+ {
+ isPublished = compareDate >= DateTime.Now;
+ }
+ else
+ {
+ isPublished = compareDate >= DateTime.Today;
+ }
+ }
+ else
+ {
+ // not a date
+ isPublished = false;
+ }
+
+ if (!isPublished) reason = App.Config.FieldNamePublishEndDate + $" being {dsItem.Data[App.Config.FieldNamePublishEndDate]}";
}
- return permissions;
+ return isPublished;
}
}
}
\ No newline at end of file
diff --git a/OpenContent/OpenContent.csproj b/OpenContent/OpenContent.csproj
index 856002cc..804d5b0e 100644
--- a/OpenContent/OpenContent.csproj
+++ b/OpenContent/OpenContent.csproj
@@ -175,6 +175,7 @@
AddEdit.ascx
+
diff --git a/OpenContent/OpenContent.dnn b/OpenContent/OpenContent.dnn
index f5b1a8f6..b9d3b42b 100644
--- a/OpenContent/OpenContent.dnn
+++ b/OpenContent/OpenContent.dnn
@@ -1,6 +1,6 @@
-
+
OpenContent
OpenContent module by Satrabel.be
~/DesktopModules/OpenContent/Images/icon_extensions.png
@@ -272,7 +272,7 @@
Satrabel.OpenContent.Components.FeatureController
[DESKTOPMODULEID]
- 02.01.00
+ 02.01.00,04.07.00
@@ -292,6 +292,10 @@
Handlebars.dll
bin
+
+
+ EPPlus.dll
+ bin
diff --git a/OpenContent/Properties/AssemblyInfo.cs b/OpenContent/Properties/AssemblyInfo.cs
index 17c00363..506ad783 100644
--- a/OpenContent/Properties/AssemblyInfo.cs
+++ b/OpenContent/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -9,7 +9,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Satrabel")]
[assembly: AssemblyProduct("OpenContent")]
-[assembly: AssemblyCopyright("Copyright © 2015-2020")]
+[assembly: AssemblyCopyright("Copyright ? 2015-2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -30,5 +30,5 @@
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("04.05.00.0")]
-[assembly: AssemblyFileVersion("04.05.00.0")]
+[assembly: AssemblyVersion("04.07.00.00")]
+[assembly: AssemblyFileVersion("04.07.00.00")]
diff --git a/appveyor.yml b/appveyor.yml
index 65bc14ce..9bee6970 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 04.05.00.{build}-{branch}
+version: 04.07.00.{build}-{branch}
assembly_info:
patch: true
file: '**\AssemblyInfo.*'