preliminary clearUNTESTEDclearUSE CAUTIONclear support for multiple tenants IT'S ABOUT TIME

This commit is contained in:
Michael Becker 2024-02-10 01:00:03 -05:00
parent a4c14c7ee7
commit bed7bfaa45
42 changed files with 628 additions and 244 deletions

View File

@ -66,7 +66,7 @@ elif [ "$1" == "tenant" ]; then
OLDTENANT=$(mocha oms tenant)
mocha oms tenant select $3
mocha oms install library /usr/share/mocha/libraries/net.alcetech.Mocha.System/
mocha oms install library /usr/share/mocha/libraries/
mocha oms tenant select $OLDTENANT

View File

@ -1,4 +1,4 @@
- include: '../../net.alcetech.Mocha.System/000-EntityDefinitions/*.yaml'
# - include: '../../net.alcetech.Mocha.System/000-EntityDefinitions/*.yaml'
- entityDefinitions:
- IDL_MochaPowered_VehiclesForHire: '{bb1d56b4-c063-4232-a789-93c8419e2d31}'
- IDI_Module_MochaPowered_VehiclesForHire: '{bb1d56b4-c063-4232-a789-93c8419e2d31}'

View File

@ -1,3 +0,0 @@
- tenant: '&IDT_RydeRentalsProduction;'
tenantType: '&IDI_TenantType_Production;'

View File

@ -0,0 +1,5 @@
- tenant: '&IDT_RydeRentalsProduction;'
globalIdentifier: '{966c02fd-65e8-4345-bc24-f76ee97c38b6}'
name: 'ryderentals'
tenantType: '&IDI_TenantType_Production;'

View File

@ -1,4 +1,4 @@
- library: '&IDL_MochaBaseSystem;'
- tenant: '&IDT_RydeRentalsProduction;'
instances:
- file: '{1079b0d3-0a1d-47d3-a98c-3f062dc88f90}'
@ -19,3 +19,6 @@
familyName: 'Trevino'
images:
- instance: '{1079b0d3-0a1d-47d3-a98c-3f062dc88f90}'
# {b8136d2a-8238-443b-8d9e-4f47c8a47c4b}

View File

@ -1,6 +0,0 @@
- library: '&IDI_Library_VehiclesForHire;'
- user: '{b8136d2a-8238-443b-8d9e-4f47c8a47c4b}'
username: btrevino
personId: '{9530a1ea-2423-43ee-a23d-bb82728b79c9}'

View File

@ -0,0 +1,30 @@
---
- entityDefinitions:
- IDC_RichTextAttribute: '{9e393eb5-0b2d-4c31-bc8c-419f9af8aee6}'
- IDA_RichTextValue: '{0afb33a8-67b8-4bf3-be61-899f7e82d85f}'
- library: '&IDL_MochaBaseSystem;'
instances:
- class: '&IDC_RichTextAttribute;'
name: Rich Text Attribute
index: 2737
customTagName: 'richTextAttribute'
superclasses:
- instance: '&IDC_Attribute;'
- instance: '&IDC_ExecutableReturningAttribute;'
attributes:
- instance: '&IDA_Name;'
customTagName: 'name'
- instance: '&IDA_Value;'
customTagName: 'value'
- instance: '&IDA_MaximumLength;'
customTagName: 'maximumLength'
defaultTask: '&IDI_Task_RichTextAttribute_View;'
relatedTasks:
- instance: '&IDI_Task_RichTextAttribute_View;'
- instance: '&IDI_Task_RichTextAttribute_Edit;'
- richTextAttribute: '&IDA_RichTextValue;'
name: Rich Text Value
index: 1

View File

@ -0,0 +1,64 @@
- entityDefinitions:
- IDI_Task_RichTextAttribute_View: '{f14e644e-c23f-4e51-8705-218f8a7f8da6}'
- IDI_Task_RichTextAttribute_Edit: '{ac1a4a78-ed7c-4ffb-9da5-0038f7e7083b}'
- IDE_RichTextAttribute_View: '{1c349bae-073f-4d2d-be02-62c7f2ac19cc}'
- IDE_RichTextAttribute_Edit: '{e5372c59-37e6-473d-8972-8197c3fadb01}'
- IDE_RichTextAttribute_Subedits: '{7e6cc769-fa92-457a-98fb-f1b01ee1b6f9}'
- IDI_TaskCategory_RichTextAttribute: '{697285cd-5c7c-416e-adae-f686f87b1a3c}'
- library: '&IDL_MochaBaseSystem;'
instances:
- taskCategory: '&IDI_TaskCategory_RichTextAttribute;'
name: 'Rich Text Attribute'
- sequenceTask: '&IDI_Task_RichTextAttribute_View;'
name: 'View Rich Text Attribute'
initiatingElement: '&IDE_RichTextAttribute_View;'
taskCategory: '&IDI_TaskCategory_RichTextAttribute;'
- sequenceTask: '&IDI_Task_RichTextAttribute_Edit;'
name: 'Edit Rich Text Attribute'
initiatingElement: '&IDE_RichTextAttribute_Edit;'
taskCategory: '&IDI_TaskCategory_RichTextAttribute;'
- element: '&IDE_RichTextAttribute_View;'
name: 'view rich text attribute'
elementContents:
- globalIdentifier: '{dfc3530a-86f0-4cad-b0eb-cb873124bc5b}'
defaultDataType: '&IDE_RichTextAttribute_Subedits;'
displayOptions:
- instance: '&IDI_DisplayOption_NotEnterable;'
- instance: '&IDI_DisplayOption_ShowSubelementsVertically;'
- instance: '&IDI_DisplayOption_Singular;'
- element: '&IDE_RichTextAttribute_Edit;'
name: 'edit rich text attribute'
elementContents:
- globalIdentifier: '{5af9cf61-29b7-4e6f-8ae3-08f35f482872}'
defaultDataType: '&IDE_RichTextAttribute_Subedits;'
displayOptions:
- instance: '&IDI_DisplayOption_ShowSubelementsVertically;'
- instance: '&IDI_DisplayOption_Singular;'
- element: '&IDE_RichTextAttribute_Subedits;'
name: 'rich text attribute subedits'
elementContents:
- globalIdentifier: '{7ee9e026-73c7-48dc-8899-49a9381bd5a2}'
defaultDataType: '&IDC_RichTextAttribute;'
displayOptions:
- instance: '&IDI_DisplayOption_NotEnterable;'
- instance: '&IDI_DisplayOption_DoNotShow;'
- globalIdentifier: '{34f9d452-a06a-4793-b09e-95dc6c80a05f}'
defaultDataType: '&IDA_Name;'
- globalIdentifier: '{a33e9e97-606d-47b7-ac4d-46971e534e01}'
defaultDataType: '&IDA_RichTextValue;'
label: 'Default Value'
- globalIdentifier: '{e71c2829-570d-45e5-99f9-0fb97a9dea57}'
defaultDataType: '&IDA_MaximumLength;'
# - globalIdentifier: '{f6fbaab7-f947-49ee-95c3-d7b652e346f4}'
# defaultDataType: '&IDR_Work_Data__in__Namespace;'
# label: Namespace

