Initial commit

This commit is contained in:
2025-02-13 22:10:32 +01:00
commit 3563d783d4
162 changed files with 14738 additions and 0 deletions

15
.codegen.json Normal file
View File

@@ -0,0 +1,15 @@
{
"Template": ".\\.templates\\Main.cshtml",
"OutputDirectory": ".\\.out",
"OrgName": "Bring2mind",
"ModuleName": "InMemoriam",
"RootNameSpace": "Bring2mind.InMemoriam.Core",
"SiteConfig": "",
"ConnectionString": "Data Source=.\\SQLEXPRESS;Initial Catalog=Robert;uid=test;pwd=test;TrustServerCertificate=True",
"ObjectQualifier": "",
"DatabaseOwner": "dbo",
"ModuleObjectQualifier": "B2M_InMemoriam_",
"IncludeSqlScripts": true,
"EnumValues": null,
"FullDbPattern": "(?<owner>\\[?dbo\\]?\\.)?\\[?(?<name>\\w+)\\]?|(?<owner>\\[?dbo\\]?\\.)\\[?(?<name>\\w+)\\]?|(?<=\\sJOIN\\s+)(?<name>\\w+)"
}

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
node_modules
**/bin
**/obj
.vs
.out
local.json
Releases
tools

View File

@@ -0,0 +1,49 @@
@inherits RazorTemplate<string>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System;
using System.Data;
using System.Runtime.Serialization;
using DotNetNuke.Common.Utilities;
namespace @(Settings.RootNameSpace).Data
{
[DataContract]
public abstract class AuditableEntity
{
public void FillAuditFields(IDataReader dr)
{
CreatedByUserID = Convert.ToInt32(Null.SetNull(dr["CreatedByUserID"], CreatedByUserID));
CreatedOnDate = Convert.ToDateTime(Null.SetNull(dr["CreatedOnDate"], CreatedOnDate));
LastModifiedByUserID = Convert.ToInt32(Null.SetNull(dr["LastModifiedByUserID"], LastModifiedByUserID));
LastModifiedOnDate = Convert.ToDateTime(Null.SetNull(dr["LastModifiedOnDate"], LastModifiedOnDate));
}
public void SetAddingUser(int userId)
{
CreatedByUserID = userId;
CreatedOnDate = DateTime.Now;
SetModifyingUser(userId);
}
public void SetModifyingUser(int userId)
{
LastModifiedByUserID = userId;
LastModifiedOnDate = DateTime.Now;
}
#region Public Properties
[DataMember]
public int CreatedByUserID { get; set; }
[DataMember]
public DateTime CreatedOnDate { get; set; }
[DataMember]
public int LastModifiedByUserID { get; set; }
[DataMember]
public DateTime LastModifiedOnDate { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,35 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
}
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="cmModalLabel">@@Html.GetLocalizedString("EditUser")</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-xs-12 form-horizontal">
@foreach (Column c in Model.Table.Columns)
{
<div class="form-group">
<label for="Title" class="col-sm-2 control-label">@@Html.GetLocalizedString("@c.Name")</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="@c.Name" value="@("@Model.")@c.Name">
</div>
</div>
}
</div>
</div>
</div>
<div class="modal-footer">
<a href="#" id="cmdCancel" class="btn btn-default" data-dismiss="modal">@@Html.GetLocalizedString("cmdCancel")</a>
<a href="#" id="cmdSubmit" class="btn btn-primary">@@Html.GetLocalizedString("cmdSubmit")</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,61 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@{
}
using @(Settings.RootNameSpace).Models.@(Model.PluralName);
using @(Settings.RootNameSpace).Repositories;
namespace @(Settings.RootNameSpace).Controllers
{
public partial class @(Model.PluralName)Controller
{
@if (@Model.Table.IsTableWithIdColumn())
{
@: public static @(Model.SingularName) Get@(Model.SingularName)(@Model.Table.PrimaryKeyParameterList())
@: {
@:
@: @(Model.SingularName)Repository repo = new @(Model.SingularName)Repository();
@: return repo.GetById(@Model.Table.PrimaryKeyParameters().Lowered());
@:
@: }
@:
@: public static int Add@(Model.SingularName)(ref @(Model.SingularName)Base @(Model.SingularName.Lowered())@(Model.HasAuditFields ? ", int userId" : ""))
@: {
if (Model.HasAuditFields)
{
@:
@: @(Model.SingularName.Lowered()).SetAddingUser(userId);
}
@: @(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
@: repo.Insert(@(Model.SingularName.Lowered()));
@: return @(Model.SingularName.Lowered()).@Model.Table.PrimaryKeyParameters();
@:
@: }
}
public static void Update@(Model.SingularName)(@(Model.SingularName)Base @(Model.SingularName.Lowered())@(Model.HasAuditFields ? ", int userId" : ""))
{
@if (Model.HasAuditFields)
{
@: @(Model.SingularName.Lowered()).SetModifyingUser(userId);
}
@(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
repo.Update(@(Model.SingularName.Lowered()));
}
public static void Delete@(Model.SingularName)(@(Model.SingularName)Base @(Model.SingularName.Lowered()))
{
@(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
repo.Delete(@(Model.SingularName.Lowered()));
}
}
}

View File

@@ -0,0 +1,82 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@{
}
using System.Net;
using System.Net.Http;
using System.Web.Http;
using DotNetNuke.Web.Api;
using @(Settings.RootNameSpace).Repositories;
namespace @(Settings.RootNameSpace).Api
{
public partial class @(Model.PluralName)Controller : @(Settings.ModuleName)ApiController
{
[HttpGet()]
[DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)]
public HttpResponseMessage MyMethod(int id)
{
bool res = true;
return Request.CreateResponse(HttpStatusCode.OK, res);
}
@if (@Model.Table.IsTableWithIdColumn())
{
@: [HttpGet]
@: [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)]
@: public HttpResponseMessage Get (@Model.Table.PrimaryKeyParameterList())
@: {
@:
@: @(Model.SingularName)Repository repo = new @(Model.SingularName)Repository();
@: return Request.CreateResponse(HttpStatusCode.OK, repo.GetById(@Model.Table.PrimaryKeyParameters().Lowered()));
@:
@: }
@:
@: [HttpPost]
@: [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.Edit)]
@: public HttpResponseMessage Add (@(Model.SingularName)Base @(Model.SingularName.Lowered()))
@: {
if (Model.HasAuditFields)
{
@:
@: @(Model.SingularName.Lowered()).SetAddingUser(userId);
}
@: @(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
@: repo.Insert(@(Model.SingularName.Lowered()));
@: return Request.CreateResponse(HttpStatusCode.OK, @(Model.SingularName.Lowered()));
@:
@: }
}
[HttpPost]
[DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.Edit)]
public HttpResponseMessage Update (@(Model.SingularName)Base @(Model.SingularName.Lowered()))
{
@if (Model.HasAuditFields)
{
@: @(Model.SingularName.Lowered()).SetModifyingUser(userId);
}
@(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
repo.Update(@(Model.SingularName.Lowered()));
return Request.CreateResponse(HttpStatusCode.OK, @(Model.SingularName.Lowered()));
}
[HttpPost]
[DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.Edit)]
public HttpResponseMessage Delete (@Model.Table.PrimaryKeyParameterList())
{
@(Model.SingularName)BaseRepository repo = new @(Model.SingularName)BaseRepository();
repo.Delete(@(Model.SingularName.Lowered()));
return Request.CreateResponse(HttpStatusCode.OK, "");
}
}
}

View File

@@ -0,0 +1,21 @@
@inherits RazorTemplate<Column>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@switch (Model.DataType.SqlDataType.ToString())
{
case "DateTime":
case "SmallDateTime":
@: @Model.Name = (DateTime)(Null.SetNull(dr["@Model.Name"], @Model.Name));
break;
case "Time":
@: if (dr["@Model.Name"] != DBNull.Value) { @Model.Name = (TimeSpan)dr["@Model.Name"]; }
break;
case "Guid":
@: @Model.Name = (Guid)(Null.SetNull(dr["@Model.Name"], @Model.Name));
break;
default:
@: @Model.Name = Convert.To@(Model.DataType.DataTypeToCsStruct())(Null.SetNull(dr["@Model.Name"], @Model.Name));
break;
}

View File

@@ -0,0 +1,39 @@
@inherits RazorTemplate<Column>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
case "@Model.Name.ToLower()": // @Model.DataType.SqlDataType.ToString()
@if (Model.Nullable)
{
@: if (@Model.Name == null)
@: {
@: return "";
@: };
}
@switch (Model.DataType.SqlDataType.ToString())
{
case "Bit":
@: return @(Model.Name).ToString();
break;
case "Char":
case "Text":
case "VarChar":
case "VarCharMax":
case "NChar":
case "NText":
case "NVarChar":
case "NVarCharMax":
@: return PropertyAccess.FormatString(@Model.Name, strFormat);
break;
default:
if (Model.Nullable)
{
@: return ((@(Model.DataType.DataTypeToCs()))@(Model.Name)).ToString(strFormat, formatProvider);
}
else
{
@: return @(Model.Name).ToString(strFormat, formatProvider);
}
break;
}

56
.templates/Main.cshtml Normal file
View File

@@ -0,0 +1,56 @@
@inherits RazorTemplate<string>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@foreach (Bring2mind.CodeGen.Cli.Data.ObjectDefinition od in DnnDb.Objects.Values)
{
Engine.RenderTemplate("Controller.cshtml", "Controllers\\" + od.PluralName + "Controller.cs", od);
Engine.RenderTemplate("Controller_Services.cshtml", "Api\\" + od.PluralName + "Controller.cs", od);
if (od.IsLinkTableWithoutFields)
{
Engine.RenderTemplate("RepositoryLinkTable.cshtml", "Repositories\\" + od.SingularName + "Repository_Core.cs", od);
}
else if (od.IsLinkTableWithFields)
{
Engine.RenderTemplate("RepositoryLinkTablePlus.cshtml", "Repositories\\" + od.SingularName + "Repository_Core.cs", od);
}
else
{
Engine.RenderTemplate("Repository.cshtml", "Repositories\\" + od.SingularName + "Repository_Core.cs", od);
}
Engine.RenderTemplate("Repository_Empty.cshtml", "Repositories\\" + od.SingularName + "Repository.cs", od);
if (od.HasTable)
{
Engine.RenderTemplate("BootstrapPopupEdit.cshtml", "Extra\\Bootstrap\\" + od.SingularName + "Popup.cs", od);
Engine.RenderTemplate("MvcEdit.cshtml", "Extra\\Mvc\\" + od.SingularName + "Edit.cshtml", od);
Engine.RenderTemplate("MvcBootstrapEdit.cshtml", "Extra\\MvcBootstrap\\" + od.SingularName + "Edit.cshtml", od);
}
if (od.TableAndView)
{
Engine.RenderTemplate("Model.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Declaration.cs", od);
Engine.RenderTemplate("Model_Interfaces.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Interfaces.cs", od);
Engine.RenderTemplate("ModelBase.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "Base.cs", od);
Engine.RenderTemplate("ModelBase_Interfaces.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "Base_Interfaces.cs", od);
}
else if (od.TableOnly)
{
Engine.RenderTemplate("ModelBase.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Declaration.cs", od);
Engine.RenderTemplate("ModelBase_Interfaces.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Interfaces.cs", od);
Engine.RenderTemplate("Model_Empty.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + ".cs", od);
}
else if (od.ViewOnly)
{
Engine.RenderTemplate("Model.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Declaration.cs", od);
Engine.RenderTemplate("Model_Interfaces.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + "_Interfaces.cs", od);
Engine.RenderTemplate("Model_Empty.cshtml", "Models\\" + od.PluralName + "\\" + od.SingularName + ".cs", od);
}
Engine.RenderTemplate("TypeScriptIModel.cshtml", "ts\\Models\\I" + od.SingularName + ".ts", od);
}
@{
Engine.RenderTemplate("TypeScriptIModelIndex.cshtml", "ts\\Models\\index.js");
Engine.RenderTemplate("RepositoryImpl.cshtml", "Data\\RepositoryImpl.cs");
Engine.RenderTemplate("AuditableEntity.cshtml", "Data\\AuditableEntity.cs");
Engine.RenderTemplate("Sprocs.cshtml", "Data\\Sprocs.cs", DnnDb.StoredProcedures);
}

89
.templates/Model.cshtml Normal file
View File

@@ -0,0 +1,89 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
}
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
[TableName("@Model.Prefix@Model.ModuleQualifier@Model.Name")]
@if (Model.Table.IsTableWithIdColumn())
{
@: [PrimaryKey("@Model.Table.PrimaryKeyParameters()", AutoIncrement = true)]
}
[DataContract]
@if (Model.Scope != "")
{
@: [Scope("@Model.Scope")]
}
public partial class @(Model.SingularName) @if (Model.TableAndView){@: : @(Model.SingularName)Base
}
{
#region .ctor
public @(Model.SingularName)() @if (Model.TableAndView){@: : base()
}
{
}
#endregion
#region Properties
@foreach (Column c in Model.UniqueViewColumns)
{
@:@Raw(Engine.RunCompile("PropertyField.cshtml", c).TrimEnd('\r', '\n'))
}
#endregion
#region Methods
@if (Model.TableAndView)
{
@: public @(Model.SingularName)Base Get@(Model.SingularName)Base()
@: {
@: @(Model.SingularName)Base res = new @(Model.SingularName)Base();
foreach (Column c in Model.TableColumns)
{
@: res.@c.Name = @c.Name;
}
if (Model.HasAuditFields)
{
@: res.CreatedByUserID = CreatedByUserID;
@: res.CreatedOnDate = CreatedOnDate;
@: res.LastModifiedByUserID = LastModifiedByUserID;
@: res.LastModifiedOnDate = LastModifiedOnDate;
}
@: return res;
@: }
}
public @(Model.SingularName) Clone()
{
@(Model.SingularName) res = new @(Model.SingularName)();
@foreach (Column c in Model.TableColumns)
{
@: res.@c.Name = @c.Name;
}
@if (Model.TableAndView)
{
foreach (Column c in Model.UniqueViewColumns)
{
@: res.@c.Name = @c.Name;
}
}
@if (Model.HasAuditFields)
{
@: res.CreatedByUserID = CreatedByUserID;
@: res.CreatedOnDate = CreatedOnDate;
@: res.LastModifiedByUserID = LastModifiedByUserID;
@: res.LastModifiedOnDate = LastModifiedOnDate;
}
return res;
}
#endregion
}
}

View File

@@ -0,0 +1,68 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
dynamic vb = new System.Dynamic.ExpandoObject();
vb.ObjectName = Model.SingularName;
string baseQualifier = "Base";
if (Model.TableOnly)
{
baseQualifier = "";
}
}
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
using @(Settings.RootNameSpace).Data;
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
[TableName("@Model.ModuleQualifier@Model.Name")]
@if (Model.Table.IsTableWithIdColumn())
{
@: [PrimaryKey("@Model.Table.PrimaryKeyParameters()", AutoIncrement = true)]
}
[DataContract]
@if (Model.Scope != "")
{
@: [Scope("@Model.Scope")]
}
public partial class @(Model.SingularName)@baseQualifier @if (Model.HasAuditFields){@: : AuditableEntity
}
{
#region .ctor
public @(Model.SingularName)@(baseQualifier)()
{
@if (@Model.Table.IsTableWithIdColumn())
{
@: @Model.Table.PrimaryKeyParameters() = -1;
}
}
#endregion
#region Properties
@foreach (Column c in Model.TableColumns)
{
@:@Raw(Engine.RunCompile("PropertyField.cshtml", c))
}
#endregion
#region Methods
public void Read@(Model.SingularName)@(baseQualifier)(@(Model.SingularName)@baseQualifier @(Model.SingularName.Lowered()))
{
@foreach (Column c in Model.TableColumns)
{
@:@Raw(Engine.RunCompile("ReadBaseField.cshtml", c, vb))
}
}
#endregion
}
}

View File

@@ -0,0 +1,81 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
string baseQualifier = "Base";
if (Model.TableOnly)
{
baseQualifier = "";
}
}
using System;
using System.Data;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel.DataAnnotations;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Tokens;
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
public partial class @(Model.SingularName)@baseQualifier : IHydratable, IPropertyAccess
{
#region IHydratable
public virtual void Fill(IDataReader dr)
{
@if (Model.HasAuditFields)
{
@: FillAuditFields(dr);
}
@foreach (Column c in Model.TableColumns)
{
@:@Raw(Engine.RunCompile("IHydratableField.cshtml", c).TrimEnd('\r', '\n'))
}
}
[IgnoreColumn()]
public int KeyID
{
@if (@Model.Table.IsTableWithIdColumn())
{
@: get { return @Model.Table.PrimaryKeyParameters(); }
@: set { @Model.Table.PrimaryKeyParameters() = value; }
}
else
{
@: get { return Null.NullInteger; }
@: set { }
}
}
#endregion
#region IPropertyAccess
public virtual string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower())
{
@foreach (Column c in Model.TableColumns)
{
@:@Raw(Engine.RunCompile("IPropertyAccessField.cshtml", c).TrimEnd('\r', '\n'))
}
default:
propertyNotFound = true;
break;
}
return Null.NullString;
}
[IgnoreColumn()]
public CacheLevel Cacheability
{
get { return CacheLevel.fullyCacheable; }
}
#endregion
}
}

View File

@@ -0,0 +1,52 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
using Newtonsoft.Json;
using System;
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
public class @(Model.SingularName)Public : @(Model.SingularName)
{
@foreach (Column c in Model.TableColumns)
{
@: [JsonIgnore]
@: public new @c.DataType.DataTypeToCs()@(c.NullSuffix()) @c.Name { get; set; }
}
@foreach (Column c in Model.UniqueViewColumns)
{
@: [JsonIgnore]
@: public new @c.DataType.DataTypeToCs()@(c.NullSuffix()) @c.Name { get; set; }
}
@if (Model.HasAuditFields)
{
@: [JsonIgnore]
@: public new int CreatedByUserID { get; set; }
@: [JsonIgnore]
@: public new DateTime CreatedOnDate { get; set; }
@: [JsonIgnore]
@: public new int LastModifiedByUserID { get; set; }
@: [JsonIgnore]
@: public new DateTime LastModifiedOnDate { get; set; }
@: [JsonIgnore]
@: public new string CreatedByUser { get; set; }
@: [JsonIgnore]
@: public new string LastModifiedByUser { get; set; }
}
public @(Model.SingularName)Public(@(Model.SingularName) input)
{
@foreach (Column c in Model.TableColumns)
{
@: @c.Name = input.@c.Name;
}
@foreach (Column c in Model.UniqueViewColumns)
{
@: @c.Name = input.@c.Name;
}
}
}
}

