finished
This commit is contained in:
175
decrypt.js
Normal file
175
decrypt.js
Normal file
@@ -0,0 +1,175 @@
|
||||
function TS_decrypt(input, secret, callback, table, id) {
|
||||
// Accept objects or plaintext strings. Also support legacy RSA{...} AES-encrypted entries.
|
||||
var __ts_sync = true;
|
||||
if (typeof input !== "string") {
|
||||
try {
|
||||
callback(input, false);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return __ts_sync;
|
||||
}
|
||||
|
||||
// Legacy encrypted format: RSA{...}
|
||||
if (
|
||||
input.startsWith("RSA{") &&
|
||||
input.endsWith("}") &&
|
||||
typeof CryptoJS !== "undefined"
|
||||
) {
|
||||
try {
|
||||
var data = input.slice(4, -1);
|
||||
var words = CryptoJS.AES.decrypt(data, secret);
|
||||
var decryptedUtf8 = null;
|
||||
try {
|
||||
decryptedUtf8 = words.toString(CryptoJS.enc.Utf8);
|
||||
} catch (utfErr) {
|
||||
// Malformed UTF-8 — try Latin1 fallback
|
||||
try {
|
||||
decryptedUtf8 = words.toString(CryptoJS.enc.Latin1);
|
||||
} catch (latinErr) {
|
||||
console.warn(
|
||||
"TS_decrypt: failed to decode decrypted bytes",
|
||||
utfErr,
|
||||
latinErr
|
||||
);
|
||||
try {
|
||||
callback(input, false);
|
||||
} catch (ee) {}
|
||||
return;
|
||||
}
|
||||
}
|
||||
var parsed = null;
|
||||
try {
|
||||
parsed = JSON.parse(decryptedUtf8);
|
||||
} catch (pe) {
|
||||
// If JSON parsing fails, the decrypted string may be raw Latin1 bytes.
|
||||
// Try to convert Latin1 byte string -> UTF-8 and parse again.
|
||||
try {
|
||||
if (
|
||||
typeof TextDecoder !== "undefined" &&
|
||||
typeof decryptedUtf8 === "string"
|
||||
) {
|
||||
var bytes = new Uint8Array(decryptedUtf8.length);
|
||||
for (var _i = 0; _i < decryptedUtf8.length; _i++)
|
||||
bytes[_i] = decryptedUtf8.charCodeAt(_i) & 0xff;
|
||||
var converted = new TextDecoder("utf-8").decode(bytes);
|
||||
try {
|
||||
parsed = JSON.parse(converted);
|
||||
decryptedUtf8 = converted;
|
||||
} catch (e2) {
|
||||
parsed = decryptedUtf8;
|
||||
}
|
||||
} else {
|
||||
parsed = decryptedUtf8;
|
||||
}
|
||||
} catch (convErr) {
|
||||
parsed = decryptedUtf8;
|
||||
}
|
||||
}
|
||||
try {
|
||||
callback(parsed, true);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
// Migrate to plaintext in DB if table/id provided
|
||||
if (table && id && window.DB && DB.put && typeof parsed !== "string") {
|
||||
DB.put(table, id, parsed).catch(() => {});
|
||||
}
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error("TS_decrypt: invalid encrypted payload", e);
|
||||
try {
|
||||
callback(input, false);
|
||||
} catch (ee) {}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (input.startsWith("SEA{") && input.endsWith("}")) {
|
||||
__ts_sync = false;
|
||||
SEA.decrypt(input, secret, (decrypted) => {
|
||||
try {
|
||||
callback(decrypted, true);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
return __ts_sync;
|
||||
}
|
||||
|
||||
// Try to parse JSON strings and migrate to object
|
||||
try {
|
||||
var parsed = JSON.parse(input);
|
||||
try {
|
||||
callback(parsed, false);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
if (table && id && window.DB && DB.put) {
|
||||
DB.put(table, id, parsed).catch(() => {});
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON, return raw string
|
||||
try {
|
||||
callback(input, false);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
return __ts_sync;
|
||||
}
|
||||
|
||||
function recursiveTSDecrypt(input, secret = "") {
|
||||
// Skip null values (do not show on decrypted output)
|
||||
if (input === null) return null;
|
||||
if (typeof input === "string") {
|
||||
let result = null;
|
||||
let resolver = null;
|
||||
const promise = new Promise((resolve) => {
|
||||
resolver = resolve;
|
||||
});
|
||||
const sync = TS_decrypt(input, secret, (decrypted) => {
|
||||
result = decrypted;
|
||||
if (resolver) resolver(decrypted);
|
||||
});
|
||||
if (sync === false) return promise;
|
||||
return result;
|
||||
} else if (Array.isArray(input)) {
|
||||
const mapped = input.map((item) => recursiveTSDecrypt(item, secret));
|
||||
if (mapped.some((v) => v && typeof v.then === "function")) {
|
||||
return Promise.all(mapped).then((values) => values.filter((v) => v !== null && typeof v !== 'undefined'));
|
||||
}
|
||||
return mapped.filter((v) => v !== null && typeof v !== 'undefined');
|
||||
} else if (typeof input === "object" && input !== null) {
|
||||
const keys = Object.keys(input);
|
||||
const mapped = keys.map((k) => recursiveTSDecrypt(input[k], secret));
|
||||
if (mapped.some((v) => v && typeof v.then === "function")) {
|
||||
return Promise.all(mapped).then((values) => {
|
||||
const out = {};
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const val = values[i];
|
||||
if (val !== null && typeof val !== 'undefined') out[keys[i]] = val;
|
||||
}
|
||||
return out;
|
||||
});
|
||||
} else {
|
||||
const out = {};
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const val = mapped[i];
|
||||
if (val !== null && typeof val !== 'undefined') out[keys[i]] = val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
gun.get(TABLE).load((DATA) => {
|
||||
var plain2 = recursiveTSDecrypt(DATA, SECRET);
|
||||
plain2.then(function (result) {
|
||||
download(
|
||||
`Export TeleSec ${GROUPID} Decrypted.json.txt`,
|
||||
JSON.stringify(result)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,12 @@ function tableScroll(query) {
|
||||
var container = document.getElementById("container");
|
||||
|
||||
function LinkAccount(LinkAccount_secret, refresh = false) {
|
||||
// Store group id for backward compatibility and keep secret
|
||||
localStorage.setItem("TELESEC_AUTO", "YES");
|
||||
SECRET = LinkAccount_secret.toUpperCase();
|
||||
localStorage.setItem("TELESEC_secret", SECRET);
|
||||
// Group identifier (no encryption). Secret usage removed.
|
||||
if (LinkAccount_secret) {
|
||||
SECRET = String(LinkAccount_secret).toUpperCase();
|
||||
} else {
|
||||
SECRET = "";
|
||||
}
|
||||
|
||||
if (refresh == true) {
|
||||
location.reload();
|
||||
@@ -30,17 +32,6 @@ function LinkAccount(LinkAccount_secret, refresh = false) {
|
||||
console.warn('DB.init failed or not available yet', e);
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem("TELESEC_AUTO") == "YES") {
|
||||
LinkAccount(
|
||||
localStorage.getItem("TELESEC_secret")
|
||||
);
|
||||
}
|
||||
if (urlParams.get("login") != null) {
|
||||
LinkAccount(
|
||||
urlParams.get("enc_password"),
|
||||
);
|
||||
//location.search = "";
|
||||
}
|
||||
|
||||
function open_page(params) {
|
||||
// Clear stored event listeners and timers
|
||||
@@ -153,11 +144,11 @@ function fixGunLocalStorage() {
|
||||
}
|
||||
|
||||
// Heartbeat: store a small "last seen" doc locally and replicate to remote when available
|
||||
setInterval(() => {
|
||||
if (typeof DB !== 'undefined') {
|
||||
DB.put('heartbeat', getDBName() || 'heartbeat', 'heartbeat-' + CurrentISOTime());
|
||||
}
|
||||
}, 5000);
|
||||
// setInterval(() => {
|
||||
// if (typeof DB !== 'undefined') {
|
||||
// DB.put('heartbeat', getDBName() || 'heartbeat', 'heartbeat-' + CurrentISOTime());
|
||||
// }
|
||||
// }, 5000);
|
||||
|
||||
|
||||
function betterSorter(a, b) {
|
||||
|
||||
@@ -313,6 +313,15 @@ function addCategory_Personas(
|
||||
btn.append(br2);
|
||||
var img = document.createElement("img");
|
||||
img.src = value.Foto || "static/ico/user_generic.png";
|
||||
// Prefer attachment 'foto' for this persona
|
||||
try {
|
||||
const personaKey = key;
|
||||
if (personaKey) {
|
||||
DB.getAttachment('personas', personaKey, 'foto').then((durl) => {
|
||||
if (durl) img.src = durl;
|
||||
}).catch(() => {});
|
||||
}
|
||||
} catch (e) {}
|
||||
img.style.height = "60px";
|
||||
img.style.padding = "5px";
|
||||
img.style.backgroundColor = "white";
|
||||
@@ -330,7 +339,16 @@ function addCategory_Personas(
|
||||
defaultval = key;
|
||||
span_0.innerText = "";
|
||||
var img_5 = document.createElement("img");
|
||||
img_5.src = value.Foto;
|
||||
img_5.src = value.Foto || "static/ico/user_generic.png";
|
||||
// Prefer attachment 'foto' when available
|
||||
try {
|
||||
const personaKey2 = key;
|
||||
if (personaKey2) {
|
||||
DB.getAttachment('personas', personaKey2, 'foto').then((durl) => {
|
||||
if (durl) img_5.src = durl;
|
||||
}).catch(() => {});
|
||||
}
|
||||
} catch (e) {}
|
||||
img_5.style.height = "30px";
|
||||
span_0.append(img_5, value.Nombre);
|
||||
change_cb(defaultval);
|
||||
@@ -537,29 +555,62 @@ const SC_actions = {
|
||||
],
|
||||
};
|
||||
// Listado precargado de personas:
|
||||
function TS_decrypt(input, secret, callback) {
|
||||
// Only support AES-based encrypted payloads in the format: RSA{<ciphertext>} or plain objects/strings
|
||||
if (typeof input != "string") {
|
||||
callback(input);
|
||||
} else if (input.startsWith("RSA{") && input.endsWith("}")) {
|
||||
var data = input.slice(4, -1);
|
||||
var decrypted = CryptoJS.AES.decrypt(data, secret).toString(CryptoJS.enc.Utf8);
|
||||
try {
|
||||
callback(JSON.parse(decrypted));
|
||||
} catch (e) {
|
||||
console.error('TS_decrypt: invalid JSON', e);
|
||||
callback(null);
|
||||
}
|
||||
} else {
|
||||
// plain string (settings, etc.)
|
||||
callback(input);
|
||||
function TS_decrypt(input, secret, callback, table, id) {
|
||||
// Accept objects or plaintext strings. Also support legacy RSA{...} AES-encrypted entries.
|
||||
if (typeof input !== "string") {
|
||||
try { callback(input, false); } catch (e) { console.error(e); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy encrypted format: RSA{...}
|
||||
if (input.startsWith("RSA{") && input.endsWith("}") && typeof CryptoJS !== 'undefined') {
|
||||
try {
|
||||
var data = input.slice(4, -1);
|
||||
var words = CryptoJS.AES.decrypt(data, secret);
|
||||
var decryptedUtf8 = null;
|
||||
try {
|
||||
decryptedUtf8 = words.toString(CryptoJS.enc.Utf8);
|
||||
} catch (utfErr) {
|
||||
// Malformed UTF-8 — try Latin1 fallback
|
||||
try {
|
||||
decryptedUtf8 = words.toString(CryptoJS.enc.Latin1);
|
||||
} catch (latinErr) {
|
||||
console.warn('TS_decrypt: failed to decode decrypted bytes', utfErr, latinErr);
|
||||
try { callback(input, false); } catch (ee) { }
|
||||
return;
|
||||
}
|
||||
}
|
||||
var parsed = null;
|
||||
try { parsed = JSON.parse(decryptedUtf8); } catch (pe) { parsed = decryptedUtf8; }
|
||||
try { callback(parsed, true); } catch (e) { console.error(e); }
|
||||
// Migrate to plaintext in DB if table/id provided
|
||||
if (table && id && window.DB && DB.put && typeof parsed !== 'string') {
|
||||
DB.put(table, id, parsed).catch(() => {});
|
||||
}
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error('TS_decrypt: invalid encrypted payload', e);
|
||||
try { callback(input, false); } catch (ee) { }
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse JSON strings and migrate to object
|
||||
try {
|
||||
var parsed = JSON.parse(input);
|
||||
try { callback(parsed, false); } catch (e) { console.error(e); }
|
||||
if (table && id && window.DB && DB.put) {
|
||||
DB.put(table, id, parsed).catch(() => {});
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON, return raw string
|
||||
try { callback(input, false); } catch (err) { console.error(err); }
|
||||
}
|
||||
}
|
||||
function TS_encrypt(input, secret, callback, mode = "RSA") {
|
||||
// Use AES symmetric encryption (RSA{} envelope for backwards compatibility)
|
||||
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(input), secret).toString();
|
||||
callback("RSA{" + encrypted + "}");
|
||||
}
|
||||
// Encryption removed: store plaintext objects directly
|
||||
try { callback(input); } catch (e) { console.error(e); }
|
||||
}
|
||||
// Populate SC_Personas from DB (PouchDB)
|
||||
DB.map('personas', (data, key) => {
|
||||
function add_row(data, key) {
|
||||
@@ -571,9 +622,9 @@ DB.map('personas', (data, key) => {
|
||||
}
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data, key);
|
||||
});
|
||||
}, 'personas', key);
|
||||
} else {
|
||||
add_row(data, key);
|
||||
}
|
||||
@@ -903,21 +954,19 @@ function TS_IndexElement(
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
data.Estado = state;
|
||||
TS_encrypt(data, SECRET, (encrypted) => {
|
||||
if (typeof ref === 'string') {
|
||||
DB.put(ref, data._key, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
// legacy
|
||||
ref.get(data._key).put(encrypted);
|
||||
toastr.success("Guardado!");
|
||||
} catch (e) {
|
||||
console.warn('Could not save item', e);
|
||||
}
|
||||
if (typeof ref === 'string') {
|
||||
DB.put(ref, data._key, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
} else {
|
||||
try {
|
||||
// legacy
|
||||
ref.get(data._key).put(data);
|
||||
toastr.success("Guardado!");
|
||||
} catch (e) {
|
||||
console.warn('Could not save item', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return button;
|
||||
@@ -992,6 +1041,17 @@ function TS_IndexElement(
|
||||
infoSpan.style.color = "black";
|
||||
const img = document.createElement("img");
|
||||
img.src = persona.Foto || "static/ico/user_generic.png";
|
||||
// Prefer attachment 'foto' stored in PouchDB if available
|
||||
try {
|
||||
const personaId = key.self === true ? (data._key || data._id || data.id) : data[key.key];
|
||||
if (personaId) {
|
||||
DB.getAttachment('personas', personaId, 'foto').then((durl) => {
|
||||
if (durl) img.src = durl;
|
||||
}).catch(() => {});
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
img.height = 70;
|
||||
infoSpan.appendChild(img);
|
||||
infoSpan.appendChild(document.createElement("br"));
|
||||
@@ -1033,9 +1093,9 @@ function TS_IndexElement(
|
||||
debounce(debounce_load, render, 300, [rows]);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data, key);
|
||||
});
|
||||
}, ref, key);
|
||||
} else {
|
||||
add_row(data, key);
|
||||
}
|
||||
@@ -1054,9 +1114,9 @@ function TS_IndexElement(
|
||||
debounce(debounce_load, render, 300, [rows]);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data, key);
|
||||
});
|
||||
}, undefined, undefined);
|
||||
} else {
|
||||
add_row(data, key);
|
||||
}
|
||||
@@ -1127,7 +1187,7 @@ function SetPages() {
|
||||
document.getElementById("appendApps2").append(a);
|
||||
}
|
||||
var Booted = false;
|
||||
var TimeoutBoot = 6;
|
||||
var TimeoutBoot = 3; // in loops of 750ms
|
||||
var BootLoops = 0;
|
||||
|
||||
function getPeers() {
|
||||
@@ -1220,12 +1280,10 @@ var BootIntervalID = setInterval(() => {
|
||||
}
|
||||
if (!data) {
|
||||
const persona = { Nombre: 'Admin (bypass)', Roles: 'ADMIN,' };
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', bypassId, encrypted).then(() => finish(persona, bypassId)).catch((e) => { console.warn('AC_BYPASS create error', e); open_page('login'); });
|
||||
});
|
||||
DB.put('personas', bypassId, persona).then(() => finish(persona, bypassId)).catch((e) => { console.warn('AC_BYPASS create error', e); open_page('login'); });
|
||||
} else {
|
||||
if (typeof data === 'string') {
|
||||
TS_decrypt(data, SECRET, (pdata) => finish(pdata, bypassId));
|
||||
TS_decrypt(data, SECRET, (pdata) => finish(pdata, bypassId), 'personas', bypassId);
|
||||
} else {
|
||||
finish(data, bypassId);
|
||||
}
|
||||
|
||||
92
src/db.js
92
src/db.js
@@ -10,6 +10,20 @@ var DB = (function () {
|
||||
let changes = null;
|
||||
let callbacks = {}; // table -> [cb]
|
||||
|
||||
function ensureLocal() {
|
||||
if (local) return;
|
||||
try {
|
||||
const localName = localStorage.getItem('TELESEC_COUCH_DBNAME') || 'telesec';
|
||||
local = new PouchDB(localName);
|
||||
if (changes) {
|
||||
try { changes.cancel(); } catch (e) {}
|
||||
changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('ensureLocal error', e);
|
||||
}
|
||||
}
|
||||
|
||||
function makeId(table, id) {
|
||||
return table + ':' + id;
|
||||
}
|
||||
@@ -47,6 +61,7 @@ var DB = (function () {
|
||||
}
|
||||
|
||||
function replicateToRemote() {
|
||||
ensureLocal();
|
||||
if (!local || !remote) return;
|
||||
PouchDB.replicate(local, remote, { live: true, retry: true }).on('error', function (err) {
|
||||
console.warn('Replication error', err);
|
||||
@@ -67,6 +82,7 @@ var DB = (function () {
|
||||
}
|
||||
|
||||
async function put(table, id, data) {
|
||||
ensureLocal();
|
||||
const _id = makeId(table, id);
|
||||
try {
|
||||
const existing = await local.get(_id).catch(() => null);
|
||||
@@ -89,6 +105,7 @@ var DB = (function () {
|
||||
}
|
||||
|
||||
async function get(table, id) {
|
||||
ensureLocal();
|
||||
const _id = makeId(table, id);
|
||||
try {
|
||||
const doc = await local.get(_id);
|
||||
@@ -103,6 +120,7 @@ var DB = (function () {
|
||||
}
|
||||
|
||||
async function list(table) {
|
||||
ensureLocal();
|
||||
try {
|
||||
const res = await local.allDocs({ include_docs: true, startkey: table + ':', endkey: table + ':\uffff' });
|
||||
return res.rows.map(r => {
|
||||
@@ -112,7 +130,62 @@ var DB = (function () {
|
||||
} catch (e) { return []; }
|
||||
}
|
||||
|
||||
// Convert data URL to Blob
|
||||
function dataURLtoBlob(dataurl) {
|
||||
const arr = dataurl.split(',');
|
||||
const mime = arr[0].match(/:(.*?);/)[1];
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return new Blob([u8arr], { type: mime });
|
||||
}
|
||||
|
||||
async function putAttachment(table, id, name, dataUrlOrBlob, contentType) {
|
||||
ensureLocal();
|
||||
const _id = makeId(table, id);
|
||||
try {
|
||||
let doc = await local.get(_id).catch(() => null);
|
||||
if (!doc) {
|
||||
// create a minimal doc so attachments can be put
|
||||
await local.put({ _id: _id, table: table, ts: new Date().toISOString(), data: {} });
|
||||
doc = await local.get(_id);
|
||||
}
|
||||
let blob = dataUrlOrBlob;
|
||||
if (typeof dataUrlOrBlob === 'string' && dataUrlOrBlob.indexOf('data:') === 0) {
|
||||
blob = dataURLtoBlob(dataUrlOrBlob);
|
||||
}
|
||||
const type = contentType || (blob && blob.type) || 'application/octet-stream';
|
||||
await local.putAttachment(_id, name, doc._rev, blob, type);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('putAttachment error', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getAttachment(table, id, name) {
|
||||
ensureLocal();
|
||||
const _id = makeId(table, id);
|
||||
try {
|
||||
const blob = await local.getAttachment(_id, name);
|
||||
if (!blob) return null;
|
||||
// convert blob to data URL
|
||||
return await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) { resolve(e.target.result); };
|
||||
reader.onerror = function (e) { reject(e); };
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function map(table, cb) {
|
||||
ensureLocal();
|
||||
callbacks[table] = callbacks[table] || [];
|
||||
callbacks[table].push(cb);
|
||||
// initial load
|
||||
@@ -131,8 +204,27 @@ var DB = (function () {
|
||||
list,
|
||||
map,
|
||||
replicateToRemote,
|
||||
putAttachment,
|
||||
getAttachment,
|
||||
_internal: { local }
|
||||
};
|
||||
})();
|
||||
|
||||
window.DB = DB;
|
||||
|
||||
// Auto-initialize DB on startup using saved settings (non-blocking)
|
||||
(function autoInitDB() {
|
||||
try {
|
||||
const remoteServer = localStorage.getItem('TELESEC_COUCH_URL') || '';
|
||||
const username = localStorage.getItem('TELESEC_COUCH_USER') || '';
|
||||
const password = localStorage.getItem('TELESEC_COUCH_PASS') || '';
|
||||
const dbname = localStorage.getItem('TELESEC_COUCH_DBNAME') || undefined;
|
||||
const secret = localStorage.getItem('TELESEC_secret') || '';
|
||||
// Call init but don't await; DB functions are safe-guarded with ensureLocal()
|
||||
DB.init({ secret, remoteServer, username, password, dbname }).catch((e) => {
|
||||
console.warn('DB.autoInit error', e);
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('DB.autoInit unexpected error', e);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -73,9 +73,9 @@ PAGES.aulas = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'comedor', CurrentISODate());
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
@@ -93,9 +93,9 @@ PAGES.aulas = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'notas', 'tareas');
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
@@ -113,9 +113,9 @@ PAGES.aulas = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'aulas_informes', 'diario-' + CurrentISODate());
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
@@ -191,9 +191,9 @@ PAGES.aulas = {
|
||||
document.getElementById(field_autor).value = data["Solicitante"] || SUB_LOGGED_IN_ID || "";
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'aulas_solicitudes', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
@@ -204,16 +204,14 @@ PAGES.aulas = {
|
||||
Contenido: document.getElementById(field_contenido).value,
|
||||
Asunto: document.getElementById(field_asunto).value,
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('aulas_solicitudes', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,solicitudes");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('aulas_solicitudes', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,solicitudes");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar esta solicitud?") == true) {
|
||||
@@ -338,16 +336,14 @@ PAGES.aulas = {
|
||||
Asunto: document.getElementById(field_asunto).value,
|
||||
Fecha: document.getElementById(field_fecha).value || CurrentISODate(),
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('aulas_informes', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,informes");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('aulas_informes', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,informes");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar este informe?") == true) {
|
||||
|
||||
@@ -114,9 +114,9 @@ PAGES.avisos = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'notificaciones', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
@@ -141,16 +141,14 @@ PAGES.avisos = {
|
||||
.getElementById(field_estado)
|
||||
.value.replace("%%", "por_leer"),
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('notificaciones', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("avisos");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('notificaciones', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("avisos");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar esta notificación?") == true) {
|
||||
|
||||
@@ -36,9 +36,9 @@ PAGES.comedor = {
|
||||
data["Platos"] || "";
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'comedor', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
@@ -55,16 +55,14 @@ PAGES.comedor = {
|
||||
DB.del('comedor', mid);
|
||||
}
|
||||
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('comedor', newDate, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("comedor");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('comedor', newDate, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("comedor");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar esta entrada?") == true) {
|
||||
|
||||
@@ -75,9 +75,9 @@ PAGES.dataman = {
|
||||
const value = entry.data;
|
||||
if (value != null) {
|
||||
if (typeof value == 'string') {
|
||||
TS_decrypt(value, SECRET, (data) => {
|
||||
TS_decrypt(value, SECRET, (data, wasEncrypted) => {
|
||||
output.materiales[key] = data;
|
||||
});
|
||||
}, 'materiales', key);
|
||||
} else {
|
||||
output.materiales[key] = value;
|
||||
}
|
||||
@@ -89,9 +89,9 @@ PAGES.dataman = {
|
||||
const value = entry.data;
|
||||
if (value != null) {
|
||||
if (typeof value == 'string') {
|
||||
TS_decrypt(value, SECRET, (data) => {
|
||||
TS_decrypt(value, SECRET, (data, wasEncrypted) => {
|
||||
output.personas[key] = data;
|
||||
});
|
||||
}, 'personas', key);
|
||||
} else {
|
||||
output.personas[key] = value;
|
||||
}
|
||||
@@ -168,12 +168,18 @@ PAGES.dataman = {
|
||||
var sel = document.getElementById(select_type).value;
|
||||
if (sel == "%telesec") {
|
||||
// legacy import, store entire payload as-is
|
||||
DB.put('%telesec', 'export_' + Date.now(), JSON.parse(val));
|
||||
// for each top-level key, store their items in DB
|
||||
var parsed = JSON.parse(val);
|
||||
Object.entries(parsed).forEach((section) => {
|
||||
const sectionName = section[0];
|
||||
const sectionData = section[1];
|
||||
Object.entries(sectionData).forEach((entry) => {
|
||||
DB.put(sectionName, entry[0], entry[1]).catch((e) => { console.warn('DB.put error', e); });
|
||||
});
|
||||
});
|
||||
} else {
|
||||
Object.entries(JSON.parse(val)["data"]).forEach((entry) => {
|
||||
var enc = TS_encrypt(entry[1], SECRET, (encrypted) => {
|
||||
DB.put(sel, entry[0], encrypted);
|
||||
});
|
||||
DB.put(sel, entry[0], entry[1]).catch((e) => { console.warn('DB.put error', e); });
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -101,10 +101,9 @@ PAGES.login = {
|
||||
document.getElementById(btn_bypass_create).onclick = () => {
|
||||
var name = prompt("Nombre de la persona (ej: Admin):");
|
||||
if (!name) return;
|
||||
var id = 'bypass-' + Date.now();
|
||||
var persona = { Nombre: name, Roles: 'ADMIN,' };
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', id, encrypted).then(() => {
|
||||
var id = 'bypass-' + Date.now();
|
||||
var persona = { Nombre: name, Roles: 'ADMIN,' };
|
||||
DB.put('personas', id, persona).then(() => {
|
||||
toastr.success('Persona creada: ' + id);
|
||||
localStorage.setItem('TELESEC_BYPASS_ID', id);
|
||||
SUB_LOGGED_IN_ID = id;
|
||||
@@ -115,7 +114,6 @@ PAGES.login = {
|
||||
}).catch((e) => {
|
||||
toastr.error('Error creando persona: ' + (e && e.message ? e.message : e));
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +74,9 @@ PAGES.materiales = {
|
||||
document.getElementById(field_notas).value = data["Notas"] || "";
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'materiales', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
@@ -91,16 +91,14 @@ PAGES.materiales = {
|
||||
Revision: document.getElementById(field_revision).value,
|
||||
Notas: document.getElementById(field_notas).value,
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('materiales', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("materiales");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('materiales', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("materiales");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar este material?") == true) {
|
||||
@@ -184,11 +182,11 @@ PAGES.materiales = {
|
||||
}
|
||||
|
||||
if (typeof data === "string") {
|
||||
TS_decrypt(data, SECRET, (dec) => {
|
||||
TS_decrypt(data, SECRET, (dec, wasEncrypted) => {
|
||||
if (dec && typeof dec === "object") {
|
||||
addUbicacion(dec);
|
||||
}
|
||||
});
|
||||
}, 'materiales', key);
|
||||
} else {
|
||||
addUbicacion(data);
|
||||
}
|
||||
|
||||
@@ -79,16 +79,14 @@ PAGES.notas = {
|
||||
Contenido: document.getElementById(field_contenido).value,
|
||||
Asunto: document.getElementById(field_asunto).value,
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('notas', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("notas");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('notas', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("notas");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (confirm("¿Quieres borrar esta nota?") == true) {
|
||||
|
||||
@@ -476,37 +476,32 @@ PAGES.pagos = {
|
||||
}
|
||||
|
||||
persona.Monedero_Balance = fixfloat(newBalance);
|
||||
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', personaId, encrypted).then(() => {
|
||||
if (callback) callback();
|
||||
});
|
||||
});
|
||||
DB.put('personas', personaId, persona).then(() => {
|
||||
if (callback) callback();
|
||||
}).catch((e) => { console.warn('DB.put error', e); if (callback) callback(); });
|
||||
}
|
||||
|
||||
function saveTransaction(ticketId, data) {
|
||||
TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('pagos', ticketId, encrypted).then(() => {
|
||||
// If this is from SuperCafé, update the order
|
||||
if (data.Origen === "SuperCafé" && data.OrigenID) {
|
||||
handleSuperCafePayment(data);
|
||||
}
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('pagos', ticketId, data).then(() => {
|
||||
// If this is from SuperCafé, update the order
|
||||
if (data.Origen === "SuperCafé" && data.OrigenID) {
|
||||
handleSuperCafePayment(data);
|
||||
}
|
||||
|
||||
// Check for promotional bonus on Ingreso transactions (Efectivo only)
|
||||
if (data.Tipo === "Ingreso" && data.Metodo === "Efectivo") {
|
||||
var bonusAmount = calculatePromoBonus(data.Monto);
|
||||
if (bonusAmount > 0) {
|
||||
createPromoBonusTransaction(data.Persona, bonusAmount, data.Monto);
|
||||
}
|
||||
// Check for promotional bonus on Ingreso transactions (Efectivo only)
|
||||
if (data.Tipo === "Ingreso" && data.Metodo === "Efectivo") {
|
||||
var bonusAmount = calculatePromoBonus(data.Monto);
|
||||
if (bonusAmount > 0) {
|
||||
createPromoBonusTransaction(data.Persona, bonusAmount, data.Monto);
|
||||
}
|
||||
}
|
||||
|
||||
toastr.success("¡Transacción completada!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + ticketId);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
toastr.success("¡Transacción completada!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + ticketId);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -555,16 +550,11 @@ PAGES.pagos = {
|
||||
var currentBalance = parseFloat(persona.Monedero_Balance || 0);
|
||||
var newBalance = currentBalance + bonusAmount;
|
||||
persona.Monedero_Balance = fixfloat(newBalance);
|
||||
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', personaId, encrypted);
|
||||
});
|
||||
DB.put('personas', personaId, persona).catch((e) => { console.warn('DB.put error', e); });
|
||||
}
|
||||
|
||||
// Save bonus transaction
|
||||
TS_encrypt(bonusData, SECRET, (encrypted) => {
|
||||
DB.put('pagos', bonusTicketId, encrypted);
|
||||
});
|
||||
DB.put('pagos', bonusTicketId, bonusData).catch((e) => { console.warn('DB.put error', e); });
|
||||
|
||||
toastr.success(
|
||||
"🎉 ¡Promo Bono aplicado! +" + bonusAmount.toFixed(2) + "€ extra"
|
||||
@@ -580,9 +570,7 @@ PAGES.pagos = {
|
||||
var persona = SC_Personas[transactionData.Persona];
|
||||
if (!persona) return;
|
||||
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', transactionData.Persona, encrypted);
|
||||
});
|
||||
DB.put('personas', transactionData.Persona, persona).catch((e) => { console.warn('DB.put error', e); });
|
||||
}
|
||||
|
||||
// Pre-fill if data provided
|
||||
@@ -847,12 +835,9 @@ PAGES.pagos = {
|
||||
}
|
||||
|
||||
persona.Monedero_Balance = fixfloat(newBalance);
|
||||
|
||||
TS_encrypt(persona, SECRET, (encrypted) => {
|
||||
DB.put('personas', personaId, encrypted).then(() => {
|
||||
if (callback) callback();
|
||||
});
|
||||
});
|
||||
DB.put('personas', personaId, persona).then(() => {
|
||||
if (callback) callback();
|
||||
}).catch((e) => { console.warn('DB.put error', e); if (callback) callback(); });
|
||||
}
|
||||
|
||||
function deleteTransaction(transactionKey) {
|
||||
@@ -1383,16 +1368,14 @@ PAGES.pagos = {
|
||||
delete updatedData.PersonaDestino;
|
||||
}
|
||||
|
||||
TS_encrypt(updatedData, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('pagos', transactionId, encrypted).then(() => {
|
||||
toastr.success("¡Transacción actualizada!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + transactionId);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('pagos', transactionId, updatedData).then(() => {
|
||||
toastr.success("¡Transacción actualizada!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + transactionId);
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
|
||||
// Cancel button
|
||||
|
||||
@@ -66,7 +66,7 @@ PAGES.personas = {
|
||||
<button type="button" id="${btn_ver_monedero}" class="btn5">Ver Transacciones del Monedero</button>
|
||||
</div>
|
||||
</details>
|
||||
<details style="background: #e3fde3ff; border: 2px solid #21f328ff; border-radius: 8px; padding: 10px; margin: 15px 0;">
|
||||
<details style="background: #e3fde3ff; border: 2px solid #21f328ff; border-radius: 8px; padding: 10px; margin: 15px 0; display: none;">
|
||||
<summary style="cursor: pointer; font-weight: bold; color: rgba(26, 141, 3, 1);">🔗 Generar enlaces</summary>
|
||||
<div style="padding: 15px;">
|
||||
<label>
|
||||
@@ -110,9 +110,16 @@ PAGES.personas = {
|
||||
document.getElementById(field_nombre).value = data["Nombre"] || "";
|
||||
document.getElementById(field_zona).value = data["Region"] || "";
|
||||
document.getElementById(field_anilla).value = data["SC_Anilla"] || "";
|
||||
document.getElementById(render_foto).src =
|
||||
data["Foto"] || "static/ico/user_generic.png";
|
||||
// set fallback image immediately
|
||||
document.getElementById(render_foto).src = data["Foto"] || "static/ico/user_generic.png";
|
||||
resized = data["Foto"] || "static/ico/user_generic.png";
|
||||
// try to load attachment 'foto' if present (preferred storage)
|
||||
DB.getAttachment('personas', mid, 'foto').then((durl) => {
|
||||
if (durl) {
|
||||
document.getElementById(render_foto).src = durl;
|
||||
resized = durl;
|
||||
}
|
||||
}).catch(() => {});
|
||||
document.getElementById(field_notas).value = data["markdown"] || "";
|
||||
document.getElementById(field_monedero_balance).value =
|
||||
data["Monedero_Balance"] || 0;
|
||||
@@ -120,29 +127,25 @@ PAGES.personas = {
|
||||
data["Monedero_Notas"] || "";
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'personas', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
});
|
||||
document
|
||||
.getElementById(field_foto)
|
||||
.addEventListener("change", function (e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
resizeInputImage(
|
||||
file,
|
||||
function (url) {
|
||||
document.getElementById(render_foto).src = url;
|
||||
resized = url;
|
||||
},
|
||||
256,
|
||||
0.7
|
||||
);
|
||||
});
|
||||
document.getElementById(field_foto).addEventListener("change", function (e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
// Do NOT resize — keep original uploaded image
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (ev) {
|
||||
const url = ev.target.result;
|
||||
document.getElementById(render_foto).src = url;
|
||||
resized = url;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
document.getElementById(btn_guardar).onclick = () => {
|
||||
var dt = new FormData(pdel);
|
||||
var data = {
|
||||
@@ -150,23 +153,28 @@ PAGES.personas = {
|
||||
Region: document.getElementById(field_zona).value,
|
||||
Roles: dt.getAll("perm").join(",") + ",",
|
||||
SC_Anilla: document.getElementById(field_anilla).value,
|
||||
Foto: resized,
|
||||
// Foto moved to PouchDB attachment named 'foto'
|
||||
markdown: document.getElementById(field_notas).value,
|
||||
Monedero_Balance:
|
||||
parseFloat(document.getElementById(field_monedero_balance).value) ||
|
||||
0,
|
||||
Monedero_Notas: document.getElementById(field_monedero_notas).value,
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('personas', mid, encrypted).then(() => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('personas', mid, data).then(() => {
|
||||
// if resized is a data URL (new/updated image), save as attachment
|
||||
var attachPromise = Promise.resolve(true);
|
||||
if (typeof resized === 'string' && resized.indexOf('data:') === 0) {
|
||||
attachPromise = DB.putAttachment('personas', mid, 'foto', resized, 'image/png');
|
||||
}
|
||||
attachPromise.then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("personas");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
}).catch((e) => { console.warn('putAttachment error', e); document.getElementById("actionStatus").style.display = "none"; });
|
||||
}).catch((e) => { console.warn('DB.put error', e); document.getElementById("actionStatus").style.display = "none"; });
|
||||
};
|
||||
document.getElementById(btn_ver_monedero).onclick = () => {
|
||||
setUrlHash("pagos"); // Navigate to pagos and show transactions for this person
|
||||
|
||||
@@ -51,9 +51,9 @@ PAGES.resumen_diario = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'comedor', CurrentISODate());
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
@@ -71,9 +71,9 @@ PAGES.resumen_diario = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'notas', 'tareas');
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
@@ -91,9 +91,9 @@ PAGES.resumen_diario = {
|
||||
);
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
add_row(data || {});
|
||||
});
|
||||
}, 'aulas_informes', 'diario-' + CurrentISODate());
|
||||
} else {
|
||||
add_row(data || {});
|
||||
}
|
||||
|
||||
@@ -91,9 +91,9 @@ PAGES.supercafe = {
|
||||
loadActions();
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
TS_decrypt(data, SECRET, (data, wasEncrypted) => {
|
||||
load_data(data, "%E");
|
||||
});
|
||||
}, 'supercafe', mid);
|
||||
} else {
|
||||
load_data(data || {});
|
||||
}
|
||||
@@ -112,16 +112,14 @@ PAGES.supercafe = {
|
||||
.getElementById(field_estado)
|
||||
.value.replace("%%", "Pedido"),
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('supercafe', mid, encrypted).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("supercafe");
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
});
|
||||
document.getElementById("actionStatus").style.display = "block";
|
||||
DB.put('supercafe', mid, data).then(() => {
|
||||
toastr.success("Guardado!");
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("supercafe");
|
||||
}, SAVE_WAIT);
|
||||
}).catch((e) => { console.warn('DB.put error', e); });
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user