View File

@ -4,10 +4,10 @@
- library: '&IDL_MochaBaseSystem;'
instances:
- element: '&IDE_Task_SystemUser_Common_Subedit;'
# elementContents:
# - globalIdentifier: '{dcc2aef3-2041-4787-a46b-4becc054b797}'
# label: 'Disabled'
# defaultDataType: '&IDA_Disabled;'
elementContents:
- globalIdentifier: '{dcc2aef3-2041-4787-a46b-4becc054b797}'
label: 'User Name'
defaultDataType: '&IDA_UserName;'
# - globalIdentifier: '{d38ae189-9b74-4922-9245-e6f1621913eb}'
# label: 'Locked'
# defaultDataType: '&IDA_Locked;'

View File

@ -15,6 +15,7 @@ class KnownClassGuids
const BooleanAttribute = "EA830448A4034ED9A3D3048D5D5C3A03";
const NumericAttribute = "9DE86AF1EFD64B719DCC202F247C94CB";
const DateAttribute = "0B7B1812DFB44F25BF6DCEB0E1DF8744";
const RichTextAttribute = "{9e393eb5-0b2d-4c31-bc8c-419f9af8aee6}";
const Element = "919295953dbd4eae8add6120a49797c7";
const ElementContent = "f85d4f5ec69f449899137a8554e233a4";

View File