View File

@@ -0,0 +1,12 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@{
}
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
public partial class @(Model.SingularName)
{
}
}

View File

@@ -0,0 +1,60 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
}
using System;
using System.Data;
using System.Xml.Serialization;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Tokens;
namespace @(Settings.RootNameSpace).Models.@(Model.PluralName)
{
[Serializable(), XmlRoot("@(Model.SingularName)")]
public partial class @(Model.SingularName)
{
#region IHydratable
public @(Model.TableAndView ? "override" : "") void Fill(IDataReader dr)
{
@if (Model.TableAndView)
{
@: base.Fill(dr);
}
@foreach (Column c in Model.UniqueViewColumns)
{
@:@Raw(Engine.RunCompile("IHydratableField.cshtml", c).TrimEnd('\r', '\n'))
}
}
#endregion
#region IPropertyAccess
public @(Model.TableAndView ? "override" : "") string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower()) {
@foreach (Column c in Model.UniqueViewColumns)
{
@:@Raw(Engine.RunCompile("IPropertyAccessField.cshtml", c).TrimEnd('\r', '\n'))
}
default:
@if (Model.TableAndView)
{
@: return base.GetProperty(strPropertyName, strFormat, formatProvider, accessingUser, accessLevel, ref propertyNotFound);
}
else
{
@: propertyNotFound = true;
@: return "";
@: break;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,55 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
}
@@inherits WebPage<@(Model.SingularName)>
@@using Connect.DNN.Modules.Conference.Common;
@@using Connect.Conference.Core.Models.Conferences;
@@using DotNetNuke.Web.Mvc.Helpers;
<div class="form-horizontal">
@foreach (Column c in Model.Table.Columns)
{
var req = c.Nullable ? "" : ", required = \"true\"";
var tp = "";
switch (c.DataType.SqlDataType) {
case SqlDataType.BigInt:
case SqlDataType.Int:
case SqlDataType.TinyInt:
case SqlDataType.SmallInt:
case SqlDataType.Real:
case SqlDataType.Numeric:
case SqlDataType.Float:
tp = ", type = \"number\"";
break;
case SqlDataType.Date:
tp = ", type = \"date\"";
break;
case SqlDataType.DateTime:
case SqlDataType.SmallDateTime:
tp = ", type = \"datetime\"";
break;
}
if (c.DataType.SqlDataType == SqlDataType.Bit) {
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
@@Html.CheckBoxFor(m => m.@c.Name) @@Dnn.LocalizeString("@c.Name")
</label>
</div>
</div>
</div>
} else {
<div class="form-group">
<label for="@c.Name" class="col-sm-2 control-label">@@Dnn.LocalizeString("@c.Name")</label>
<div class="col-sm-10">
@@Html.TextBoxFor(m => m.@c.Name, new { @@class = "form-control", placeholder = Dnn.LocalizeString("@c.Name")@req@tp })
</div>
</div>
}
}
</div>

23
.templates/MvcEdit.cshtml Normal file
View File

@@ -0,0 +1,23 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{
}
@@inherits WebPage<@(Model.SingularName)>
@@using Connect.DNN.Modules.Conference.Common;
@@using Connect.Conference.Core.Models.Conferences;
@@using DotNetNuke.Web.Mvc.Helpers;
<fieldset>
@foreach (Column c in Model.Table.Columns)
{
<div class="dnnFormItem">
<div class="dnnLabel" style="position: relative;">
<label>@@Dnn.LocalizeString("@c.Name")</label>
</div>
@@Html.TextBoxFor(m => m.@c.Name, new { placeholder = Dnn.LocalizeString("@c.Name") })
</div>
}
</fieldset>

View File

@@ -0,0 +1,7 @@
@inherits RazorTemplate<Column>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
[DataMember]
public @Model.DataType.DataTypeToCs()@(Model.NullSuffix()) @Model.Name { get; set; }

View File

@@ -0,0 +1,35 @@
@inherits RazorTemplate<Column>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@switch (Model.DataType.SqlDataType.ToString())
{
case "Int":
case "TinyInt":
case "SmallInt":
@: if (@(((string)ViewBag.ObjectName).Lowered()).@Model.Name > -1)
@: @Model.Name = @(((string)ViewBag.ObjectName).Lowered()).@Model.Name;
break;
case "Real":
case "Numeric":
case "Float":
case "Decimal":
case "Money":
case "SmallMoney":
case "Date":
case "DateTime":
case "Time":
case "SmallDateTime":
case "Bit":
if (Model.Nullable)
{
@: if (@(((string)ViewBag.ObjectName).Lowered()).@Model.Name != null)
}
@: @Model.Name = @(((string)ViewBag.ObjectName).Lowered()).@Model.Name;
break;
default:
@: if (!String.IsNullOrEmpty(@(((string)ViewBag.ObjectName).Lowered()).@Model.Name))
@: @Model.Name = @(((string)ViewBag.ObjectName).Lowered()).@Model.Name;
break;
}

View File

@@ -0,0 +1,142 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using @(Settings.RootNameSpace).Models.@(Model.PluralName);
namespace @(Settings.RootNameSpace).Repositories
{
public partial class @(Model.SingularName)Repository : ServiceLocator<I@(Model.SingularName)Repository, @(Model.SingularName)Repository>, I@(Model.SingularName)Repository
{
protected override Func<I@(Model.SingularName)Repository> GetFactory()
{
return () => new @(Model.SingularName)Repository();
}
public IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)(@(Model.GetScopeDeclaration(true, true, false, false)))
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<@(Model.SingularName)>();
return rep.Get(@(Model.GetScopeDeclaration(true, false, false, false)));
}
}
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: public IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")))
@: {
@: using (var context = DataContext.Instance())
@: {
@: return context.ExecuteQuery<@(Model.SingularName)>(System.Data.CommandType.Text,
@: "SELECT * FROM {databaseOwner}{objectQualifier}@Model.Prefix@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.Parameter(fo.Key, false, false, ""))=@@0",
@: @(Model.Table.Parameter(fo.Key, false, true, "")));
@: }
@: }
}
}
@if (Model.HasTable)
{
if (!Model.HasNoPrimaryKey)
{
@: public @(Model.SingularName) Get@(Model.SingularName)(@(Model.GetScopeDeclaration(true, true, false, true))@Model.Table.PrimaryKeyParameterList())
@: {
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.SingularName)>();
@: return rep.GetById(@Model.Table.PrimaryKeyParameters().Lowered()@(Model.GetScopeDeclaration(true, false, true, false)));
@: }
@: }
}
@: public @(Model.TableObjectName) Add@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""))
@: {
@: Requires.NotNull(@(Model.SingularNameLowered));
if (Model.Scope != "")
{
@: Requires.PropertyNotNegative(@(Model.SingularNameLowered), "@(Model.GetScopeDeclaration(false, false, false, false))");
}
if (Model.HasAuditFields)
{
@: @(Model.SingularNameLowered).CreatedByUserID = userId;
@: @(Model.SingularNameLowered).CreatedOnDate = DateTime.Now;
@: @(Model.SingularNameLowered).LastModifiedByUserID = userId;
@: @(Model.SingularNameLowered).LastModifiedOnDate = DateTime.Now;
}
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.TableObjectName)>();
@: rep.Insert(@(Model.SingularNameLowered));
@: }
@: return @(Model.SingularNameLowered);
@: }
@: public void Delete@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered))
@: {
@: Requires.NotNull(@(Model.SingularNameLowered));
@: Requires.PropertyNotNegative(@(Model.SingularNameLowered), "@(Model.SingularName)Id");
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.TableObjectName)>();
@: rep.Delete(@(Model.SingularNameLowered));
@: }
@: }
if (!Model.HasNoPrimaryKey)
{
@: public void Delete@(Model.SingularName)(@(Model.GetScopeDeclaration(true, true, false, true))@Model.Table.PrimaryKeyParameterList())
@: {
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.TableObjectName)>();
@: rep.Delete("@(Model.GetParameterList(true, true, ObjectDefinition.ParameterListType.SqlWhereClause))", @(Model.GetParameterList(true, true, ObjectDefinition.ParameterListType.Plain)));
@: }
@: }
}
@: public void Update@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""))
@: {
@: Requires.NotNull(@(Model.SingularNameLowered));
@: Requires.PropertyNotNegative(@(Model.SingularNameLowered), "@(Model.SingularName)Id");
if (Model.HasAuditFields)
{
@: @(Model.SingularNameLowered).LastModifiedByUserID = userId;
@: @(Model.SingularNameLowered).LastModifiedOnDate = DateTime.Now;
}
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.TableObjectName)>();
@: rep.Update(@(Model.SingularNameLowered));
@: }
@: }
}
}
public partial interface I@(Model.SingularName)Repository
{
IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)(@(Model.GetScopeDeclaration(true, true, false, false)));
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")));
}
}
@if (Model.HasTable)
{
if (!Model.HasNoPrimaryKey)
{
@: @(Model.SingularName) Get@(Model.SingularName)(@(Model.GetScopeDeclaration(true, true, false, true))@Model.Table.PrimaryKeyParameterList());
}
@: @(Model.TableObjectName) Add@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""));
@: void Delete@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered));
if (!Model.HasNoPrimaryKey)
{
@: void Delete@(Model.SingularName)(@(Model.GetScopeDeclaration(true, true, false, true))@Model.Table.PrimaryKeyParameterList());
}
@: void Update@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""));
}
}
}

View File

@@ -0,0 +1,135 @@
@inherits RazorTemplate<string>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System.Collections.Generic;
using DotNetNuke.Collections;
using DotNetNuke.Data;
namespace @(Settings.RootNameSpace).Data
{
public abstract class RepositoryImpl<T> : IRepository<T> where T : class
{
public virtual void Delete(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Delete(item);
}
}
public virtual void Delete(string sqlCondition, params object[] args)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Delete(sqlCondition, args);
}
}
public virtual IEnumerable<T> Find(string sqlCondition, params object[] args)
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Find(sqlCondition, args);
}
return list;
}
public virtual IPagedList<T> Find(int pageIndex, int pageSize, string sqlCondition, params object[] args)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Find(pageIndex, pageSize, sqlCondition, args);
}
return list;
}
public virtual IEnumerable<T> Get()
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Get();
}
return list;
}
public virtual IEnumerable<T> Get<TScopeType>(TScopeType scopeValue)
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Get<TScopeType>(scopeValue);
}
return list;
}
public virtual T GetById<TProperty>(TProperty id)
{
T item = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
item = repo.GetById<TProperty>(id);
}
return item;
}
public virtual T GetById<TProperty, TScopeType>(TProperty id, TScopeType scopeValue)
{
T item = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
item = repo.GetById<TProperty, TScopeType>(id, scopeValue);
}
return item;
}
public virtual IPagedList<T> GetPage(int pageIndex, int pageSize)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.GetPage(pageIndex, pageSize);
}
return list;
}
public virtual IPagedList<T> GetPage<TScopeType>(TScopeType scopeValue, int pageIndex, int pageSize)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.GetPage<TScopeType>(scopeValue, pageIndex, pageSize);
}
return list;
}
public virtual void Insert(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Insert(item);
}
}
public virtual void Update(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Update(item);
}
}
public virtual void Update(string sqlCondition, params object[] args)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Update(sqlCondition, args);
}
}
}
}

View File

@@ -0,0 +1,111 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Collections;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using @(Settings.RootNameSpace).Data;
using @(Settings.RootNameSpace).Models.@(Model.PluralName);
namespace @(Settings.RootNameSpace).Repositories
{
public partial class @(Model.SingularName)Repository : ServiceLocator<I@(Model.SingularName)Repository, @(Model.SingularName)Repository>, I@(Model.SingularName)Repository
{
protected override Func<I@(Model.SingularName)Repository> GetFactory()
{
return () => new @(Model.SingularName)Repository();
}
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: public IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")))
@: {
@: using (var context = DataContext.Instance())
@: {
@: return context.ExecuteQuery<@(Model.SingularName)>(System.Data.CommandType.Text,
@: "SELECT * FROM {databaseOwner}{objectQualifier}@Model.Prefix@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.Parameter(fo.Key, false, false, ""))=@@0",
@: @(Model.Table.Parameter(fo.Key, false, true, "")));
@: }
@: }
}
}
public void Set@(Model.SingularName)(@Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, true, true))
{
using (var context = DataContext.Instance())
{
context.Execute(System.Data.CommandType.Text,
"IF NOT EXISTS (SELECT * FROM {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) " +
"WHERE @Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, 0, " AND ")) " +
"INSERT INTO {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) (@Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, false, "", ", ")) " +
"SELECT @@0, @@1", @Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, true));
}
}
public void Set@(Model.PluralName)(@(Model.Table.FirstPrimaryKeyParameter().ColumnParameter()), List<int> @(Model.PluralName.Lowered()))
{
using (var context = DataContext.Instance())
{
context.Execute(System.Data.CommandType.Text,
"DELETE FROM {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) WHERE @(Model.Table.FirstPrimaryKeyParameter().Name)=@@0", @(Model.Table.FirstPrimaryKeyParameter().Name.Lowered()));
context.Execute(System.Data.CommandType.Text,
"INSERT INTO {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) (@Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, false, "", ", ")) " +
"SELECT @@0, s.RecordID " +
"FROM {databaseOwner}{objectQualifier}SplitDelimitedIDs(@@1, ',') s", @(Model.Table.FirstPrimaryKeyParameter().Name.Lowered()), string.Join(",", @(Model.PluralName.Lowered())));
}
}
public void Delete@(Model.SingularName)(@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, true, true)))
{
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: Requires.NotNull(@(Model.Table.Parameter(fo.Key, false, true, "")));
}
}
using (var context = DataContext.Instance())
{
context.Execute(System.Data.CommandType.Text,
"DELETE FROM {databaseOwner}{objectQualifier}@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, 0, " AND "))",
@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, true, "", ",")));
}
}
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
@: public void Delete@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")))
@: {
@: Requires.NotNull(@(Model.Table.Parameter(fo.Key, false, true, "")));
@: using (var context = DataContext.Instance())
@: {
@: var rep = context.GetRepository<@(Model.TableObjectName)>();
@: rep.Delete("WHERE @(Model.Table.Parameter(fo.Key, false, false, ""))=@@0", @(Model.Table.Parameter(fo.Key, false, true, "")));
@: }
@: }
}
}
public partial interface I@(Model.SingularName)Repository
{
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")));
}
}
void Set@(Model.SingularName)(@Model.Table.PrimaryKeyParameterList());
void Set@(Model.PluralName)(@(Model.Table.FirstPrimaryKeyParameter().ColumnParameter()), List<int> @(Model.PluralName.Lowered()));
void Delete@(Model.SingularName)(@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, true, true)));
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
@: void Delete@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")));
}
}
}

View File

@@ -0,0 +1,152 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System;
using System.Collections.Generic;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using @(Settings.RootNameSpace).Models.@(Model.PluralName);
namespace @(Settings.RootNameSpace).Repositories
{
public partial class @(Model.SingularName)Repository : ServiceLocator<I@(Model.SingularName)Repository, @(Model.SingularName)Repository>, I@(Model.SingularName)Repository
{
protected override Func<I@(Model.SingularName)Repository> GetFactory()
{
return () => new @(Model.SingularName)Repository();
}
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: public IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")))
@: {
@: using (var context = DataContext.Instance())
@: {
@: return context.ExecuteQuery<@(Model.SingularName)>(System.Data.CommandType.Text,
@: "SELECT * FROM {databaseOwner}{objectQualifier}@Model.Prefix@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.Parameter(fo.Key, false, false, ""))=@@0",
@: @(Model.Table.Parameter(fo.Key, false, true, "")));
@: }
@: }
}
}
public @(Model.SingularName) Get@(Model.SingularName)(@Model.Table.PrimaryKeyParameterList())
{
using (var context = DataContext.Instance())
{
return context.ExecuteSingleOrDefault<@(Model.SingularName)>(System.Data.CommandType.Text,
"SELECT * FROM {databaseOwner}{objectQualifier}@Model.Prefix@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, 0, " AND "))",
@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, true, "", ",")));
}
}
public void Add@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""))
{
Requires.NotNull(@(Model.SingularNameLowered));
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: Requires.NotNull(@(Model.SingularNameLowered).@(Model.Table.Parameter(fo.Key, false, false, "")));
}
}
@if (Model.HasAuditFields)
{
@: @(Model.SingularNameLowered).CreatedByUserID = userId;
@: @(Model.SingularNameLowered).CreatedOnDate = DateTime.Now;
@: @(Model.SingularNameLowered).LastModifiedByUserID = userId;
@: @(Model.SingularNameLowered).LastModifiedOnDate = DateTime.Now;
}
using (var context = DataContext.Instance())
{
context.Execute(System.Data.CommandType.Text,
"IF NOT EXISTS (SELECT * FROM {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) " +
"WHERE @Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, 0, " AND ")) " +
"INSERT INTO {databaseOwner}{objectQualifier}@(Model.ModuleQualifier)@(Model.Name) (@Model.Table.ParameterList(Globals.ColumnGroup.All, false, false, "", ", ")) " +
"SELECT @(Globals.GetSqlParameterNumbers(Model.Table.Columns.Count, 0, ", "))", @(Model.Table.ParameterList(Globals.ColumnGroup.All, false, false, Model.SingularNameLowered + ".", ", ")));
}
}
public void Delete@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered))
{
Delete@(Model.SingularName)(@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, false, Model.SingularNameLowered + ".", ", ")));
}
public void Delete@(Model.SingularName)(@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, true, true)))
{
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: Requires.NotNull(@(Model.Table.Parameter(fo.Key, false, true, "")));
}
}
using (var context = DataContext.Instance())
{
context.Execute(System.Data.CommandType.Text,
"DELETE FROM {databaseOwner}{objectQualifier}@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, 0, " AND "))",
@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, true, "", ",")));
}
}
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: public void Delete@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")))
@: {
@: using (var context = DataContext.Instance())
@: {
@: context.Execute(System.Data.CommandType.Text,
@: "DELETE FROM {databaseOwner}{objectQualifier}@Model.ModuleQualifier@Model.Name WHERE @(Model.Table.Parameter(fo.Key, false, false, ""))=@@0",
@: @(Model.Table.Parameter(fo.Key, false, true, "")));
@: }
@: }
}
}
public void Update@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""))
{
Requires.NotNull(@(Model.SingularNameLowered));
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: Requires.NotNull(@(Model.SingularNameLowered).@(Model.Table.Parameter(fo.Key, false, false, "")));
}
}
@if (Model.HasAuditFields)
{
@: @(Model.SingularNameLowered).LastModifiedByUserID = userId;
@: @(Model.SingularNameLowered).LastModifiedOnDate = DateTime.Now;
}
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<@(Model.TableObjectName)>();
rep.Update("SET @(Model.Table.SqlParameterList(Globals.ColumnGroup.NonePrimaryKey, true, 0, ", ")) WHERE @(Model.Table.SqlParameterList(Globals.ColumnGroup.PrimaryKey, true, Model.Table.GetColumns(Globals.ColumnGroup.NonePrimaryKey).Count, " AND "))",
@(Model.Table.ParameterList(Globals.ColumnGroup.NonePrimaryKey, false, false, Model.SingularNameLowered + ".", ",")), @(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, false, false, Model.SingularNameLowered + ".", ",")));
}
}
}
public partial interface I@(Model.SingularName)Repository
{
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: IEnumerable<@(Model.SingularName)> Get@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")));
}
}
@(Model.SingularName) Get@(Model.SingularName)(@Model.Table.PrimaryKeyParameterList());
void Add@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""));
void Delete@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered));
void Delete@(Model.SingularName)(@(Model.Table.ParameterList(Globals.ColumnGroup.PrimaryKey, true, true)));
@foreach (KeyValuePair<String, ObjectDefinition> fo in Model.ForeignKeyObjects)
{
if (fo.Key != Model.Scope)
{
@: void Delete@(Model.PluralName)By@(fo.Value.SingularName)(@(Model.Table.Parameter(fo.Key, true, true, "")));
}
}
void Update@(Model.SingularName)(@(Model.TableObjectName) @(Model.SingularNameLowered)@(Model.HasAuditFields ? ", int userId" : ""));
}
}

