begin migration to logic fully on OMS so we can deprecate sloooow PHP logic

This commit is contained in:
Michael Becker 2024-11-07 07:31:33 -05:00
parent f0c428e3f9
commit c815b1de4f
17 changed files with 950 additions and 221 deletions

@ -1 +1 @@
Subproject commit 3fb99e1159a9ffcd0e031f04ca3ed0b5df18743d
Subproject commit a542b975e5fcd1014f0c8caab0e020c47617ebb3

View File

@ -10,10 +10,11 @@ using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
using Mocha.Core.UI;
public class Program : WebApplication
{
protected override int DefaultPort => 14678;
protected override int DefaultPort => 4436;
public Program()
{
@ -25,6 +26,14 @@ public class Program : WebApplication
private Oms oms;
protected override WebServer CreateWebServer()
{
WebServer server = base.CreateWebServer();
// server.SSLCertificateFile = "/etc/ssl/certs/localhost.crt";
// server.SSLCertificateKeyFile = "/etc/ssl/certs/localhost.key";
return server;
}
protected override void OnStartup(EventArgs e)
{
// this all has to be done before the Web server is started...
@ -32,10 +41,20 @@ public class Program : WebApplication
TenantHandle th = oms.CreateTenant("super");
oms.SelectTenant(th);
LibraryHandle lh = oms.LoadLibrary("/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output/net.alcetech.Mocha.System.mcl");
string path = "/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output";
if (!System.IO.Directory.Exists(path))
{
path = "/usr/share/mocha/system";
if (!System.IO.Directory.Exists(path))
{
Console.Error.WriteLine("path not found: " + path);
}
}
LibraryHandle lh = oms.LoadLibrary(path + "/net.alcetech.Mocha.System.mcl");
oms.AddLibraryReference(lh);
LibraryHandle lh2 = oms.LoadLibrary("/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output/net.alcetech.Mocha.Web.mcl");
LibraryHandle lh2 = oms.LoadLibrary(path + "/net.alcetech.Mocha.Web.mcl");
oms.AddLibraryReference(lh2);
// now we can start the Web server
@ -46,6 +65,9 @@ public class Program : WebApplication
{
base.OnProcessRequest(e);
e.Context.Response.ResponseCode = 404;
e.Context.Response.ResponseText = "Not Found";
StreamWriter sw = new StreamWriter(e.Context.Response.Stream);
if (e.Context.Request.Path == "/robots.txt")
{
@ -53,22 +75,81 @@ public class Program : WebApplication
}
else if (e.Context.Request.PathParts.Length > 1)
{
if (e.Context.Request.PathParts[1] == "instances")
if (e.Context.Request.PathParts.Length == 2 && e.Context.Request.PathParts[1] == "ping")
{
if (e.Context.Request.PathParts.Length > 2)
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
obj.Add("result", JsonValue.Create("success"));
sw.Write(obj.ToJsonString());
sw.Flush();
sw.Close();
return;
}
if (e.Context.Request.PathParts[1] == "tenants")
{
if (e.Context.Request.PathParts[2] == "create")
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
JsonArray ary = new JsonArray();
IEnumerable<string> tenants = oms.GetTenants();
foreach (string tenant in tenants)
{
ary.Add(JsonValue.Create(tenant));
}
if (e.Context.Request.PathParts.Length == 2)
{
JsonObject obj = new JsonObject();
obj.Add("result", JsonValue.Create("success"));
obj.Add("tenants", ary);
sw.Write(obj.ToJsonString());
}
else if (e.Context.Request.PathParts.Length > 3)
{
// /tenants/{tenantName}/instances
string tenantName = e.Context.Request.PathParts[2];
TenantHandle th = oms.GetTenantByName(tenantName);
if (th == TenantHandle.Empty)
{
e.Context.Response.ResponseCode = 404;
e.Context.Response.ResponseText = "Not Found";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
obj.Add("result", JsonValue.Create("failure"));
obj.Add("message", JsonValue.Create("tenant does not exist"));
sw.Write(obj.ToJsonString());
sw.Flush();
return;
}
else
{
oms.SelectTenant(th);
}
if (e.Context.Request.PathParts[3] == "instances")
{
if (e.Context.Request.PathParts.Length > 4)
{
if (e.Context.Request.PathParts[4] == "create")
{
// usage:
// POST /instances/create
// POST /tenants/{tenantName}/instances/create
//
// parentClassIid=1$1&title=My+New+Class
if (e.Context.Request.Form.ContainsKey("parentClassIid"))
{
string pclass = e.Context.Request.Form["parentClassIid"];
InstanceKey key = InstanceKey.Parse(pclass);
if (oms.TryGetInstance(key, out InstanceHandle ihParentClass))
if (TryParseInstanceRef(pclass, out InstanceHandle ihParentClass))
{
InstanceHandle ihRet = oms.CreateInstanceOf(ihParentClass);
@ -83,7 +164,7 @@ public class Program : WebApplication
JsonObject obj = new JsonObject();
obj.Add("result", JsonValue.Create("success"));
obj.Add("iid", JsonValue.Create(oms.GetInstanceKey(ihRet).ToString()));
obj.Add("value", InstanceToJson(ihRet));
sw.Write(obj.ToJsonString());
}
else
@ -99,8 +180,231 @@ public class Program : WebApplication
}
}
}
else if (e.Context.Request.PathParts[2] == "search")
else if (e.Context.Request.PathParts.Length >= 5)
{
// /tenants/{tenantName}/instances/{instanceKey}/...
TryParseInstanceRef(e.Context.Request.PathParts[4], out InstanceHandle h);
if (h == InstanceHandle.Empty)
{
e.Context.Response.ResponseCode = 404;
e.Context.Response.ResponseText = "Not Found";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
obj.Add("result", "failure");
obj.Add("message", String.Format("invalid inst id {0} (inst not found)", e.Context.Request.PathParts[4]));
sw.Write(obj.ToJsonString());
sw.Flush();
sw.Close();
return;
}
if (e.Context.Request.PathParts.Length >= 6)
{
string command = e.Context.Request.PathParts[5];
if (command == "attributes")
{
if (e.Context.Request.PathParts.Length > 7)
{
// /tenants/{tenantName}/instances/{iid}/attrbutes/{attkey}/current
TryParseInstanceRef(e.Context.Request.PathParts[6], out InstanceHandle att);
string value;
if (e.Context.Request.Method == "POST" && e.Context.Request.PathParts[7].Equals("update"))
{
value = e.Context.Request.Form["value"];
oms.SetAttributeValue(h, att, value);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "text/plain";
sw.Write(value);
sw.Flush();
sw.Close();
return;
}
DateTime dt = DateTime.Now;
if (e.Context.Request.PathParts[7].Equals("current"))
{
}
value = oms.GetAttributeValue<string>(h, att, String.Empty, dt);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "text/plain";
sw.Write(value);
sw.Flush();
sw.Close();
return;
}
JsonObject obj = new JsonObject();
InstanceHandle hAtt = InstanceHandle.Empty;
if (e.Context.Request.PathParts.Length == 7)
{
TryParseInstanceRef(e.Context.Request.PathParts[6], out hAtt);
}
JsonArray objAttributes = GetAttributesAsJson(h, hAtt);
obj.Add("attributes", objAttributes);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
else if (command == "relationships")
{
if (e.Context.Request.PathParts.Length >= 7)
{
TryParseInstanceRef(e.Context.Request.PathParts[6], out InstanceHandle rel);
DateTime dt = DateTime.Now;
if (e.Context.Request.PathParts.Length > 7)
{
if (e.Context.Request.Method == "POST" && e.Context.Request.PathParts[7].Equals("update"))
{
if (Int32.TryParse(e.Context.Request.Form["count"], out int count))
{
JsonObject obj1 = new JsonObject();
obj1.Add("result", "success");
JsonArray ary1 = new JsonArray();
List<InstanceHandle> list = new List<InstanceHandle>();
for (int i = 0; i < count; i++)
{
string key = String.Format("item{0}", i);
if (e.Context.Request.Form.ContainsKey(key))
{
Console.Error.WriteLine("debug: trying to add inst " + e.Context.Request.Form[key]);
if (TryParseInstanceRef(e.Context.Request.Form[key], out InstanceHandle inst))
{
ary1.Add(InstanceToJson(inst));
list.Add(inst);
}
}
}
Console.Error.WriteLine("ok assigning relationship");
oms.AssignRelationship(h, rel, list.ToArray());
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
obj1.Add("targetInstances", ary1);
sw.Write(obj1.ToJsonString());
sw.Flush();
sw.Close();
}
return;
}
if (e.Context.Request.PathParts[7].Equals("current"))
{
}
}
IEnumerable<InstanceHandle> rel_insts = oms.GetRelatedInstances(h, rel, dt);
JsonObject obj = new JsonObject();
JsonArray a = new JsonArray();
foreach (InstanceHandle ih in rel_insts)
{
a.Add(InstanceToJson(ih));
}
obj.Add("result", JsonValue.Create("success"));
obj.Add("sourceInstance", InstanceToJson(h));
obj.Add("relationshipInstance", InstanceToJson(rel));
obj.Add("value", a);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
sw.Flush();
sw.Close();
return;
}
else
{
JsonObject obj = new JsonObject();
obj.Add("relationships", GetRelationshipsAsJson(h));
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
}
else if (command == "element")
{
Renderer renderer = new Renderer(oms);
if (oms.IsInstanceOf(h, oms.GetInstance(KnownInstanceGuids.Classes.Element)))
{
Widget widget = renderer.Parse(h);
JsonObject obj3 = widget.ToJSONObject();
JsonObject obj2 = new JsonObject();
obj2.Add("widget", JsonValue.Create("root"));
obj2.Add("body", widget.ToJSONObject());
JsonObject obj = new JsonObject();
obj.Add("result", "success");
obj.Add("value", obj2);
RespondWithJson(sw, e.Context, 200, "OK", obj);
}
}
else
{
JsonObject obj = new JsonObject();
obj.Add("result", "failure");
obj.Add("message", String.Format("unknown cmd '{0}'", command));
RespondWithJson(sw, e.Context, 404, "Not Found", obj);
}
}
else
{
JsonObject obj = new JsonObject();
obj.Add("instanceKey", JsonValue.Create(oms.GetInstanceKey(h).ToString()));
obj.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(h).ToString("b")));
obj.Add("text", JsonValue.Create(oms.GetInstanceText(h)));
obj.Add("attributes", GetAttributesAsJson(h));
obj.Add("relationshps", GetRelationshipsAsJson(h));
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
}
}
else
{
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
Stopwatch watch = new Stopwatch();
watch.Start();
string query = "";
if (e.Context.Request.Query.ContainsKey("q") && e.Context.Request.Query["q"].Count > 0)
{
@ -112,10 +416,7 @@ public class Program : WebApplication
if (e.Context.Request.Query.ContainsKey("parentClassIid") && e.Context.Request.Query["parentClassIid"].Count > 0)
{
parentClassIid = e.Context.Request.Query["parentClassIid"][0];
if (InstanceKey.TryParse(parentClassIid, out InstanceKey ikParentClass))
{
ihParentClass = oms.GetInstance(ikParentClass);
}
TryParseInstanceRef(parentClassIid, out ihParentClass);
}
IEnumerable<InstanceHandle> ihs = null;
@ -146,157 +447,18 @@ public class Program : WebApplication
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
JsonArray objInstances = InstancesToJson(ihs);
obj.Add("instances", objInstances);
sw.Write(obj.ToJsonString());
}
else if (e.Context.Request.PathParts.Length > 2)
{
InstanceKey k = InstanceKey.Parse(e.Context.Request.PathParts[2]);
InstanceHandle h = InstanceHandle.Empty;
if (!oms.TryGetInstance(k, out h))
{
e.Context.Response.ResponseCode = 404;
e.Context.Response.ResponseText = "Not Found";
sw.Flush();
sw.Close();
return;
}
if (e.Context.Request.PathParts.Length > 3)
{
if (e.Context.Request.PathParts[3] == "attributes")
{
if (e.Context.Request.PathParts.Length > 5)
{
string iid = e.Context.Request.PathParts[4];
InstanceHandle att = oms.GetInstance(InstanceKey.Parse(iid));
DateTime dt = DateTime.Now;
if (e.Context.Request.PathParts[5].Equals("current"))
{
}
string value = oms.GetAttributeValue<string>(h, att, String.Empty, dt);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "text/plain";
sw.Write(value);
sw.Flush();
sw.Close();
return;
}
JsonObject obj = new JsonObject();
InstanceHandle hAtt = InstanceHandle.Empty;
if (e.Context.Request.PathParts.Length > 4)
{
hAtt = oms.GetInstance(InstanceKey.Parse(e.Context.Request.PathParts[4]));
}
JsonArray objAttributes = GetAttributesAsJson(h, hAtt);
obj.Add("attributes", objAttributes);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
else if (e.Context.Request.PathParts[3] == "relationships")
{
if (e.Context.Request.PathParts.Length > 5)
{
string iid = e.Context.Request.PathParts[4];
InstanceHandle rel = oms.GetInstance(InstanceKey.Parse(iid));
DateTime dt = DateTime.Now;
if (e.Context.Request.PathParts[5].Equals("current"))
{
}
IEnumerable<InstanceHandle> rel_insts = oms.GetRelatedInstances(h, rel, dt);
JsonObject obj = new JsonObject();
JsonArray a = new JsonArray();
foreach (InstanceHandle ih in rel_insts)
{
a.Add(oms.GetInstanceKey(ih));
}
obj.Add("relationships", a);
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
sw.Flush();
sw.Close();
return;
}
else
{
JsonObject obj = new JsonObject();
obj.Add("relationships", GetRelationshipsAsJson(h));
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
}
}
else
{
JsonObject obj = new JsonObject();
obj.Add("instanceKey", JsonValue.Create(oms.GetInstanceKey(h).ToString()));
obj.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(h).ToString("b")));
obj.Add("attributes", GetAttributesAsJson(h));
obj.Add("relationshps", GetRelationshipsAsJson(h));
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
}
}
else
{
e.Context.Response.ResponseCode = 200;
e.Context.Response.ResponseText = "OK";
e.Context.Response.ContentType = "application/json";
JsonObject obj = new JsonObject();
Stopwatch watch = new Stopwatch();
watch.Start();
IEnumerable<InstanceHandle> ihs = oms.GetInstances();
watch.Stop();
obj.Add("time", JsonValue.Create(watch.ElapsedMilliseconds.ToString()));
JsonArray objInstances = InstancesToJson(ihs);
obj.Add("instances", objInstances);
sw.Write(obj.ToJsonString());
}
}
}
}
}
else
{
e.Context.Response.ResponseCode = 404;
@ -310,6 +472,102 @@ public class Program : WebApplication
sw.Close();
}
/*
private JsonObject? ElementContentToJSON(InstanceHandle content)
{
JsonObject? objC = null;
InstanceHandle contentWidget = oms.GetRelatedInstance(content, oms.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance));
// Mocha.Core.UI.Widget widget = renderer.BuildFromInstance()
if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.Element)))
{
objC = ElementToJSON(contentWidget, content);
}
else if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.TextAttribute)))
{
objC = TextAttributeToJSON(contentWidget, content);
}
else if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.File)))
{
objC = FileToJSON(contentWidget, content);
}
return objC;
}
private JsonObject? FileToJSON(InstanceHandle contentWidget, InstanceHandle parentElementContent)
{
JsonObject obj3 = new JsonObject();
InsertCommonProperties(obj3, contentWidget, parentElementContent);
string value = oms.GetAttributeValue<string>(contentWidget, oms.GetInstance(KnownAttributeGuids.Text.Value));
if (value != null)
{
obj3.Add("value", JsonValue.Create(value));
}
return obj3;
}
private JsonObject? TextAttributeToJSON(InstanceHandle contentWidget, InstanceHandle parentElementContent)
{
JsonObject obj3 = new JsonObject();
InsertCommonProperties(obj3, contentWidget, parentElementContent);
string value = oms.GetAttributeValue<string>(contentWidget, oms.GetInstance(KnownAttributeGuids.Text.Value));
if (value != null)
{
obj3.Add("value", JsonValue.Create(value));
}
return obj3;
}
*/
private void RespondWithJson(StreamWriter sw, WebContext context, int responseCode, string responseText, JsonObject obj)
{
context.Response.ResponseCode = responseCode;
context.Response.ResponseText = responseText;
context.Response.ContentType = "application/json";
sw.Write(obj.ToJsonString());
}
private bool TryParseInstanceRef(string instanceKeyOrGuid, out InstanceHandle h)
{
h = InstanceHandle.Empty;
if (InstanceKey.TryParse(instanceKeyOrGuid, out InstanceKey k))
{
oms.TryGetInstance(k, out h);
return true;
}
else if (Guid.TryParse(instanceKeyOrGuid, out Guid g))
{
oms.TryGetInstance(g, out h);
return true;
}
else
{
Console.Error.WriteLine("could not parse: {0}", instanceKeyOrGuid);
}
return false;
}
private JsonNode? InstanceToJson(InstanceHandle ih)
{
InstanceHandle parentClass = oms.GetParentClass(ih);
JsonObject objInstance = new JsonObject();
objInstance.Add("iid", JsonValue.Create(oms.GetInstanceKey(ih).ToString()));
objInstance.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(ih).ToString()));
objInstance.Add("text", JsonValue.Create(oms.GetInstanceText(ih)));
JsonObject objParentClass = new JsonObject();
objParentClass.Add("iid", JsonValue.Create(oms.GetInstanceKey(parentClass).ToString()));
objParentClass.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(parentClass).ToString()));
objParentClass.Add("text", JsonValue.Create(oms.GetInstanceText(parentClass)));
objInstance.Add("parentClass", objParentClass);
return objInstance;
}
private JsonArray GetRelationshipsAsJson(InstanceHandle h, InstanceHandle hRel = default(InstanceHandle))
{
JsonArray a = new JsonArray();
@ -386,18 +644,7 @@ public class Program : WebApplication
JsonArray array = new JsonArray();
foreach (InstanceHandle ih in ihs)
{
InstanceHandle parentClass = oms.GetParentClass(ih);
JsonObject objInstance = new JsonObject();
objInstance.Add("iid", JsonValue.Create(oms.GetInstanceKey(ih).ToString()));
objInstance.Add("text", JsonValue.Create(oms.GetInstanceText(ih)));
JsonObject objParentClass = new JsonObject();
objParentClass.Add("iid", JsonValue.Create(oms.GetInstanceKey(parentClass).ToString()));
objParentClass.Add("text", JsonValue.Create(oms.GetInstanceText(parentClass)));
objInstance.Add("parentClass", objParentClass);
array.Add(objInstance);
array.Add(InstanceToJson(ih));
}
return array;
}

View File

@ -69,6 +69,14 @@ public abstract class MochaWebApplication : WebApplication
return oms;
}
protected override WebServer CreateWebServer()
{
WebServer server = base.CreateWebServer();
server.SSLCertificateFile = "/etc/ssl/certs/localhost.crt";
server.SSLCertificateKeyFile = "/etc/ssl/certs/localhost.key";
return server;
}
protected override void OnProcessRequest(WebServerProcessRequestEventArgs e)
{
base.OnProcessRequest(e);

View File

@ -199,3 +199,11 @@ body > div.uwt-page-content
{
padding: 16px;
}
a.uwt-external-link::after
{
content: "\f08e";
font-family: "Font Awesome 6 Pro";
padding-left: 8px;
font-weight: 300;
}

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System;
using System;
namespace Mocha.Core
{
public static class KnownAttributeGuids
@ -43,6 +43,8 @@ namespace Mocha.Core
public static Guid Token { get; } = new Guid("{da7686b6-3803-4f15-97f6-7f8f3ae16668}");
public static Guid DebugDefinitionFileName { get; } = new Guid("{03bf47c7-dc97-43c8-a8c9-c6147bee4e1f}");
public static Guid Label { get; } = new Guid("{69cdf8af-fcf2-4477-b75d-71593e7dbb22}");
public static Guid LabelOverride { get; } = new Guid("{89b361e0-9f13-4fea-9b1e-6eca573bd6ba}");
}
public static class Boolean
{

View File

@ -126,6 +126,9 @@ namespace Mocha.Core
public static Guid User { get; } = new Guid("{9C6871C1-9A7F-4A3A-900E-69D1D9E24486}");
public static Guid UserLogin { get; } = new Guid("{64F4BCDB-38D0-4373-BA30-8AE99AF1A5F7}");
public static Guid GroupLayout { get; } = new Guid("{108605af-c20d-42eb-af4f-35b2ff701921}");
public static Guid ImageLayout { get; } = new Guid("{4b1bb7c6-168e-4ce0-b4f8-76dd5069a80b}");
public static Guid Menu { get; } = new Guid("{c952ef83-af18-4512-9dd9-0f00a19d399c}");
public static Guid MenuItem { get; } = new Guid("{f606f612-2d12-4600-bee1-a071d1019ffe}");
public static Guid MenuItemCommand { get; } = new Guid("{9D3EDE23-6DB9-4664-9145-ABCBD3A0A2C2}");
@ -444,5 +447,16 @@ namespace Mocha.Core
public static Guid Japanese { get; } = new Guid ("{1e16de9d-0e49-4a79-b690-4905c46a94cc}");
public static Guid Korean { get; } = new Guid ("{d03a795e-906b-49ee-87ea-c1bef4b8ee9a}");
}
public static class GroupLayoutOptions
{
public static Guid Tabbed { get; } = new Guid("{f600c4f6-964b-4a27-b5b0-24fd4c8d0878}");
public static Guid FieldSet { get; } = new Guid("{7dd84757-e1c1-4bbb-9ef6-5b88fb9a76fc}");
}
public static class Alignments
{
public static Guid Near { get; } = new Guid("{35ea407a-45e1-462f-a923-a526d12fbc47}");
public static Guid Far { get; } = new Guid("{f19d16c7-99ff-48a3-b86a-7db8f400d869}");
public static Guid Center { get; } = new Guid("{63179b92-9a6a-495b-a823-f45e353be9d8}");
}
}
}