@ -32,9 +32,10 @@
public function getInstances() : array
{
$query = "SELECT * FROM mocha_instances WHERE tenant_id = :tenant_id";
$query = "SELECT * FROM mocha_instances WHERE (" . $this->buildTenantIDQuery() . ")";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array("tenant_id" => $this->getTenant()->ID));
$result = $stmt->execute();
$values = $stmt->fetchAll();
$insts = array();
foreach ($values as $value)
@ -85,6 +86,22 @@
}
return null;
}
public function getTenantByID(int $id) : ?TenantReference
{
$query = "SELECT * FROM mocha_tenants WHERE id = :tenant_id;";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"tenant_id" => $id
));
$values = $stmt->fetch();
if ($values !== false)
{
$tenant = new TenantReference($values["id"], $values["tenant_name"], $values["global_identifier"]);
return $tenant;
}
return null;
}
public function __construct($hostname, $port, $databasename, $username, $password)
@ -255,36 +272,64 @@
plus the SP actually works, and the straight query INTRODUCES bugs... wtf?
*/
public function getReferencedTenants(TenantReference $tenantReference) : array
{
$retval = [];
$query = "SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = :source_tenant_id";
$stmt = $this->PDO->prepare($query);
$result = $stmt->execute(array
(
"source_tenant_id" => $tenantReference->ID
));
if ($result === false)
{
$this->logDatabaseError($query);
}
else
{
$values = $stmt->fetchAll();
$count = count($values);
for ($i = 0; $i < $count; $i++)
{
$target_tenant_id = $values[$i][0];
$target_tenant = $this->getTenantByID($target_tenant_id);
if ($target_tenant !== null)
{
$retval[] = $target_tenant;
}
}
}
return $retval;
}
private function logDatabaseError(string $query, ?array $parms = null)
{
trigger_error("unknown database error, query was:", \E_USER_ERROR);
trigger_error($query, \E_USER_NOTICE);
return null;
}
private function buildTenantIDQuery(string $tenantIdParmName = "tenant_id")
{
$tenant_id_qry = $tenantIdParmName . " = " . $this->getTenant()->ID;
$tenant_references = $this->getReferencedTenants($this->getTenant());
foreach ($tenant_references as $tenantref)
{
$tenant_id_qry .= " OR " . $tenantIdParmName . " = " . $tenantref->ID;
}
return $tenant_id_qry;
}
public function initializeInstanceCache()
{
error_log("invalidating instance cache");
$instanceCache = array();
$query = "SELECT * FROM mocha_instances WHERE tenant_id = :tenant_id AND class_id IS NOT NULL";
$stmt = $this->PDO->prepare($query);
$parms = array
(
"tenant_id" => $this->getTenant()->ID
);
$result = $stmt->execute($parms);
if ($result === false)
$insts = $this->getInstances();
foreach ($insts as $ir)
{
trigger_error("unknown database error, query was:", \E_USER_ERROR);
trigger_error($query, \E_USER_NOTICE);
return null;
}
$values = $stmt->fetchAll();
$count = count($values);
for ($i = 0; $i < $count; $i++)
{
$dbid = $values[$i]["id"];
$class_id = $values[$i]["class_id"];
$inst_id = $values[$i]["inst_id"];
$global_id = $values[$i]["global_identifier"];
$ir = new InstanceReference($dbid, new InstanceKey($class_id, $inst_id), $global_id);
$instanceCache[$ir->GlobalIdentifier->__toStringFormat(false, "", "")] =
array
(
@ -366,11 +411,10 @@
// $query = "CALL mocha_get_instance_by_global_identifier(mocha_normalize_uuid(:global_identifier))";
echo ("query using SQL");
$query = "SELECT * FROM mocha_instances WHERE tenant_id = :tenant_id AND global_identifier = :global_identifier AND class_id IS NOT NULL";
$query = "SELECT * FROM mocha_instances WHERE (" . $this->buildTenantIDQuery() . ") AND global_identifier = :global_identifier AND class_id IS NOT NULL";
$stmt = $this->PDO->prepare($query);
$parms = array
(
"tenant_id" => $this->getTenant()->ID,
//"global_identifier" => $globalIdentifier->__toString()
"global_identifier" => $globalIdentifier->__toStringFormat(false, "", "")
);
@ -445,12 +489,11 @@
$query = "SELECT mocha_instances.* FROM mocha_instances INNER JOIN mocha_relationships ON mocha_instances.id = mocha_relationships.destination_inst_id WHERE mocha_relationships.tenant_id = :tenant_id " .
"AND source_inst_id = :src_inst_id AND relationship_inst_id = :rel_inst_id" ; // AND :eff_date IS NULL OR (effective_date >= :eff_date)";
*/
$query = "SELECT destination_inst_id, remove_flag FROM mocha_relationships WHERE mocha_relationships.tenant_id = :tenant_id " .
$query = "SELECT destination_inst_id, remove_flag FROM mocha_relationships WHERE (" . $this->buildTenantIDQuery("mocha_relationships.tenant_id") . ") " .
"AND source_inst_id = :src_inst_id AND relationship_inst_id = :rel_inst_id" ; // AND :eff_date IS NULL OR (effective_date >= :eff_date)";
$stmt = $this->PDO->prepare($query);
$parms = array
(
"tenant_id" => $this->getTenant()->ID,
"src_inst_id" => $this->getDbId($sourceInstance),
"rel_inst_id" => $this->getDbId($relationshipInstance) //,
//"eff_date" => $dt
@ -542,14 +585,17 @@
protected function getAttributeValueInternal(InstanceReference $sourceInstance, InstanceReference $attributeInstance, $defaultValue = null, $effectiveDate = null) : ?string
{
$dt = $this->normalizeSqlDateTime($effectiveDate, true);
$query = "CALL mocha_get_attribute_value(:src_inst_id, :attr_inst_id, :eff_date)";
// $query = "CALL mocha_get_attribute_value(:src_inst_id, :att_inst_id, :eff_date)";
//echo ("GAV: " . $sourceInstance->InstanceKey . " : " . $attributeInstance->InstanceKey );
$query = "SELECT * FROM mocha_attributes WHERE tenant_id = :tenant_id AND src_inst_id = :src_inst_id AND att_inst_id = :att_inst_id AND att_effective_date <= NOW() ORDER BY att_effective_date DESC";
$stmt = $this->PDO->prepare($query);
$vars = array
(
"tenant_id" => $this->getTenant()->ID,
"src_inst_id" => $this->getDbId($sourceInstance),
"attr_inst_id" => $this->getDbId($attributeInstance),
"eff_date" => $dt
"att_inst_id" => $this->getDbId($attributeInstance)//,
//"eff_date" => $dt
);
$result = $stmt->execute($vars);
@ -564,6 +610,36 @@
$value = $values[0]["att_value"];
return $value;
}
// the attribute was not set on the current tenant,
// so retry the query with our parent tenants
$parentTenants = $this->getReferencedTenants($this->getTenant());
foreach ($parentTenants as $parentTenant)
{
$vars["tenant_id"] = $parentTenant->ID;
$result = $stmt->execute($vars);
if ($result === false)
{
return $defaultValue;
}
$values = $stmt->fetchAll();
if (count($values) > 0)
{
// we have a value!
$value = $values[0]["att_value"];
return $value;
}
}
// attribute has not been defined anywhere
/*
echo ("<!-- NOK - query : " . $query);
print_r($vars);
echo (" -->");
*/
return $defaultValue;
}
public function setAttributeValueInternal(InstanceReference $sourceInstance, InstanceReference $attributeInstance, mixed $value, ?\DateTime $effectiveDate = null)
@ -673,7 +749,7 @@
// FIXME: NOT IMPLEMENTED
//usage:
// getInstanceByAttributes (array ( getInstanceByGlobalIdentifier(NAME_ATTRIBUTE) => "zq-developer" ))
$query = "SELECT mocha_instances.* FROM mocha_instances, mocha_attributes WHERE mocha_instances.tenant_id = mocha_get_current_tenant() AND mocha_attributes.tenant_id = mocha_get_current_tenant() AND mocha_instances.id = mocha_attributes.src_inst_id";
$query = "SELECT mocha_instances.* FROM mocha_instances, mocha_attributes WHERE (" . $this->buildTenantIDQuery("mocha_instances.tenant_id") . ") AND mocha_attributes.tenant_id = mocha_instances.tenant_id AND mocha_instances.id = mocha_attributes.src_inst_id";
if (count($parms) > 0)
{
$query .= " AND ";

View File

@ -35,6 +35,7 @@
require("ui/controls/InstanceBrowser.inc.php");
require("ui/renderers/html/Editor.inc.php");
require("ui/renderers/html/HTMLRenderer.inc.php");
require("ui/tasks/Task.inc.php");

View File

@ -0,0 +1,21 @@
<?php
namespace Mocha\UI\Renderers\HTML;
use Mocha\Core\InstanceReference;
class Editor
{
public InstanceReference $ForClass;
public $ViewFunction;
public $EditFunction;
public function __construct(InstanceReference $forClass, callable $viewFunction, callable $editFunction)
{
$this->ForClass = $forClass;
$this->ViewFunction = $viewFunction;
$this->EditFunction = $editFunction;
}
}
?>

View File

@ -19,6 +19,7 @@
use Phast\HTMLControls\Input;
use Phast\HTMLControls\InputType;
use Phast\HTMLControls\RichTextBox;
use Phast\QuickSort;
use Phast\System;
use Phast\Utilities\Stopwatch;
@ -40,6 +41,8 @@
*/
public $DebugMode;
public array $Editors;
public $TargetInstance;
/**
@ -67,6 +70,7 @@
{
$this->DebugMode = false;
$this->Context = $context;
$this->Editors = array();
$this->FailedValidations = [];
$this->FailedValidationElements = [];
$this->IsPostback = false;
@ -75,7 +79,56 @@
$this->IncludeTopNavigationBar = true;
$this->__renderingElement = null;
$this->__processingElement = null;
$this->registerEditors();
}
public function registerEditors()
{
/**
* @var MySQLDatabaseOms
*/
$oms = mocha_get_oms();
$genericViewFunc = function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
echo ($value);
};
$booleanAttributeViewFunc = function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
if ($value == "1")
{
echo ("Yes");
}
else
{
// if display option "Show No When False"
// echo ("No");
}
};
$this->registerEditor($oms->getInstanceByGlobalIdentifier(KnownClassGuids::BooleanAttribute), $booleanAttributeViewFunc, function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
$displayOptions = $oms->getRelatedInstances($elementContent, KnownRelationshipGuids::Element_Content__has__Element_Content_Display_Option);
$this->renderBooleanAttributeEC($parentElementContents, $elementContent, $ecInst, $value);
});
$this->registerEditor($oms->getInstanceByGlobalIdentifier(KnownClassGuids::TextAttribute), $genericViewFunc, function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
$displayOptions = $oms->getRelatedInstances($elementContent, KnownRelationshipGuids::Element_Content__has__Element_Content_Display_Option);
$this->renderTextAttributeEC($parentElementContents, $elementContent, $ecInst, $oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__ObscuredText)), $value);
});
$this->registerEditor($oms->getInstanceByGlobalIdentifier(KnownClassGuids::NumericAttribute), $genericViewFunc, function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
$displayOptions = $oms->getRelatedInstances($elementContent, KnownRelationshipGuids::Element_Content__has__Element_Content_Display_Option);
$this->renderNumericAttributeEC($parentElementContents, $elementContent, $ecInst, $oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__ObscuredText)), $value);
});
$this->registerEditor($oms->getInstanceByGlobalIdentifier(KnownClassGuids::RichTextAttribute), $genericViewFunc, function($oms, $parentElementContents, $elementContent, $ecInst, $value)
{
$displayOptions = $oms->getRelatedInstances($elementContent, KnownRelationshipGuids::Element_Content__has__Element_Content_Display_Option);
$this->renderRichTextAttributeEC($parentElementContents, $elementContent, $ecInst, $value);
});
}
/**
* Thanks https://stackoverflow.com/a/31107425
*
@ -325,6 +378,25 @@
echo ("</div>");
$this->renderEndForm($allElementsAreReadonly);
if (!$allElementsAreReadonly)
{
echo("<script type=\"text/javascript\">");
echo(<<<EOF
window.onbeforeunload = function(event)
{
var message = "Are you sure you want to exit without saving your changes?";
var e = event || window.event;
if (e)
{
e.returnValue = message;
}
return message;
};
EOF
);
echo("</script>");
}
$this->renderEndPage();
}
@ -358,7 +430,19 @@
//!FIXME: refactor out the casting of POST values to actual instances or primitive literals
if ($oms->is_a($ecInst, KnownClassGuids::Clasz))
{
$value = $oms->getInstanceByKey(InstanceKey::Parse($value));
if ($value == "")
{
$value = null;
}
else
{
$ik = InstanceKey::Parse($value);
if ($ik === null)
{
echo ("invalid ik: " . $value);
}
$value = $oms->getInstanceByKey($ik);
}
}
$this->Context->setWorkData($ecInst, $value);
}
@ -1385,6 +1469,27 @@
return $defaultValue;
}
public function registerEditor(InstanceReference $forClass, callable $viewFunction, callable $editFunction)
{
$this->Editors[] = new Editor($forClass, $viewFunction, $editFunction);
}
public function getEditor(InstanceReference $ecInst)
{
/**
* @var MySQLDatabaseOms
*/
$oms = mocha_get_oms();
foreach ($this->Editors as $editor)
{
if ($oms->is_a($ecInst, $editor->ForClass))
{
return $editor;
}
}
return null;
}
public function renderExecutableReturningAttribute(array &$parentElementContents, InstanceReference $elementContent, InstanceReference $ecInst, ?InstanceReference $relatedInstance, $renderNotEnterable = false)
{
/**
@ -1422,38 +1527,19 @@
$value = $_POST[$ecid];
}
$editor = $this->getEditor($ecInst);
if ($oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__NotEnterable)) || $renderNotEnterable)
{
if ($oms->is_a($ecInst, KnownClassGuids::BooleanAttribute))
if ($editor !== null)
{
if ($value == "1")
{
echo ("Yes");
}
else
{
// if display option "Show No When False"
// echo ("No");
}
}
else
{
echo($value);
call_user_func($editor->ViewFunction, $oms, $parentElementContents, $elementContent, $ecInst, $value);
}
}
else
{
if ($oms->is_a($ecInst, KnownClassGuids::TextAttribute))
if ($editor !== null)
{
$this->renderTextAttributeEC($parentElementContents, $elementContent, $ecInst, $oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__ObscuredText)), $value);
}
else if ($oms->is_a($ecInst, KnownClassGuids::BooleanAttribute))
{
$this->renderBooleanAttributeEC($parentElementContents, $elementContent, $ecInst, $oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__ObscuredText)), $value);
}
else if ($oms->is_a($ecInst, KnownClassGuids::NumericAttribute))
{
$this->renderNumericAttributeEC($parentElementContents, $elementContent, $ecInst, $oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__ObscuredText)), $value);
call_user_func($editor->EditFunction, $oms, $parentElementContents, $elementContent, $ecInst, $value);
}
}
}
@ -1505,7 +1591,7 @@
$p->Render();
}
public function renderBooleanAttributeEC(array $parentElementContents, InstanceReference $ec, InstanceReference $inst, $password = false, $value = null)
public function renderBooleanAttributeEC(array $parentElementContents, InstanceReference $ec, InstanceReference $inst, $value = null)
{
/**
* @var MySQLDatabaseOms
@ -1542,10 +1628,6 @@
$p->Attributes[] = new WebControlAttribute("maxlength", $maxLength);
}
$p->HasContent = false;
if ($password)
{
$p->Type = InputType::Password;
}
$p->Render();
}
@ -1580,6 +1662,42 @@
$p->Render();
}
public function renderRichTextAttributeEC(array $parentElementContents, InstanceReference $ec, InstanceReference $inst, $value = null)
{
/**
* @var MySQLDatabaseOms
*/
$oms = mocha_get_oms();
$displayOptions = $oms->getRelatedInstances($ec, $oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::Element_Content__has__Element_Content_Display_Option));
$fullyQualifiedECID = $this->getElementContentId($parentElementContents, $ec);
$ecid = "ec_" . $fullyQualifiedECID;
$p = new RichTextBox();
$p->ClientID = $ecid;
$p->Name = $ecid;
$p->Attributes[] = new WebControlAttribute("data-ecid", $ecid);
$p->Value = $value;
if ($oms->instanceSetContains($displayOptions, $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::DisplayOption__Required)))
{
$p->ClassList[] = "uwt-required";
}
if ($this->IsPostback && array_key_exists($ec->DatabaseId, $this->FailedValidationElements))
{
$p->ClassList[] = "uwt-failed-validation";
}
$maxLength = $oms->getAttributeValue($inst, KnownAttributeGuids::MaximumLength);
if ($maxLength !== null)
{
$p->Attributes[] = new WebControlAttribute("maxlength", $maxLength);
}
$p->Render();
}
public function renderArray(?array $array, string $separator, string $prefix = "", string $suffix = "")
{
if ($array === null)
@ -1656,6 +1774,7 @@
"href" => System::ExpandRelativePath("~/themes/mocha/theme.css", false, true)
));
$this->renderTag("script", array("type" => "text/javascript", "src" => System::ExpandRelativePath("~/scripts/phast/ckeditor/ckeditor.js", false, true)));
$this->renderTag("script", array("type" => "text/javascript", "src" => System::ExpandRelativePath("~/scripts/phast/System.js.php", false, true)));
$this->renderTag("script", array("type" => "text/javascript", "src" => System::ExpandRelativePath("~/scripts/mocha.js.php", false, true)));
$this->renderBeginTag("script", array("type" => "text/javascript"));