View File

@@ -0,0 +1,21 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using @(Settings.RootNameSpace).Models.@(Model.PluralName);
namespace @(Settings.RootNameSpace).Repositories
{
public partial class @(Model.SingularName)Repository : ServiceLocator<I@(Model.SingularName)Repository, @(Model.SingularName)Repository>, I@(Model.SingularName)Repository
{
}
public partial interface I@(Model.SingularName)Repository
{
}
}

51
.templates/Sprocs.cshtml Normal file
View File

@@ -0,0 +1,51 @@
@inherits RazorTemplate<Dictionary<String, SprocDefinition>>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@{}
using System;
using System.Collections.Generic;
using DotNetNuke.Data;
namespace @(Settings.RootNameSpace).Data
{
public class Sprocs
{
@foreach (SprocDefinition sp in Model.Values)
{
var objName = "object";
if (sp.ReturnObject != "")
{
objName = sp.ReturnObject;
}
@: // @Raw(System.Text.RegularExpressions.Regex.Replace(sp.Sproc.TextBody, "(\n|\r\n?)", "\r\n // "));
if (sp.ReturnsData)
{
@: public static IEnumerable<@objName> @(sp.Name)(@sp.Sproc.ParameterList(true, true, "", ", "))
}
else
{
@: public static void @(sp.Name)(@sp.Sproc.ParameterList(true, true, "", ", "))
}
@: {
@: using (var context = DataContext.Instance())
@: {
if (sp.ReturnsData)
{
@: return context.ExecuteQuery<@objName>(System.Data.CommandType.StoredProcedure,
}
else
{
@: context.Execute(System.Data.CommandType.StoredProcedure,
}
var pl = sp.Sproc.ParameterList(false, true, "", ", ");
var comma = string.IsNullOrEmpty(pl) ? "" : ",";
@: "@sp.Sproc.Name"@comma
@: @pl);
@: }
@: }
@:
}
}
}

View File

@@ -0,0 +1,89 @@
@inherits RazorTemplate<ObjectDefinition>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
export interface I@(Model.SingularName) {
@foreach (Column c in Model.TableColumns)
{
@: @(c.Name)@(c.NullSuffix()): @(c.DataType.DataTypeToJs());
}
@if (Model.HasAuditFields)
{
@: CreatedByUserID: number;
@: CreatedOnDate: Date;
@: LastModifiedByUserID: number;
@: LastModifiedOnDate: Date;
}
@foreach (Column c in Model.UniqueViewColumns)
{
@: @(c.Name)@(c.NullSuffix()): @(c.DataType.DataTypeToJs());
}
}
export class @(Model.SingularName) implements I@(Model.SingularName) {
@foreach (Column c in Model.TableColumns)
{
@: @(c.Name)@(c.NullSuffix()): @(c.DataType.DataTypeToJs());
}
@if (Model.HasAuditFields)
{
@: CreatedByUserID: number;
@: CreatedOnDate: Date;
@: LastModifiedByUserID: number;
@: LastModifiedOnDate: Date;
}
@foreach (Column c in Model.UniqueViewColumns)
{
@: @(c.Name)@(c.NullSuffix()): @(c.DataType.DataTypeToJs());
}
constructor() {
@foreach (Column c in Model.TableColumns)
{
if (!c.Nullable) {
switch (c.DataType.DataTypeToJs())
{
case "number":
@: this.@(c.Name) = -1;
break;
case "string":
@: this.@(c.Name) = "";
break;
case "boolean":
@: this.@(c.Name) = false;
break;
case "Date":
@: this.@(c.Name) = new Date();
break;
}
}
}
@if (Model.HasAuditFields)
{
@: this.CreatedByUserID = -1;
@: this.CreatedOnDate = new Date();
@: this.LastModifiedByUserID = -1;
@: this.LastModifiedOnDate = new Date();
}
@foreach (Column c in Model.UniqueViewColumns)
{
if (!c.Nullable) {
switch (c.DataType.DataTypeToJs())
{
case "number":
@: this.@(c.Name) = -1;
break;
case "string":
@: this.@(c.Name) = "";
break;
case "boolean":
@: this.@(c.Name) = false;
break;
case "Date":
@: this.@(c.Name) = new Date();
break;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
@inherits RazorTemplate<string>
@using Bring2mind.CodeGen.Cli.Common
@using Bring2mind.CodeGen.Cli.Data
@using Bring2mind.CodeGen.Cli.Razor
@using Microsoft.SqlServer.Management.Smo
@using System.Linq
@foreach (ObjectDefinition od in DnnDb.Objects.Values.OrderBy(od => od.SingularName))
{
@:export * from './I@(od.SingularName)';
}

29
.yo-rc.json Normal file
View File

@@ -0,0 +1,29 @@
{
"generator-dotnetnuke": {
"promptValues": {
"projType": "react",
"dnnVersion": "9.13.0",
"npm": true,
"projectname": "InMemoriam",
"projectdescription": "In Memoriam module",
"yourname": "Peter Donker",
"email": "peter@bring2mind.net",
"companyfull": "Bring2mind",
"companyshort": "Bring2mind",
"companyUrl": "bring2mind.net",
"dnnHost": "http://dnndev.me",
"dnnRoot": "DL/",
"namespace": "Bring2mind.InMemoriam",
"Name": "InMemoriam",
"Namespace": "Bring2mind.InMemoriam",
"FileOutName": "skin",
"ModuleName": "InMemoriam",
"Separate": true,
"ReactOptions": []
},
"Company": "Bring2mind",
"Project": "InMemoriam",
"Namespace": "Bring2mind.InMemoriam",
"Solution": "Bring2mind.InMemoriam"
}
}

42
Bring2mind.InMemoriam.sln Normal file
View File

@@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Themes", "Themes", "{404978B5-8C01-4201-A7FA-0B358DCFE99F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InMemoriamSkin", "Themes\Skins\InMemoriamSkin\InMemoriamSkin.csproj", "{04747D14-1B14-4960-BB36-EFD061E47FAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InMemoriamContainer", "Themes\Containers\InMemoriamContainer\InMemoriamContainer.csproj", "{1517F2C9-F610-4F81-A09C-1C7E109A1ED6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bring2mind.InMemoriam.Core", "Server\Core\Bring2mind.InMemoriam.Core.csproj", "{081727B2-44B2-4819-9836-2C6F3B890CC2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bring2mind.InMemoriam", "Server\InMemoriam\Bring2mind.InMemoriam.csproj", "{DE141835-4474-431A-A2AC-D82F54DDB3B1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{04747D14-1B14-4960-BB36-EFD061E47FAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{04747D14-1B14-4960-BB36-EFD061E47FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1517F2C9-F610-4F81-A09C-1C7E109A1ED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1517F2C9-F610-4F81-A09C-1C7E109A1ED6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{081727B2-44B2-4819-9836-2C6F3B890CC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{081727B2-44B2-4819-9836-2C6F3B890CC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{081727B2-44B2-4819-9836-2C6F3B890CC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{081727B2-44B2-4819-9836-2C6F3B890CC2}.Release|Any CPU.Build.0 = Release|Any CPU
{DE141835-4474-431A-A2AC-D82F54DDB3B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE141835-4474-431A-A2AC-D82F54DDB3B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE141835-4474-431A-A2AC-D82F54DDB3B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE141835-4474-431A-A2AC-D82F54DDB3B1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{04747D14-1B14-4960-BB36-EFD061E47FAD} = {404978B5-8C01-4201-A7FA-0B358DCFE99F}
{1517F2C9-F610-4F81-A09C-1C7E109A1ED6} = {404978B5-8C01-4201-A7FA-0B358DCFE99F}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,42 @@
@import "../../../../node_modules/bootstrap/scss/bootstrap";
// Custom.scss
// Option B: Include parts of Bootstrap
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "../../../../node_modules/bootstrap/scss/functions";
// 2. Include any default variable overrides here
// $body-bg: #383E42;
// $color-contrast-dark: #fff;
// $color-contrast-light: #383E42;
// $light: #383E42;
// $dark: #fff;
// 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
@import "../../../../node_modules/bootstrap/scss/variables";
@import "../../../../node_modules/bootstrap/scss/variables-dark";
// 4. Include any default map overrides here
// 5. Include remainder of required parts
@import "../../../../node_modules/bootstrap/scss/maps";
@import "../../../../node_modules/bootstrap/scss/mixins";
@import "../../../../node_modules/bootstrap/scss/root";
// 6. Optionally include any other parts as needed
@import "../../../../node_modules/bootstrap/scss/utilities";
@import "../../../../node_modules/bootstrap/scss/reboot";
@import "../../../../node_modules/bootstrap/scss/type";
@import "../../../../node_modules/bootstrap/scss/images";
@import "../../../../node_modules/bootstrap/scss/containers";
@import "../../../../node_modules/bootstrap/scss/grid";
@import "../../../../node_modules/bootstrap/scss/helpers";
// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "../../../../node_modules/bootstrap/scss/utilities/api";
// 8. Add additional custom code here
[data-bs-theme="dark"] {
--bs-body-bg: #383E42;
}

View File

@@ -0,0 +1,98 @@
.pictures {
display: grid;
grid-template-columns: repeat(auto-fill, 222px);
column-gap: 20px;
width: 100%;
.picture {
border: 1px solid #ccc;
min-height: 300px;
padding: 10px;
background-color: rgb(96 139 168 / 0.2);
display: flex;
flex-direction: column;
justify-content: space-between;
.footer {
display: flex;
justify-content: space-between;
border-top: 1px solid #777;
padding-top: 6px;
.buttons {
a {
padding: 0;
border: 0;
height: 1em;
}
}
}
}
}
.picture-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.8);
transition: opacity 0.3s;
z-index: 1000;
padding: 3vw;
display: flex;
flex-direction: column;
overflow: hidden;
.top {
height: 3em;
flex-shrink: 0;
display: flex;
justify-content: space-between;
.close {
cursor: pointer;
font-size: 2em;
color: white;
}
.title {
color: white;
font-size: 2em;
height: 2em;
overflow: hidden;
}
}
.overlay-container {
flex-grow: 1;
min-height: 0;
display: grid;
overflow: hidden;
grid-template-columns: 70% 30%;
.picture {
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
img {
max-width: 100%;
max-height: 100%;
height: auto;
width: auto;
object-fit: contain;
}
}
}
.bottom {
height: 3em;
flex-shrink: 0;
display: flex;
justify-content: space-between;
.previous {
cursor: pointer;
font-size: 2em;
color: white;
}
.next {
cursor: pointer;
font-size: 2em;
color: white;
text-align: right;
}
}
}

View File

@@ -0,0 +1,29 @@
.stories {
width: 100%;
.story {
width: 100%;
border: 1px solid #ccc;
padding: 20px;
.title {
font-size: 1.5em;
font-weight: bold;
.date {
font-size: 0.8em;
color: #aaa;
}
}
.footer {
display: flex;
justify-content: space-between;
border-top: 1px solid #777;
padding-top: 6px;
.buttons {
a {
padding: 0;
border: 0;
height: 1em;
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
.messages {
display: grid;
grid-template-columns: repeat(auto-fill, 350px);
column-gap: 20px;
width: 100%;
.message {
border: 1px solid #ccc;
min-height: 300px;
padding: 10px;
background-color: rgb(96 139 168 / 0.2);
display: flex;
flex-direction: column;
justify-content: space-between;
.content {
height: 100%;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
font-style: italic;
}
.footer {
display: flex;
justify-content: space-between;
border-top: 1px solid #777;
padding-top: 6px;
}
}
}

View File

@@ -0,0 +1,98 @@
@import "./bootstrap";
@import "./inpictures.scss";
@import "./instories.scss";
@import "./messages.scss";
body {
font-family: "Quicksand", serif !important;
font-optical-sizing: auto;
}
.home-dates {
width: 100%;
height: 80vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
h2 {
margin-top: auto;
font-size: 4em;
font-weight: bold;
color: #fff;
}
}
#dnn_MenuPane,
header > div {
display: flex;
justify-content: space-between;
padding: 20px;
}
ul.homemenu,
ul.mainmenu,
ul.rightmenu {
list-style-type: none;
overflow: hidden;
padding-left: 0;
li {
display: inline;
}
li.active {
display: none;
}
}
ul.rightmenu {
justify-content: flex-end;
}
div.language-object {
display: inline;
li {
a {
margin-right: 5px;
}
}
}
#loginContainer,
#registrationContainer,
.doublePane,
.triplePane {
display: flex;
justify-content: center;
}
#loginContainer {
padding-top: 200px;
> div {
width: 300px;
}
}
#registrationContainer {
padding-top: 100px;
> div {
width: 500px;
}
}
.dnnHelperTip {
display: none;
}
.password-strength-container {
width: 100%;
max-width: 100%;
}
.dnnFormMessage.dnnFormError {
background-color: transparent;
color: red;
padding: 0;
}
ul.dnnActions {
list-style-type: none;
li {
display: inline;
}
}
div.defaultContainer {
padding: 20px;
}

View File

@@ -0,0 +1,36 @@
var path = require("path"),
MiniCssExtractPlugin = require("mini-css-extract-plugin"),
FileManagerPlugin = require("filemanager-webpack-plugin");
var outPath = path.resolve(__dirname, "../../../Themes/Skins/InMemoriamSkin");
var inmemoriamAppConfig = {
context: path.join(__dirname, "."),
entry: "./scss/styles.scss",
output: {
path: outPath,
filename: "skin.css.js"
},
module: {
rules: [
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "skin.css"
}),
new FileManagerPlugin({
events: {
onEnd: {
delete: [outPath + "/skin.css.js"],
},
},
})
]
};
module.exports = inmemoriamAppConfig;

View File

@@ -0,0 +1,9 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import { AppManager } from "./AppManager";
import { ComponentLoader } from "./ComponentLoader";
document.addEventListener("DOMContentLoaded", () => {
AppManager.loadData();
ComponentLoader.load();
});

View File

@@ -0,0 +1,52 @@
import { AppModule, IAppModule } from "./Models/IAppModule";
import { KeyedCollection } from "./Models/IKeyedCollection";
import DataService from "./Service";
declare global {
interface Element {
dataInt: (prop: string) => number;
dataString: (prop: string, defaultValue: string) => string;
dataObject: (prop: string) => any;
}
}
Element.prototype.dataInt = function (this: Element, prop: string): number {
if (this.getAttribute("data-" + prop) == null) return 0;
return parseInt(this.getAttribute("data-" + prop) as string);
};
Element.prototype.dataString = function (
this: Element,
prop: string,
defaultValue: string
): string {
if (this.getAttribute("data-" + prop) == null) return defaultValue;
return this.getAttribute("data-" + prop) as string;
};
Element.prototype.dataObject = function (this: Element, prop: string): any {
if (this.getAttribute("data-" + prop) == null) return null;
return JSON.parse(this.getAttribute("data-" + prop) as string);
};
export class AppManager {
public static Modules = new KeyedCollection<IAppModule>();
public static loadData(): void {
document.querySelectorAll(".Bring2mindInMemoriam").forEach((el) => {
var moduleId = el.dataInt("moduleid");
AppManager.Modules.Add(
moduleId.toString(),
new AppModule(
moduleId,
el.dataInt("tabid"),
el.dataString("locale", "en-US"),
el.dataObject("resources"),
el.dataObject("common"),
el.dataObject("security"),
new DataService(moduleId)
)
);
});
}
}

View File

@@ -0,0 +1,33 @@
import * as React from "react";
import { createRoot } from "react-dom/client";
import { AppManager } from "./AppManager";
import InPicturesPage from "./Components/InPictures/InPicturesPage";
import InStoriesPage from "./Components/InStories/InStoriesPage";
import MessagesPage from "./Components/Messages/MessagesPage";
export class ComponentLoader {
public static load(): void {
document.querySelectorAll(".InPictures").forEach((el) => {
const root = createRoot(el);
const moduleId = el.dataInt("moduleid");
root.render(
<InPicturesPage module={AppManager.Modules.Item(moduleId.toString())} />
);
});
document.querySelectorAll(".InWords").forEach((el) => {
const root = createRoot(el);
const moduleId = el.dataInt("moduleid");
root.render(
<InStoriesPage module={AppManager.Modules.Item(moduleId.toString())} />
);
});
document.querySelectorAll(".Messages").forEach((el) => {
const root = createRoot(el);
const moduleId = el.dataInt("moduleid");
root.render(
<MessagesPage module={AppManager.Modules.Item(moduleId.toString())} />
);
});
}
}

View File

@@ -0,0 +1,209 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { Modal, Form } from "react-bootstrap";
import { IPicture } from "../../Models/IPicture";
interface IEditImageProps {
module: IAppModule;
picture: IPicture;
shown: boolean;
dismiss: () => void;
editedPicture: (editedPicture: IPicture | null) => void;
}
const EditImage: React.FC<IEditImageProps> = (props) => {
const [title, setTitle] = React.useState(props.picture.Title);
const [description, setDescription] = React.useState(
props.picture.Description
);
const [visibility, setVisibility] = React.useState(props.picture.Visibility); // 0 = public, 1 = friends, 2 = private
const [pictureYear, setPictureYear] = React.useState(
props.picture.PictureYear < 1 ? "" : props.picture.PictureYear.toString()
);
const [pictureMonth, setPictureMonth] = React.useState(
props.picture.PictureMonth < 1 ? "" : props.picture.PictureMonth.toString()
);
const [pictureDay, setPictureDay] = React.useState(
props.picture.PictureDay < 1 ? "" : props.picture.PictureDay.toString()
);
const pictureYearIsValid =
pictureYear.length === 0 || /^\d{4}$/.test(pictureYear);
const pictureMonthIsValid =
pictureMonth.length === 0 || /^\d{1,2}$/.test(pictureMonth);
const pictureDayIsValid =
pictureDay.length === 0 || /^\d{1,2}$/.test(pictureDay);
const formIsValid =
pictureYearIsValid &&
pictureMonthIsValid &&
pictureDayIsValid &&
title !== "";
return (
<Modal show={props.shown} onHide={props.dismiss}>
<Modal.Header closeButton>
<Modal.Title>{props.module.resources.AddImage}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
<img
src={
props.module.service.baseServicepath +
"Pictures/Get?id=" +
props.picture.ImageIdentifier +
"&width=200&height=200&method=c&moduleId=" +
props.module.moduleId +
"&tabId=" +
props.module.service.tabId
}
alt={props.picture.Title}
/>
</div>
<Form.Group controlId="title" className="mb-3">
<Form.Label>{props.module.resources.Title}</Form.Label>
<Form.Control
type="text"
value={title}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTitle(e.target.value);
}}
isValid={title !== ""}
isInvalid={title === ""}
/>
</Form.Group>
<Form.Group controlId="description" className="mb-3">
<Form.Label>{props.module.resources.Description}</Form.Label>
<Form.Control
as="textarea"
value={description}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setDescription(e.target.value);
}}
/>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Visibility}</Form.Label>
<Form.Control
as="select"
value={visibility}
onChange={(e) => {
setVisibility(parseInt(e.target.value));
}}
>
<option value="0">{props.module.resources.Public}</option>
<option value="1">{props.module.resources.Friends}</option>
<option value="2">{props.module.resources.Private}</option>
</Form.Control>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Date}</Form.Label>
<div style={{ display: "flex" }}>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Year}
value={pictureYear}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureYear(e.target.value);
}}
isInvalid={!pictureYearIsValid}
/>
</div>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Month}
value={pictureMonth}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureMonth(e.target.value);
}}
isInvalid={!pictureMonthIsValid}
/>
</div>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Day}
value={pictureDay}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureDay(e.target.value);
}}
isInvalid={!pictureDayIsValid}
/>
</div>
</div>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<button
className="btn btn-secondary"
onClick={(e) => {
e.preventDefault();
props.dismiss();
}}
>
{props.module.resources.Cancel}
</button>
<button
className="btn btn-danger"
onClick={(e) => {
e.preventDefault();
if (confirm(props.module.resources.DeleteConfirm) === false) {
return;
}
props.module.service.deletePicture(
props.picture.PictureId,
() => {
// Success
props.editedPicture(null);
props.dismiss();
},
(error: string) => {
// Error
alert(error);
console.error(error);
}
);
props.dismiss();
}}
>
{props.module.resources.Delete}
</button>
<button
className="btn btn-primary"
disabled={formIsValid === false}
onClick={(e) => {
e.preventDefault();
const picture = {
...props.picture,
Title: title,
Description: description,
Visibility: visibility,
PictureYear: pictureYear === "" ? -1 : parseInt(pictureYear),
PictureMonth: pictureMonth === "" ? -1 : parseInt(pictureMonth),
PictureDay: pictureDay === "" ? -1 : parseInt(pictureDay),
};
props.module.service.editPicture(
picture,
(picture: IPicture) => {
// Success
props.editedPicture(picture);
props.dismiss();
},
(error: string) => {
// Error
alert(error);
console.error(error);
}
);
props.dismiss();
}}
>
{props.module.resources.Save}
</button>
</Modal.Footer>
</Modal>
);
};
export default EditImage;

View File

@@ -0,0 +1,139 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import NewImage from "./NewImage";
import { IPicture } from "../../Models/IPicture";
import Picture from "./Picture";
import EditImage from "./EditImage";
import PictureOverlay from "./PictureOverlay";
interface IInPicturesPageProps {
module: IAppModule;
}
const InPicturesPage: React.FC<IInPicturesPageProps> = (props) => {
const [showNewImage, setShowNewImage] = React.useState(false);
const [showEditImage, setShowEditImage] = React.useState(false);
const [pictures, setPictures] = React.useState<IPicture[]>([]);
const [pictureInEdit, setPictureInEdit] = React.useState<IPicture | null>(
null
);
const [selectedPictureIndex, setSelectedPictureIndex] = React.useState(-1);
React.useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
console.log(e.key, selectedPictureIndex, pictures.length);
if (e.key === "Escape") {
setSelectedPictureIndex(-1);
} else if (
e.key === "ArrowRight" &&
selectedPictureIndex < pictures.length - 1
) {
setSelectedPictureIndex(selectedPictureIndex + 1);
} else if (e.key === "ArrowLeft" && selectedPictureIndex > 0) {
setSelectedPictureIndex(selectedPictureIndex - 1);
}
};
window.addEventListener("keydown", handleKeyPress);
return () => window.removeEventListener("keydown", handleKeyPress);
}, [selectedPictureIndex]);
React.useEffect(() => {
props.module.service.getPictures(
(data) => {
setPictures(data);
},
(error) => {
console.error(error);
}
);
}, []);
React.useEffect(() => {
setShowEditImage(pictureInEdit !== null);
}, [pictureInEdit]);
return (
<>
{props.module.security.CanAdd && (
<div className="d-flex flex-row-reverse">
<div>
<button
className="btn btn-primary"
onClick={(e) => {
e.preventDefault();
setShowNewImage(true);
}}
>
{props.module.resources.Add}
</button>
</div>
</div>
)}
<div className="pictures">
{pictures.map((picture, index) => {
return (
<Picture
key={index}
module={props.module}
picture={picture}
onEdit={(picture) => {
setPictureInEdit(picture);
}}
onClick={(picture) => {
setSelectedPictureIndex(index);
}}
/>
);
})}
</div>
<NewImage
module={props.module}
shown={showNewImage}
dismiss={() => {
setShowNewImage(false);
}}
addNewPicture={(picture) => {
setPictures([...pictures, picture]);
}}
/>
{pictureInEdit && (
<EditImage
module={props.module}
picture={pictureInEdit}
shown={showEditImage}
dismiss={() => {
setPictureInEdit(null);
}}
editedPicture={(picture) => {
if (picture) {
setPictures(
pictures.map((p) => {
return p.PictureId === picture.PictureId ? picture : p;
})
);
}
}}
/>
)}
{selectedPictureIndex > -1 && (
<PictureOverlay
module={props.module}
picture={pictures[selectedPictureIndex]}
onClose={() => {
setSelectedPictureIndex(-1);
}}
hasNext={selectedPictureIndex < pictures.length - 1}
hasPrevious={selectedPictureIndex > 0}
onNext={() => {
setSelectedPictureIndex(selectedPictureIndex + 1);
}}
onPrevious={() => {
setSelectedPictureIndex(selectedPictureIndex - 1);
}}
/>
)}
</>
);
};
export default InPicturesPage;

