+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wco/privatri/message.mustache b/wco/privatri/message.mustache
new file mode 100644
index 0000000..9aa563f
--- /dev/null
+++ b/wco/privatri/message.mustache
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/wco/privatri/privatri.js b/wco/privatri/privatri.js
index a7baf37..b001e84 100644
--- a/wco/privatri/privatri.js
+++ b/wco/privatri/privatri.js
@@ -1,25 +1,754 @@
var apx = apx || {};
+
apx.privatri = {};
-apx.privatri.loadwco = async (id, ctx) => {
- // check if not authenticate, do nothing cause by default screensignin and wait authentification
- // if authenticate, if url xhash then redirect if no url then change wco-link=screenmyworld
- // if (dayjs(apx.data.headers.xdays).diff(dayjs(), "hours") >= 24) apx.apxauth.checkisauth();
- //load main.mustache of the component
- //when wco-xxx change it run this function
- console.log(
- `Load wconame:privatri apx.privatri.loadwco with id:${id} and ctx: ${JSON.stringify(
- ctx
- )}`
- );
- //refresh thread from BE
- const threadlist = apx.privatri.getthread(apx.data.headers.xalias,1000000)
- const tpldataname = `${apx.data.pagename}_${id}_privatri`;
- const privatriid = document.getElementById(id);
- privatriid.innerHTML = Mustache.render(apx.data.tpl.privatrimain, threadlist);
+apx.privatri.templates = {};
-}
+apx.privatri.loadwco = async (id, dataObj = {}, ctx = null) => {
+ // check if not authenticate, do nothing cause by default screensignin and wait authentification
+ // if authenticate, if url xhash then redirect if no url then change wco-link=screenmyworld
+ // if (dayjs(apx.data.headers.xdays).diff(dayjs(), "hours") >= 24) apx.apxauth.checkisauth();
+ //load main.mustache of the component
+ //when wco-xxx change it run this function
+ console.log(
+ `Load wconame:privatri apx.privatri.loadwco with id:${id} and ctx: ${JSON.stringify(
+ ctx
+ )}`
+ );
+
+ const template = JSON.parse(localStorage.getItem("admin")).tpl[`privatri${id}`];
+
+ return Mustache.render(template, dataObj);
+};
-apx.privatri.getthread=async(alias,timestamp)=>{
- //store in indexdb the thread
- return true
-}
\ No newline at end of file
+apx.privatri.syncronizeBackend = async (alias, lastConnection) => {
+ // const response = await fetch
+ const response = [];
+
+ for (const message of response) {
+ await apx.indexedDB.set("privatri", "messages", message);
+ };
+};
+
+apx.privatri.templates.scripts = {
+ createThread: async () => {
+ const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn");
+
+ autoDeletionBtnElArray.forEach(btn => {
+ btn.addEventListener("click", () => {
+ autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200"));
+ btn.classList.add("bg-base-200");
+ });
+ });
+
+ document.querySelector("#createThreadBtn").addEventListener("click", async () => {
+ const { publicKey, privateKey } = await apx.crypto.genKey();
+
+ const messageObj = await (async (publicKey) => {
+ const uuid = crypto.randomUUID();
+ const timestamp = Date.now();
+ const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("apx")).data.headers.xalias, publicKey);
+
+ return {
+ privatriid: `${uuid}_${timestamp}`,
+ thread: uuid,
+ timestamp: timestamp,
+ owner: alias,
+ title: await apx.crypto.encryptMessage(document.querySelector("#threadNameInput").value, publicKey),
+ sender_alias: alias,
+ publicKey: publicKey,
+ aliases: [
+ alias
+ ],
+ message: await apx.crypto.encryptMessage(document.querySelector("#threadDescriptionInput").value, publicKey),
+ dt_autodestruction: (() => {
+ const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200"));
+ return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10);
+ })(),
+ urgencydeletion: document.querySelector('input[type="checkbox"].toggle').checked
+ };
+ })(publicKey);
+
+ // Faire un post sur l'endpoint /privatri
+
+ await apx.indexedDB.set("privatri", "threads", { uuid: messageObj.thread, privateKey: privateKey });
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+ });
+ },
+ inviteAlias: async () => {
+ const url = "https://www.facebook.com/";
+
+ const bodyEl = document.querySelector("body");
+ const qrCodeCanvasEl = document.querySelector("#qrCodeCanvas");
+ const invitationLinkInputEl = document.querySelector("#invitationLinkInput");
+
+ const displayToastAlert = async (message) => {
+ return await apx.privatri.loadwco("toastAlert", { message });
+ };
+
+ const qrCode = new QRCodeStyling({
+ width: 425,
+ height: 425,
+ type: "svg",
+ data: url,
+ image: "./assets/icon.png",
+ dotsOptions: {
+ color: "#ffffff",
+ type: "rounded"
+ },
+ backgroundOptions: {
+ color: getComputedStyle(bodyEl).backgroundColor || "#000000",
+ },
+ imageOptions: {
+ crossOrigin: "anonymous",
+ margin: 20
+ }
+ });
+
+ qrCode.append(qrCodeCanvasEl);
+
+ invitationLinkInputEl.value = url;
+
+ copyBtn.addEventListener("click", async () => {
+ navigator.clipboard.writeText(invitationLinkInputEl.value);
+
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("Invitation link copied to clipboard."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ });
+ },
+ threadAliasList: async () => {
+ const bodyEl = document.querySelector("body");
+ const aliasListContainerEl = document.querySelector("#aliasListContainer");
+
+ let aliasesArray = [];
+
+ const newAlias = async (alias) => {
+ return await apx.privatri.loadwco("alias", { alias });
+ };
+
+ const displayToastAlert = async (message) => {
+ return await apx.privatri.loadwco("toastAlert", { message });
+ };
+
+ const params = new URLSearchParams(window.location.search);
+ const uuid = params.get("uuid");
+
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey;
+
+ const privatriidArray = await getOldestPrivatriids("privatri", "messages");
+
+ privatriidArray.forEach(async privatriid => {
+ if (privatriid.split("_")[0] === uuid) {
+ aliasesArray = (await apx.indexedDB.get("privatri", "messages", privatriid)).aliases;
+ const ownerAlias = (await apx.indexedDB.get("privatri", "messages", privatriid)).owner;
+
+ for (const alias of aliasesArray) {
+ aliasListContainerEl.insertAdjacentHTML("beforeend", await newAlias({
+ decrypted: (await apx.crypto.decryptMessage(alias, privateKey)).data,
+ crypted: alias
+ }));
+ };
+
+ document.querySelectorAll("button.removeAliasBtn").forEach(btn => {
+ btn.addEventListener("click", async () => {
+ if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) {
+ if (btn.getAttribute("data-alias") !== ownerAlias) {
+ const alias = btn.getAttribute("data-alias");
+ aliasesArray = aliasesArray.filter(a => a !== alias);
+ btn.parentElement.parentElement.remove();
+
+ privatriidArray.forEach(async privatriid => {
+ if (privatriid.split("_")[0] === uuid) {
+ const messageObj = await apx.indexedDB.get("privatri", "messages", privatriid);
+ messageObj.aliases = aliasesArray;
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+ };
+ });
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You cannot remove the owner of the thread."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to remove this alias."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+ });
+ });
+ };
+ });
+ },
+ threadSettings: async () => {
+ const bodyEl = document.querySelector("body");
+ const threadNameInputEl = document.querySelector("#threadNameInput");
+ const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn");
+ const applyModificationsBtnEl = document.querySelector("#applyModificationsBtn");
+
+ const displayToastAlert = async (message) => {
+ return await apx.privatri.loadwco("toastAlert", { message });
+ };
+
+ let messageObj = {};
+
+ const params = new URLSearchParams(window.location.search);
+ const uuid = params.get("uuid");
+
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey;
+
+ const privatriidArray = await getOldestPrivatriids("privatri", "messages");
+ let ownerAlias = "";
+
+ privatriidArray.forEach(async privatriid => {
+ if (privatriid.split("_")[0] === uuid) {
+ messageObj = await apx.indexedDB.get("privatri", "messages", privatriid);
+ ownerAlias = messageObj.owner;
+
+ threadNameInputEl.value = (await apx.crypto.decryptMessage(messageObj.title, privateKey)).data;
+
+ (Array.from(autoDeletionBtnElArray).find(el => el.getAttribute("data-auto-deletion") === String(messageObj.dt_autodestruction))).classList.add("bg-base-200");
+
+ if (messageObj.urgencydeletion === true) {
+ document.querySelector('input[type="checkbox"].toggle').checked = true;
+ };
+ };
+ });
+
+ applyModificationsBtnEl.addEventListener("click", async () => {
+ if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) {
+ messageObj.title = await apx.crypto.encryptMessage(threadNameInputEl.value, privateKey);
+ messageObj.dt_autodestruction = (() => {
+ const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200"));
+ return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10);
+ })();
+ messageObj.urgencydeletion = document.querySelector('input[type="checkbox"].toggle').checked;
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this thread."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+ });
+
+ autoDeletionBtnElArray.forEach(btn => {
+ btn.addEventListener("click", () => {
+ autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200"));
+ btn.classList.add("bg-base-200");
+ });
+ });
+ }
+};
+
+async function getOldestPrivatriids(dbName, storeName) {
+ return new Promise((resolve, reject) => {
+ const request = indexedDB.open(dbName, 1);
+
+ request.onsuccess = (event) => {
+ const db = event.target.result;
+
+ const transaction = db.transaction(storeName, "readonly");
+ const store = transaction.objectStore(storeName);
+ const cursorRequest = store.openCursor();
+ const uuidMap = {};
+
+ cursorRequest.onsuccess = (event) => {
+ const cursor = event.target.result;
+ if (cursor) {
+ const obj = cursor.value;
+
+ const [uuid, timestamp] = obj.privatriid.split("_");
+
+ if (!uuidMap[uuid] || Number(timestamp) < uuidMap[uuid].timestamp) {
+ uuidMap[uuid] = { privatriid: obj.privatriid, timestamp: Number(timestamp) };
+ };
+
+ cursor.continue();
+ } else {
+ const result = Object.values(uuidMap).map(event => event.privatriid);
+
+ resolve(result);
+ };
+ };
+
+ cursorRequest.onerror = (event) => reject(event);
+ };
+
+ request.onerror = (event) => reject(event);
+ });
+};
+
+apx.ready(async () => {
+ await (async () => {
+ console.log("ok")
+ document.querySelector("body").innerHTML = await apx.privatri.loadwco("main");
+
+ const lastConnection = JSON.parse(localStorage.getItem("lastConnection")) || Date.now();
+
+ await apx.privatri.syncronizeBackend(apx.data.headers.xalias, lastConnection);
+
+ const privatriidArray = await getOldestPrivatriids("privatri", "messages");
+
+ const thread = async (name, uuid) => {
+ return await apx.privatri.loadwco("threadAliasList", { uuid, name });
+ };
+
+ for (const privatriid of privatriidArray) {
+ const obj = await apx.indexedDB.get("privatri", "messages", privatriid)
+
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", obj.thread)).privateKey;
+ const name = (await apx.crypto.decryptMessage(obj.title, privateKey)).data;
+
+ threadsContainerEl.insertAdjacentHTML("beforeend", await thread(name, obj.thread));
+ };
+
+ Array.from(threadsContainerEl.children).forEach(child => {
+ child.addEventListener("click", async () => {
+ const uuid = child.getAttribute("data-uuid");
+
+ const messagesObj = await new Promise((resolve, reject) => {
+ const request = indexedDB.open("privatri", 1);
+
+ request.onsuccess = (event) => {
+ const db = event.target.result;
+
+ const transaction = db.transaction("messages", "readonly");
+ const store = transaction.objectStore("messages");
+ const cursorRequest = store.openCursor();
+
+ const result = [];
+ cursorRequest.onsuccess = (event) => {
+ const cursor = event.target.result;
+
+ if (cursor) {
+ const obj = cursor.value;
+ const keyUuid = obj.privatriid.split("_")[0];
+
+ if (keyUuid === uuid) {
+ result.push(obj);
+ };
+ cursor.continue();
+ } else {
+ resolve(result);
+ };
+ };
+
+ cursorRequest.onerror = (event) => reject(event);
+ };
+
+ request.onerror = (event) => reject(event);
+ });
+
+ threadPageEl.setAttribute("data-uuid", uuid);
+ threadPageEl.querySelector("#threadName").innerText = (await apx.crypto.decryptMessage(messagesObj[0].title, (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey)).data;
+
+ messagesContainerEl.innerHTML = "";
+
+ let privateKey = "";
+
+ for (const message of messagesObj) {
+ if (privateKey === "") {
+ privateKey = (await apx.indexedDB.get("privatri", "threads", message.thread)).privateKey;
+ };
+
+ const decryptedMessage = (await apx.crypto.decryptMessage(message.message, privateKey)).data;
+
+ let decryptedAttachments = [];
+
+ if (message.attachments !== undefined) {
+ decryptedAttachments = await (async () => {
+ const attachmentsArray = [];
+
+ if (message.attachments.length > 0) {
+ for (const attachment of message.attachments) {
+ attachmentsArray.push({
+ fileType: attachment.fileType,
+ filename: attachment.filename,
+ content: (await apx.crypto.decryptMessage(attachment.content, privateKey)).data
+ });
+ };
+ };
+
+ return attachmentsArray;
+ })();
+ };
+
+ messagesContainerEl.insertAdjacentHTML("beforeend", await sendNewMessage(message.timestamp, decryptedMessage, decryptedAttachments));
+ };
+ });
+ });
+
+ document.querySelectorAll("a").forEach(link => {
+ link.addEventListener("click", async (event) => {
+ event.preventDefault();
+
+ window.history.replaceState({}, document.title, window.location.pathname);
+
+ const templateName = link.getAttribute("data-template");
+
+ if (templateName === "threadAliasList" || templateName === "threadSettings") {
+ window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`);
+ };
+
+ bodyEl.firstElementChild.innerHTML = await apx.privatri.loadwco(templateName);
+
+ await apx.privatri.templates.scripts[templateName]();
+ });
+ });
+ })();
+
+ const bodyEl = document.querySelector("body");
+ const searchInputEl = document.querySelector("#threadSearchBar");
+ const threadFilterOptionsElArray = document.querySelector("#threadFilterOptions").querySelectorAll("li");
+ const threadsContainerEl = document.querySelector("#threadsContainer");
+ const threadPageEl = document.querySelector("#threadPage");
+ const messageInputEl = document.getElementById("messageInput");
+ const messagesContainerEl = document.querySelector("#messagesContainer");
+ const attachmentsInputEl = document.querySelector("#attachmentsInput");
+
+ function formatDate(timestamp) {
+ const date = new Date(timestamp);
+ const day = String(date.getDate()).padStart(2, "0");
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const year = date.getFullYear();
+ const hours = String(date.getHours()).padStart(2, "0");
+ const minutes = String(date.getMinutes()).padStart(2, "0");
+
+ return `${day}/${month}/${year} ${hours}:${minutes}`;
+ };
+
+ searchInputEl.addEventListener("input", () => {
+ const value = searchInputEl.value.toLowerCase();
+
+ Array.from(threadsContainerEl.children).forEach(child => {
+ if (child.querySelector("li > div").textContent.toLowerCase().includes(value)) {
+ child.style.display = "block";
+ } else {
+ child.style.display = "none";
+ };
+ });
+ });
+
+ threadFilterOptionsElArray.forEach(option => {
+ option.addEventListener("click", async () => {
+ const filter = option.getAttribute("data-filter");
+
+ if (filter === "date") {
+ Array.from(threadsContainerEl.children).sort((a, b) => {
+ return a.querySelector("li > span").getAttribute("data-timestamp") - b.querySelector("li > span").getAttribute("data-timestamp");
+ }).forEach(child => {
+ threadsContainerEl.appendChild(child);
+ });
+ } else if (filter === "name") {
+ Array.from(threadsContainerEl.children).sort((a, b) => {
+ return a.querySelector("li > div").textContent.localeCompare(b.querySelector("li > div").textContent);
+ }).forEach(child => {
+ threadsContainerEl.appendChild(child);
+ });
+ };
+ });
+ });
+
+ const sendNewMessage = async (timestamp, message, attachmentsArray) => {
+ const messageTemplate = await apx.privatri.loadwco("message", { timestamp, message, date: formatDate(timestamp) });
+
+ const tempNode = document.createElement("div");
+ tempNode.innerHTML = messageTemplate;
+ const messageNode = tempNode.firstElementChild;
+
+ attachmentsArray.forEach(attachment => {
+ messageNode.querySelector("div.attachmentsContainer").insertAdjacentHTML("beforeend", `
`);
+ });
+
+ return messageNode.outerHTML;
+ };
+
+ const editMessage = async (timestamp, message) => {
+ return await apx.privatri.loadwco("editMessage", { message, date: formatDate(timestamp) });
+ };
+
+ const displayToastAlert = async (message) => {
+ return await apx.privatri.loadwco("toastAlert", { message });
+ };
+
+ sendMessageBtn.addEventListener("click", async () => {
+ const message = messageInputEl.value.trim();
+
+ if (message !== "") {
+ const messageObj = await (async (publicKey) => {
+ const timestamp = Date.now();
+ const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("apx")).data.headers.xalias, publicKey);
+
+ return {
+ privatriid: `${threadPageEl.getAttribute("data-uuid")}_${timestamp}`,
+ timestamp: timestamp,
+ sender_alias: alias,
+ message: await apx.crypto.encryptMessage(message, publicKey),
+ attachments: await (async () => {
+ const attachmentsArray = [];
+ const localAttachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || [];
+
+ if (localAttachmentsArray.length > 0) {
+ for (const attachment of localAttachmentsArray) {
+ attachmentsArray.push(
+ {
+ fileType: attachment.fileType,
+ filename: attachment.filename,
+ content: await apx.crypto.encryptMessage(attachment.content, publicKey)
+ }
+ );
+ };
+ };
+
+ return attachmentsArray;
+ })()
+ };
+ })((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messagesContainerEl.firstElementChild.getAttribute("data-timestamp")}`)).publicKey);
+
+ const newMessageHTML = await sendNewMessage(messageObj.timestamp, message, JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || []);
+
+ sessionStorage.removeItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`);
+
+ messagesContainerEl.insertAdjacentHTML("beforeend", newMessageHTML);
+
+ messageInputEl.value = "";
+
+ // Faire un post sur l'endpoint /privatri
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+ };
+ });
+
+ window.addEventListener("beforeunload", () => {
+ // if (apx)
+ localStorage.setItem("lastConnection", JSON.stringify(Date.now()));
+ });
+
+ window.attachDeleteMessageEvent = async function attachDeleteMessageEvent(btn) {
+ const messageEl = btn.parentElement.parentElement.parentElement;
+
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey;
+
+ const signatureMessage = `${JSON.parse(localStorage.getItem("apx")).data.headers.xalias}_${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`;
+ const signature = await apx.crypto.sign(signatureMessage, privateKey);
+
+ let verified = false;
+
+ try {
+ verified = await fetch("", {
+ method: "GET",
+ body: JSON.stringify({
+ message: signatureMessage,
+ signature: signature,
+ uuid: threadPageEl.getAttribute("data-uuid"),
+ timestamp: messageEl.getAttribute("data-timestamp"),
+ })
+ });
+ } catch (error) {
+ console.error("Error while verifying signature:", error);
+ };
+
+ const authorAlias = await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, privateKey).data;
+
+ if ((JSON.parse(localStorage.getItem("apx")).data.headers.xalias === authorAlias) && (verified === true)) {
+ await apx.indexedDB.del("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageEl.remove();
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to delete this message."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+ };
+
+ window.attachEditMessageEvent = async function attachEditMessageEvent(btn) {
+ const messageEl = btn.parentElement.parentElement.parentElement;
+
+ const authorAlias = (await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey)).data;
+
+ if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === authorAlias) {
+ const messageValue = messageEl.querySelector("div.message").innerText;
+
+ const attachmentsArray = (() => {
+ const attachmentsArray = [];
+
+ messageEl.querySelector("div.attachmentsContainer").querySelectorAll("img").forEach(img => {
+ attachmentsArray.push(
+ {
+ fileType: img.getAttribute("src").match(/^data:(.*);base64,/)[1],
+ filename: img.getAttribute("alt"),
+ content: img.getAttribute("src").split(",")[1]
+ }
+ );
+ });
+
+ return attachmentsArray;
+ })();
+
+ messageEl.innerHTML = await editMessage(parseInt(messageEl.getAttribute("data-timestamp"), 10), messageEl.querySelector("div.message").innerText);
+
+ messageEl.querySelector("button.cancelEditBtn").addEventListener("click", async () => {
+ const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, messageValue, attachmentsArray);
+ });
+
+ messageEl.querySelector("button.saveEditBtn").addEventListener("click", async () => {
+ const newMessageValue = messageEl.querySelector("textarea").value.trim();
+
+ if (newMessageValue !== "") {
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey;
+
+ const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageObj.message = await apx.crypto.encryptMessage(newMessageValue, privateKey),
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+
+ messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, newMessageValue, attachmentsArray);
+ };
+ });
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this message."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+ };
+
+ window.attachEventDisplayAttachment = function(img) {
+ let overlay = document.getElementById("imageOverlay");
+
+ if (overlay === null) {
+ overlay = document.createElement('div');
+
+ overlay.id = "imageOverlay";
+ overlay.style.position = "fixed";
+ overlay.style.top = 0;
+ overlay.style.left = 0;
+ overlay.style.width = "100vw";
+ overlay.style.height = "100vh";
+ overlay.style.background = "rgba(0, 0, 0, 0.75)";
+ overlay.style.display = "flex";
+ overlay.style.alignItems = "center";
+ overlay.style.justifyContent = "center";
+ overlay.style.zIndex = 999;
+
+ overlay.onclick = () => {
+ overlay.remove();
+ };
+
+ document.body.appendChild(overlay);
+ } else {
+ overlay.innerHTML = "";
+ overlay.style.display = "flex";
+ };
+
+ const fullScreenImage = document.createElement("img");
+
+ fullScreenImage.src = img.src;
+ fullScreenImage.alt = img.alt;
+ fullScreenImage.style.maxWidth = "90vw";
+ fullScreenImage.style.maxHeight = "90vh";
+ overlay.appendChild(fullScreenImage);
+ };
+
+ document.querySelector("#attachmentsBtn").addEventListener("click", () => {
+ attachmentsInputEl.click();
+ });
+
+ attachmentsInputEl.addEventListener("change", async () => {
+ const filesArray = Array.from(attachmentsInputEl.files);
+ const maxFileSize = 5 * 1024 * 1024;
+ const maxSize = 512;
+
+ for (const file of filesArray) {
+ if (file.size <= maxFileSize) {
+ const attachmentObj = await new Promise((resolve, reject) => {
+ const attachmentObj = {
+ fileType: file.type,
+ filename: file.name,
+ content: ""
+ };
+
+ const img = new Image();
+
+ img.onload = () => {
+ if (img.width > maxSize || img.height > maxSize) {
+ let width = img.width;
+ let height = img.height;
+
+ if (width > maxSize) {
+ height *= maxSize / width;
+ width = maxSize;
+ };
+
+ if (height > maxSize) {
+ width *= maxSize / height;
+ height = maxSize;
+ };
+
+ const canvas = document.createElement("canvas");
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext("2d");
+
+ ctx.drawImage(img, 0, 0, width, height);
+
+ canvas.toBlob(blob => {
+ const reader = new FileReader();
+
+ reader.onload = (event) => {
+ attachmentObj.content = event.target.result.split(",")[1];
+
+ resolve(attachmentObj);
+ };
+
+ reader.onerror = reject;
+ reader.readAsDataURL(blob);
+ }, "image/jpeg", 0.8);
+ } else {
+ const reader = new FileReader();
+
+ reader.onload = (event) => {
+ attachmentObj.content = event.target.result.split(",")[1];
+
+ resolve(attachmentObj);
+ };
+
+ reader.onerror = reject;
+ reader.readAsDataURL(file);
+ };
+ };
+
+ img.onerror = reject;
+ img.src = URL.createObjectURL(file);
+
+ return attachmentObj;
+ });
+
+ if (sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`) === null) {
+ sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify([attachmentObj]));
+ } else {
+ const attachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`));
+ attachmentsArray.push(attachmentObj);
+
+ sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify(attachmentsArray));
+ };
+ };
+ };
+ });
+});
\ No newline at end of file
diff --git a/wco/privatri/thread.mustache b/wco/privatri/thread.mustache
new file mode 100644
index 0000000..2103725
--- /dev/null
+++ b/wco/privatri/thread.mustache
@@ -0,0 +1,7 @@
+
+
+
+ {{name}}
+ 17
+
+
\ No newline at end of file
diff --git a/wco/privatri/threadAliasList.mustache b/wco/privatri/threadAliasList.mustache
new file mode 100644
index 0000000..a42e90a
--- /dev/null
+++ b/wco/privatri/threadAliasList.mustache
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/wco/privatri/threadSettings.mustache b/wco/privatri/threadSettings.mustache
new file mode 100644
index 0000000..3ea3a91
--- /dev/null
+++ b/wco/privatri/threadSettings.mustache
@@ -0,0 +1,33 @@
+
+
Thread settings
+
+
+
+ Message auto destruction
+
+
+
+
+
+
+
+
Apply modifications
+
\ No newline at end of file
diff --git a/wco/privatri/toastAlert.mustache b/wco/privatri/toastAlert.mustache
new file mode 100644
index 0000000..00a4393
--- /dev/null
+++ b/wco/privatri/toastAlert.mustache
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/wwws/admin/src/static/lib/dayjs/plugin/arraySupport.d.ts b/wwws/admin/src/static/lib/dayjs/plugin/arraySupport.d.ts
old mode 100755
new mode 100644
diff --git a/wwws/admin/src/static/lib/dayjs/plugin/objectSupport.d.ts b/wwws/admin/src/static/lib/dayjs/plugin/objectSupport.d.ts
old mode 100755
new mode 100644
diff --git a/wwws/admin/src/tpldata/privatri_main_privatri.json b/wwws/admin/src/tpldata/privatri_main_privatri.json
index 1c240d9..90d4fee 100644
--- a/wwws/admin/src/tpldata/privatri_main_privatri.json
+++ b/wwws/admin/src/tpldata/privatri_main_privatri.json
@@ -1,19 +1,16 @@
{
- "menuapp": [
+ "appOptions": [
{
"onclick": "onclick='apx.privatri.notificationsMenu();'",
- "title": "Notification",
- "comment": "./notificationsMenu.html"
+ "title": "Notifications"
},
{
- "onclick": "onclick='apx.privatri.addthread();'",
- "title": "Nouveau fil",
- "comment": "./newMenu3.html"
+ "title": "New thread",
+ "template": "createThread"
},
{
- "onclick": "href='apxid_fr.html'",
- "title": "Compte",
- "comment": ""
+ "title": "Account",
+ "template": ""
}
],
"searchplaceholder": "Recherche parmis les fils",
@@ -26,5 +23,19 @@
"title": "Tri par NOM DE FIL",
"onclick": "onclick='apx.privatri.sortby('bytitlethread');'"
}
+ ],
+ "threadOptions": [
+ {
+ "title": "Invite an alias",
+ "template": "inviteAlias"
+ },
+ {
+ "title": "See all alias",
+ "template": "threadAliasList"
+ },
+ {
+ "title": "Settings",
+ "template": "threadSettings"
+ }
]
}
\ No newline at end of file
diff --git a/wwws/apx/src/static/lib/dayjs/plugin/arraySupport.d.ts b/wwws/apx/src/static/lib/dayjs/plugin/arraySupport.d.ts
old mode 100755
new mode 100644
diff --git a/wwws/apx/src/static/lib/dayjs/plugin/objectSupport.d.ts b/wwws/apx/src/static/lib/dayjs/plugin/objectSupport.d.ts
old mode 100755
new mode 100644
diff --git a/wwws/itm/admin.json b/wwws/itm/admin.json
index 05cc34e..f5ae830 100644
--- a/wwws/itm/admin.json
+++ b/wwws/itm/admin.json
@@ -80,10 +80,21 @@
"anonymous"
],
"tpl": {
- "privatrimain": "apxtri/objects/wco/privatri/main.mustache"
+ "privatrimain": "apxtri/objects/wco/privatri/main.mustache",
+ "privatriAlias": "apxtri/objects/wco/privatri/alias.mustache",
+ "privatriCreateThread": "apxtri/objects/wco/privatri/createThread.mustache",
+ "privatriEditMessage": "apxtri/objects/wco/privatri/editMessage.mustache",
+ "privatriInviteAlias": "apxtri/objects/wco/privatri/inviteAlias.mustache",
+ "privatriMessage": "apxtri/objects/wco/privatri/message.mustache",
+ "privatriThread": "apxtri/objects/wco/privatri/thread.mustache",
+ "privatriThreadAlias": "apxtri/objects/wco/privatri/threadAlias.mustache",
+ "privatriThreadSettings": "apxtri/objects/wco/privatri/threadSettings.mustache",
+ "privatriToastAlert": "apxtri/objects/wco/privatri/toastAlert.mustache",
+ "privatriThreadAliasList": "apxtri/objects/wco/privatri/threadAliasList.mustache"
},
"tpldata": {
- "privatri_main_privatri": "apxtri/objects/wwws/admin/src/tpldata/privatri_main_privatri"
+ "privatri_main_privatri": "apxtri/objects/wwws/admin/src/tpldata/privatri_main_privatri",
+ "privatri_privatrimain_privatri": "apxtri/objects/wwws/admin/src/tpldata/privatri_privatrimain_privatri"
},
"schema": [],
"ref": {