View File

@ -107,6 +107,10 @@ function McxElementContent(parentElement)
this.NativeObject.ValueElement.NativeObject.__inhibit_update = true;
this.NativeObject.ValueElement.NativeObject.ToggleChecked();
this.NativeObject.ValueElement.NativeObject.__inhibit_update = false;
if (this.status === 403 || this.status === 401)
{
Alert.show("Please log in to continue", "Not Logged In", "uwt-color-danger", 5000, "NotLoggedIn");
}
}
}
};

View File

@ -3,6 +3,12 @@ div.uwt-alert
padding: .9375rem;
box-shadow: 4px 4px 10px rgba(0,0,0,0.3);
&:not(.uwt-visible)
{
opacity: 0;
visibility: hidden;
}
&> div.uwt-title
{
font-weight: 300;

View File

@ -0,0 +1,10 @@
div.ck-editor
{
&:hover
{
&> div.ck-content
{
border-color: var(--uwt-color-accent);
}
}
}

View File

@ -34,3 +34,9 @@ input[type=text], input[type=password], input[type=number], input[type=search],
padding: 6px 12px;
transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;
}
div.uwt-richtextbox
{
border: 1px solid var(--uwt-color-gray-400);
height: 100px;
background-color: var(--uwt-color-gray-200);
}