View File

@@ -0,0 +1,189 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { Modal, Form } from "react-bootstrap";
import { IPicture } from "../../Models/IPicture";
interface INewImageProps {
module: IAppModule;
shown: boolean;
dismiss: () => void;
addNewPicture: (newPicture: IPicture) => void;
}
const NewImage: React.FC<INewImageProps> = (props) => {
const [newFile, setNewFile] = React.useState<File | null>(null);
const [title, setTitle] = React.useState("");
const [description, setDescription] = React.useState("");
const [visibility, setVisibility] = React.useState(0); // 0 = public, 1 = friends, 2 = private
const [pictureYear, setPictureYear] = React.useState("");
const [pictureMonth, setPictureMonth] = React.useState("");
const [pictureDay, setPictureDay] = React.useState("");
const clearFormAndDismiss = () => {
setNewFile(null);
setTitle("");
setDescription("");
setVisibility(1);
setPictureYear("");
setPictureMonth("");
setPictureDay("");
props.dismiss();
};
const pictureYearIsValid =
pictureYear.length === 0 || /^\d{4}$/.test(pictureYear);
const pictureMonthIsValid =
pictureMonth.length === 0 || /^\d{1,2}$/.test(pictureMonth);
const pictureDayIsValid =
pictureDay.length === 0 || /^\d{1,2}$/.test(pictureDay);
const formIsValid =
pictureYearIsValid &&
pictureMonthIsValid &&
pictureDayIsValid &&
newFile &&
title !== "";
return (
<Modal show={props.shown} onHide={props.dismiss}>
<Modal.Header closeButton>
<Modal.Title>{props.module.resources.AddImage}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group controlId="formFile" className="mb-3">
<Form.Label>{props.module.resources.SelectJpg}</Form.Label>
<Form.Control
type="file"
accept=".jpg"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.item(0);
if (file) {
setNewFile(file);
}
}}
isValid={newFile !== null}
isInvalid={newFile === null}
/>
</Form.Group>
<Form.Group controlId="title" className="mb-3">
<Form.Label>{props.module.resources.Title}</Form.Label>
<Form.Control
type="text"
value={title}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTitle(e.target.value);
}}
isValid={title !== ""}
isInvalid={title === ""}
/>
</Form.Group>
<Form.Group controlId="description" className="mb-3">
<Form.Label>{props.module.resources.Description}</Form.Label>
<Form.Control
as="textarea"
value={description}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setDescription(e.target.value);
}}
/>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Visibility}</Form.Label>
<Form.Control
as="select"
value={visibility}
onChange={(e) => {
setVisibility(parseInt(e.target.value));
}}
>
<option value="0">{props.module.resources.Public}</option>
<option value="1">{props.module.resources.Friends}</option>
<option value="2">{props.module.resources.Private}</option>
</Form.Control>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Date}</Form.Label>
<div style={{ display: "flex" }}>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Year}
value={pictureYear}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureYear(e.target.value);
}}
isInvalid={!pictureYearIsValid}
/>
</div>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Month}
value={pictureMonth}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureMonth(e.target.value);
}}
isInvalid={!pictureMonthIsValid}
/>
</div>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Day}
value={pictureDay}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPictureDay(e.target.value);
}}
isInvalid={!pictureDayIsValid}
/>
</div>
</div>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<button
className="btn btn-secondary"
onClick={(e) => {
e.preventDefault();
clearFormAndDismiss();
}}
>
{props.module.resources.Cancel}
</button>
<button
className="btn btn-primary"
disabled={formIsValid === false}
onClick={(e) => {
e.preventDefault();
// Do something with newFile, title, description, and visibility
if (newFile !== null) {
props.module.service.createPicture(
newFile,
title,
description,
visibility,
pictureYear === "" ? -1 : parseInt(pictureYear),
pictureMonth === "" ? -1 : parseInt(pictureMonth),
pictureDay === "" ? -1 : parseInt(pictureDay),
(newPicture: IPicture) => {
// Success
props.addNewPicture(newPicture);
clearFormAndDismiss();
},
(error: string) => {
// Error
alert(error);
console.error(error);
}
);
}
clearFormAndDismiss();
}}
>
{props.module.resources.Save}
</button>
</Modal.Footer>
</Modal>
);
};
export default NewImage;

View File

@@ -0,0 +1,86 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IPicture } from "../../Models/IPicture";
import Icon from "@mdi/react";
import { mdiPencil } from "@mdi/js";
interface IPictureProps {
module: IAppModule;
picture: IPicture;
onEdit: (picture: IPicture) => void;
onClick: (picture: IPicture) => void;
}
const Picture: React.FC<IPictureProps> = (props) => {
const canEdit =
props.module.security.IsFamily ||
props.module.security.UserId === props.picture.CreatedByUserID;
let dt = "";
if (props.picture.PictureYear > 0) {
dt = props.picture.PictureYear.toString();
if (props.picture.PictureMonth > 0) {
const month = new Date(0, props.picture.PictureMonth - 1).toLocaleString(
undefined,
{ month: "long" }
);
dt = month + ", " + dt;
if (props.picture.PictureDay > 0) {
dt = props.picture.PictureDay.toString() + " " + dt;
}
}
dt = "(" + dt + ")";
}
return (
<div
className="picture"
onClick={(e) => {
e.stopPropagation();
props.onClick(props.picture);
}}
>
<div>
<img
src={
props.module.service.baseServicepath +
"Pictures/Get?id=" +
props.picture.ImageIdentifier +
"&width=200&height=200&method=c&moduleId=" +
props.module.moduleId +
"&tabId=" +
props.module.service.tabId
}
alt={props.picture.Title}
/>
</div>
<div className="w-100 text-body-secondary text-center text-small mt-1 overflow-hidden">
{props.picture.Title} <span className="date">{dt}</span>
</div>
<div className="footer mt-3">
<div>
<small>
<strong>by</strong> {props.picture.CreatedByUser}
</small>
</div>
<div className="buttons">
{canEdit && (
<a
href="#"
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
props.onEdit(props.picture);
}}
>
<Icon path={mdiPencil} size={0.5} />
</a>
)}
</div>
</div>
</div>
);
};
export default Picture;

View File

@@ -0,0 +1,107 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IPicture } from "../../Models/IPicture";
interface IPictureOverlayProps {
module: IAppModule;
picture: IPicture;
hasNext: boolean;
hasPrevious: boolean;
onClose: () => void;
onNext: () => void;
onPrevious: () => void;
}
const PictureOverlay: React.FC<IPictureOverlayProps> = (props) => {
let dt = "";
if (props.picture.PictureYear > 0) {
dt = props.picture.PictureYear.toString();
if (props.picture.PictureMonth > 0) {
const month = new Date(0, props.picture.PictureMonth - 1).toLocaleString(
undefined,
{ month: "long" }
);
dt = month + ", " + dt;
if (props.picture.PictureDay > 0) {
dt = props.picture.PictureDay.toString() + " " + dt;
}
}
}
return (
<div className="picture-overlay">
<div className="top">
<div className="title">{props.picture.Title}</div>
<div className="close" onClick={props.onClose}>
&times;
</div>
</div>
<div className="overlay-container">
<div className="picture">
<img
src={
props.module.service.baseServicepath +
"Pictures/Get?id=" +
props.picture.ImageIdentifier +
"&width=800&height=800&method=b&moduleId=" +
props.module.moduleId +
"&tabId=" +
props.module.service.tabId
}
alt={props.picture.Title}
/>
</div>
<div className="details">
<div className="data">
<strong>{props.module.resources.Created}:</strong>{" "}
{new Intl.DateTimeFormat(undefined, { dateStyle: "short" }).format(
new Date(props.picture.CreatedOnDate)
)}{" "}
<strong>{props.module.resources.By}</strong>{" "}
{props.picture.CreatedByUser}
</div>
{dt !== "" && (
<div className="data">
<strong>{props.module.resources.Date}:</strong> {dt}
</div>
)}
<div className="description">{props.picture.Description}</div>
</div>
</div>
<div className="bottom">
<div className="previous">
<button
type="button"
disabled={!props.hasPrevious}
onClick={(e) => {
e.preventDefault();
if (props.hasPrevious) {
props.onPrevious();
}
}}
className="btn"
>
&lt;
</button>
</div>
<div className="next">
<button
type="button"
disabled={!props.hasNext}
onClick={(e) => {
e.preventDefault();
if (props.hasNext) {
props.onNext();
}
}}
className="btn"
>
&gt;
</button>
</div>
</div>
</div>
);
};
export default PictureOverlay;

View File