View File

@ -231,6 +231,12 @@ namespace Mocha.Core
public static Guid Style__has__Style_Rule { get; } = new Guid("{4CC8A654-B2DF-4B17-A956-24939530790E}");
public static Guid Style_Rule__has__Style_Property { get; } = new Guid("{B69C2708-E78D-413A-B491-ABB6F1D2A6E0}");
public static Guid Style__has_width__Measurement { get; } = new Guid("{4930ca87-641a-426d-9d67-cda6d5f22303}");
public static Guid Style__has_height__Measurement { get; } = new Guid("{978e6de0-af73-45a0-bb56-aaf451615b06}");
public static Guid Style__has_horizontal__Alignment { get; } = new Guid("{cc8d60e3-1b42-4ab1-a918-3d109891bb4e}");
public static Guid Style__has_vertical__Alignment { get; } = new Guid("{24c175dd-c34c-4ffc-aef0-440aa032ceeb}");
public static Guid Page__has_master__Page { get; } = new Guid("{9bdbfd64-0915-419f-83fd-e8cf8bcc74ae}");
public static Guid Page__master_for__Page { get; } = new Guid("{7fe8f2a2-c94d-4010-83aa-9300cc99d71d}");
@ -311,6 +317,12 @@ namespace Mocha.Core
public static Guid Element_Content__has__Instance { get; } = new Guid("{315b71ba-953d-45fc-87e5-4f0a268242a9}");
public static Guid Instance__for__Element_Content { get; } = new Guid("{c3959f84-248d-4ede-a3f2-f262917c7b56}");
public static Guid Element_Content__has__Layout { get; } = new Guid("{1ab74120-05ea-4aca-b6d3-c7e0133e0c4f}");
public static Guid Layout__has__Style { get; } = new Guid("{e684bb26-7e78-4a21-b8b4-5a550f3053d5}");
public static Guid Group_Layout__uses__Group_Layout_Option { get; } = new Guid("{5bea01b6-c33e-4f37-a940-579712ab47c7}");
public static Guid Element_Content__has__Element_Content_Display_Option { get; } = new Guid("{f070dfa7-6260-4488-a779-fae291903f2d}");
public static Guid Element_Content_Display_Option__for__Element_Content { get; } = new Guid("{12fe7923-b3d2-4152-96c7-a901410b3466}");