View File

@ -25,6 +25,7 @@
@import "uwt-page.less";
@import "uwt-panel.less";
@import "uwt-popup.less";
@import "uwt-richtextbox.less";
@import "uwt-sidebar.less";
@import "uwt-slider.less";
@import "uwt-spinner.less";

View File

@ -135,6 +135,8 @@
$instUser = $oms->execute($context, $mbUser__get__User_for_User_Name_parm, true, array( KnownAttributeGuids::UserName => $userName ));
$instUser = $context->getWorkData($instUser);
echo ("user: " . $instUser->InstanceKey);
if ($instUser !== null)
{
$passwordSalt = $oms->getAttributeValue($instUser, $oms->getInstanceByGlobalIdentifier(KnownAttributeGuids::PasswordSalt));
@ -157,6 +159,11 @@
$oms->setAttributeValue($instLogin, KnownAttributeGuids::IPAddress, $_SERVER["REMOTE_ADDR"]);
$oms->assignRelationship($instLogin, $oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::User_Login__has__User), $instUser);
}
else
{
echo ("could not create login token");
die();
}
$_SESSION["user_token_" . $oms->getTenant()->ID] = $token;
$oms->setCurrentUser($instUser);

View File

@ -2,6 +2,10 @@
namespace Mocha\UI\Pages;
use Mocha\Core\InstanceKey;
use Mocha\Core\InstanceReference;
use Mocha\Core\KnownAttributeGuids;
use Mocha\Core\KnownClassGuids;
use Mocha\Core\KnownInstanceGuids;
use Mocha\Core\KnownRelationshipGuids;
@ -11,6 +15,43 @@
class OTSPage extends WebPage
{
private $EntityDefinitions;
private $EntityDefinitions2;
public function __construct()
{
parent::__construct();
$this->EntityDefinitions = array
(
);
$this->EntityDefinitions2 = array
(
"98cc2a320289406e8df45e154ca601d2" => "IDC_CircuitBreakerPanel",
"89102e1cc3144a5fa752aa84e05ca83f" => "IDI_CircuitBreakerPanel_CarmelBay"
);
}
private function zqGetClassName(InstanceReference $i)
{
$oms = mocha_get_oms();
$key = $i->GlobalIdentifier->__toStringFormat(false, "", "");
if (array_key_exists($key, $this->EntityDefinitions2))
{
return "&" . $this->EntityDefinitions2[$key] . ";";
}
else
{
$name = $oms->getAttributeValue($i, KnownAttributeGuids::Name);
$name = str_replace(" ", "", $name);
return "&IDC_" . $name . ";";
}
return $i->GlobalIdentifier->__toString();
}
protected function OnRendering(RenderingEventArgs $re)
{
parent::OnRendering($re);
@ -46,8 +87,6 @@
{
if (count($path) >= 5)
{
header("HTTP/1.1 200 OK");
// e.g. https://i-0c0398f84acecb702.privatesuv.com/ots/super/services/zq/v1/module/list
// ots/{tenant}/services/{serviceName}/{version}/{command}
@ -61,33 +100,129 @@
$instClass = $oms->getInstanceByGlobalIdentifier(KnownClassGuids::Clasz);
$instances = $oms->getRelatedInstances($instClass, $oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::Class__has__Instance));
if ($command == "module/list")
$cmdparts = explode("/", $command);
if (count($cmdparts) >= 2)
{
header("Content-Type: application/json");
print("{ \"items\": [ ");
print("{ \"name\": \"mocha\", \"title\": \"mocha\", \"type\": \"module\", \"items\": [ ");
$ct = count($instances);
for ($i = 0; $i < $ct; $i++)
if ($cmdparts[0] === "instance")
{
print("{ \"name\": \"mocha:inst" . $i . "\", \"title\": \"" . $oms->getInstanceText($instances[$i]) . "\", \"type\": \"class\", \"instanceId\": \"" . $instances[$i]->InstanceKey . "\" }");
if ($i < $ct - 1)
$ik = InstanceKey::Parse($cmdparts[1]);
if ($ik === null)
{
print(", ");
header("HTTP/1.1 404 Not Found");
header("Content-Type: text/plain");
echo("invalid inst id " . $cmdparts[1]);
die();
}
$ir = $oms->getInstanceByKey($ik);
header("HTTP/1.1 200 OK");
header("Content-Type: text/plain");
echo ("- library: '&IDL_MochaBaseSystem;'\n");
echo (" instances:\n");
if ($ik->ClassIndex == 1)
{
echo (" - class: '" . $this->zqGetClassName($ir) . "'\n");
}
else
{
echo (" - instance: '" . $this->zqGetClassName($ir) . "'\n");
}
//$attrs = $oms->getRelatedInstances($ir, KnownRelationshipGuids::Class__has__Attribute);
$attrs = $oms->getAttributes($ir);
if (count($attrs) > 0)
{
echo (" - attributes:\n");
foreach ($attrs as $attr)
{
echo (" - instance: '" . $attr->GlobalIdentifier . "'\n");
echo (" - value: '" . $oms->getAttributeValue($ir, $attr) . "'\n");
}
}
$rels = $oms->getRelationships($ir);
if (count($rels) > 0)
{
echo (" - relationships:\n");
foreach ($rels as $rel)
{
$gid = $rel->GlobalIdentifier->__toString();
if (array_key_exists($rel->GlobalIdentifier->__toStringFormat(false, "", ""), $this->EntityDefinitions2))
{
$gid = "&" . $this->EntityDefinitions2[$rel->GlobalIdentifier->__toStringFormat(false, "", "")] . ";";
}
echo (" - instance: '" . $rel->GlobalIdentifier . "'\n");
$targs = $oms->getRelatedInstances($ir, $rel);
if (count($targs) > 0)
{
echo (" targetInstances:\n");
}
foreach ($targs as $targ)
{
$iid = $targ->GlobalIdentifier->__toString();
if (array_key_exists($targ->GlobalIdentifier->__toStringFormat(false, "", ""), $this->EntityDefinitions2))
{
$iid = "&" . $this->EntityDefinitions2[$targ->GlobalIdentifier->__toStringFormat(false, "", "")] . ";";
}
echo (" = instance: '" . $iid . "'\n");
}
}
}
$defaultTask = $oms->getRelatedInstance($ir, KnownRelationshipGuids::Class__has_default__Task);
if ($defaultTask !== null)
{
echo (" - defaultTask: '" . $defaultTask->GlobalIdentifier . "'\n");
}
$relTasks = $oms->getRelatedINstances($ir, KnownRelationshipGuids::Class__has_related__Task);
if (count($relTasks) > 0)
{
echo (" - relatedTasks:\n");
foreach ($relTasks as $relTask)
{
echo (" - instance: '" . $relTask->GlobalIdentifier . "'\n");
}
}
$re->Cancel = true;
return;
}
else if ($cmdparts[0] === "module")
{
if ($cmdparts[1] === "list")
{
header("Content-Type: application/json");
print("{ \"items\": [ ");
print("{ \"name\": \"mocha\", \"title\": \"mocha\", \"type\": \"module\", \"items\": [ ");
$ct = count($instances);
for ($i = 0; $i < $ct; $i++)
{
print("{ \"name\": \"mocha:inst" . $i . "\", \"title\": \"" . $oms->getInstanceText($instances[$i]) . "\", \"type\": \"class\", \"instanceId\": \"" . $instances[$i]->InstanceKey . "\" }");
if ($i < $ct - 1)
{
print(", ");
}
}
print("] }");
print("] }");
return;
}
}
}
print("] }");
print("] }");
}
else
{
header("Content-Type: text/plain");
print("tenantName: " . $tenantName . "\n");
print("serviceName: " . $serviceName . "\n");
print("version: " . $version . "\n");
print("command: " . $command . "\n");
}
header("HTTP/1.1 501 Not Implemented");
header("Content-Type: text/plain");
print("tenantName: " . $tenantName . "\n");
print("serviceName: " . $serviceName . "\n");
print("version: " . $version . "\n");
print("command: " . $command . "\n");
die();
}
else

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,6 +7,7 @@ CREATE FUNCTION mocha_get_instance_by_global_identifier
RETURNS INT
DETERMINISTIC
RETURN (
SELECT id FROM mocha_instances WHERE tenant_id = mocha_get_current_tenant()
SELECT id FROM mocha_instances
WHERE (tenant_id = mocha_get_current_tenant() OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = mocha_get_current_tenant()))
AND mocha_normalize_uuid(global_identifier) = mocha_normalize_uuid(p_global_identifier)
ORDER BY id DESC LIMIT 1);