@@ -0,0 +1,189 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IStory, Story } from "../../Models/IStory";
import { Modal, Form } from "react-bootstrap";
interface IEditStoryProps {
module: IAppModule;
story: IStory;
shown: boolean;
dismiss: () => void;
editedStory: (editedStory: IStory | null) => void;
}
const EditStory: React.FC<IEditStoryProps> = (props) => {
console.log(props.story);
const [title, setTitle] = React.useState(props.story.Title);
const [contents, setContents] = React.useState(props.story.Contents);
const [visibility, setVisibility] = React.useState(props.story.Visibility); // 0 = public, 1 = friends, 2 = private
const [storyYear, setStoryYear] = React.useState(
props.story.StoryYear < 1 ? "" : props.story.StoryYear.toString()
);
const [storyMonth, setStoryMonth] = React.useState(
props.story.StoryMonth < 1 ? "" : props.story.StoryMonth.toString()
);
const [storyDay, setStoryDay] = React.useState(
props.story.StoryDay < 1 ? "" : props.story.StoryDay.toString()
);
console.log(title);
const clearFormAndDismiss = () => {
setTitle("");
setContents("");
setVisibility(1);
setStoryYear("");
setStoryMonth("");
setStoryDay("");
props.dismiss();
};
const storyYearIsValid = storyYear.length === 0 || /^\d{4}$/.test(storyYear);
const storyMonthIsValid =
storyMonth.length === 0 || /^\d{1,2}$/.test(storyMonth);
const storyDayIsValid = storyDay.length === 0 || /^\d{1,2}$/.test(storyDay);
return (
<Modal show={props.shown} onHide={props.dismiss} size="lg">
<Modal.Header closeButton>
<Modal.Title>{props.module.resources.EditStory}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="title" className="mb-3">
<Form.Label>{props.module.resources.Title}</Form.Label>
<Form.Control
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="contents" className="mb-3">
<Form.Label>{props.module.resources.Contents}</Form.Label>
<Form.Control
as="textarea"
value={contents}
rows={10}
onChange={(e) => setContents(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Visibility}</Form.Label>
<Form.Control
as="select"
value={visibility}
onChange={(e) => setVisibility(parseInt(e.target.value))}
>
<option value="0">{props.module.resources.Public}</option>
<option value="1">{props.module.resources.Friends}</option>
<option value="2">{props.module.resources.Private}</option>
</Form.Control>
</Form.Group>
<Form.Group controlId="visibility" className="mb-3">
<Form.Label>{props.module.resources.Date}</Form.Label>
<div style={{ display: "flex" }}>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Year}
value={storyYear}
onChange={(e) => setStoryYear(e.target.value)}
isInvalid={!storyYearIsValid}
/>
</div>
<div>
<Form.Control
type="text"
placeholder={props.module.resources.Month}
value={storyMonth}
onChange={(e) => setStoryMonth(e.target.value)}
isInvalid={!storyMonthIsValid}
/>
</div>
<div>
{" "}
<Form.Control
type="text"
placeholder={props.module.resources.Day}
value={storyDay}
onChange={(e) => setStoryDay(e.target.value)}
isInvalid={!storyDayIsValid}
/>
</div>
</div>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<button
className="btn"
onClick={(e) => {
e.preventDefault();
clearFormAndDismiss();
}}
>
{props.module.resources.Cancel}
</button>
{props.story && props.story.StoryId !== -1 && (
<button
className="btn btn-danger"
onClick={(e) => {
e.preventDefault();
if (confirm(props.module.resources.DeleteConfirm) === false) {
return;
}
props.module.service.deleteStory(
(props.story as IStory).StoryId,
() => {
// Success
props.editedStory(null);
clearFormAndDismiss();
},
(error: string) => {
// Error
alert(error);
console.error(error);
}
);
clearFormAndDismiss();
}}
>
{props.module.resources.Delete}
</button>
)}
<button
className="btn btn-primary"
onClick={() => {
if (storyYearIsValid && storyMonthIsValid && storyDayIsValid) {
const story = {
...new Story(),
StoryId: props.story ? props.story.StoryId : -1,
Title: title,
Contents: contents,
Visibility: visibility,
StoryYear: storyYear.length === 0 ? 0 : parseInt(storyYear),
StoryMonth: storyMonth.length === 0 ? 0 : parseInt(storyMonth),
StoryDay: storyDay.length === 0 ? 0 : parseInt(storyDay),
};
props.module.service.editStory(
story,
(editedStory: IStory) => {
props.editedStory(editedStory);
clearFormAndDismiss();
},
(error: string) => {
alert(error);
console.error(error);
}
);
clearFormAndDismiss();
}
}}
>
{props.module.resources.Save}
</button>
</Modal.Footer>
</Modal>
);
};
export default EditStory;

View File

@@ -0,0 +1,84 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IStory, Story as NewStory } from "../../Models/IStory";
import Story from "./Story";
import EditStory from "./EditStory";
interface IInStoriesPageProps {
module: IAppModule;
}
const InStoriesPage: React.FC<IInStoriesPageProps> = (props) => {
const [showEditStory, setShowEditStory] = React.useState(false);
const [stories, setStories] = React.useState<IStory[]>([]);
const [storyInEdit, setStoryInEdit] = React.useState<IStory | null>(null);
const getStories = () => {
props.module.service.getStories(
(data) => {
setStories(data);
},
(error) => {
console.error(error);
}
);
};
React.useEffect(() => {
getStories();
}, []);
React.useEffect(() => {
setShowEditStory(storyInEdit !== null);
}, [storyInEdit]);
return (
<div>
<div className="d-flex flex-row-reverse mb-4">
{props.module.security.CanAdd && (
<div>
<button
className="btn btn-primary"
onClick={(e) => {
e.preventDefault();
setStoryInEdit(new NewStory());
}}
>
{props.module.resources.Add}
</button>
</div>
)}
</div>
<div className="stories">
{stories.map((story, index) => {
return (
<Story
key={index}
module={props.module}
story={story}
onEdit={(story) => {
setStoryInEdit(story);
}}
/>
);
})}
</div>
{storyInEdit && (
<EditStory
module={props.module}
shown={showEditStory}
story={storyInEdit}
editedStory={(story) => {
setStoryInEdit(null);
getStories();
}}
dismiss={() => {
setStoryInEdit(null);
}}
/>
)}
</div>
);
};
export default InStoriesPage;

View File

@@ -0,0 +1,72 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IStory } from "../../Models/IStory";
import Icon from "@mdi/react";
import { mdiPencil } from "@mdi/js";
import SanitizedHTML from "react-sanitized-html";
interface IStoryProps {
module: IAppModule;
story: IStory;
onEdit: (story: IStory) => void;
}
const Story: React.FC<IStoryProps> = (props) => {
const canEdit =
props.module.security.IsFamily ||
props.module.security.UserId === props.story.CreatedByUserID;
let dt = "";
if (props.story.StoryYear > 0) {
dt = props.story.StoryYear.toString();
if (props.story.StoryMonth > 0) {
const month = new Date(0, props.story.StoryMonth - 1).toLocaleString(
undefined,
{ month: "long" }
);
dt = month + ", " + dt;
if (props.story.StoryDay > 0) {
dt = props.story.StoryDay.toString() + " " + dt;
}
}
dt = "(" + dt + ")";
}
return (
<div className="story mb-4">
<div className="title">
{props.story.Title} <span className="date">{dt}</span>
</div>
<div className="content">
<SanitizedHTML html={props.story.Contents.replace(/\n/g, "<br />")} />
</div>
<div className="footer mt-3">
<div>
<small>
<strong>Created:</strong>{" "}
{new Intl.DateTimeFormat(undefined, { dateStyle: "short" }).format(
new Date(props.story.CreatedOnDate)
)}{" "}
<strong>by</strong> {props.story.CreatedByUser}
</small>
</div>
<div className="buttons">
{canEdit && (
<a
href="#"
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
props.onEdit(props.story);
}}
>
<Icon path={mdiPencil} size={0.5} />
</a>
)}
</div>
</div>
</div>
);
};
export default Story;

View File

@@ -0,0 +1,113 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IMessage, Message } from "../../Models/IMessage";
import { Modal, Form } from "react-bootstrap";
interface ICreateMessageProps {
module: IAppModule;
shown: boolean;
dismiss: () => void;
addNewMessage: (newMessage: IMessage) => void;
}
const CreateMessage: React.FC<ICreateMessageProps> = (props) => {
const [contents, setContents] = React.useState("");
const [senderName, setSenderName] = React.useState("");
const [senderEmail, setSenderEmail] = React.useState("");
const clearFormAndDismiss = () => {
setContents("");
setSenderName("");
setSenderEmail("");
props.dismiss();
};
const contentsIsValid = contents.trim() !== "";
const senderNameIsValid = senderName.trim() !== "";
const formIsValid = contentsIsValid && senderNameIsValid;
return (
<Modal show={props.shown} onHide={props.dismiss}>
<Modal.Header closeButton>
<Modal.Title>{props.module.resources.AddMessage}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group controlId="contents" className="mb-3">
<Form.Label>{props.module.resources.Contents}</Form.Label>
<Form.Control
as="textarea"
value={contents}
isInvalid={!contentsIsValid}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setContents(e.target.value);
}}
/>
</Form.Group>
<Form.Group controlId="senderName" className="mb-3">
<Form.Label>{props.module.resources.SenderName}</Form.Label>
<Form.Control
type="text"
value={senderName}
isInvalid={!senderNameIsValid}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSenderName(e.target.value);
}}
/>
</Form.Group>
<Form.Group controlId="senderEmail" className="mb-3">
<Form.Label>{props.module.resources.SenderEmail}</Form.Label>
<Form.Control
type="email"
value={senderEmail}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSenderEmail(e.target.value);
}}
/>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<button
className="btn btn-secondary"
onClick={(e) => {
e.preventDefault();
clearFormAndDismiss();
}}
>
{props.module.resources.Cancel}
</button>
<button
className="btn btn-primary"
disabled={formIsValid === false}
onClick={(e) => {
e.preventDefault();
// Do something with newFile, title, description, and visibility
const newMessage = {
...new Message(),
Contents: contents.trim(),
SenderName: senderName.trim(),
SenderEmail: senderEmail.trim(),
};
props.module.service.addMessage(
newMessage,
(newMessage: IMessage) => {
// Success
props.addNewMessage(newMessage);
clearFormAndDismiss();
},
(error: string) => {
// Error
alert(error);
console.error(error);
}
);
clearFormAndDismiss();
}}
>
{props.module.resources.Save}
</button>
</Modal.Footer>
</Modal>
);
};
export default CreateMessage;

View File

@@ -0,0 +1,60 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IMessage } from "../../Models/IMessage";
import SanitizedHTML from "react-sanitized-html";
import Icon from "@mdi/react";
import { mdiDeleteForever } from "@mdi/js";
interface IMessageProps {
module: IAppModule;
message: IMessage;
onDelete: () => void;
}
const Message: React.FC<IMessageProps> = (props) => {
return (
<div className="message">
<div className="content">
<SanitizedHTML html={props.message.Contents.replace(/\n/g, "<br />")} />
</div>
<div className="footer mt-3">
<div>
<small>
<strong>Created:</strong>{" "}
{new Intl.DateTimeFormat(undefined, { dateStyle: "short" }).format(
new Date(props.message.CreatedOn)
)}{" "}
<strong>by</strong> {props.message.SenderName}
</small>
</div>
{props.module.security.IsFamily && (
<div className="buttons">
<a
href="#"
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
if (confirm(props.module.resources.DeleteConfirm)) {
props.module.service.deleteMessage(
props.message.MessageId,
() => {
props.onDelete();
},
(error) => {
console.error(error);
props.onDelete();
}
);
}
}}
>
<Icon path={mdiDeleteForever} size={1} />
</a>
</div>
)}
</div>
</div>
);
};
export default Message;

View File

@@ -0,0 +1,73 @@
import * as React from "react";
import { IAppModule } from "../../Models/IAppModule";
import { IMessage } from "../../Models/IMessage";
import Message from "./Message";
import CreateMessage from "./CreateMessage";
interface IMessagesPageProps {
module: IAppModule;
}
const MessagesPage: React.FC<IMessagesPageProps> = (props) => {
const [messages, setMessages] = React.useState<IMessage[]>([]);
const [showAddMessage, setShowAddMessage] = React.useState(false);
const refreshMessages = () => {
props.module.service.getMessages(
(data) => {
setMessages(data);
},
(error) => {
console.error(error);
}
);
};
React.useEffect(() => {
refreshMessages();
}, []);
return (
<div>
<div className="d-flex flex-row-reverse mb-4">
{props.module.security.CanMessage && (
<div>
<button
className="btn btn-primary"
onClick={(e) => {
e.preventDefault();
setShowAddMessage(true);
}}
>
{props.module.resources.Add}
</button>
</div>
)}
</div>
<div className="messages">
{messages.map((message) => (
<Message
key={message.MessageId}
message={message}
module={props.module}
onDelete={() => {
setMessages(messages.filter((m) => m.MessageId !== message.MessageId));
}}
/>
))}
</div>
{showAddMessage && (
<CreateMessage
module={props.module}
shown={showAddMessage}
dismiss={() => setShowAddMessage(false)}
addNewMessage={(message) => {
setMessages([message, ...messages]);
}}
/>
)}
</div>
);
};
export default MessagesPage;

View File

@@ -0,0 +1,35 @@
import { Utils } from "./Utils";
function createHandler(
component: any,
key: string,
property: string,
type?: string
) {
return (e: any) => {
const el: any = e.target;
var value: any = el.type === "checkbox" ? el.checked : el.value;
if (type) {
switch (type) {
case "int":
if (value != "" && !Utils.isInt(value)) return;
if (value != "") value = parseInt(value);
}
}
var obj = component.state[key];
obj[property] = value;
component.setState({
[key]: obj
});
};
}
export function linkState(
component: any,
key: string,
property: string,
type?: string
) {
return createHandler(component, key, property, type);
}

View File

@@ -0,0 +1,31 @@
import DataService from "../Service";
import { IContextSecurity } from "./IContextSecurity";
export interface IAppModule {
moduleId: number;
tabId: number;
locale: string;
resources: any;
common: any;
security: IContextSecurity;
service: DataService;
}
export class AppModule implements IAppModule {
public moduleId: number;
public tabId: number;
public locale: string;
public resources: any;
public common: any;
public security: IContextSecurity;
public service: DataService;
constructor(moduleId: number, tabId: number, locale: string, resources: any, common: any, security: IContextSecurity, service: DataService) {
this.moduleId = moduleId;
this.tabId = tabId;
this.locale = locale;
this.resources = resources;
this.common = common;
this.security = security;
this.service = service;
}
}

View File

@@ -0,0 +1,9 @@
export interface IContextSecurity {
UserId: number;
CanView: boolean;
CanEdit: boolean;
CanAdd: boolean;
CanMessage: boolean;
IsFamily: boolean;
IsAdmin: boolean;
}

View File

@@ -0,0 +1,62 @@
export interface IKeyedCollection<T> {
Add(key: string, value: T): void;
ContainsKey(key: string): boolean;
Count(): number;
Item(key: string): T;
Keys(): string[];
Remove(key: string): T;
Values(): T[];
}
export class KeyedCollection<T> implements IKeyedCollection<T> {
private items: { [index: string]: T } = {};
private count: number = 0;
public ContainsKey(key: string): boolean {
return this.items.hasOwnProperty(key);
}
public Count(): number {
return this.count;
}
public Add(key: string, value: T) {
this.items[key] = value;
this.count++;
}
public Remove(key: string): T {
var val = this.items[key];
delete this.items[key];
this.count--;
return val;
}
public Item(key: string): T {
return this.items[key];
}
public Keys(): string[] {
var keySet: string[] = [];
for (var prop in this.items) {
if (this.items.hasOwnProperty(prop)) {
keySet.push(prop);
}
}
return keySet;
}
public Values(): T[] {
var values: T[] = [];
for (var prop in this.items) {
if (this.items.hasOwnProperty(prop)) {
values.push(this.items[prop]);
}
}
return values;
}
}

View File

@@ -0,0 +1,24 @@
export interface IMessage {
MessageId: number;
ModuleId: number;
Contents: string;
SenderName: string;
SenderEmail: string;
CreatedOn: Date;
}
export class Message implements IMessage {
MessageId: number;
ModuleId: number;
Contents: string;
SenderName: string;
SenderEmail: string;
CreatedOn: Date;
constructor() {
this.MessageId = -1;
this.ModuleId = -1;
this.Contents = "";
this.CreatedOn = new Date();
}
}

View File

@@ -0,0 +1,56 @@
export interface IPicture {
PictureId: number;
ModuleId: number;
ImageIdentifier: any;
OriginalWidth: number;
OriginalHeight: number;
OriginalName: string;
Title: string;
Description: string;
PictureYear: number;
PictureMonth: number;
PictureDay: number;
Visibility: number;
CreatedByUserID: number;
CreatedOnDate: Date;
LastModifiedByUserID: number;
LastModifiedOnDate: Date;
CreatedByUser: string;
LastModifiedByUser: string;
}
export class Picture implements IPicture {
PictureId: number;
ModuleId: number;
ImageIdentifier: any;
OriginalWidth: number;
OriginalHeight: number;
OriginalName: string;
Title: string;
Description: string;
PictureYear: number;
PictureMonth: number;
PictureDay: number;
Visibility: number;
CreatedByUserID: number;
CreatedOnDate: Date;
LastModifiedByUserID: number;
LastModifiedOnDate: Date;
CreatedByUser: string;
LastModifiedByUser: string;
constructor() {
this.PictureId = -1;
this.ModuleId = -1;
this.OriginalWidth = -1;
this.OriginalHeight = -1;
this.PictureYear = -1;
this.PictureMonth = -1;
this.PictureDay = -1;
this.Visibility = -1;
this.CreatedByUserID = -1;
this.CreatedOnDate = new Date();
this.LastModifiedByUserID = -1;
this.LastModifiedOnDate = new Date();
}
}

View File

@@ -0,0 +1,45 @@
export interface IStory {
StoryId: number;
ModuleId: number;
Title: string;
Contents: string;
StoryYear: number;
StoryMonth: number;
StoryDay: number;
Visibility: number;
CreatedByUserID: number;
CreatedOnDate: Date;
LastModifiedByUserID: number;
LastModifiedOnDate: Date;
CreatedByUser: string;
LastModifiedByUser: string;
}
export class Story implements IStory {
StoryId: number;
ModuleId: number;
Title: string;
Contents: string;
StoryYear: number;
StoryMonth: number;
StoryDay: number;
Visibility: number;
CreatedByUserID: number;
CreatedOnDate: Date;
LastModifiedByUserID: number;
LastModifiedOnDate: Date;
CreatedByUser: string;
LastModifiedByUser: string;
constructor() {
this.StoryId = -1;
this.ModuleId = -1;
this.StoryYear = -1;
this.StoryMonth = -1;
this.StoryDay = -1;
this.Visibility = -1;
this.CreatedByUserID = -1;
this.CreatedOnDate = new Date();
this.LastModifiedByUserID = -1;
this.LastModifiedOnDate = new Date();
}
}

View File