View File

@ -17,7 +17,6 @@
namespace Mocha.Core;
using System.Collections.Frozen;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.SqlTypes;
@ -452,6 +451,16 @@ public abstract class Oms
return true;
}
}
else if (val is string && typeof(T) == typeof(decimal))
{
// HACK HACK HACK - fix the underlying assignment so it assigns boolean true instead of string "True"
// !!! !!! !!! it's probably in the yaml2mcl compiler somewhere
if (Decimal.TryParse((string)val, out decimal actual))
{
value = (T)((object)actual);
return true;
}
}
}
value = default(T);
@ -601,11 +610,15 @@ public abstract class Oms
public string GetAttachmentUrl(InstanceHandle fileInstance)
{
string entropy = "";
string accessKey = BuildAccessKeyForOmsAttachment(fileInstance, entropy);
return BasePath + TenantName + "/attachment/" + GetInstanceKey(fileInstance).ToString() + "/" + accessKey;
string accessKey = BuildAccessKeyForOmsAttachment(fileInstance);
return String.Format("{0}{1}/attachment/{2}/{3}", BasePath, TenantName, GetInstanceKey(fileInstance), accessKey);
}
public string BuildAccessKeyForOmsAttachment(InstanceHandle fileInstance)
{
string entropy = "";
return BuildAccessKeyForOmsAttachment(fileInstance, entropy);
}
private string BuildAccessKeyForOmsAttachment(InstanceHandle fileInstance, string entropy)
{
/*
@ -1403,4 +1416,9 @@ public abstract class Oms
{
return GetRelationshipsInternal(h);
}
public IEnumerable<string> GetTenants()
{
return _tenantsByName.Keys;
}
}

View File

@ -177,7 +177,13 @@ public class MemoryOms : Oms
if (oms._libraries.ContainsKey(lh))
{
IReadOnlyCollection<InstanceHandle> insts2 = oms._libraries[lh].GetRelatedInstances(source, relationship, effectiveDate);
list2.AddRange(insts2);
foreach (InstanceHandle i in insts2)
{
if (!list2.Contains(i))
{
list2.Add(i);
}
}
}
}
@ -190,7 +196,13 @@ public class MemoryOms : Oms
{
if (val.EffectiveDate <= effectiveDate)
{
list2.AddRange(val.TargetInstances);
foreach (InstanceHandle i in val.TargetInstances)
{
if (!list2.Contains(i))
{
list2.Add(i);
}
}
}
}
}
@ -277,10 +289,17 @@ public class MemoryOms : Oms
public void AddLibraryReference(LibraryHandle library)
{
if (!_libraryReferences.Contains(library))
{
if (oms._libraries.ContainsKey(library))
{
// please don't reference the same library multiple times
_libraryReferences.Add(library);
}
else
{
Console.Error.WriteLine("oms: error: trying to add reference to library which hasn't been loaded yet");
}
}
}
public void RemoveLibraryReference(LibraryHandle library)
{

View File

@ -0,0 +1,70 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public class Renderer
{
public Oms OMS { get; private set; }
public Renderer(Oms oms)
{
OMS = oms;
}
public Widget Parse(InstanceHandle h)
{
return Parse(h, InstanceHandle.Empty);
}
public Widget Parse(InstanceHandle h, InstanceHandle parentElementContent)
{
Widget[] availableWidgets = MBS.Core.Reflection.TypeLoader.GetAvailableTypes<Widget>();
InstanceHandle parentClassInstance = OMS.GetParentClass(h);
Guid gid = OMS.GetGlobalIdentifier(parentClassInstance);
Widget? useWidget = null;
foreach (Widget w in availableWidgets)
{
if (w.SupportedClassGuids.Contains(gid))
{
useWidget = w;
break;
}
}
if (useWidget == null)
{
Console.Error.WriteLine("not found widget for GID " + gid.ToString());
return null;
}
useWidget.OMS = OMS;
useWidget.ParentInstance = h;
useWidget.ParentElementContent = parentElementContent;
useWidget.Renderer = this;
return useWidget;
}
public Widget ParseElementContent(InstanceHandle content)
{
InstanceHandle h = OMS.GetRelatedInstance(content, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance));
return Parse(h, content);
}
}

View File

@ -0,0 +1,85 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public abstract class Widget
{
protected abstract void RenderJSONInternal(JsonObject obj);
protected abstract string GetWidgetName();
public InstanceHandle ParentInstance { get; internal set; } = InstanceHandle.Empty;
public InstanceHandle ParentElementContent { get; internal set; } = InstanceHandle.Empty;
public JsonObject ToJSONObject()
{
JsonObject obj = new JsonObject();
InsertCommonProperties(obj);
RenderJSONInternal(obj);
return obj;
}
public virtual Guid[] SupportedClassGuids { get; } = new Guid[0];
public Oms OMS { get; internal set; }
public Renderer Renderer { get; internal set; }
public IEnumerable<InstanceHandle> GetDisplayOptions()
{
IEnumerable<InstanceHandle> displayOptions = OMS.GetRelatedInstances(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Element_Content_Display_Option));
return displayOptions;
}
private void InsertCommonProperties(JsonObject obj)
{
obj.Add("widget", GetWidgetName());
obj.Add("iid", JsonValue.Create(OMS.GetInstanceKey(ParentInstance).ToString()));
if (ParentElementContent != InstanceHandle.Empty)
{
IEnumerable<InstanceHandle> displayOptions = GetDisplayOptions();
obj.Add("ecid", JsonValue.Create(OMS.GetInstanceKey(ParentElementContent).ToString()));
if (!displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.DoNotShowLabel)))
{
string label = OMS.GetAttributeValue<string>(ParentElementContent, OMS.GetInstance(KnownAttributeGuids.Text.LabelOverride));
if (label == null)
{
label = OMS.GetAttributeValue<string>(ParentElementContent, OMS.GetInstance(KnownAttributeGuids.Text.Label));
if (label == null)
{
label = OMS.GetInstanceText(ParentInstance);
}
}
obj.Add("label", label);
}
if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.NotEnterable)))
{
obj.Add("enabled", false);
}
if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.DoNotShow)))
{
obj.Add("visible", false);
}
if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.Required)))
{
obj.Add("required", true);
}
}
}
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public class Element : Widget
{
protected override string GetWidgetName()
{
InstanceHandle layout = OMS.GetRelatedInstance(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Layout));
if (OMS.IsInstanceOf(layout, OMS.GetInstance(KnownInstanceGuids.Classes.GroupLayout)))
{
InstanceHandle ihGLOFieldSet = OMS.GetInstance(KnownInstanceGuids.GroupLayoutOptions.FieldSet);
IEnumerable<InstanceHandle> groupLayoutOptions = OMS.GetRelatedInstances(layout, OMS.GetInstance(KnownRelationshipGuids.Group_Layout__uses__Group_Layout_Option));
if (groupLayoutOptions.Contains(ihGLOFieldSet))
{
return "fieldSet";
}
}
return "vbox";
}
public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.Element };
protected override void RenderJSONInternal(JsonObject obj)
{
JsonArray objA = new JsonArray();
IEnumerable<InstanceHandle> contents = OMS.GetRelatedInstances(ParentInstance, OMS.GetInstance(KnownRelationshipGuids.Element__has__Element_Content));
foreach (InstanceHandle content in contents)
{
Widget widget = Renderer.ParseElementContent(content);
if (widget == null)
{
JsonObject objC = new JsonObject();
objC.Add("widget", JsonValue.Create("error"));
objC.Add("text", JsonValue.Create("could not create EC"));
objC.Add("ecid", JsonValue.Create(OMS.GetInstanceKey(content).ToString()));
objC.Add("iid", JsonValue.Create(OMS.GetInstanceKey(OMS.GetRelatedInstance(content, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance))).ToString()));
objA.Add(objC);
}
else
{
objA.Add(widget.ToJSONObject());
}
}
obj.Add("children", objA);
}
}

View File

@ -0,0 +1,95 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public class File : Widget
{
protected override string GetWidgetName() => "image";
public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.File };
protected override void RenderJSONInternal(JsonObject obj)
{
obj.Add("target", OMS.BuildAccessKeyForOmsAttachment(ParentInstance));
if (ParentElementContent != null)
{
InstanceHandle layoutInstance = OMS.GetRelatedInstance(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Layout));
if (layoutInstance != InstanceHandle.Empty)
{
InstanceHandle styleInstance = OMS.GetRelatedInstance(layoutInstance, OMS.GetInstance(KnownRelationshipGuids.Layout__has__Style));
if (styleInstance != InstanceHandle.Empty)
{
InstanceHandle attValue = OMS.GetInstance(KnownAttributeGuids.Text.Value);
// ! FIXME: output the proper Measurement string representations for HTML/CSS
InstanceHandle widthMeasurement = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_width__Measurement));
if (widthMeasurement != InstanceHandle.Empty)
{
obj.Add("width", OMS.GetAttributeValue<string>(widthMeasurement, attValue) + "px");
}
InstanceHandle heightMeasurement = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_height__Measurement));
if (heightMeasurement != InstanceHandle.Empty)
{
obj.Add("height", OMS.GetAttributeValue<string>(heightMeasurement, attValue) + "px");
}
InstanceHandle horizontalAlignment = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_horizontal__Alignment));
if (horizontalAlignment != InstanceHandle.Empty)
{
if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Center)
{
obj.Add("horizontalAlignment", "center");
}
if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Far)
{
obj.Add("horizontalAlignment", "far");
}
if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Near)
{
obj.Add("horizontalAlignment", "near");
}
}
InstanceHandle verticalAlignment = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_vertical__Alignment));
if (verticalAlignment != InstanceHandle.Empty)
{
if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Center)
{
obj.Add("verticalAlignment", "center");
}
if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Far)
{
obj.Add("verticalAlignment", "far");
}
if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Near)
{
obj.Add("verticalAlignment", "near");
}
}
}
if (OMS.IsInstanceOf(layoutInstance, OMS.GetInstance(KnownInstanceGuids.Classes.ImageLayout)))
{
}
}
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public class MonikerList : Widget
{
protected override string GetWidgetName() => "monikerList";
public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.WorkSet };
protected override void RenderJSONInternal(JsonObject obj)
{
}
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Text.Json.Nodes;
namespace Mocha.Core.UI;
public class Text : Widget
{
protected override string GetWidgetName()
{
if (ParentElementContent != InstanceHandle.Empty)
{
IEnumerable<InstanceHandle> displayOptions = GetDisplayOptions();
if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.ObscuredText)))
{
return "obscuredText";
}
}
return "text";
}
public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.TextAttribute };
protected override void RenderJSONInternal(JsonObject obj)
{
string value = OMS.GetAttributeValue<string>(ParentInstance, OMS.GetInstance(KnownAttributeGuids.Text.Value));
if (value != null)
{
obj.Add("value", value);
}
if (OMS.TryGetAttributeValue<decimal>(ParentInstance, OMS.GetInstance(KnownAttributeGuids.Numeric.MaximumLength), out decimal maximumLength))
{
obj.Add("maximumLength", maximumLength);
}
}
}

View File

@ -103,12 +103,14 @@ public class GetRelationshipTests : MethodTestsBase
InstanceHandle valueIH = Oms.Execute(context, rsmb);
object? value_o = context.GetWorkData(valueIH);
IEnumerable<InstanceHandle> values = (IEnumerable<InstanceHandle>)value_o;
if (value_o is IEnumerable<InstanceHandle> values)
{
for (int i = 0; i < TEST_VALUES.Length; i++)
{
Assert.That(values.ElementAt(i), Is.EqualTo(TEST_VALUES[i]));
}
}
}
[Test]
public void GetParentClassMatchesActualParentClass()

@ -1 +1 @@
Subproject commit 05c3fd5274e76511bd2ccf8b33d347c2de1930e3
Subproject commit 0054320a0ea9592fe691205f21441a8c9e01319a