View File

@ -6,4 +6,12 @@ CREATE FUNCTION mocha_get_instance_by_key
p_inst_id INT
)
RETURNS INT
RETURN (SELECT id FROM mocha_instances WHERE tenant_id = mocha_get_current_tenant() AND class_id = p_class_id AND inst_id = p_inst_id LIMIT 1);
RETURN (SELECT id FROM mocha_instances
WHERE (tenant_id = mocha_get_current_tenant()
OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = mocha_get_current_tenant())
)
AND class_id = p_class_id
AND inst_id = p_inst_id
LIMIT 1
);

View File

@ -7,7 +7,7 @@ CREATE FUNCTION mocha_get_user_by_username
RETURNS INT
RETURN (
SELECT src_inst_id FROM mocha_attributes
WHERE tenant_id = mocha_get_current_tenant()
WHERE (tenant_id = mocha_get_current_tenant() OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = mocha_get_current_tenant()))
AND att_inst_id = mocha_get_instance_by_global_identifier('960FAF025C5940F791A720012A99D9ED')
AND att_value = p_user_name
ORDER BY att_effective_date DESC

View File

@ -19,7 +19,9 @@ sp: BEGIN
SET p_tenant_id = mocha_get_current_tenant();
SET p_class_index = (SELECT inst_id FROM mocha_instances WHERE tenant_id = p_tenant_id AND class_id = 1 AND id = p_class_inst_id);
SET p_class_index = (SELECT inst_id FROM mocha_instances
WHERE (tenant_id = p_tenant_id OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = p_tenant_id))
AND class_id = 1 AND id = p_class_inst_id);
IF p_class_index IS NULL THEN
SELECT "cannot create an instance of something that is not a Class" AS error_description;