@@ -0,0 +1,90 @@
import { IMessage } from "./Models/IMessage";
import { IPicture } from "./Models/IPicture";
import { IStory } from "./Models/IStory";
export interface DnnServiceFramework extends JQueryStatic {
dnnSF(moduleId: number): DnnServiceFramework;
getServiceRoot(path: string): string;
setModuleHeaders(): void;
getTabId(): string;
}
export default class DataService {
private moduleId: number = -1;
private dnn: DnnServiceFramework = <DnnServiceFramework>$;
public baseServicepath: string = this.dnn.dnnSF(this.moduleId).getServiceRoot('Bring2mind/InMemoriam');
public tabId: string = this.dnn.dnnSF(this.moduleId).getTabId();
constructor(mid: number) {
this.moduleId = mid;
};
private ajaxCall(type: string, servicePath: string, controller: string, action: string, id: any, headers: any, data: any, success: Function, fail?: Function, isUploadForm?: boolean)
: void {
var opts: JQuery.AjaxSettings = {
headers: headers,
type: type === "POSTFORM" ? "POST": type,
url: servicePath + controller + '/' + action + (id != undefined
? '/' + id
: ''),
beforeSend: this
.dnn
.dnnSF(this.moduleId)
.setModuleHeaders,
contentType: type === "POSTFORM" ? undefined : "application/json; charset=utf-8",
data: type == "POST" ? JSON.stringify(data) : data,
dataType: "json"
};
if (isUploadForm) {
opts.contentType = false;
opts.processData = false;
}
$.ajax(opts)
.done(function (retdata: any) {
if (success != undefined) {
success(retdata);
}
})
.fail(function (xhr: any, status: any) {
if (fail != undefined) {
fail(xhr.responseText);
}
});
};
public deletePicture(pictureId: number, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Pictures', 'DeletePicture', pictureId, null, null, success, fail);
}
public editPicture(picture: IPicture, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Pictures', 'EditPicture', picture.PictureId, null, picture, success, fail, true)
}
public getPictures(success: Function, fail: Function): void {
this.ajaxCall('GET', this.baseServicepath, 'Pictures', 'GetPictures', null, null, null, success, fail);
}
public createPicture(file: File, title: string, description: string, visibility: number, pictureYear: number, pictureMonth: number, pictureDay: number, success: Function, fail: Function): void {
var formData = new FormData();
formData.append('file', file);
formData.append('title', title);
formData.append('description', description);
formData.append('visibility', visibility.toString());
formData.append('pictureYear', pictureYear.toString());
formData.append('pictureMonth', pictureMonth.toString());
formData.append('pictureDay', pictureDay.toString());
this.ajaxCall('POSTFORM', this.baseServicepath, 'Pictures', 'UploadPicture', null, null, formData, success, fail, true)
}
public getStories(success: Function, fail: Function): void {
this.ajaxCall('GET', this.baseServicepath, 'Stories', 'GetStories', null, null, null, success, fail);
}
public editStory(story: IStory, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Stories', 'EditStory', story.StoryId, null, story, success, fail, true)
}
public deleteStory(storyId: number, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Stories', 'DeleteStory', storyId, null, null, success, fail);
}
public addMessage(message: IMessage, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Messages', 'AddMessage', -1, null, message, success, fail, true)
}
public getMessages(success: Function, fail: Function): void {
this.ajaxCall('GET', this.baseServicepath, 'Messages', 'GetMessages', null, null, null, success, fail);
}
public deleteMessage(messageId: number, success: Function, fail: Function): void {
this.ajaxCall('POST', this.baseServicepath, 'Messages', 'DeleteMessage', messageId, null, null, success, fail);
}
}

View File

@@ -0,0 +1,69 @@
export class Utils {
public static UnNull(input: Date | undefined, defaultValue: Date): Date {
if (input == undefined) {
return defaultValue;
} else {
return input;
}
}
public static Merge(input: any, mergeObject: any, property: string): void {
if (input[property] == undefined) {
input[property] = mergeObject[property];
}
}
public static ArraySort(array: any[], sortProperty: string, sortDirection: string): any[] {
var res = array;
if (sortDirection == "asc") {
res.sort((a, b) => {
return a[sortProperty] > b[sortProperty] ? 1 : b[sortProperty] > a[sortProperty] ? -1 : 0;
});
} else {
res.sort((a, b) => {
return a[sortProperty] > b[sortProperty] ? -1 : b[sortProperty] > a[sortProperty] ? 1 : 0;
});
}
return res;
}
public static ArrayContains(
array: any[],
propertyName: string | null,
propertyValue: any
): boolean {
if (propertyName) {
for (var i = 0; i < array.length; i++) {
if (array[i][propertyName] == propertyValue) {
return true;
}
}
} else {
for (var i = 0; i < array.length; i++) {
if (array[i] == propertyValue) {
return true;
}
}
}
return false;
}
public static UnNullStr(input: any): string {
if (input) return input;
return "";
}
public static isInt(value: any): boolean {
return (
!isNaN(value) && parseInt(Number(value).toString()) == value && !isNaN(parseInt(value, 10))
);
}
public static Round(value: number, decimals: number) {
switch (decimals) {
case 0:
return Math.round(value);
case 1:
return Math.round(value * 10) / 10;
case 2:
return Math.round(value * 100) / 100;
default:
var m = Math.pow(10, decimals);
return Math.round(value * m) / m;
}
}
}

View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es2015",
"module": "esnext",
"jsx": "react-jsx",
"noImplicitAny": false,
"sourceMap": true,
"strictNullChecks": true,
"allowJs": true,
"outDir": "./dist",
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": false,
"noEmit": false
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules", "dist"],
"typeRoots": ["node_modules/@types", "Types"]
}

View File

@@ -0,0 +1,20 @@
var path = require("path"),
commonConfig = require("../../webpack.common.config");
var clientAppConfig = Object.assign({}, commonConfig, {
context: path.join(__dirname, "."),
entry: "./App.tsx",
output: {
path: path.resolve(__dirname, "../../../Server/InMemoriam/js"),
filename: "inmemoriam.js"
},
resolve: {
extensions: [".js", ".ts", ".tsx"],
mainFields: ["module", "browser", "main"],
alias: {
app: path.resolve(__dirname, "src/app/")
}
}
});
module.exports = clientAppConfig;

View File

@@ -0,0 +1,69 @@
var path = require("path"),
webpack = require("webpack"),
MiniCssExtractPlugin = require("mini-css-extract-plugin");
var isProduction =
process.argv.indexOf("-p") >= 0 || process.env.NODE_ENV === "production";
var sourcePath = path.join(__dirname, ".");
var commonConfig = {
context: sourcePath,
target: "web",
mode: isProduction ? "production" : "development",
module: {
rules: [
{
test: /\.tsx?$/,
exclude: [/node_modules/, /_Development/],
use: {
loader: "ts-loader",
},
},
{
test: /.jsx?$/,
exclude: [/node_modules/, /_Development/],
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
!isProduction ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: "file-loader",
},
],
},
externals: {
jquery: "jQuery",
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: "development", // use 'development' unless process.env.NODE_ENV is defined
DEBUG: false,
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "../module.css",
chunkFilename: "[id].css",
}),
],
};
module.exports = commonConfig;

6
Client/webpack.config.js Normal file
View File

@@ -0,0 +1,6 @@
var InMemoriamAppConfigSkinCss = require("./Css/InMemoriam/webpack.config");
var InMemoriamAppConfigReact = require("./Js/InMemoriam/webpack.config");
module.exports = [
InMemoriamAppConfigSkinCss,
InMemoriamAppConfigReact,
];

10
License.md Normal file
View File

@@ -0,0 +1,10 @@
Copyright (c) 2025 Bring2mind, All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Bring2mind.InMemoriam.Core</AssemblyName>
<TargetFramework>net472</TargetFramework>
<OutputPath>..\..\bin</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Authors>Peter Donker</Authors>
<Company>Bring2mind</Company>
<Product>inmemoriam</Product>
<Copyright>Copyright 2025 by Bring2mind</Copyright>
<PackageId>InMemoriam</PackageId>
<AssemblyVersion>1.0.2</AssemblyVersion>
<FileVersion>1.0.2</FileVersion>
<Description>In Memoriam module</Description>
<NeutralLanguage>en-US</NeutralLanguage>
<ApplicationIcon />
<OutputType>Library</OutputType>
<StartupObject />
<DebugType>Portable</DebugType>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DotNetNuke.Core" Version="9.13.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
namespace Bring2mind.InMemoriam.Core.Common
{
public static class Globals
{
public const string uploadPath = @"InMemoriam\Pictures";
}
}

View File

@@ -0,0 +1,43 @@
using System.IO;
namespace Bring2mind.InMemoriam.Core.Common
{
public class Image
{
public string ResizedFile { get; set; }
public bool ImageExists { get; set; }
private string Location { get; set; }
public Image(string location, string id, int width, int height, string method)
{
Location = location;
var filePath = Path.Combine(location, id + ".resources");
ImageExists = File.Exists(filePath);
if (ImageExists)
{
ResizedFile = $"{id}_{width}_{height}_{method}.jpg";
var m = ImageResizer.ResizeMethod.Stretch;
switch (method)
{
case "b":
m = ImageResizer.ResizeMethod.Box;
break;
case "c":
m = ImageResizer.ResizeMethod.Crop;
break;
}
ImageResizer.ResizeImage(filePath, $"{location}\\{ResizedFile}", width, height, m);
}
}
public void CopyToStream(Stream s)
{
var imgFile = ImageExists ? string.Format("{0}\\{1}", Location, ResizedFile) : string.Format("{0}\\images\\no-content.png", DotNetNuke.Common.Globals.ApplicationMapPath);
using (var fs = new FileStream(imgFile, FileMode.Open, FileAccess.Read))
{
fs.CopyTo(s);
fs.Flush();
}
}
}
}

View File

