@cocreate/organizations
Version:
A simple organizations component in vanilla javascript. Easily configured using HTML5 attributes and/or JavaScript API.
325 lines (282 loc) • 7.96 kB
JavaScript
import Crud from "@cocreate/crud-client";
import Action from "@cocreate/actions";
import Elements from "@cocreate/elements";
import Config from "@cocreate/config";
import Indexeddb from "@cocreate/indexeddb";
import uuid from "@cocreate/uuid";
async function generateDB(organization = {}, user = {}, key = []) {
try {
// Create organization
organization._id = organization._id || Crud.ObjectId().toString();
organization.name = organization.name || "untitiled";
// Create user
user._id = user._id || Crud.ObjectId().toString();
user.firstname = user.firstname || "untitiled";
user.lastname = user.lastname || "untitiled";
// Create default key
let defaultKey = {
_id: Crud.ObjectId().toString(),
type: "key",
key: uuid.generate(),
actions: {
object: {
"*": {
users: {
"_id.$eq": "$user_id"
}
},
read: {
$array: ["ai", "blog-posts"]
}
},
checkSession: "true",
signIn: "true",
signUp: "true",
acceptInvite: "true",
forgotPassword: "true",
resetPassword: "true",
updateUserStatus: "true",
isUnique: "true",
inviteUser: "true"
},
default: true
};
// Create File key
let fileKey = {
_id: Crud.ObjectId().toString(),
type: "key",
key: uuid.generate(),
admin: "true"
};
// Create role
let role_id = Crud.ObjectId().toString();
let role = {
_id: role_id,
type: "role",
name: "admin",
admin: "true"
};
// Create user key
let userKey = {
_id: Crud.ObjectId().toString(),
type: "user",
key: user._id,
array: "users", // could be any array
roles: [role_id],
email: user.email,
password: user.password || btoa("0000")
};
return {
organization,
user,
key: [defaultKey, fileKey, userKey, role]
};
} catch (error) {
return false;
}
}
function saveLocally(objects) {
const organization_id = objects.organization._id;
for (let key of Object.keys(objects)) {
let data = {
method: "object.create",
storage: "indexeddb",
database: organization_id,
array: key + "s",
object: objects[key],
organization_id
};
Indexeddb.send(data);
}
}
async function get() {
let organization_id = await getOrganizationFromServiceWorker();
if (!organization_id) {
let data = await Indexeddb.send({ method: "database.read" });
for (let database of data.database) {
let name = database.name;
if (name.match(/^[0-9a-fA-F]{24}$/)) {
organization_id = name;
}
}
}
if (!organization_id) {
let file = await fetch("/");
organization_id = file.headers.get("organization");
}
if (!organization_id) organization_id = await createOrganization();
if (organization_id) Config.set("organization_id", organization_id);
return organization_id;
}
async function getOrganizationFromServiceWorker() {
return new Promise((resolve, reject) => {
if (!navigator.serviceWorker) return resolve();
const handleMessage = (event) => {
if (event.data.action === "getOrganization") {
navigator.serviceWorker.removeEventListener(
"message",
handleMessage
); // Remove the event listener
resolve(event.data.organization_id);
}
};
navigator.serviceWorker.addEventListener("message", handleMessage);
// Send message to Service Worker
const msg = new MessageChannel();
navigator.serviceWorker.ready
.then((registration) => {
if (navigator.serviceWorker.controller) {
// If there's an active controller, send the message
navigator.serviceWorker.controller.postMessage(
{ action: "getOrganization" },
[msg.port1]
);
} else {
// Listen for a new service worker to start controlling the page
navigator.serviceWorker.addEventListener(
"controllerchange",
() => {
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(
{ action: "getOrganization" },
[msg.port1]
);
}
}
);
}
})
.catch((error) => {
console.error(reject);
});
});
}
let organizationPromise = null;
async function createOrganizationPromise() {
let createOrganization = document.querySelector(
'[actions*="createOrganization"]'
);
if (createOrganization) return (Crud.socket.organization = "canceled");
if (
Crud.socket.organization == "canceled" ||
Crud.socket.organization == "pending"
)
return;
const organization_id = prompt(
"An organization_id could not be found, if you already have an organization_id input it now.\n\nOr leave blank and click 'OK' to create a new organization"
);
if (organization_id) return organization_id;
if (organization_id === null)
return (Crud.socket.organization = "canceled");
Crud.socket.organization = "pending";
if (Indexeddb) {
try {
let org = { object: {} };
if (organization_id) org.object._id = organization_id;
let { organization, fileKey, user, key } = await generateDB(org);
if (organization && key && user) {
Crud.socket.apikey = key[0].key;
Crud.socket.user_id = user._id;
Config.set("organization_id", organization._id);
Config.set("apikey", key[0].key);
Config.set("user_id", user._id);
Crud.socket.organization = true;
saveLocally;
({ organization, user, key, fileKey });
return organization._id;
}
} catch (error) {
console.error("Failed to load the script:", error);
}
}
}
async function createOrganization() {
return (
organizationPromise ||
(organizationPromise = createOrganizationPromise())
);
}
async function create(action) {
let form = action.form;
if (!form) return;
let data = await Elements.getData(form);
let organization, user;
if (Array.isArray(data)) {
for (const item of data) {
if (item.array === "organizations") {
organization = item;
}
if (item.array === "users") {
user = item;
}
if (organization && user) {
break;
}
}
}
organization.method = "object.read";
organization = await Crud.send(organization);
user.method = "object.read";
user = await Crud.send(user);
if (organization && organization.object && organization.object[0]) {
organization = organization.object[0];
}
if (user && user.object && user.object[0]) {
user = user.object[0];
}
let objects = await generateDB(organization, user);
let organization_id = organization._id || objects.organization._id;
if (Crud.socket.organization !== true) {
Crud.socket.organization = true;
Crud.socket.create({ organization_id });
}
let response = await Crud.socket.send({
method: "createOrganization",
...objects,
broadcastBrowser: false
});
action.element.dispatchEvent(
new CustomEvent("createdOrganization", {
detail: response
})
);
}
async function createEnvironment(action) {
let form = action.form;
if (!form) return;
let organization = form.querySelector("#organization");
if (organization) {
organization = organization.value;
}
let hostname = form.querySelector("#hostname");
if (hostname) {
hostname = hostname.value;
hostname = ["dev." + hostname, "test." + hostname];
}
let response = await Crud.socket.send({
method: "createEnvironments",
organization,
hostname,
broadcastBrowser: false
});
action.element.dispatchEvent(
new CustomEvent("createdEnvironments", {
detail: response
})
);
}
Action.init({
name: "createOrganization",
endEvent: "createdOrganization",
callback: (action) => {
create(action);
}
});
Action.init({
name: "createEnvironments",
endEvent: "createdEnvironments",
callback: (action) => {
createEnvironment(action);
}
});
export default { generateDB, create, get };