View File

@ -19,11 +19,11 @@ BEGIN
END IF;
SELECT att_value FROM mocha_attributes
WHERE tenant_id = p_tenant_id
WHERE (tenant_id = p_tenant_id OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = p_tenant_id))
AND src_inst_id = p_source_inst_id
AND att_inst_id = p_attribute_inst_id
AND att_effective_date <= z_effective_date
ORDER BY att_effective_date DESC, id DESC
ORDER BY tenant_id DESC, att_effective_date DESC, id DESC
LIMIT 1;
END;

View File

@ -5,9 +5,13 @@ CREATE PROCEDURE mocha_get_instance_by_global_identifier
IN p_global_identifier CHAR(40)
)
BEGIN
DECLARE p_tenant_id INT;
SET p_tenant_id = mocha_get_current_tenant();
SELECT * FROM mocha_instances
WHERE tenant_id = mocha_get_current_tenant()
WHERE (tenant_id = p_tenant_id OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = p_tenant_id))
AND UPPER(global_identifier) = UPPER(REPLACE(REPLACE(REPLACE(p_global_identifier, '{', ''), '}', ''), '-', ''))
ORDER BY id DESC
LIMIT 1;

View File

@ -11,7 +11,7 @@ BEGIN
SET p_tenant_id = mocha_get_current_tenant();
SELECT * FROM mocha_instances
WHERE tenant_id = p_tenant_id
WHERE (tenant_id = p_tenant_id OR tenant_id IN (SELECT target_tenant_id FROM mocha_tenant_references WHERE source_tenant_id = p_tenant_id))
AND class_id = p_class_id
AND inst_id = p_inst_id;

View File

@ -5,5 +5,6 @@ CREATE TABLE mocha_tenants
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
tenant_name VARCHAR(32),
global_identifier CHAR(32),
effective_date DATETIME
effective_date DATETIME,
is_library INT NOT NULL DEFAULT 0
);

View File

@ -3,11 +3,19 @@ INSERT INTO mocha_tenants
(
tenant_name,
global_identifier,
effective_date
effective_date,
is_library
)
VALUES
(
'net.alcetech.Mocha.System',
'2826E41F763A413FB2393D9698AB629F',
NOW(),
1
),
(
'default',
'2552F66B0DBE41EB8A8076DE8575A468',
NOW()
NOW(),
0
)

View File

@ -0,0 +1,9 @@
INSERT INTO mocha_tenant_references
(
source_tenant_id,
target_tenant_id
)
VALUES
(
2, 1
)

View File