@@ -0,0 +1,15 @@
namespace Bring2mind.InMemoriam.Core.Common
{
public enum ImageOrientation
{
Unknown = 0,
Normal = 1,
FlipHorizontal = 2,
Rotate180 = 3,
FlipVertical = 4,
Transpose = 5,
Rotate270 = 6,
Transverse = 7,
Rotate90 = 8
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace Bring2mind.InMemoriam.Core.Common
{
public class ImageResizer
{
public enum ResizeMethod
{
Box,
Crop,
Stretch
}
public static void ResizeImage(string source, string destination, int desiredWidth, int desiredHeight, ResizeMethod method)
{
var format = ImageFormat.Jpeg;
var target = Resize(source, desiredWidth, desiredHeight, method);
target.Save(destination, format);
}
private static System.Drawing.Image Resize(string sourceImageMapPath, int desiredWidth, int desiredHeight, ResizeMethod method)
{
//throw error if bouning box is to small
if (desiredWidth < 4 || desiredHeight < 4)
throw new InvalidOperationException("Bounding Box of Resize Photo must be larger than 4X4 pixels.");
var original = Bitmap.FromFile(sourceImageMapPath);
try
{
var orientation = (ImageOrientation)original.GetPropertyItem(274).Value[0];
switch (orientation)
{
case ImageOrientation.FlipHorizontal:
original.RotateFlip(RotateFlipType.RotateNoneFlipX);
break;
case ImageOrientation.Rotate180:
original.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
case ImageOrientation.FlipVertical:
original.RotateFlip(RotateFlipType.RotateNoneFlipY);
break;
case
ImageOrientation.Transpose:
original.RotateFlip(RotateFlipType.RotateNoneFlipXY);
break;
case ImageOrientation.Rotate270:
original.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case
ImageOrientation.Transverse:
original.RotateFlip(RotateFlipType.Rotate90FlipXY);
break;
case ImageOrientation.Rotate90:
original.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
default:
break;
}
}
catch (Exception ex)
{
}
//store image widths in variable for easier use
var oW = (decimal)original.Width;
var oH = (decimal)original.Height;
var dW = (decimal)desiredWidth;
var dH = (decimal)desiredHeight;
var scaleWidth = dW / oW;
var scaleHeight = dH / oH;
int tW = desiredWidth;
int tH = desiredHeight;
int tX = 0;
int tY = 0;
int tDX = desiredWidth;
int tDY = desiredHeight;
//check if image already fits
if (oW <= dW && oH <= dH)
return original; //image fits in bounding box, keep size (center with css) If we made it bigger it would stretch the image resulting in loss of quality.
//check for double squares or plain stretch resizing
if ((oW == oH && dW == dH) || method == ResizeMethod.Stretch)
{
// don't do anything
}
else
{
switch (method)
{
case ResizeMethod.Crop:
var scaleMax = Math.Max(scaleHeight, scaleWidth);
if (scaleHeight > scaleWidth)
{
tX = -1 * Convert.ToInt32(((scaleMax * oW) - dW) / 2);
tDX = Convert.ToInt32(scaleMax * oW);
}
else
{
tY = -1 * Convert.ToInt32(((scaleMax * oH) - dH) / 2);
tDY = Convert.ToInt32(scaleMax * oH);
}
break;
default:
var scaleMin = Math.Min(scaleHeight, scaleWidth);
tW = Convert.ToInt32(oW * scaleMin);
tH = Convert.ToInt32(oH * scaleMin);
tDX = tW;
tDY = tH;
break;
}
}
var destImage = new Bitmap(tW, tH);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(original, tX, tY, tDX, tDY);
}
return destImage;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Bring2mind.InMemoriam.Core.Common
{
public enum Visibility
{
Public = 0,
Friends = 1,
Private = 2
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Data;
using System.Runtime.Serialization;
using DotNetNuke.Common.Utilities;
namespace Bring2mind.InMemoriam.Core.Data
{
[DataContract]
public abstract class AuditableEntity
{
public void FillAuditFields(IDataReader dr)
{
CreatedByUserID = Convert.ToInt32(Null.SetNull(dr["CreatedByUserID"], CreatedByUserID));
CreatedOnDate = Convert.ToDateTime(Null.SetNull(dr["CreatedOnDate"], CreatedOnDate));
LastModifiedByUserID = Convert.ToInt32(Null.SetNull(dr["LastModifiedByUserID"], LastModifiedByUserID));
LastModifiedOnDate = Convert.ToDateTime(Null.SetNull(dr["LastModifiedOnDate"], LastModifiedOnDate));
}
public void SetAddingUser(int userId)
{
CreatedByUserID = userId;
CreatedOnDate = DateTime.Now;
SetModifyingUser(userId);
}
public void SetModifyingUser(int userId)
{
LastModifiedByUserID = userId;
LastModifiedOnDate = DateTime.Now;
}
#region Public Properties
[DataMember]
public int CreatedByUserID { get; set; }
[DataMember]
public DateTime CreatedOnDate { get; set; }
[DataMember]
public int LastModifiedByUserID { get; set; }
[DataMember]
public DateTime LastModifiedOnDate { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,132 @@
using System.Collections.Generic;
using DotNetNuke.Collections;
using DotNetNuke.Data;
namespace Bring2mind.InMemoriam.Core.Data
{
public abstract class RepositoryImpl<T> : IRepository<T> where T : class
{
public virtual void Delete(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Delete(item);
}
}
public virtual void Delete(string sqlCondition, params object[] args)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Delete(sqlCondition, args);
}
}
public virtual IEnumerable<T> Find(string sqlCondition, params object[] args)
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Find(sqlCondition, args);
}
return list;
}
public virtual IPagedList<T> Find(int pageIndex, int pageSize, string sqlCondition, params object[] args)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Find(pageIndex, pageSize, sqlCondition, args);
}
return list;
}
public virtual IEnumerable<T> Get()
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Get();
}
return list;
}
public virtual IEnumerable<T> Get<TScopeType>(TScopeType scopeValue)
{
IEnumerable<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.Get<TScopeType>(scopeValue);
}
return list;
}
public virtual T GetById<TProperty>(TProperty id)
{
T item = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
item = repo.GetById<TProperty>(id);
}
return item;
}
public virtual T GetById<TProperty, TScopeType>(TProperty id, TScopeType scopeValue)
{
T item = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
item = repo.GetById<TProperty, TScopeType>(id, scopeValue);
}
return item;
}
public virtual IPagedList<T> GetPage(int pageIndex, int pageSize)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.GetPage(pageIndex, pageSize);
}
return list;
}
public virtual IPagedList<T> GetPage<TScopeType>(TScopeType scopeValue, int pageIndex, int pageSize)
{
IPagedList<T> list = null;
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
list = repo.GetPage<TScopeType>(scopeValue, pageIndex, pageSize);
}
return list;
}
public virtual void Insert(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Insert(item);
}
}
public virtual void Update(T item)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Update(item);
}
}
public virtual void Update(string sqlCondition, params object[] args)
{
using (IDataContext db = DataContext.Instance()) {
IRepository<T> repo = db.GetRepository<T>();
repo.Update(sqlCondition, args);
}
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using DotNetNuke.Data;
namespace Bring2mind.InMemoriam.Core.Data
{
public class Sprocs
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Bring2mind.InMemoriam.Core.Models.Messages
{
public partial class Message
{
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
using Bring2mind.InMemoriam.Core.Data;
namespace Bring2mind.InMemoriam.Core.Models.Messages
{
[TableName("B2M_InMemoriam_Messages")]
[PrimaryKey("MessageId", AutoIncrement = true)]
[DataContract]
[Scope("ModuleId")]
public partial class Message {
#region .ctor
public Message()
{
MessageId = -1;
}
#endregion
#region Properties
[DataMember]
public int MessageId { get; set; }
[DataMember]
public int ModuleId { get; set; }
[DataMember]
public string Contents { get; set; }
[DataMember]
public string SenderName { get; set; }
[DataMember]
public string SenderEmail { get; set; }
[DataMember]
public DateTime CreatedOn { get; set; }
#endregion
#region Methods
public void ReadMessage(Message message)
{
if (message.MessageId > -1)
MessageId = message.MessageId;
if (message.ModuleId > -1)
ModuleId = message.ModuleId;
if (!String.IsNullOrEmpty(message.Contents))
Contents = message.Contents;
if (!String.IsNullOrEmpty(message.SenderName))
SenderName = message.SenderName;
if (!String.IsNullOrEmpty(message.SenderEmail))
SenderEmail = message.SenderEmail;
CreatedOn = message.CreatedOn;
}
#endregion
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Data;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel.DataAnnotations;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Tokens;
namespace Bring2mind.InMemoriam.Core.Models.Messages
{
public partial class Message : IHydratable, IPropertyAccess
{
#region IHydratable
public virtual void Fill(IDataReader dr)
{
MessageId = Convert.ToInt32(Null.SetNull(dr["MessageId"], MessageId));
ModuleId = Convert.ToInt32(Null.SetNull(dr["ModuleId"], ModuleId));
Contents = Convert.ToString(Null.SetNull(dr["Contents"], Contents));
SenderName = Convert.ToString(Null.SetNull(dr["SenderName"], SenderName));
SenderEmail = Convert.ToString(Null.SetNull(dr["SenderEmail"], SenderEmail));
CreatedOn = (DateTime)(Null.SetNull(dr["CreatedOn"], CreatedOn));
}
[IgnoreColumn()]
public int KeyID
{
get { return MessageId; }
set { MessageId = value; }
}
#endregion
#region IPropertyAccess
public virtual string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower())
{
case "messageid": // Int
return MessageId.ToString(strFormat, formatProvider);
case "moduleid": // Int
return ModuleId.ToString(strFormat, formatProvider);
case "contents": // NVarCharMax
return PropertyAccess.FormatString(Contents, strFormat);
case "sendername": // NVarChar
if (SenderName == null)
{
return "";
};
return PropertyAccess.FormatString(SenderName, strFormat);
case "senderemail": // NVarChar
if (SenderEmail == null)
{
return "";
};
return PropertyAccess.FormatString(SenderEmail, strFormat);
case "createdon": // DateTime
return CreatedOn.ToString(strFormat, formatProvider);
default:
propertyNotFound = true;
break;
}
return Null.NullString;
}
[IgnoreColumn()]
public CacheLevel Cacheability
{
get { return CacheLevel.fullyCacheable; }
}
#endregion
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
using Bring2mind.InMemoriam.Core.Data;
namespace Bring2mind.InMemoriam.Core.Models.Pictures
{
[TableName("B2M_InMemoriam_Pictures")]
[PrimaryKey("PictureId", AutoIncrement = true)]
[DataContract]
[Scope("ModuleId")]
public partial class PictureBase : AuditableEntity
{
#region .ctor
public PictureBase()
{
PictureId = -1;
}
#endregion
#region Properties
[DataMember]
public int PictureId { get; set; }
[DataMember]
public int ModuleId { get; set; }
[DataMember]
public Guid ImageIdentifier { get; set; }
[DataMember]
public int OriginalWidth { get; set; }
[DataMember]
public int OriginalHeight { get; set; }
[DataMember]
public string OriginalName { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public int PictureYear { get; set; }
[DataMember]
public int PictureMonth { get; set; }
[DataMember]
public int PictureDay { get; set; }
[DataMember]
public int Visibility { get; set; }
#endregion
#region Methods
public void ReadPictureBase(PictureBase picture)
{
if (picture.PictureId > -1)
PictureId = picture.PictureId;
if (picture.ModuleId > -1)
ModuleId = picture.ModuleId;
ImageIdentifier = picture.ImageIdentifier;
if (picture.OriginalWidth > -1)
OriginalWidth = picture.OriginalWidth;
if (picture.OriginalHeight > -1)
OriginalHeight = picture.OriginalHeight;
if (!String.IsNullOrEmpty(picture.OriginalName))
OriginalName = picture.OriginalName;
if (!String.IsNullOrEmpty(picture.Title))
Title = picture.Title;
if (!String.IsNullOrEmpty(picture.Description))
Description = picture.Description;
if (picture.PictureYear > -1)
PictureYear = picture.PictureYear;
if (picture.PictureMonth > -1)
PictureMonth = picture.PictureMonth;
if (picture.PictureDay > -1)
PictureDay = picture.PictureDay;
if (picture.Visibility > -1)
Visibility = picture.Visibility;
}
#endregion
}
}

View File

@@ -0,0 +1,20 @@
using Bring2mind.InMemoriam.Core.Data;
namespace Bring2mind.InMemoriam.Core.Models.Pictures
{
public partial class PictureBase : AuditableEntity
{
public void ReadEditedPictureBase(PictureBase picture)
{
Title = picture.Title.Trim();
Description = picture.Description.Trim();
PictureYear = picture.PictureYear;
PictureMonth = picture.PictureMonth;
PictureDay = picture.PictureDay;
Visibility = picture.Visibility;
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Data;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel.DataAnnotations;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Tokens;
namespace Bring2mind.InMemoriam.Core.Models.Pictures
{
public partial class PictureBase : IHydratable, IPropertyAccess
{
#region IHydratable
public virtual void Fill(IDataReader dr)
{
FillAuditFields(dr);
PictureId = Convert.ToInt32(Null.SetNull(dr["PictureId"], PictureId));
ModuleId = Convert.ToInt32(Null.SetNull(dr["ModuleId"], ModuleId));
ImageIdentifier = new Guid(Convert.ToString(Null.SetNull(dr["ImageIdentifier"], ImageIdentifier)));
OriginalWidth = Convert.ToInt32(Null.SetNull(dr["OriginalWidth"], OriginalWidth));
OriginalHeight = Convert.ToInt32(Null.SetNull(dr["OriginalHeight"], OriginalHeight));
OriginalName = Convert.ToString(Null.SetNull(dr["OriginalName"], OriginalName));
Title = Convert.ToString(Null.SetNull(dr["Title"], Title));
Description = Convert.ToString(Null.SetNull(dr["Description"], Description));
PictureYear = Convert.ToInt32(Null.SetNull(dr["PictureYear"], PictureYear));
PictureMonth = Convert.ToInt32(Null.SetNull(dr["PictureMonth"], PictureMonth));
PictureDay = Convert.ToInt32(Null.SetNull(dr["PictureDay"], PictureDay));
Visibility = Convert.ToInt32(Null.SetNull(dr["Visibility"], Visibility));
}
[IgnoreColumn()]
public int KeyID
{
get { return PictureId; }
set { PictureId = value; }
}
#endregion
#region IPropertyAccess
public virtual string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower())
{
case "pictureid": // Int
return PictureId.ToString(strFormat, formatProvider);
case "moduleid": // Int
return ModuleId.ToString(strFormat, formatProvider);
case "imageidentifier": // UniqueIdentifier
return ImageIdentifier.ToString(strFormat, formatProvider);
case "originalwidth": // Int
return OriginalWidth.ToString(strFormat, formatProvider);
case "originalheight": // Int
return OriginalHeight.ToString(strFormat, formatProvider);
case "originalname": // NVarChar
if (OriginalName == null)
{
return "";
};
return PropertyAccess.FormatString(OriginalName, strFormat);
case "title": // NVarChar
if (Title == null)
{
return "";
};
return PropertyAccess.FormatString(Title, strFormat);
case "description": // NVarCharMax
if (Description == null)
{
return "";
};
return PropertyAccess.FormatString(Description, strFormat);
case "pictureyear": // Int
return PictureYear.ToString(strFormat, formatProvider);
case "picturemonth": // Int
return PictureMonth.ToString(strFormat, formatProvider);
case "pictureday": // Int
return PictureDay.ToString(strFormat, formatProvider);
case "visibility": // Int
return Visibility.ToString(strFormat, formatProvider);
default:
propertyNotFound = true;
break;
}
return Null.NullString;
}
[IgnoreColumn()]
public CacheLevel Cacheability
{
get { return CacheLevel.fullyCacheable; }
}
#endregion
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
namespace Bring2mind.InMemoriam.Core.Models.Pictures
{
[TableName("vw_B2M_InMemoriam_Pictures")]
[PrimaryKey("PictureId", AutoIncrement = true)]
[DataContract]
[Scope("ModuleId")]
public partial class Picture : PictureBase
{
#region .ctor
public Picture() : base()
{
}
#endregion
#region Properties
[DataMember]
public string CreatedByUser { get; set; }
[DataMember]
public string LastModifiedByUser { get; set; }
#endregion
#region Methods
public PictureBase GetPictureBase()
{
PictureBase res = new PictureBase();
res.PictureId = PictureId;
res.ModuleId = ModuleId;
res.ImageIdentifier = ImageIdentifier;
res.OriginalWidth = OriginalWidth;
res.OriginalHeight = OriginalHeight;
res.OriginalName = OriginalName;
res.Title = Title;
res.Description = Description;
res.PictureYear = PictureYear;
res.PictureMonth = PictureMonth;
res.PictureDay = PictureDay;
res.Visibility = Visibility;
res.CreatedByUserID = CreatedByUserID;
res.CreatedOnDate = CreatedOnDate;
res.LastModifiedByUserID = LastModifiedByUserID;
res.LastModifiedOnDate = LastModifiedOnDate;
return res;
}
public Picture Clone()
{
Picture res = new Picture();
res.PictureId = PictureId;
res.ModuleId = ModuleId;
res.ImageIdentifier = ImageIdentifier;
res.OriginalWidth = OriginalWidth;
res.OriginalHeight = OriginalHeight;
res.OriginalName = OriginalName;
res.Title = Title;
res.Description = Description;
res.PictureYear = PictureYear;
res.PictureMonth = PictureMonth;
res.PictureDay = PictureDay;
res.Visibility = Visibility;
res.CreatedByUser = CreatedByUser;
res.LastModifiedByUser = LastModifiedByUser;
res.CreatedByUserID = CreatedByUserID;
res.CreatedOnDate = CreatedOnDate;
res.LastModifiedByUserID = LastModifiedByUserID;
res.LastModifiedOnDate = LastModifiedOnDate;
return res;
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Data;
using System.Xml.Serialization;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Tokens;
namespace Bring2mind.InMemoriam.Core.Models.Pictures
{
[Serializable(), XmlRoot("Picture")]
public partial class Picture
{
#region IHydratable
public override void Fill(IDataReader dr)
{
base.Fill(dr);
CreatedByUser = Convert.ToString(Null.SetNull(dr["CreatedByUser"], CreatedByUser));
LastModifiedByUser = Convert.ToString(Null.SetNull(dr["LastModifiedByUser"], LastModifiedByUser));
}
#endregion
#region IPropertyAccess
public override string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower()) {
case "createdbyuser": // NVarChar
if (CreatedByUser == null)
{
return "";
};
return PropertyAccess.FormatString(CreatedByUser, strFormat);
case "lastmodifiedbyuser": // NVarChar
if (LastModifiedByUser == null)
{
return "";
};
return PropertyAccess.FormatString(LastModifiedByUser, strFormat);
default:
return base.GetProperty(strPropertyName, strFormat, formatProvider, accessingUser, accessLevel, ref propertyNotFound);
}
}
#endregion
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
using Bring2mind.InMemoriam.Core.Data;
namespace Bring2mind.InMemoriam.Core.Models.Stories
{
[TableName("B2M_InMemoriam_Stories")]
[PrimaryKey("StoryId", AutoIncrement = true)]
[DataContract]
[Scope("ModuleId")]
public partial class StoryBase : AuditableEntity
{
#region .ctor
public StoryBase()
{
StoryId = -1;
}
#endregion
#region Properties
[DataMember]
public int StoryId { get; set; }
[DataMember]
public int ModuleId { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Contents { get; set; }
[DataMember]
public int StoryYear { get; set; }
[DataMember]
public int StoryMonth { get; set; }
[DataMember]
public int StoryDay { get; set; }
[DataMember]
public int Visibility { get; set; }
#endregion
#region Methods
public void ReadStoryBase(StoryBase story)
{
if (story.StoryId > -1)
StoryId = story.StoryId;
if (story.ModuleId > -1)
ModuleId = story.ModuleId;
if (!String.IsNullOrEmpty(story.Title))
Title = story.Title;
if (!String.IsNullOrEmpty(story.Contents))
Contents = story.Contents;
if (story.StoryYear > -1)
StoryYear = story.StoryYear;
if (story.StoryMonth > -1)
StoryMonth = story.StoryMonth;
if (story.StoryDay > -1)
StoryDay = story.StoryDay;
if (story.Visibility > -1)
Visibility = story.Visibility;
}
#endregion
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
using Bring2mind.InMemoriam.Core.Data;
namespace Bring2mind.InMemoriam.Core.Models.Stories
{
public partial class StoryBase : AuditableEntity
{
public void ReadEditedStoryBase(StoryBase story)
{
Title = story.Title.Trim();
Contents = story.Contents.Trim();
StoryYear = story.StoryYear;
StoryMonth = story.StoryMonth;
StoryDay = story.StoryDay;
Visibility = story.Visibility;
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
using System.Data;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel.DataAnnotations;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Tokens;
namespace Bring2mind.InMemoriam.Core.Models.Stories
{
public partial class StoryBase : IHydratable, IPropertyAccess
{
#region IHydratable
public virtual void Fill(IDataReader dr)
{
FillAuditFields(dr);
StoryId = Convert.ToInt32(Null.SetNull(dr["StoryId"], StoryId));
ModuleId = Convert.ToInt32(Null.SetNull(dr["ModuleId"], ModuleId));
Title = Convert.ToString(Null.SetNull(dr["Title"], Title));
Contents = Convert.ToString(Null.SetNull(dr["Contents"], Contents));
StoryYear = Convert.ToInt32(Null.SetNull(dr["StoryYear"], StoryYear));
StoryMonth = Convert.ToInt32(Null.SetNull(dr["StoryMonth"], StoryMonth));
StoryDay = Convert.ToInt32(Null.SetNull(dr["StoryDay"], StoryDay));
Visibility = Convert.ToInt32(Null.SetNull(dr["Visibility"], Visibility));
}
[IgnoreColumn()]
public int KeyID
{
get { return StoryId; }
set { StoryId = value; }
}
#endregion
#region IPropertyAccess
public virtual string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower())
{
case "storyid": // Int
return StoryId.ToString(strFormat, formatProvider);
case "moduleid": // Int
return ModuleId.ToString(strFormat, formatProvider);
case "title": // NVarChar
if (Title == null)
{
return "";
};
return PropertyAccess.FormatString(Title, strFormat);
case "contents": // NVarCharMax
if (Contents == null)
{
return "";
};
return PropertyAccess.FormatString(Contents, strFormat);
case "storyyear": // Int
return StoryYear.ToString(strFormat, formatProvider);
case "storymonth": // Int
return StoryMonth.ToString(strFormat, formatProvider);
case "storyday": // Int
return StoryDay.ToString(strFormat, formatProvider);
case "visibility": // Int
return Visibility.ToString(strFormat, formatProvider);
default:
propertyNotFound = true;
break;
}
return Null.NullString;
}
[IgnoreColumn()]
public CacheLevel Cacheability
{
get { return CacheLevel.fullyCacheable; }
}
#endregion
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Runtime.Serialization;
using DotNetNuke.ComponentModel.DataAnnotations;
namespace Bring2mind.InMemoriam.Core.Models.Stories
{
[TableName("vw_B2M_InMemoriam_Stories")]
[PrimaryKey("StoryId", AutoIncrement = true)]
[DataContract]
[Scope("ModuleId")]
public partial class Story : StoryBase
{
#region .ctor
public Story() : base()
{
}
#endregion
#region Properties
[DataMember]
public string CreatedByUser { get; set; }
[DataMember]
public string LastModifiedByUser { get; set; }
#endregion
#region Methods
public StoryBase GetStoryBase()
{
StoryBase res = new StoryBase();
res.StoryId = StoryId;
res.ModuleId = ModuleId;
res.Title = Title;
res.Contents = Contents;
res.StoryYear = StoryYear;
res.StoryMonth = StoryMonth;
res.StoryDay = StoryDay;
res.Visibility = Visibility;
res.CreatedByUserID = CreatedByUserID;
res.CreatedOnDate = CreatedOnDate;
res.LastModifiedByUserID = LastModifiedByUserID;
res.LastModifiedOnDate = LastModifiedOnDate;
return res;
}
public Story Clone()
{
Story res = new Story();
res.StoryId = StoryId;
res.ModuleId = ModuleId;
res.Title = Title;
res.Contents = Contents;
res.StoryYear = StoryYear;
res.StoryMonth = StoryMonth;
res.StoryDay = StoryDay;
res.Visibility = Visibility;
res.CreatedByUser = CreatedByUser;
res.LastModifiedByUser = LastModifiedByUser;
res.CreatedByUserID = CreatedByUserID;
res.CreatedOnDate = CreatedOnDate;
res.LastModifiedByUserID = LastModifiedByUserID;
res.LastModifiedOnDate = LastModifiedOnDate;
return res;
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Data;
using System.Xml.Serialization;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Tokens;
namespace Bring2mind.InMemoriam.Core.Models.Stories
{
[Serializable(), XmlRoot("Story")]
public partial class Story
{
#region IHydratable
public override void Fill(IDataReader dr)
{
base.Fill(dr);
CreatedByUser = Convert.ToString(Null.SetNull(dr["CreatedByUser"], CreatedByUser));
LastModifiedByUser = Convert.ToString(Null.SetNull(dr["LastModifiedByUser"], LastModifiedByUser));
}
#endregion
#region IPropertyAccess
public override string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, DotNetNuke.Services.Tokens.Scope accessLevel, ref bool propertyNotFound)
{
switch (strPropertyName.ToLower()) {
case "createdbyuser": // NVarChar
if (CreatedByUser == null)
{
return "";
};
return PropertyAccess.FormatString(CreatedByUser, strFormat);
case "lastmodifiedbyuser": // NVarChar
if (LastModifiedByUser == null)
{
return "";
};
return PropertyAccess.FormatString(LastModifiedByUser, strFormat);
default:
return base.GetProperty(strPropertyName, strFormat, formatProvider, accessingUser, accessLevel, ref propertyNotFound);
}
}
#endregion
}
}

View File

@@ -0,0 +1,54 @@
using Bring2mind.InMemoriam.Core.Models.Pictures;
using System;
using System.IO;
using System.Web;
namespace Bring2mind.InMemoriam.Core
{
public class PicturesService
{
public static PictureBase UploadPicture(string portalMapPath, int moduleId, HttpPostedFile file)
{
var newGuid = Guid.NewGuid();
var filePath = Path.Combine(portalMapPath, Common.Globals.uploadPath, moduleId.ToString());
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
var fileName = Path.Combine(filePath, newGuid.ToString() + ".resources");
file.SaveAs(fileName);
var res = new PictureBase
{
ImageIdentifier = newGuid,
OriginalName = file.FileName,
OriginalWidth = 0,
OriginalHeight = 0
};
// detect image size
using (var img = System.Drawing.Image.FromFile(fileName))
{
res.OriginalHeight = img.Height;
res.OriginalWidth = img.Width;
}
return res;
}
public static void DeletePicture(string portalMapPath, int moduleId, Guid fileId)
{
var imagesDir = new DirectoryInfo(Path.Combine(portalMapPath, Common.Globals.uploadPath, moduleId.ToString()));
var files = imagesDir.GetFiles($"{fileId}*.jpg");
foreach (var file in files)
{
file.Delete();
}
var originalFile = Path.Combine(portalMapPath, Common.Globals.uploadPath, fileId.ToString() + ".resources");
if (File.Exists(originalFile))
{
File.Delete(originalFile);
}
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using Bring2mind.InMemoriam.Core.Models.Messages;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class MessageRepository : ServiceLocator<IMessageRepository, MessageRepository>, IMessageRepository
{
}
public partial interface IMessageRepository
{
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using Bring2mind.InMemoriam.Core.Models.Messages;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class MessageRepository : ServiceLocator<IMessageRepository, MessageRepository>, IMessageRepository
{
protected override Func<IMessageRepository> GetFactory()
{
return () => new MessageRepository();
}
public IEnumerable<Message> GetMessages(int moduleId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
return rep.Get(moduleId);
}
}
public Message GetMessage(int moduleId, int messageId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
return rep.GetById(messageId, moduleId);
}
}
public Message AddMessage(Message message)
{
Requires.NotNull(message);
Requires.PropertyNotNegative(message, "ModuleId");
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
rep.Insert(message);
}
return message;
}
public void DeleteMessage(Message message)
{
Requires.NotNull(message);
Requires.PropertyNotNegative(message, "MessageId");
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
rep.Delete(message);
}
}
public void DeleteMessage(int moduleId, int messageId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
rep.Delete("WHERE ModuleId = @0 AND MessageId = @1", moduleId, messageId);
}
}
public void UpdateMessage(Message message)
{
Requires.NotNull(message);
Requires.PropertyNotNegative(message, "MessageId");
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Message>();
rep.Update(message);
}
}
}
public partial interface IMessageRepository
{
IEnumerable<Message> GetMessages(int moduleId);
Message GetMessage(int moduleId, int messageId);
Message AddMessage(Message message);
void DeleteMessage(Message message);
void DeleteMessage(int moduleId, int messageId);
void UpdateMessage(Message message);
}
}

View File

@@ -0,0 +1,26 @@
using Bring2mind.InMemoriam.Core.Models.Pictures;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using System.Collections.Generic;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class PictureRepository : ServiceLocator<IPictureRepository, PictureRepository>, IPictureRepository
{
public IEnumerable<Picture> GetPictures(int moduleId, int userId, string sortBy, string sortOrder)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Picture>();
var sql = userId == -1 ? "WHERE ModuleId=@0 AND Visibility=0" : "WHERE ModuleId=@0 AND (CreatedByUserID=@1 OR Visibility<2)";
sql += " ORDER BY " + sortBy + " " + sortOrder;
return rep.Find(sql, moduleId, userId);
}
}
}
public partial interface IPictureRepository
{
IEnumerable<Picture> GetPictures(int moduleId, int userId, string sortBy, string sortOrder);
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using Bring2mind.InMemoriam.Core.Models.Pictures;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class PictureRepository : ServiceLocator<IPictureRepository, PictureRepository>, IPictureRepository
{
protected override Func<IPictureRepository> GetFactory()
{
return () => new PictureRepository();
}
public IEnumerable<Picture> GetPictures(int moduleId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Picture>();
return rep.Get(moduleId);
}
}
public Picture GetPicture(int moduleId, int pictureId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Picture>();
return rep.GetById(pictureId, moduleId);
}
}
public PictureBase AddPicture(PictureBase picture, int userId)
{
Requires.NotNull(picture);
Requires.PropertyNotNegative(picture, "ModuleId");
picture.CreatedByUserID = userId;
picture.CreatedOnDate = DateTime.Now;
picture.LastModifiedByUserID = userId;
picture.LastModifiedOnDate = DateTime.Now;
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<PictureBase>();
rep.Insert(picture);
}
return picture;
}
public void DeletePicture(PictureBase picture)
{
Requires.NotNull(picture);
Requires.PropertyNotNegative(picture, "PictureId");
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<PictureBase>();
rep.Delete(picture);
}
}
public void DeletePicture(int moduleId, int pictureId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<PictureBase>();
rep.Delete("WHERE ModuleId = @0 AND PictureId = @1", moduleId, pictureId);
}
}
public void UpdatePicture(PictureBase picture, int userId)
{
Requires.NotNull(picture);
Requires.PropertyNotNegative(picture, "PictureId");
picture.LastModifiedByUserID = userId;
picture.LastModifiedOnDate = DateTime.Now;
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<PictureBase>();
rep.Update(picture);
}
}
}
public partial interface IPictureRepository
{
IEnumerable<Picture> GetPictures(int moduleId);
Picture GetPicture(int moduleId, int pictureId);
PictureBase AddPicture(PictureBase picture, int userId);
void DeletePicture(PictureBase picture);
void DeletePicture(int moduleId, int pictureId);
void UpdatePicture(PictureBase picture, int userId);
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using Bring2mind.InMemoriam.Core.Models.Stories;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class StoryRepository : ServiceLocator<IStoryRepository, StoryRepository>, IStoryRepository
{
}
public partial interface IStoryRepository
{
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Data;
using DotNetNuke.Framework;
using Bring2mind.InMemoriam.Core.Models.Stories;
namespace Bring2mind.InMemoriam.Core.Repositories
{
public partial class StoryRepository : ServiceLocator<IStoryRepository, StoryRepository>, IStoryRepository
{
protected override Func<IStoryRepository> GetFactory()
{
return () => new StoryRepository();
}
public IEnumerable<Story> GetStories(int moduleId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Story>();
return rep.Get(moduleId);
}
}
public Story GetStory(int moduleId, int storyId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<Story>();
return rep.GetById(storyId, moduleId);
}
}
public StoryBase AddStory(StoryBase story, int userId)
{
Requires.NotNull(story);
Requires.PropertyNotNegative(story, "ModuleId");
story.CreatedByUserID = userId;
story.CreatedOnDate = DateTime.Now;
story.LastModifiedByUserID = userId;
story.LastModifiedOnDate = DateTime.Now;
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<StoryBase>();
rep.Insert(story);
}
return story;
}
public void DeleteStory(StoryBase story)
{
Requires.NotNull(story);
Requires.PropertyNotNegative(story, "StoryId");
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<StoryBase>();
rep.Delete(story);
}
}
public void DeleteStory(int moduleId, int storyId)
{
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<StoryBase>();
rep.Delete("WHERE ModuleId = @0 AND StoryId = @1", moduleId, storyId);
}
}
public void UpdateStory(StoryBase story, int userId)
{
Requires.NotNull(story);
Requires.PropertyNotNegative(story, "StoryId");
story.LastModifiedByUserID = userId;
story.LastModifiedOnDate = DateTime.Now;
using (var context = DataContext.Instance())
{
var rep = context.GetRepository<StoryBase>();
rep.Update(story);
}
}
}
public partial interface IStoryRepository
{
IEnumerable<Story> GetStories(int moduleId);
Story GetStory(int moduleId, int storyId);
StoryBase AddStory(StoryBase story, int userId);
void DeleteStory(StoryBase story);
void DeleteStory(int moduleId, int storyId);
void UpdateStory(StoryBase story, int userId);
}
}

View File

@@ -0,0 +1,48 @@
using Bring2mind.InMemoriam.Common;
using Bring2mind.InMemoriam.Core.Models.Messages;
using Bring2mind.InMemoriam.Core.Repositories;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Bring2mind.InMemoriam.Api
{
public class MessagesController : InMemoriamApiController
{
[HttpGet]
[InMemoriamAuthorize(SecurityAccessLevel.View)]
public HttpResponseMessage GetMessages()
{
return Request.CreateResponse(HttpStatusCode.OK, MessageRepository.Instance.GetMessages(ActiveModule.ModuleID).OrderByDescending(m => m.CreatedOn));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddMessage)]
public HttpResponseMessage AddMessage(int id, [FromBody] string data)
{
var message = Newtonsoft.Json.JsonConvert.DeserializeObject<Message>(data);
if (message == null || string.IsNullOrEmpty(message.Contents.Trim()))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid message data");
}
message.CreatedOn = System.DateTime.Now;
message.ModuleId = ActiveModule.ModuleID;
message = MessageRepository.Instance.AddMessage(message);
return Request.CreateResponse(HttpStatusCode.OK, MessageRepository.Instance.GetMessage(this.ActiveModule.ModuleID, message.MessageId));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.Family)]
public HttpResponseMessage DeleteMessage(int id)
{
var message = MessageRepository.Instance.GetMessage(ActiveModule.ModuleID, id);
if (message == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound, "Message not found");
}
MessageRepository.Instance.DeleteMessage(message);
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}

View File

@@ -0,0 +1,109 @@
using Bring2mind.InMemoriam.Common;
using Bring2mind.InMemoriam.Core;
using Bring2mind.InMemoriam.Core.Common;
using Bring2mind.InMemoriam.Core.Models.Pictures;
using Bring2mind.InMemoriam.Core.Repositories;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;
namespace Bring2mind.InMemoriam.Api
{
public class PicturesController : InMemoriamApiController
{
[HttpGet]
[InMemoriamAuthorize(SecurityAccessLevel.View)]
public HttpResponseMessage Get(string id, int width, int height, string method)
{
var i = new Image(
Path.Combine(PortalSettings.HomeDirectoryMapPath, Globals.uploadPath, ActiveModule.ModuleID.ToString()),
id, width, height, method);
if (!i.ImageExists)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
var res = new HttpResponseMessage(HttpStatusCode.OK);
var mem = new MemoryStream();
i.CopyToStream(mem);
mem.Seek(0, SeekOrigin.Begin);
res.Content = new StreamContent(mem);
res.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
return res;
}
[HttpGet]
[InMemoriamAuthorize(SecurityAccessLevel.View)]
public HttpResponseMessage GetPictures()
{
return Request.CreateResponse(HttpStatusCode.OK, PictureRepository.Instance.GetPictures(ActiveModule.ModuleID, UserInfo.UserID, "CreatedOnDate", "DESC"));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddContent)]
public HttpResponseMessage UploadPicture()
{
var context = HttpContext.Current;
var file = context.Request.Files[0];
var title = context.Request.Form["title"];
var description = context.Request.Form["description"];
var visiblity = int.Parse(context.Request.Form["visibility"]);
var pictureYear = int.Parse(context.Request.Form["pictureYear"]);
var pictureMonth = int.Parse(context.Request.Form["pictureMonth"]);
var pictureDay = int.Parse(context.Request.Form["pictureDay"]);
var pic = PicturesService.UploadPicture(PortalSettings.HomeDirectoryMapPath, ActiveModule.ModuleID, file);
pic.ModuleId = ActiveModule.ModuleID;
pic.Title = title;
pic.Description = description;
pic.Visibility = visiblity;
pic.PictureYear = pictureYear;
pic.PictureMonth = pictureMonth;
pic.PictureDay = pictureDay;
var id = PictureRepository.Instance.AddPicture(pic, UserInfo.UserID).PictureId;
return Request.CreateResponse(HttpStatusCode.OK, PictureRepository.Instance.GetPicture(ActiveModule.ModuleID, id));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddContent)]
public HttpResponseMessage EditPicture(int id, [FromBody] string serializedData)
{
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<PictureBase>(serializedData);
var original = PictureRepository.Instance.GetPicture(ActiveModule.ModuleID, data.PictureId);
if (original == null)
{
return ServiceError("Picture not found.");
}
if (!this.InMemoriamModuleContext.Security.IsFamily && original.CreatedByUserID != UserInfo.UserID)
{
return AccessViolation("You do not have permission to edit this picture.");
}
original.ReadEditedPictureBase(data);
PictureRepository.Instance.UpdatePicture(original.GetPictureBase(), UserInfo.UserID);
return Request.CreateResponse(HttpStatusCode.OK, PictureRepository.Instance.GetPicture(PortalSettings.PortalId, data.PictureId));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddContent)]
public HttpResponseMessage DeletePicture(int id)
{
var original = PictureRepository.Instance.GetPicture(ActiveModule.ModuleID, id);
if (original == null)
{
return ServiceError("Picture not found.");
}
if (!this.InMemoriamModuleContext.Security.IsFamily && original.CreatedByUserID != UserInfo.UserID)
{
return AccessViolation("You do not have permission to edit this picture.");
}
PictureRepository.Instance.DeletePicture(ActiveModule.ModuleID, id);
PicturesService.DeletePicture(PortalSettings.HomeDirectoryMapPath, ActiveModule.ModuleID, original.ImageIdentifier);
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}

View File

@@ -0,0 +1,70 @@
using Bring2mind.InMemoriam.Common;
using Bring2mind.InMemoriam.Core.Models.Stories;
using Bring2mind.InMemoriam.Core.Repositories;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Bring2mind.InMemoriam.Api
{
public class StoriesController : InMemoriamApiController
{
[HttpGet]
[InMemoriamAuthorize(SecurityAccessLevel.View)]
public HttpResponseMessage GetStories()
{
return Request.CreateResponse(HttpStatusCode.OK, StoryRepository.Instance.GetStories(ActiveModule.ModuleID).OrderByDescending(s => s.CreatedOnDate));
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddContent)]
public HttpResponseMessage EditStory(int id, [FromBody] string data)
{
var story = Newtonsoft.Json.JsonConvert.DeserializeObject<StoryBase>(data);
if (story == null || string.IsNullOrEmpty(story.Title.Trim()) || string.IsNullOrEmpty(story.Contents.Trim()))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid story data");
}
if (id == -1)
{
story.ModuleId = ActiveModule.ModuleID;
story = StoryRepository.Instance.AddStory(story, UserInfo.UserID);
return Request.CreateResponse(HttpStatusCode.OK, StoryRepository.Instance.GetStory(ActiveModule.ModuleID, story.StoryId));
}
else
{
var originalStory = StoryRepository.Instance.GetStory(ActiveModule.ModuleID, id);
if (originalStory == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound, "Story not found");
}
if (!this.InMemoriamModuleContext.Security.IsFamily && originalStory.CreatedByUserID != UserInfo.UserID)
{
return AccessViolation("You are not allowed to edit this story");
}
originalStory.ReadEditedStoryBase(story);
StoryRepository.Instance.UpdateStory(originalStory, UserInfo.UserID);
return Request.CreateResponse(HttpStatusCode.OK, StoryRepository.Instance.GetStory(ActiveModule.ModuleID, id));
}
}
[HttpPost]
[InMemoriamAuthorize(SecurityAccessLevel.AddContent)]
public HttpResponseMessage DeleteStory(int id)
{
var story = StoryRepository.Instance.GetStory(ActiveModule.ModuleID, id);
if (story == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound, "Story not found");
}
if (!this.InMemoriamModuleContext.Security.IsFamily && story.CreatedByUserID != UserInfo.UserID)
{
return AccessViolation("You are not allowed to delete this story");
}
StoryRepository.Instance.DeleteStory(ActiveModule.ModuleID, story.StoryId);
return Request.CreateResponse(HttpStatusCode.OK, "Story deleted");
}
}
}

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Add" xml:space="preserve">
<value>Add</value>
</data>
<data name="AddImage" xml:space="preserve">
<value>Add Picture</value>
</data>
<data name="By" xml:space="preserve">
<value>by</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Contents" xml:space="preserve">
<value>Contents</value>
</data>
<data name="Created" xml:space="preserve">
<value>Created</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="Day" xml:space="preserve">
<value>Day</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="DeleteConfirm" xml:space="preserve">
<value>Do you wish to delete this?</value>
</data>
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="EditStory" xml:space="preserve">
<value>Edit Story</value>
</data>
<data name="Friends" xml:space="preserve">
<value>Friends</value>
</data>
<data name="Month" xml:space="preserve">
<value>Month</value>
</data>
<data name="Private" xml:space="preserve">
<value>Private (to you and family)</value>
</data>
<data name="Public" xml:space="preserve">
<value>Public</value>
</data>
<data name="Save" xml:space="preserve">
<value>Save</value>
</data>
<data name="SelectJpg" xml:space="preserve">
<value>Select jpg file</value>
</data>
<data name="SenderEmail" xml:space="preserve">
<value>Sender Email (not publically visible)</value>
</data>
<data name="SenderName" xml:space="preserve">
<value>Sender Name</value>
</data>
<data name="Title" xml:space="preserve">
<value>Title</value>
</data>
<data name="Visibility" xml:space="preserve">
<value>Visibility</value>
</data>
<data name="Year" xml:space="preserve">
<value>Year</value>
</data>
</root>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="InPictures.Text" xml:space="preserve">
<value>In Pictures</value>
</data>
<data name="InWords.Text" xml:space="preserve">
<value>In Words</value>
</data>
<data name="Messages.Text" xml:space="preserve">
<value>Condolences</value>
</data>
</root>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BasicSettings.Text" xml:space="preserve">
<value>Basic Settings</value>
</data>
<data name="View.Help" xml:space="preserve">
<value>Select view to load for this module</value>
</data>
<data name="View.Text" xml:space="preserve">
<value>View</value>
</data>
</root>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Add" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Toevoegen</value>
</data>
<data name="AddImage" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Afbeelding toevoegen</value>
</data>
<data name="By" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>door</value>
</data>
<data name="Cancel" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Annuleren</value>
</data>
<data name="Contents" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Inhoud</value>
</data>
<data name="Created" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Gemaakt</value>
</data>
<data name="Date" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Datum</value>
</data>
<data name="Day" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Dag</value>
</data>
<data name="Delete" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Verwijderen</value>
</data>
<data name="DeleteConfirm" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Wilt u dit verwijderen?</value>
</data>
<data name="Description" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Beschrijving</value>
</data>
<data name="Edit" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Bewerking</value>
</data>
<data name="EditStory" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Verhaal bewerken</value>
</data>
<data name="Friends" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Vrienden</value>
</data>
<data name="Month" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Maand</value>
</data>
<data name="Private" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Privé (voor jou en je familie)</value>
</data>
<data name="Public" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Openbaar</value>
</data>
<data name="Save" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Redden</value>
</data>
<data name="SelectJpg" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Selecteer jpg-bestand</value>
</data>
<data name="SenderEmail" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>E-mail van de afzender (niet openbaar zichtbaar)</value>
</data>
<data name="SenderName" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Naam van de afzender</value>
</data>
<data name="Title" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Titel</value>
</data>
<data name="Visibility" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Zichtbaarheid</value>
</data>
<data name="Year" xml:space="preserve" lastModified="2025-02-12 23:39:47">
<value>Jaar</value>
</data>
</root>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Add" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Добавлять</value>
</data>
<data name="AddImage" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Добавить картинку</value>
</data>
<data name="By" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>к</value>
</data>
<data name="Cancel" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Отмена</value>
</data>
<data name="Contents" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Содержание</value>
</data>
<data name="Created" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Созданный</value>
</data>
<data name="Date" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Дата</value>
</data>
<data name="Day" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>День</value>
</data>
<data name="Delete" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Удалить</value>
</data>
<data name="DeleteConfirm" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Вы хотите это удалить?</value>
</data>
<data name="Description" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Описание</value>
</data>
<data name="Edit" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Редактировать</value>
</data>
<data name="EditStory" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Редактировать историю</value>
</data>
<data name="Friends" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Друзья</value>
</data>
<data name="Month" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Месяц</value>
</data>
<data name="Private" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Конфиденциально (для вас и вашей семьи)</value>
</data>
<data name="Public" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Публичный</value>
</data>
<data name="Save" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Сохранять</value>
</data>
<data name="SelectJpg" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Выберите файл jpg</value>
</data>
<data name="SenderEmail" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Адрес электронной почты отправителя (не виден публично)</value>
</data>
<data name="SenderName" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Имя отправителя</value>
</data>
<data name="Title" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Заголовок</value>
</data>
<data name="Visibility" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Видимость</value>
</data>
<data name="Year" xml:space="preserve" lastModified="2025-02-12 23:41:06">
<value>Год</value>
</data>
</root>

Some files were not shown because too many files have changed in this diff Show More