Add org leave/disband bridge flow across client and server
- Introduce `OrgUIBridge` to centralize UI event/request/response handling - Add leave and disband org requests with server handlers and client bridge events - Enforce portal permissions for leaving/disbanding and protect owner/self from member removal
This commit is contained in:
parent
6eb6ac79d1
commit
9cd7278746
@ -1,3 +1,4 @@
|
||||
PREP(handleUIEvents);
|
||||
PREP(initOrgClass);
|
||||
PREP(initOrgUIBridge);
|
||||
PREP(openUI);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (isNil QGVAR(OrgClass)) then { call FUNC(initOrgClass); };
|
||||
if (isNil QGVAR(OrgUIBridge)) then { call FUNC(initOrgUIBridge); };
|
||||
|
||||
[QGVAR(initOrg), {
|
||||
GVAR(OrgClass) call ["init", []];
|
||||
@ -21,27 +22,19 @@ if (isNil QGVAR(OrgClass)) then { call FUNC(initOrgClass); };
|
||||
[QGVAR(responseCreateOrg), {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
private _control = uiNamespace getVariable [QGVAR(PendingBrowserControl), controlNull];
|
||||
uiNamespace setVariable [QGVAR(PendingBrowserControl), controlNull];
|
||||
GVAR(OrgUIBridge) call ["handleCreateResponse", [_payload]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
private _success = _payload getOrDefault ["success", false];
|
||||
if (!_success) exitWith {
|
||||
if (_control isNotEqualTo controlNull) then {
|
||||
private _json = toJSON (createHashMapFromArray [
|
||||
["message", _payload getOrDefault ["message", "Organization registration failed."]]
|
||||
]);
|
||||
[QGVAR(responseDisbandOrg), {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
_control ctrlWebBrowserAction ["ExecJS", format ["OrgUIBridge.receiveCreateFailure(%1)", _json]];
|
||||
};
|
||||
};
|
||||
GVAR(OrgUIBridge) call ["handleDisbandResponse", [_payload]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
private _orgData = _payload getOrDefault ["org", createHashMap];
|
||||
GVAR(OrgClass) call ["sync", [_orgData, true]];
|
||||
[QGVAR(responseLeaveOrg), {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
if (_control isNotEqualTo controlNull) then {
|
||||
private _json = toJSON (GVAR(OrgClass) call ["buildPortalPayload", []]);
|
||||
_control ctrlWebBrowserAction ["ExecJS", format ["OrgUIBridge.receiveCreateSuccess(%1)", _json]];
|
||||
};
|
||||
GVAR(OrgUIBridge) call ["handleLeaveResponse", [_payload]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[{
|
||||
|
||||
@ -21,52 +21,25 @@ params ["_control", "_isConfirmDialog", "_message"];
|
||||
private _alert = fromJSON _message;
|
||||
private _event = _alert get "event";
|
||||
private _data = _alert get "data";
|
||||
// private _display = displayChild findDisplay 46;
|
||||
|
||||
private _fnc_execBridge = {
|
||||
params ["_control", "_fnName", "_payload"];
|
||||
|
||||
private _json = toJSON _payload;
|
||||
_control ctrlWebBrowserAction ["ExecJS", format ["OrgUIBridge.%1(%2)", _fnName, _json]];
|
||||
};
|
||||
|
||||
diag_log format ["[FORGE:Client:Org] Handling UI event: %1 with data: %2", _event, _data];
|
||||
|
||||
switch (_event) do {
|
||||
case "org::close": { closeDialog 1; };
|
||||
case "org::login::request": {
|
||||
private _orgData = GVAR(OrgClass) get "org";
|
||||
private _orgId = _orgData getOrDefault ["id", ""];
|
||||
private _orgName = _orgData getOrDefault ["name", ""];
|
||||
|
||||
if (_orgId isEqualTo "" && {_orgName isEqualTo ""}) exitWith {
|
||||
[_control, "receiveLoginFailure", createHashMapFromArray [
|
||||
["message", "No organization data is available for this player."]
|
||||
]] call _fnc_execBridge;
|
||||
};
|
||||
|
||||
private _payload = GVAR(OrgClass) call ["buildPortalPayload", []];
|
||||
[_control, "receiveLoginSuccess", _payload] call _fnc_execBridge;
|
||||
GVAR(OrgUIBridge) call ["handleLoginRequest", [_control]];
|
||||
};
|
||||
case "org::create::request": {
|
||||
private _orgName = _data getOrDefault ["orgName", ""];
|
||||
|
||||
if (_orgName isEqualTo "") exitWith {
|
||||
[_control, "receiveCreateFailure", createHashMapFromArray [
|
||||
["message", "Enter an organization name."]
|
||||
]] call _fnc_execBridge;
|
||||
};
|
||||
|
||||
uiNamespace setVariable [QGVAR(PendingBrowserControl), _control];
|
||||
[SRPC(org,requestCreateOrg), [getPlayerUID player, _orgName]] call CFUNC(serverEvent);
|
||||
GVAR(OrgUIBridge) call ["handleCreateRequest", [_control, _data]];
|
||||
};
|
||||
case "org::disband::request": {
|
||||
GVAR(OrgUIBridge) call ["requestDisband", []];
|
||||
};
|
||||
case "org::leave::request": {
|
||||
GVAR(OrgUIBridge) call ["requestLeave", []];
|
||||
};
|
||||
case "org::ready": {
|
||||
[_control, "receive", createHashMapFromArray [
|
||||
["event", "org::ready"],
|
||||
["data", createHashMapFromArray [
|
||||
["loaded", true]
|
||||
]]
|
||||
]] call _fnc_execBridge;
|
||||
GVAR(OrgUIBridge) call ["handleReady", [_control]];
|
||||
};
|
||||
default { hint format ["Unhandled UI event: %1", _event]; };
|
||||
};
|
||||
|
||||
@ -101,7 +101,10 @@ GVAR(OrgBaseClass) = compileFinal createHashMapFromArray [
|
||||
if (_memberUid isEqualTo _ownerUid && {_ownerName isEqualTo ""}) then { _ownerName = _memberName; };
|
||||
if (_memberUid isEqualTo _playerUid) then { _sessionRole = "Member"; };
|
||||
|
||||
_membersList pushBack (createHashMapFromArray [["name", _memberName]]);
|
||||
_membersList pushBack (createHashMapFromArray [
|
||||
["uid", _memberUid],
|
||||
["name", _memberName]
|
||||
]);
|
||||
} forEach _membersRaw;
|
||||
|
||||
if (_ownerName isEqualTo "" && { _ownerUid isEqualTo _playerUid }) then { _ownerName = _playerName; };
|
||||
|
||||
173
arma/client/addons/org/functions/fnc_initOrgUIBridge.sqf
Normal file
173
arma/client/addons/org/functions/fnc_initOrgUIBridge.sqf
Normal file
@ -0,0 +1,173 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_initOrgUIBridge.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-10
|
||||
* Last Update: 2026-03-10
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the org UI bridge for browser control state and event routing.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* Org UI bridge object [HASHMAP OBJECT]
|
||||
*
|
||||
* Examples:
|
||||
* call forge_client_org_fnc_initOrgUIBridge
|
||||
*/
|
||||
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
GVAR(OrgUIBridgeBaseClass) = compileFinal createHashMapFromArray [
|
||||
["#type", "OrgUIBridgeBaseClass"],
|
||||
["#create", compileFinal {
|
||||
_self set ["pendingBrowserControl", controlNull];
|
||||
}],
|
||||
["setPendingBrowserControl", compileFinal {
|
||||
params [["_control", controlNull, [controlNull]]];
|
||||
|
||||
_self set ["pendingBrowserControl", _control];
|
||||
_control
|
||||
}],
|
||||
["consumePendingBrowserControl", compileFinal {
|
||||
private _control = _self getOrDefault ["pendingBrowserControl", controlNull];
|
||||
_self set ["pendingBrowserControl", controlNull];
|
||||
|
||||
_control
|
||||
}],
|
||||
["getActiveBrowserControl", compileFinal {
|
||||
private _display = uiNamespace getVariable ["RscOrg", displayNull];
|
||||
if (isNull _display) exitWith { controlNull };
|
||||
|
||||
_display displayCtrl 1003
|
||||
}],
|
||||
["execBridge", compileFinal {
|
||||
params [
|
||||
["_control", controlNull, [controlNull]],
|
||||
["_fnName", "", [""]],
|
||||
["_payload", createHashMap, [createHashMap]]
|
||||
];
|
||||
|
||||
if (isNull _control || { _fnName isEqualTo "" }) exitWith { false };
|
||||
|
||||
private _json = toJSON _payload;
|
||||
_control ctrlWebBrowserAction ["ExecJS", format ["OrgUIBridge.%1(%2)", _fnName, _json]];
|
||||
|
||||
true
|
||||
}],
|
||||
["sendBridgeEvent", compileFinal {
|
||||
params [
|
||||
["_event", "", [""]],
|
||||
["_data", createHashMap, [createHashMap]],
|
||||
["_control", controlNull, [controlNull]]
|
||||
];
|
||||
|
||||
if (_event isEqualTo "") exitWith { false };
|
||||
|
||||
private _targetControl = _control;
|
||||
if (isNull _targetControl) then {
|
||||
_targetControl = _self call ["getActiveBrowserControl", []];
|
||||
};
|
||||
|
||||
if (isNull _targetControl) exitWith { false };
|
||||
|
||||
_self call ["execBridge", [_targetControl, "receive", createHashMapFromArray [
|
||||
["event", _event],
|
||||
["data", _data]
|
||||
]]]
|
||||
}],
|
||||
["handleLoginRequest", compileFinal {
|
||||
params [["_control", controlNull, [controlNull]]];
|
||||
|
||||
private _orgData = GVAR(OrgClass) get "org";
|
||||
private _orgId = _orgData getOrDefault ["id", ""];
|
||||
private _orgName = _orgData getOrDefault ["name", ""];
|
||||
|
||||
if (_orgId isEqualTo "" && { _orgName isEqualTo "" }) exitWith {
|
||||
_self call ["execBridge", [_control, "receiveLoginFailure", createHashMapFromArray [
|
||||
["message", "No organization data is available for this player."]
|
||||
]]];
|
||||
};
|
||||
|
||||
_self call ["execBridge", [_control, "receiveLoginSuccess", GVAR(OrgClass) call ["buildPortalPayload", []]]];
|
||||
}],
|
||||
["handleCreateRequest", compileFinal {
|
||||
params [
|
||||
["_control", controlNull, [controlNull]],
|
||||
["_data", createHashMap, [createHashMap]]
|
||||
];
|
||||
|
||||
private _orgName = _data getOrDefault ["orgName", ""];
|
||||
if (_orgName isEqualTo "") exitWith {
|
||||
_self call ["execBridge", [_control, "receiveCreateFailure", createHashMapFromArray [
|
||||
["message", "Enter an organization name."]
|
||||
]]];
|
||||
};
|
||||
|
||||
_self call ["setPendingBrowserControl", [_control]];
|
||||
[SRPC(org,requestCreateOrg), [getPlayerUID player, _orgName]] call CFUNC(serverEvent);
|
||||
}],
|
||||
["handleCreateResponse", compileFinal {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
private _control = _self call ["consumePendingBrowserControl", []];
|
||||
private _success = _payload getOrDefault ["success", false];
|
||||
if (!_success) exitWith {
|
||||
if (isNull _control) exitWith {};
|
||||
|
||||
_self call ["execBridge", [_control, "receiveCreateFailure", createHashMapFromArray [
|
||||
["message", _payload getOrDefault ["message", "Organization registration failed."]]
|
||||
]]];
|
||||
};
|
||||
|
||||
private _orgData = _payload getOrDefault ["org", createHashMap];
|
||||
GVAR(OrgClass) call ["sync", [_orgData, true]];
|
||||
|
||||
if (isNull _control) exitWith {};
|
||||
_self call ["execBridge", [_control, "receiveCreateSuccess", GVAR(OrgClass) call ["buildPortalPayload", []]]];
|
||||
}],
|
||||
["handleDisbandResponse", compileFinal {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
private _eventName = if (_payload getOrDefault ["success", false]) then {
|
||||
["org::portal::revoked", "org::disband::success"] select (_payload getOrDefault ["requester", false])
|
||||
} else {
|
||||
"org::disband::failure"
|
||||
};
|
||||
|
||||
_self call ["sendBridgeEvent", [_eventName, _payload]];
|
||||
}],
|
||||
["handleLeaveResponse", compileFinal {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
private _eventName = [
|
||||
"org::leave::failure",
|
||||
"org::leave::success"
|
||||
] select (_payload getOrDefault ["success", false]);
|
||||
|
||||
_self call ["sendBridgeEvent", [_eventName, _payload]];
|
||||
}],
|
||||
["requestDisband", compileFinal {
|
||||
[SRPC(org,requestDisbandOrg), [getPlayerUID player]] call CFUNC(serverEvent);
|
||||
}],
|
||||
["requestLeave", compileFinal {
|
||||
[SRPC(org,requestLeaveOrg), [getPlayerUID player]] call CFUNC(serverEvent);
|
||||
}],
|
||||
["handleReady", compileFinal {
|
||||
params [["_control", controlNull, [controlNull]]];
|
||||
|
||||
_self call ["sendBridgeEvent", [
|
||||
"org::ready",
|
||||
createHashMapFromArray [
|
||||
["loaded", true]
|
||||
],
|
||||
_control
|
||||
]];
|
||||
}]
|
||||
];
|
||||
|
||||
GVAR(OrgUIBridge) = createHashMapObject [GVAR(OrgUIBridgeBaseClass)];
|
||||
GVAR(OrgUIBridge)
|
||||
@ -41,6 +41,36 @@
|
||||
store.failCreate("Arma registration bridge is unavailable.");
|
||||
}
|
||||
|
||||
function requestDisbandOrg() {
|
||||
const sent = sendEvent("org::disband::request", {});
|
||||
if (sent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const OrgPortal = window.OrgPortal;
|
||||
if (OrgPortal && OrgPortal.actions) {
|
||||
OrgPortal.actions.showTreasuryNotice(
|
||||
"error",
|
||||
"Arma disband bridge is unavailable.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function requestLeaveOrg() {
|
||||
const sent = sendEvent("org::leave::request", {});
|
||||
if (sent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const OrgPortal = window.OrgPortal;
|
||||
if (OrgPortal && OrgPortal.actions) {
|
||||
OrgPortal.actions.showTreasuryNotice(
|
||||
"error",
|
||||
"Arma leave bridge is unavailable.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function receive(eventOrPayload, data = {}) {
|
||||
const event =
|
||||
typeof eventOrPayload === "object" && eventOrPayload !== null
|
||||
@ -70,12 +100,76 @@
|
||||
store.failCreate(
|
||||
payloadData.message || "Organization registration failed.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const OrgPortal = window.OrgPortal;
|
||||
if (event === "org::disband::success") {
|
||||
if (OrgPortal && OrgPortal.store) {
|
||||
OrgPortal.store.setModal(null);
|
||||
OrgPortal.store.setOrgDisbanded(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event === "org::disband::failure") {
|
||||
if (OrgPortal && OrgPortal.store) {
|
||||
OrgPortal.store.setModal(null);
|
||||
}
|
||||
|
||||
if (OrgPortal && OrgPortal.actions) {
|
||||
OrgPortal.actions.showTreasuryNotice(
|
||||
"error",
|
||||
payloadData.message || "Organization disbanding failed.",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event === "org::leave::success") {
|
||||
if (OrgPortal && OrgPortal.store) {
|
||||
OrgPortal.store.setModal(null);
|
||||
}
|
||||
|
||||
store.failLogin(
|
||||
payloadData.message || "You have left the organization.",
|
||||
);
|
||||
store.setView("home");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event === "org::leave::failure") {
|
||||
if (OrgPortal && OrgPortal.store) {
|
||||
OrgPortal.store.setModal(null);
|
||||
}
|
||||
|
||||
if (OrgPortal && OrgPortal.actions) {
|
||||
OrgPortal.actions.showTreasuryNotice(
|
||||
"error",
|
||||
payloadData.message || "Unable to leave the organization.",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event === "org::portal::revoked") {
|
||||
if (OrgPortal && OrgPortal.store) {
|
||||
OrgPortal.store.setModal(null);
|
||||
}
|
||||
|
||||
store.failLogin(
|
||||
payloadData.message ||
|
||||
"Organization access is no longer available.",
|
||||
);
|
||||
store.setView("home");
|
||||
}
|
||||
}
|
||||
|
||||
RegistryApp.bridge = {
|
||||
requestLogin,
|
||||
requestCreateOrg,
|
||||
requestDisbandOrg,
|
||||
requestLeaveOrg,
|
||||
receive,
|
||||
sendEvent,
|
||||
};
|
||||
@ -83,6 +177,8 @@
|
||||
window.OrgUIBridge = {
|
||||
requestLogin,
|
||||
requestCreateOrg,
|
||||
requestDisbandOrg,
|
||||
requestLeaveOrg,
|
||||
receive,
|
||||
receiveLoginSuccess: (data) => receive("org::login::success", data),
|
||||
receiveLoginFailure: (data) => receive("org::login::failure", data),
|
||||
|
||||
@ -71,6 +71,14 @@
|
||||
: null;
|
||||
|
||||
const view = store.getView();
|
||||
const portalPermissions =
|
||||
window.OrgPortal && window.OrgPortal.permissions
|
||||
? window.OrgPortal.permissions
|
||||
: null;
|
||||
const portalActions =
|
||||
window.OrgPortal && window.OrgPortal.actions
|
||||
? window.OrgPortal.actions
|
||||
: null;
|
||||
const viewLabel =
|
||||
view === "create"
|
||||
? "Organization Registration"
|
||||
@ -116,6 +124,11 @@
|
||||
}
|
||||
|
||||
if (view === "portal" && PortalApp) {
|
||||
const canLeaveOrg =
|
||||
portalPermissions &&
|
||||
typeof portalPermissions.canLeaveOrg === "function" &&
|
||||
portalPermissions.canLeaveOrg();
|
||||
|
||||
return h(
|
||||
"div",
|
||||
{ className: "app-shell" },
|
||||
@ -126,6 +139,13 @@
|
||||
Navbar({
|
||||
title: "Global Organization Network",
|
||||
viewLabel,
|
||||
actionLabel: canLeaveOrg ? "Leave Organization" : "",
|
||||
onAction:
|
||||
canLeaveOrg &&
|
||||
portalActions &&
|
||||
typeof portalActions.openModal === "function"
|
||||
? () => portalActions.openModal("leave")
|
||||
: null,
|
||||
}),
|
||||
PortalApp(),
|
||||
);
|
||||
|
||||
@ -3,10 +3,26 @@
|
||||
const { h, ensureScopedStyle } = OrgPortal.runtime;
|
||||
const scopeAttr = "data-ui-future-card";
|
||||
const ROADMAP = [
|
||||
{ name: "Contracts Board", status: "Planned", detail: "Track payouts, assignments, and claim approvals." },
|
||||
{ name: "Diplomacy", status: "Future Review", detail: "Possible future module pending a full design and scope review." },
|
||||
{ name: "Logistics Queue", status: "Future Review", detail: "Possible future module pending a full design and scope review." },
|
||||
{ name: "Permissions", status: "Future Review", detail: "Possible future module pending a full design and scope review." },
|
||||
{
|
||||
name: "Contracts Board",
|
||||
status: "Planned",
|
||||
detail: "Track payouts, assignments, and claim approvals.",
|
||||
},
|
||||
{
|
||||
name: "Diplomacy",
|
||||
status: "Future Review",
|
||||
detail: "Possible future module pending a full design and scope review.",
|
||||
},
|
||||
{
|
||||
name: "Logistics Queue",
|
||||
status: "Future Review",
|
||||
detail: "Possible future module pending a full design and scope review.",
|
||||
},
|
||||
{
|
||||
name: "Permissions",
|
||||
status: "Future Review",
|
||||
detail: "Possible future module pending a full design and scope review.",
|
||||
},
|
||||
];
|
||||
const scopeSelector = `[${scopeAttr}]`;
|
||||
const futureCardCss = `
|
||||
|
||||
@ -63,7 +63,7 @@ ${scopeSelector} .org-name-row button {
|
||||
className: "org-scroll-panel org-span-5",
|
||||
title: "Members",
|
||||
subtitle:
|
||||
"Current roster listing. The organization owner cannot be removed.",
|
||||
"Current roster listing. The organization owner and your own member entry cannot be removed.",
|
||||
rootProps: { [scopeAttr]: "" },
|
||||
body: h(
|
||||
"div",
|
||||
@ -71,7 +71,7 @@ ${scopeSelector} .org-name-row button {
|
||||
...members.map((member) => {
|
||||
const canRemoveMember =
|
||||
allowMemberManagement &&
|
||||
!actions.isOwnerMember(member.name);
|
||||
!actions.isProtectedMember(member);
|
||||
|
||||
return h(
|
||||
"article",
|
||||
@ -86,7 +86,7 @@ ${scopeSelector} .org-name-row button {
|
||||
title: `Remove ${member.name}`,
|
||||
"aria-label": `Remove ${member.name}`,
|
||||
onClick: () =>
|
||||
actions.removeMember(member.name),
|
||||
actions.removeMember(member),
|
||||
},
|
||||
h(
|
||||
"svg",
|
||||
|
||||
@ -246,6 +246,41 @@
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (modal.type === "leave") {
|
||||
title = "Leave Organization";
|
||||
body = h(
|
||||
"div",
|
||||
{ className: "app-modal-danger" },
|
||||
h(
|
||||
"p",
|
||||
null,
|
||||
"Leave ",
|
||||
portalData.org.name,
|
||||
" and return to the default organization?",
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ className: "app-modal-danger-actions" },
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "org-secondary-btn",
|
||||
onClick: () => actions.closeModal(),
|
||||
},
|
||||
"Cancel",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "org-danger-btn",
|
||||
onClick: () => actions.leaveOrganization(),
|
||||
},
|
||||
"Confirm Leave",
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Modal({
|
||||
|
||||
@ -88,17 +88,58 @@
|
||||
return el ? el.value : "";
|
||||
}
|
||||
|
||||
isOwnerMember(memberName) {
|
||||
getMemberName(member) {
|
||||
if (member && typeof member === "object") {
|
||||
return String(member.name || "");
|
||||
}
|
||||
|
||||
return String(member || "");
|
||||
}
|
||||
|
||||
getMemberUid(member) {
|
||||
if (member && typeof member === "object") {
|
||||
return String(member.uid || "");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
isOwnerMember(member) {
|
||||
return (
|
||||
String(memberName || "")
|
||||
.trim()
|
||||
.toLowerCase() ===
|
||||
this.getMemberName(member).trim().toLowerCase() ===
|
||||
String(portalData.org.owner || "")
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
isCurrentMember(member) {
|
||||
const session = window.OrgPortal?.data?.session || {};
|
||||
const memberUid = this.getMemberUid(member)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const actorUid = String(session.actorUid || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
|
||||
if (memberUid && actorUid) {
|
||||
return memberUid === actorUid;
|
||||
}
|
||||
|
||||
return (
|
||||
this.getMemberName(member).trim().toLowerCase() ===
|
||||
String(session.actorName || "")
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
isProtectedMember(member) {
|
||||
return (
|
||||
this.isOwnerMember(member) || this.isCurrentMember(member)
|
||||
);
|
||||
}
|
||||
|
||||
closePortal() {
|
||||
if (
|
||||
typeof A3API !== "undefined" &&
|
||||
@ -136,6 +177,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "leave" && !permissions.canLeaveOrg()) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.setModal({ type });
|
||||
}
|
||||
|
||||
@ -143,18 +188,23 @@
|
||||
store.setModal(null);
|
||||
}
|
||||
|
||||
removeMember(memberName) {
|
||||
removeMember(member) {
|
||||
if (!permissions.canManageMembers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isOwnerMember(memberName)) {
|
||||
if (this.isProtectedMember(member)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const memberUid = this.getMemberUid(member);
|
||||
const memberName = this.getMemberName(member);
|
||||
|
||||
store.setMembers((currentMembers) =>
|
||||
currentMembers.filter(
|
||||
(member) => member.name !== memberName,
|
||||
currentMembers.filter((entry) =>
|
||||
memberUid
|
||||
? entry.uid !== memberUid
|
||||
: entry.name !== memberName,
|
||||
),
|
||||
);
|
||||
store.setCreditLines((currentLines) =>
|
||||
@ -168,8 +218,42 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
store.setOrgDisbanded(true);
|
||||
const bridge = window.RegistryApp
|
||||
? window.RegistryApp.bridge
|
||||
: null;
|
||||
|
||||
if (!bridge || typeof bridge.requestDisbandOrg !== "function") {
|
||||
this.showTreasuryNotice(
|
||||
"error",
|
||||
"Disband bridge is unavailable.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.closeModal();
|
||||
bridge.requestDisbandOrg();
|
||||
return true;
|
||||
}
|
||||
|
||||
leaveOrganization() {
|
||||
if (!permissions.canLeaveOrg()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bridge = window.RegistryApp
|
||||
? window.RegistryApp.bridge
|
||||
: null;
|
||||
|
||||
if (!bridge || typeof bridge.requestLeaveOrg !== "function") {
|
||||
this.showTreasuryNotice(
|
||||
"error",
|
||||
"Leave bridge is unavailable.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.closeModal();
|
||||
bridge.requestLeaveOrg();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,11 @@
|
||||
}
|
||||
|
||||
canDisbandOrg() {
|
||||
return this.isOrgLeaderOrCeo();
|
||||
return this.isOrgOwner() && !this.isDefaultOrg();
|
||||
}
|
||||
|
||||
canLeaveOrg() {
|
||||
return !this.isDefaultOrg() && !this.isOrgOwner();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,11 +25,8 @@ PREP_RECOMPILE_END;
|
||||
private _result = GVAR(OrgStore) call ["register", [_uid, _orgName]];
|
||||
|
||||
if (_result getOrDefault ["success", false]) then {
|
||||
private _org = _result getOrDefault ["org", createHashMap];
|
||||
private _orgID = _org getOrDefault ["id", ""];
|
||||
|
||||
if (_orgID isNotEqualTo "") then {
|
||||
private _actorPatch = EGVAR(actor,ActorStore) call ["set", [EGVAR(actor,Registry), "actor:update", _uid, "organization", _orgID, true]];
|
||||
private _actorPatch = _result getOrDefault ["actorPatch", createHashMap];
|
||||
if (_actorPatch isNotEqualTo createHashMap) then {
|
||||
[CRPC(actor,responseSyncActor), [_actorPatch], _player] call CFUNC(targetEvent);
|
||||
};
|
||||
};
|
||||
@ -89,5 +86,85 @@ PREP_RECOMPILE_END;
|
||||
|
||||
private _index = GVAR(IndexRegistry) get _uid;
|
||||
private _key = _index get "orgID";
|
||||
GVAR(OrgStore) call ["remove", [GVAR(Registry), "org:update", _key]];
|
||||
GVAR(OrgStore) call ["delete", [_key]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(requestLeaveOrg), {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
diag_log "[FORGE:Server:Org] Empty/Invalid UID for leave request!"
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
if (_player isEqualTo objNull) exitWith {};
|
||||
|
||||
private _result = GVAR(OrgStore) call ["leave", [_uid]];
|
||||
if (_result getOrDefault ["success", false]) then {
|
||||
private _actorPatch = _result getOrDefault ["actorPatch", createHashMap];
|
||||
if (_actorPatch isNotEqualTo createHashMap) then {
|
||||
[CRPC(actor,responseSyncActor), [_actorPatch], _player] call CFUNC(targetEvent);
|
||||
};
|
||||
|
||||
GVAR(OrgStore) call ["init", [_uid]];
|
||||
|
||||
private _notificationParams = _result getOrDefault ["notification", []];
|
||||
if (_notificationParams isEqualType [] && { count _notificationParams > 0 }) then {
|
||||
[CRPC(notifications,recieveNotification), _notificationParams, _player] call CFUNC(targetEvent);
|
||||
};
|
||||
};
|
||||
|
||||
[CRPC(org,responseLeaveOrg), [createHashMapFromArray [
|
||||
["success", _result getOrDefault ["success", false]],
|
||||
["message", _result getOrDefault ["message", "Unable to leave the organization."]]
|
||||
]], _player] call CFUNC(targetEvent);
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(requestDisbandOrg), {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
diag_log "[FORGE:Server:Org] Empty/Invalid UID for disband request!"
|
||||
};
|
||||
|
||||
private _requester = [_uid] call EFUNC(common,getPlayer);
|
||||
if (_requester isEqualTo objNull) exitWith {};
|
||||
|
||||
private _result = GVAR(OrgStore) call ["disband", [_uid]];
|
||||
if !(_result getOrDefault ["success", false]) exitWith {
|
||||
[CRPC(org,responseDisbandOrg), [createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", _result getOrDefault ["message", "Failed to disband organization."]],
|
||||
["requester", true]
|
||||
]], _requester] call CFUNC(targetEvent);
|
||||
};
|
||||
|
||||
{
|
||||
[_x, _result] call {
|
||||
params [["_member", createHashMap, [createHashMap]], ["_disbandResult", createHashMap, [createHashMap]]];
|
||||
|
||||
private _memberUid = _member getOrDefault ["uid", ""];
|
||||
if (_memberUid isEqualTo "") exitWith {};
|
||||
|
||||
private _memberPlayer = [_memberUid] call EFUNC(common,getPlayer);
|
||||
if (_memberPlayer isEqualTo objNull) exitWith {};
|
||||
|
||||
private _actorPatch = _member getOrDefault ["actorPatch", createHashMap];
|
||||
if (_actorPatch isNotEqualTo createHashMap) then {
|
||||
[CRPC(actor,responseSyncActor), [_actorPatch], _memberPlayer] call CFUNC(targetEvent);
|
||||
};
|
||||
|
||||
GVAR(OrgStore) call ["init", [_memberUid]];
|
||||
[CRPC(org,responseDisbandOrg), [createHashMapFromArray [
|
||||
["success", true],
|
||||
["message", _member getOrDefault ["message", _disbandResult getOrDefault ["message", "Organization disbanded."]]],
|
||||
["requester", _member getOrDefault ["requester", false]]
|
||||
]], _memberPlayer] call CFUNC(targetEvent);
|
||||
|
||||
private _notificationParams = _member getOrDefault ["notification", []];
|
||||
if (_notificationParams isEqualType [] && { count _notificationParams > 0 }) then {
|
||||
[CRPC(notifications,recieveNotification), _notificationParams, _memberPlayer] call CFUNC(targetEvent);
|
||||
};
|
||||
};
|
||||
} forEach (_result getOrDefault ["members", []]);
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
@ -140,13 +140,281 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
|
||||
_org
|
||||
}],
|
||||
["loadById", compileFinal {
|
||||
params [["_orgID", "", [""]]];
|
||||
|
||||
if (_orgID isEqualTo "") exitWith { createHashMap };
|
||||
|
||||
private _cached = GVAR(Registry) getOrDefault [_orgID, createHashMap];
|
||||
if (_cached isNotEqualTo createHashMap) exitWith { _cached };
|
||||
|
||||
["org:exists", [_orgID]] call EFUNC(extension,extCall) params ["_existsResult", "_existsSuccess"];
|
||||
if (!_existsSuccess || { _existsResult isNotEqualTo "true" }) exitWith { createHashMap };
|
||||
|
||||
private _org = _self call ["fetch", ["org:get", _orgID]];
|
||||
if (_org isEqualTo createHashMap) exitWith { _org };
|
||||
|
||||
private _memberRows = _self call ["fetch", ["org:members:get", _orgID]];
|
||||
if !(_memberRows isEqualType []) then {
|
||||
_memberRows = [];
|
||||
};
|
||||
|
||||
private _memberMap = createHashMap;
|
||||
{
|
||||
private _memberUid = _x getOrDefault ["uid", ""];
|
||||
if (_memberUid isNotEqualTo "") then {
|
||||
_memberMap set [_memberUid, _x];
|
||||
};
|
||||
} forEach _memberRows;
|
||||
|
||||
_org set ["members", _memberMap];
|
||||
GVAR(Registry) set [_orgID, _org, true];
|
||||
_org
|
||||
}],
|
||||
["addMember", compileFinal {
|
||||
params [
|
||||
["_orgID", "", [""]],
|
||||
["_uid", "", [""]],
|
||||
["_player", objNull, [objNull]],
|
||||
["_actor", createHashMap, [createHashMap]]
|
||||
];
|
||||
|
||||
if (_orgID isEqualTo "" || { _uid isEqualTo "" }) exitWith { createHashMap };
|
||||
|
||||
private _org = _self call ["loadById", [_orgID]];
|
||||
if (_org isEqualTo createHashMap) exitWith { _org };
|
||||
|
||||
_org = _self call ["verifyMember", [_org, _orgID, _uid, _player, _actor]];
|
||||
GVAR(Registry) set [_orgID, _org, true];
|
||||
_org
|
||||
}],
|
||||
["removeMember", compileFinal {
|
||||
params [
|
||||
["_orgID", "", [""]],
|
||||
["_uid", "", [""]]
|
||||
];
|
||||
|
||||
if (_orgID isEqualTo "" || { _uid isEqualTo "" }) exitWith { createHashMap };
|
||||
|
||||
private _org = _self call ["loadById", [_orgID]];
|
||||
if (_org isEqualTo createHashMap) exitWith { _org };
|
||||
|
||||
["org:members:remove", [_orgID, _uid]] call EFUNC(extension,extCall) params ["_memberResult", "_memberSuccess"];
|
||||
if (!_memberSuccess) exitWith {
|
||||
["WARNING", format ["Failed to remove %1 from org %2 members: %3", _uid, _orgID, _memberResult]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
};
|
||||
|
||||
private _members = +(_org getOrDefault ["members", createHashMap]);
|
||||
_members deleteAt _uid;
|
||||
_org set ["members", _members];
|
||||
GVAR(Registry) set [_orgID, _org, true];
|
||||
|
||||
_org
|
||||
}],
|
||||
["delete", compileFinal {
|
||||
params [["_orgID", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", ""]
|
||||
];
|
||||
|
||||
if (_orgID isEqualTo "" || { toLower _orgID isEqualTo "default" }) exitWith {
|
||||
_result set ["message", "Invalid organization ID."];
|
||||
_result
|
||||
};
|
||||
|
||||
["org:delete", [_orgID]] call EFUNC(extension,extCall) params ["_deleteResult", "_deleteSuccess"];
|
||||
if (!_deleteSuccess || { _deleteResult isNotEqualTo "OK" }) exitWith {
|
||||
_result set ["message", format ["Failed to delete organization: %1", _deleteResult]];
|
||||
_result
|
||||
};
|
||||
|
||||
GVAR(Registry) deleteAt _orgID;
|
||||
_result set ["success", true];
|
||||
_result
|
||||
}],
|
||||
["restoreDefaultMembership", compileFinal {
|
||||
params [
|
||||
["_uid", "", [""]],
|
||||
["_player", objNull, [objNull]],
|
||||
["_actor", createHashMap, [createHashMap]]
|
||||
];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", ""],
|
||||
["actorPatch", createHashMap]
|
||||
];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
_result set ["message", "A valid player UID is required."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _resolvedPlayer = _player;
|
||||
if (_resolvedPlayer isEqualTo objNull) then {
|
||||
_resolvedPlayer = [_uid] call EFUNC(common,getPlayer);
|
||||
};
|
||||
|
||||
private _resolvedActor = EGVAR(actor,Registry) getOrDefault [_uid, _actor];
|
||||
private _actorPatch = EGVAR(actor,ActorStore) call ["set", [EGVAR(actor,Registry), "actor:update", _uid, "organization", "default", true]];
|
||||
private _defaultOrg = _self call ["addMember", ["default", _uid, _resolvedPlayer, EGVAR(actor,Registry) getOrDefault [_uid, _resolvedActor]]];
|
||||
if (_defaultOrg isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Failed to restore default organization membership."];
|
||||
_result
|
||||
};
|
||||
|
||||
GVAR(IndexRegistry) set [_uid, createHashMapFromArray [["orgID", "default"]]];
|
||||
_result set ["success", true];
|
||||
_result set ["actorPatch", _actorPatch];
|
||||
_result
|
||||
}],
|
||||
["leave", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", ""],
|
||||
["actorPatch", createHashMap],
|
||||
["notification", []]
|
||||
];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
_result set ["message", "A valid player UID is required."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
|
||||
private _orgID = _actor getOrDefault ["organization", ""];
|
||||
if (_orgID isEqualTo "" || { toLower _orgID isEqualTo "default" }) exitWith {
|
||||
_result set ["message", "You are already assigned to the default organization."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _org = _self call ["loadById", [_orgID]];
|
||||
if (_org isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Unable to load organization data for leave request."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _ownerUid = _org getOrDefault ["owner", ""];
|
||||
if (_ownerUid isEqualTo _uid) exitWith {
|
||||
_result set ["message", "Organization owners must disband the organization instead of leaving it."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _orgName = _org getOrDefault ["name", "Organization"];
|
||||
private _updatedOrg = _self call ["removeMember", [_orgID, _uid]];
|
||||
if (_updatedOrg isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Failed to remove you from the organization roster."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _defaultResult = _self call ["restoreDefaultMembership", [_uid, _player, _actor]];
|
||||
if !(_defaultResult getOrDefault ["success", false]) exitWith {
|
||||
_result set ["message", _defaultResult getOrDefault ["message", "Failed to restore default organization membership."]];
|
||||
_result
|
||||
};
|
||||
|
||||
private _message = format ["You left %1 and returned to the default organization.", _orgName];
|
||||
_result set ["success", true];
|
||||
_result set ["message", _message];
|
||||
_result set ["actorPatch", _defaultResult getOrDefault ["actorPatch", createHashMap]];
|
||||
_result set ["notification", ["info", "Organization Left", _message, 6000]];
|
||||
_result
|
||||
}],
|
||||
["disband", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", ""],
|
||||
["members", []]
|
||||
];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
_result set ["message", "A valid player UID is required."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
|
||||
private _orgID = _actor getOrDefault ["organization", ""];
|
||||
if (_orgID isEqualTo "" || { toLower _orgID isEqualTo "default" }) exitWith {
|
||||
_result set ["message", "Only active player organizations can be disbanded."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _org = _self call ["loadById", [_orgID]];
|
||||
if (_org isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Unable to load organization data for disbanding."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _ownerUid = _org getOrDefault ["owner", ""];
|
||||
if (_ownerUid isEqualTo "" || { _ownerUid isNotEqualTo _uid }) exitWith {
|
||||
_result set ["message", "Only the organization owner can disband this organization."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _orgName = _org getOrDefault ["name", "Organization"];
|
||||
private _memberMap = _org getOrDefault ["members", createHashMap];
|
||||
private _memberUids = keys _memberMap;
|
||||
if !(_uid in _memberUids) then {
|
||||
_memberUids pushBack _uid;
|
||||
};
|
||||
|
||||
private _deleteResult = _self call ["delete", [_orgID]];
|
||||
if !(_deleteResult getOrDefault ["success", false]) exitWith {
|
||||
_result set ["message", _deleteResult getOrDefault ["message", "Failed to disband organization."]];
|
||||
_result
|
||||
};
|
||||
|
||||
private _memberResults = [];
|
||||
{
|
||||
private _memberUid = _x;
|
||||
if (_memberUid isNotEqualTo "") then {
|
||||
private _memberPlayer = [_memberUid] call EFUNC(common,getPlayer);
|
||||
private _defaultResult = _self call ["restoreDefaultMembership", [_memberUid, _memberPlayer, EGVAR(actor,Registry) getOrDefault [_memberUid, createHashMap]]];
|
||||
if !(_defaultResult getOrDefault ["success", false]) then {
|
||||
["WARNING", format ["Failed to restore default org for %1 after disbanding %2: %3", _memberUid, _orgID, _defaultResult getOrDefault ["message", "Unknown error."]]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _responseMessage = [
|
||||
format ["%1 has been disbanded.", _orgName],
|
||||
format ["Your organization, %1, has been disbanded.", _orgName]
|
||||
] select (_memberUid isEqualTo _uid);
|
||||
|
||||
private _notificationParams = [
|
||||
["warning", "Organization Disbanded", _responseMessage, 6000],
|
||||
["success", "Organization Disbanded", _responseMessage, 6000]
|
||||
] select (_memberUid isEqualTo _uid);
|
||||
|
||||
_memberResults pushBack (createHashMapFromArray [
|
||||
["uid", _memberUid],
|
||||
["requester", _memberUid isEqualTo _uid],
|
||||
["message", _responseMessage],
|
||||
["notification", _notificationParams],
|
||||
["actorPatch", _defaultResult getOrDefault ["actorPatch", createHashMap]]
|
||||
]);
|
||||
};
|
||||
} forEach _memberUids;
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["message", format ["%1 has been disbanded.", _orgName]];
|
||||
_result set ["members", _memberResults];
|
||||
_result
|
||||
}],
|
||||
["register", compileFinal {
|
||||
params [["_uid", "", [""]], ["_orgName", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", ""],
|
||||
["org", createHashMap]
|
||||
["org", createHashMap],
|
||||
["actorPatch", createHashMap]
|
||||
];
|
||||
|
||||
if (_uid isEqualTo "" || { _orgName isEqualTo "" }) exitWith {
|
||||
@ -158,7 +426,7 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
|
||||
private _existingOrgID = _actor getOrDefault ["organization", ""];
|
||||
|
||||
if (_existingOrgID isNotEqualTo "") exitWith {
|
||||
if (_existingOrgID isNotEqualTo "" && { toLower _existingOrgID isNotEqualTo "default" }) exitWith {
|
||||
_result set ["message", "Player already belongs to an organization."];
|
||||
_result
|
||||
};
|
||||
@ -205,21 +473,20 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
_org set ["members", createHashMap];
|
||||
_org = _self call ["verifyMember", [_org, _orgID, _uid, _player, _actor]];
|
||||
|
||||
["org:members:remove", ["default", _uid]] call EFUNC(extension,extCall);
|
||||
|
||||
private _defaultOrg = GVAR(Registry) getOrDefault ["default", createHashMap];
|
||||
if (_defaultOrg isNotEqualTo createHashMap) then {
|
||||
private _defaultMembers = _defaultOrg getOrDefault ["members", createHashMap];
|
||||
_defaultMembers deleteAt _uid;
|
||||
_defaultOrg set ["members", _defaultMembers];
|
||||
GVAR(Registry) set ["default", _defaultOrg, true];
|
||||
if (toLower _existingOrgID isEqualTo "default") then {
|
||||
private _defaultOrg = _self call ["removeMember", ["default", _uid]];
|
||||
if (_defaultOrg isEqualTo createHashMap) then {
|
||||
["WARNING", format ["Failed to remove %1 from default org members after creating org %2.", _uid, _orgID]] call EFUNC(common,log);
|
||||
};
|
||||
};
|
||||
|
||||
private _actorPatch = EGVAR(actor,ActorStore) call ["set", [EGVAR(actor,Registry), "actor:update", _uid, "organization", _orgID, true]];
|
||||
GVAR(IndexRegistry) set [_uid, createHashMapFromArray [["orgID", _orgID]]];
|
||||
GVAR(Registry) set [_orgID, _org, true];
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["org", _org];
|
||||
_result set ["actorPatch", _actorPatch];
|
||||
_result
|
||||
}],
|
||||
["init", compileFinal {
|
||||
@ -258,12 +525,9 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
};
|
||||
|
||||
private _finalOrg = createHashMap;
|
||||
private _finalAssets = createHashMap;
|
||||
private _finalFleet = createHashMap;
|
||||
private _finalMembers = createHashMap;
|
||||
|
||||
if (_result == "true") then {
|
||||
_finalOrg = _self call ["fetch", ["org:get", _orgID]];
|
||||
_finalOrg = _self call ["loadById", [_orgID]];
|
||||
["INFO", format ["Found org for %1", _orgID]] call EFUNC(common,log);
|
||||
} else {
|
||||
["WARNING", format ["No existing org found for %1, using default org.", _uid]] call EFUNC(common,log);
|
||||
@ -274,26 +538,6 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _entry = createHashMapFromArray [["orgID", _orgID]];
|
||||
GVAR(IndexRegistry) set [_uid, _entry];
|
||||
|
||||
// private _assets = _self call ["fetch", ["org:assets:get", _orgID]];
|
||||
// private _fleet = _self call ["fetch", ["org:fleet:get", _orgID]];
|
||||
private _members = _self call ["fetch", ["org:members:get", _orgID]];
|
||||
|
||||
{
|
||||
private _key = _x get "uid";
|
||||
private _value = _x;
|
||||
_finalMembers set [_key, _value];
|
||||
} forEach _members;
|
||||
|
||||
// {
|
||||
// private _key = _x get "classname";
|
||||
// private _value = _x;
|
||||
// _finalAssets set [_key, _value];
|
||||
// } forEach _assets;
|
||||
|
||||
_finalOrg set ["assets", _finalAssets];
|
||||
_finalOrg set ["fleet", _finalFleet];
|
||||
_finalOrg set ["members", _finalMembers];
|
||||
|
||||
private _finalOwner = _finalOrg getOrDefault ["owner", ""];
|
||||
if (_orgID isEqualTo "default" || { _finalOwner isEqualTo _uid }) then {
|
||||
_finalOrg = _self call ["verifyMember", [_finalOrg, _orgID, _uid, _player, _actor]];
|
||||
|
||||
@ -147,15 +147,21 @@ impl<C: RedisClient> OrgRepository for RedisOrgRepository<C> {
|
||||
|
||||
/// Permanently deletes an organization and all associated data from Redis.
|
||||
///
|
||||
/// Removes the organization hash and the associated members list.
|
||||
/// Removes the organization hash and related subordinate keys.
|
||||
/// This operation is irreversible.
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
// Generate Redis key using organization ID
|
||||
let redis_key = format!("org:{}", id);
|
||||
let redis_keys = [
|
||||
format!("org:{}", id),
|
||||
format!("org:{}:members", id),
|
||||
format!("org:{}:assets", id),
|
||||
format!("org:{}:fleet", id),
|
||||
];
|
||||
|
||||
// Delete the organization hash key from Redis
|
||||
// Note: This does NOT delete member data stored separately
|
||||
self.client.delete_key(redis_key)
|
||||
for redis_key in redis_keys {
|
||||
self.client.delete_key(redis_key)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if an organization exists in Redis without retrieving the data.
|
||||
|
||||
@ -163,16 +163,7 @@ impl<R: OrgRepository> OrgService<R> {
|
||||
///
|
||||
/// Irreversible operation. Delegates to repository.
|
||||
pub fn delete_org(&self, key: String) -> Result<(), String> {
|
||||
let redis_key = format!("org:{}", key);
|
||||
let assets_key = format!("org:{}:assets", key);
|
||||
let members_key = format!("org:{}:members", key);
|
||||
|
||||
// Delegate deletion to repository layer
|
||||
self.repository.delete(&redis_key)?;
|
||||
self.repository.delete(&assets_key)?;
|
||||
self.repository.delete(&members_key)?;
|
||||
|
||||
Ok(())
|
||||
self.repository.delete(&key)
|
||||
}
|
||||
|
||||
/// Checks if an organization exists in the system.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user