@ -1,129 +0,0 @@
--
-- mocha_instances.sql - defines the mocha_instances table
--
-- Author:
-- Michael Becker <alcexhim@gmail.com>
--
-- Copyright (c) 2021 Mike Becker's Software
--
-- This program 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.
--
-- This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
DROP PROCEDURE IF EXISTS mocha_build_tenant_from_template;
CREATE PROCEDURE mocha_build_tenant_from_template
(
IN p_tenant_id INT,
IN p_template_id INT
)
BEGIN
-- we don't want to use TRUNCATE here since we only want to zap the specified tenant
CALL mocha_truncate_tenant(p_tenant_id);
CALL mocha_select_tenant(p_tenant_id);
/*
-- Class
CALL mocha_create_class(1, 'B9C9B9B7AD8A4CBDAA6BE05784630B6B', NULL, NULL, @dummy);
-- Attribute
CALL mocha_create_class(2, 'F9CD7751EF624F7C8A28EBE90B8F46AA', NULL, NULL, @dummy);
-- Relationship
CALL mocha_create_class(3, '9B0A80F9C3254D36997CFB4106204648', NULL, NULL, @dummy);
-- Class.has Instance
CALL mocha_create_instance_of(mocha_get_instance_by_global_identifier('9B0A80F9C3254D36997CFB4106204648'), '7EB41D3C2AE9488483A4E59441BCAEFB', NULL, NULL, @dummy)
-- Instance.for Class
CALL mocha_create_instance_of(mocha_get_instance_by_global_identifier('9B0A80F9C3254D36997CFB4106204648'), '494D5A6D04BE477B8763E3F57D0DD8C8', NULL, NULL, @dummy)
CALL mocha_set_parent_class(mocha_get_instance_by_key(1, 1), mocha_get_instance_by_key(1, 1), NULL, NOW());
-- Text Attribute
CALL mocha_create_class(4, 'C2F3654260C34B9E9A96CA9B309C43AF', NULL, NULL, @dummy);
-- Text Attribute: 'Name'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), '9153A637992E4712ADF2B03F0D9EDEA6', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 1), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Name', NULL, NULL);
-- Text Attribute: 'Value'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), '041DD7FD2D9C412B8B9DD7125C166FE0', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 2), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Value', NULL, NULL);
-- Text Attribute: 'Verb'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), '61345a5d33974a9687978863f03a476c', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 3), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Verb', NULL, NULL);
-- Text Attribute: 'User Name'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), '960FAF025C5940F791A720012A99D9ED', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 4), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'User Name', NULL, NULL);
-- Text Attribute: 'Password Hash'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), 'F377FC294DF14AFB96434191F37A00A9', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 5), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Password Hash', NULL, NULL);
-- Text Attribute: 'Password Salt'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), '8C5A99BC40ED4FA2B23FF373C1F3F4BE', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 6), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Password Salt', NULL, NULL);
-- Text Attribute: 'Token'
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 4), 'da7686b638034f1597f67f8f3ae16668', NULL, NOW(), @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(4, 7), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Token', NULL, NULL);
-- name = 9153A637992E4712ADF2B03F0D9EDEA6
-- value = 041DD7FD2D9C412B8B9DD7125C166FE0
-- CALL mocha_assign_translation(mocha_get_instance_by_global_identifier('61345a5d33974a9687978863f03a476c'), mocha_get_instance_by_global_identifier(''))
CALL mocha_create_class(39, '9C6871C19A7F4A3A900E69D1D9E24486', NULL, NULL, @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(1, 39), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'System User', NULL, NULL);
CALL mocha_create_class(96, '703F9D65C5844D9FA656D0E3C247FF1F', NULL, NULL, @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(1, 96), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'Tenant', NULL, NULL);
-- zq-environments, 39$1
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 39), 'B066A54BB1604510A805436D3F90C2E6', NULL, NOW(), @dummy);
-- username
CALL mocha_set_attribute_value(mocha_get_instance_by_key(39, 1), mocha_get_instance_by_global_identifier('960FAF025C5940F791A720012A99D9ED'), 'zq-environments', NULL, NULL);
-- zq-developer, 39$2
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 39), '098DDA82CD044B538C7589D420EA6902', NULL, NOW(), @dummy);
-- username
CALL mocha_set_attribute_value(mocha_get_instance_by_key(39, 2), mocha_get_instance_by_global_identifier('960FAF025C5940F791A720012A99D9ED'), 'zq-developer', NULL, NULL);
-- password
CALL mocha_set_attribute_value(mocha_get_instance_by_key(39, 2), mocha_get_instance_by_global_identifier('F377FC294DF14AFB96434191F37A00A9'), 'f4f166c4d578cb5ca942e07851d7c09de07d417463f2d8e5165a779f768d14b370cd1e82826a94b617b6c6359253e8c12ea8285cba1e6e69e2e13f2bdc0425d0', NULL, NULL);
-- salt
CALL mocha_set_attribute_value(mocha_get_instance_by_key(39, 2), mocha_get_instance_by_global_identifier('8C5A99BC40ED4FA2B23FF373C1F3F4BE'), '7e893ba949b041bab73c6f4f0bcb9413', NULL, NULL);
CALL mocha_create_user('superuser', '69e291d8381b4ad89013f3b0a0c693fe');
CALL mocha_create_user('zq-support', '232A8CBF0D2B4BDABE863E2FA25A3FB5');
CALL mocha_create_user('zq-configurator', 'FB20A79CEAA24A98A1DABDC351854694');
CALL mocha_create_user('zq-implementer', '63F2EF51DC7348EC856A6FBBEDE01A8A');
CALL mocha_create_user('admin', '739C26BC740F4CB0BCB12A28FA570E7D');
-- default tenant
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 96), 'F2C9D4A99EFB426384DB66A9DA65AD00', NULL, NOW(), @dummy);
-- User Login
CALL mocha_create_class(105, '64F4BCDB38D04373BA308AE99AF1A5F7', NULL, NULL, @dummy);
CALL mocha_set_attribute_value(mocha_get_instance_by_key(1, 105), mocha_get_instance_by_global_identifier('9153A637992E4712ADF2B03F0D9EDEA6'), 'User Login', NULL, NULL);
-- relationship : User Login.has User
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 3), '85B40E4B849B4006A9C04E201B25975F', NULL, NOW(), @dummy);
-- relationship : User.for User Login
CALL mocha_create_instance_of(mocha_get_instance_by_key(1, 3), 'C79A6041FC9441A59860D443C60FA7DE', NULL, NOW(), @dummy);
*/
CALL mocha_release_tenant();
END;