Merge branch 'main' into add-user-persona-creation-feature
This commit is contained in:
@@ -88,6 +88,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<p id="activePersonaStatus" class="status persona-status">No persona equipped.</p>
|
<p id="activePersonaStatus" class="status persona-status">No persona equipped.</p>
|
||||||
<div id="personaList" class="persona-list"></div>
|
<div id="personaList" class="persona-list"></div>
|
||||||
|
<form id="personaForm" class="persona-form hidden">
|
||||||
|
<h3 id="personaFormTitle">Create persona</h3>
|
||||||
|
<label class="field">
|
||||||
|
<span>Name</span>
|
||||||
|
<input id="personaName" placeholder="Persona name" required/>
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span>Pronouns</span>
|
||||||
|
<input id="personaPronouns" placeholder="e.g. she/her, they/them"/>
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span>Appearance</span>
|
||||||
|
<textarea id="personaAppearance" rows="2" placeholder="Describe their look"></textarea>
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span>Background</span>
|
||||||
|
<textarea id="personaBackground" rows="2" placeholder="Backstory or origins"></textarea>
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span>Details</span>
|
||||||
|
<textarea id="personaDetails" rows="3"
|
||||||
|
placeholder="Personality traits, voice, or quirks"></textarea>
|
||||||
|
</label>
|
||||||
|
<div class="persona-actions">
|
||||||
|
<button id="personaSave" type="submit" class="primary-action">Save persona</button>
|
||||||
|
<button id="personaCancel" type="button" class="secondary-action">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
<section class="chat-main">
|
<section class="chat-main">
|
||||||
|
|||||||
+4
-74
@@ -28,10 +28,6 @@ const personaPronounsInput = document.getElementById("personaPronouns");
|
|||||||
const personaAppearanceInput = document.getElementById("personaAppearance");
|
const personaAppearanceInput = document.getElementById("personaAppearance");
|
||||||
const personaBackgroundInput = document.getElementById("personaBackground");
|
const personaBackgroundInput = document.getElementById("personaBackground");
|
||||||
const personaDetailsInput = document.getElementById("personaDetails");
|
const personaDetailsInput = document.getElementById("personaDetails");
|
||||||
const personaModal = document.getElementById("personaModal");
|
|
||||||
const personaCloseBtn = document.getElementById("personaClose");
|
|
||||||
const addCustomFieldBtn = document.getElementById("addCustomField");
|
|
||||||
const customFieldsList = document.getElementById("customFieldsList");
|
|
||||||
const newPersonaBtn = document.getElementById("newPersona");
|
const newPersonaBtn = document.getElementById("newPersona");
|
||||||
const clearPersonaBtn = document.getElementById("clearPersona");
|
const clearPersonaBtn = document.getElementById("clearPersona");
|
||||||
const personaCancelBtn = document.getElementById("personaCancel");
|
const personaCancelBtn = document.getElementById("personaCancel");
|
||||||
@@ -198,7 +194,7 @@ function setActivePersonaStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openPersonaForm(persona = null) {
|
function openPersonaForm(persona = null) {
|
||||||
personaModal.classList.remove('hidden');
|
personaForm.classList.remove('hidden');
|
||||||
if (persona) {
|
if (persona) {
|
||||||
editingPersonaId = persona.id;
|
editingPersonaId = persona.id;
|
||||||
personaFormTitle.textContent = 'Edit persona';
|
personaFormTitle.textContent = 'Edit persona';
|
||||||
@@ -207,7 +203,6 @@ function openPersonaForm(persona = null) {
|
|||||||
personaAppearanceInput.value = persona.appearance || '';
|
personaAppearanceInput.value = persona.appearance || '';
|
||||||
personaBackgroundInput.value = persona.background || '';
|
personaBackgroundInput.value = persona.background || '';
|
||||||
personaDetailsInput.value = persona.details || '';
|
personaDetailsInput.value = persona.details || '';
|
||||||
renderCustomFields(persona.customFields || []);
|
|
||||||
} else {
|
} else {
|
||||||
editingPersonaId = null;
|
editingPersonaId = null;
|
||||||
personaFormTitle.textContent = 'Create persona';
|
personaFormTitle.textContent = 'Create persona';
|
||||||
@@ -216,60 +211,15 @@ function openPersonaForm(persona = null) {
|
|||||||
personaAppearanceInput.value = '';
|
personaAppearanceInput.value = '';
|
||||||
personaBackgroundInput.value = '';
|
personaBackgroundInput.value = '';
|
||||||
personaDetailsInput.value = '';
|
personaDetailsInput.value = '';
|
||||||
renderCustomFields([]);
|
|
||||||
}
|
}
|
||||||
personaNameInput.focus();
|
personaNameInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function closePersonaForm() {
|
function closePersonaForm() {
|
||||||
personaModal.classList.add('hidden');
|
personaForm.classList.add('hidden');
|
||||||
editingPersonaId = null;
|
editingPersonaId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCustomFields(fields) {
|
|
||||||
customFieldsList.innerHTML = '';
|
|
||||||
fields.forEach((field, index) => {
|
|
||||||
addCustomFieldRow(field.label || '', field.value || '', index);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCustomFieldRow(label = '', value = '') {
|
|
||||||
const row = document.createElement('div');
|
|
||||||
row.className = 'custom-field-row';
|
|
||||||
|
|
||||||
const labelInput = document.createElement('input');
|
|
||||||
labelInput.type = 'text';
|
|
||||||
labelInput.placeholder = 'Label';
|
|
||||||
labelInput.value = label;
|
|
||||||
|
|
||||||
const valueInput = document.createElement('input');
|
|
||||||
valueInput.type = 'text';
|
|
||||||
valueInput.placeholder = 'Value';
|
|
||||||
valueInput.value = value;
|
|
||||||
|
|
||||||
const removeBtn = document.createElement('button');
|
|
||||||
removeBtn.type = 'button';
|
|
||||||
removeBtn.textContent = 'Remove';
|
|
||||||
removeBtn.className = 'secondary-action';
|
|
||||||
removeBtn.addEventListener('click', () => row.remove());
|
|
||||||
|
|
||||||
row.appendChild(labelInput);
|
|
||||||
row.appendChild(valueInput);
|
|
||||||
row.appendChild(removeBtn);
|
|
||||||
customFieldsList.appendChild(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
function collectCustomFields() {
|
|
||||||
const rows = customFieldsList.querySelectorAll('.custom-field-row');
|
|
||||||
return Array.from(rows).map(row => {
|
|
||||||
const [labelInput, valueInput] = row.querySelectorAll('input');
|
|
||||||
return {
|
|
||||||
label: labelInput.value.trim(),
|
|
||||||
value: valueInput.value.trim()
|
|
||||||
};
|
|
||||||
}).filter(field => field.label || field.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderPersonaList() {
|
function renderPersonaList() {
|
||||||
personaList.innerHTML = '';
|
personaList.innerHTML = '';
|
||||||
if (!personas.length) {
|
if (!personas.length) {
|
||||||
@@ -321,10 +271,7 @@ function renderPersonaList() {
|
|||||||
async function loadPersonas() {
|
async function loadPersonas() {
|
||||||
const res = await get('/personas');
|
const res = await get('/personas');
|
||||||
if (res.error) return;
|
if (res.error) return;
|
||||||
personas = (res.personas || []).map(persona => ({
|
personas = res.personas || [];
|
||||||
...persona,
|
|
||||||
customFields: persona.customFields || []
|
|
||||||
}));
|
|
||||||
activePersonaId = res.activePersonaId || null;
|
activePersonaId = res.activePersonaId || null;
|
||||||
renderPersonaList();
|
renderPersonaList();
|
||||||
}
|
}
|
||||||
@@ -349,8 +296,7 @@ async function savePersona() {
|
|||||||
pronouns: personaPronounsInput.value.trim(),
|
pronouns: personaPronounsInput.value.trim(),
|
||||||
appearance: personaAppearanceInput.value.trim(),
|
appearance: personaAppearanceInput.value.trim(),
|
||||||
background: personaBackgroundInput.value.trim(),
|
background: personaBackgroundInput.value.trim(),
|
||||||
details: personaDetailsInput.value.trim(),
|
details: personaDetailsInput.value.trim()
|
||||||
customFields: collectCustomFields()
|
|
||||||
};
|
};
|
||||||
if (!payload.name) return;
|
if (!payload.name) return;
|
||||||
let res;
|
let res;
|
||||||
@@ -374,12 +320,6 @@ async function deletePersona(personaId) {
|
|||||||
await loadPersonas();
|
await loadPersonas();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', (event) => {
|
|
||||||
if (event.key === 'Escape' && !personaModal.classList.contains('hidden')) {
|
|
||||||
closePersonaForm();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function setLoadingState(loading) {
|
function setLoadingState(loading) {
|
||||||
isProcessing = loading;
|
isProcessing = loading;
|
||||||
sendBtn.disabled = loading;
|
sendBtn.disabled = loading;
|
||||||
@@ -650,16 +590,6 @@ newPersonaBtn.addEventListener('click', () => openPersonaForm());
|
|||||||
|
|
||||||
personaCancelBtn.addEventListener('click', () => closePersonaForm());
|
personaCancelBtn.addEventListener('click', () => closePersonaForm());
|
||||||
|
|
||||||
personaCloseBtn.addEventListener('click', () => closePersonaForm());
|
|
||||||
|
|
||||||
personaModal.addEventListener('click', (event) => {
|
|
||||||
if (event.target === personaModal) {
|
|
||||||
closePersonaForm();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addCustomFieldBtn.addEventListener('click', () => addCustomFieldRow());
|
|
||||||
|
|
||||||
clearPersonaBtn.addEventListener('click', () => clearPersona());
|
clearPersonaBtn.addEventListener('click', () => clearPersona());
|
||||||
|
|
||||||
personaForm.addEventListener('submit', (event) => {
|
personaForm.addEventListener('submit', (event) => {
|
||||||
|
|||||||
+8
-80
@@ -461,9 +461,14 @@ button:disabled {
|
|||||||
.persona-form {
|
.persona-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
max-height: 65vh;
|
background: rgba(10, 10, 20, 0.75);
|
||||||
overflow-y: auto;
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
padding-right: 6px;
|
border-radius: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-form.hidden {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.persona-form h3 {
|
.persona-form h3 {
|
||||||
@@ -477,83 +482,6 @@ button:disabled {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
background: rgba(5, 5, 20, 0.75);
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
z-index: 1000;
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-overlay.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card {
|
|
||||||
width: min(520px, 92vw);
|
|
||||||
background: rgba(19, 19, 42, 0.96);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
||||||
border-radius: 22px;
|
|
||||||
padding: 18px;
|
|
||||||
box-shadow: 0 25px 60px -12px var(--shadow);
|
|
||||||
display: grid;
|
|
||||||
gap: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-fields {
|
|
||||||
display: grid;
|
|
||||||
gap: 10px;
|
|
||||||
background: rgba(10, 10, 20, 0.6);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
||||||
border-radius: 14px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-fields-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-fields-list {
|
|
||||||
display: grid;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-field-row {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr auto;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-field-row input {
|
|
||||||
padding: 10px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-field-row button {
|
|
||||||
padding: 8px 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-main {
|
.chat-main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr auto auto;
|
grid-template-rows: auto 1fr auto auto;
|
||||||
|
|||||||
@@ -171,8 +171,6 @@ db.prepare(`
|
|||||||
TEXT,
|
TEXT,
|
||||||
details
|
details
|
||||||
TEXT,
|
TEXT,
|
||||||
custom_fields
|
|
||||||
TEXT,
|
|
||||||
created_at
|
created_at
|
||||||
DATETIME
|
DATETIME
|
||||||
DEFAULT
|
DEFAULT
|
||||||
@@ -274,25 +272,25 @@ const deleteChatMessagesStmt = db.prepare(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const listPersonasStmt = db.prepare(`
|
const listPersonasStmt = db.prepare(`
|
||||||
SELECT id, name, pronouns, appearance, background, details, custom_fields, created_at, updated_at
|
SELECT id, name, pronouns, appearance, background, details, created_at, updated_at
|
||||||
FROM personas
|
FROM personas
|
||||||
WHERE username = ?
|
WHERE username = ?
|
||||||
ORDER BY datetime(updated_at) DESC
|
ORDER BY datetime(updated_at) DESC
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const getPersonaStmt = db.prepare(`
|
const getPersonaStmt = db.prepare(`
|
||||||
SELECT id, name, pronouns, appearance, background, details, custom_fields
|
SELECT id, name, pronouns, appearance, background, details
|
||||||
FROM personas
|
FROM personas
|
||||||
WHERE id = ? AND username = ?
|
WHERE id = ? AND username = ?
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const insertPersonaStmt = db.prepare(
|
const insertPersonaStmt = db.prepare(
|
||||||
"INSERT INTO personas (username, name, pronouns, appearance, background, details, custom_fields) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
"INSERT INTO personas (username, name, pronouns, appearance, background, details) VALUES (?, ?, ?, ?, ?, ?)"
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatePersonaStmt = db.prepare(`
|
const updatePersonaStmt = db.prepare(`
|
||||||
UPDATE personas
|
UPDATE personas
|
||||||
SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, custom_fields = ?, updated_at = CURRENT_TIMESTAMP
|
SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = ? AND username = ?
|
WHERE id = ? AND username = ?
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -311,7 +309,7 @@ const setActivePersonaStmt = db.prepare(`
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
const getActivePersonaStmt = db.prepare(`
|
const getActivePersonaStmt = db.prepare(`
|
||||||
SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details, p.custom_fields
|
SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details
|
||||||
FROM user_settings us
|
FROM user_settings us
|
||||||
JOIN personas p ON p.id = us.active_persona_id
|
JOIN personas p ON p.id = us.active_persona_id
|
||||||
WHERE us.username = ?
|
WHERE us.username = ?
|
||||||
@@ -389,27 +387,6 @@ const normalizePersonaField = (value) => {
|
|||||||
return trimmed ? trimmed : null;
|
return trimmed ? trimmed : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeCustomFields = (fields) => {
|
|
||||||
if (!Array.isArray(fields)) return null;
|
|
||||||
const cleaned = fields
|
|
||||||
.map(field => ({
|
|
||||||
label: (field?.label || "").trim(),
|
|
||||||
value: (field?.value || "").trim()
|
|
||||||
}))
|
|
||||||
.filter(field => field.label || field.value);
|
|
||||||
return cleaned.length ? JSON.stringify(cleaned) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseCustomFields = (value) => {
|
|
||||||
if (!value) return [];
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(value);
|
|
||||||
return Array.isArray(parsed) ? parsed : [];
|
|
||||||
} catch (error) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildPersonaPrompt = (persona) => {
|
const buildPersonaPrompt = (persona) => {
|
||||||
const lines = [
|
const lines = [
|
||||||
"You are roleplaying with the following persona. Stay in character, be engaging, and align with these details."
|
"You are roleplaying with the following persona. Stay in character, be engaging, and align with these details."
|
||||||
@@ -419,10 +396,6 @@ const buildPersonaPrompt = (persona) => {
|
|||||||
if (persona.appearance) lines.push(`Appearance: ${persona.appearance}`);
|
if (persona.appearance) lines.push(`Appearance: ${persona.appearance}`);
|
||||||
if (persona.background) lines.push(`Background: ${persona.background}`);
|
if (persona.background) lines.push(`Background: ${persona.background}`);
|
||||||
if (persona.details) lines.push(`Details: ${persona.details}`);
|
if (persona.details) lines.push(`Details: ${persona.details}`);
|
||||||
const customFields = parseCustomFields(persona.custom_fields);
|
|
||||||
customFields.forEach(field => {
|
|
||||||
lines.push(`${field.label || "Custom"}: ${field.value}`);
|
|
||||||
});
|
|
||||||
return lines.join("\n");
|
return lines.join("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -511,10 +484,7 @@ app.post("/chats/:id/clear", requireLogin, (req, res) => {
|
|||||||
|
|
||||||
app.get("/personas", requireLogin, (req, res) => {
|
app.get("/personas", requireLogin, (req, res) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
const personas = listPersonasStmt.all(user).map(persona => ({
|
const personas = listPersonasStmt.all(user);
|
||||||
...persona,
|
|
||||||
customFields: parseCustomFields(persona.custom_fields)
|
|
||||||
}));
|
|
||||||
const activePersonaId = getActivePersonaIdStmt.get(user)?.active_persona_id ?? null;
|
const activePersonaId = getActivePersonaIdStmt.get(user)?.active_persona_id ?? null;
|
||||||
res.json({personas, activePersonaId});
|
res.json({personas, activePersonaId});
|
||||||
});
|
});
|
||||||
@@ -529,23 +499,16 @@ app.post("/personas", requireLogin, (req, res) => {
|
|||||||
const appearance = normalizePersonaField(req.body?.appearance);
|
const appearance = normalizePersonaField(req.body?.appearance);
|
||||||
const background = normalizePersonaField(req.body?.background);
|
const background = normalizePersonaField(req.body?.background);
|
||||||
const details = normalizePersonaField(req.body?.details);
|
const details = normalizePersonaField(req.body?.details);
|
||||||
const customFields = normalizeCustomFields(req.body?.customFields);
|
|
||||||
const personaId = insertPersonaStmt.run(
|
const personaId = insertPersonaStmt.run(
|
||||||
user,
|
user,
|
||||||
name,
|
name,
|
||||||
pronouns,
|
pronouns,
|
||||||
appearance,
|
appearance,
|
||||||
background,
|
background,
|
||||||
details,
|
details
|
||||||
customFields
|
|
||||||
).lastInsertRowid;
|
).lastInsertRowid;
|
||||||
const persona = getPersonaStmt.get(personaId, user);
|
const persona = getPersonaStmt.get(personaId, user);
|
||||||
res.json({
|
res.json({persona});
|
||||||
persona: {
|
|
||||||
...persona,
|
|
||||||
customFields: parseCustomFields(persona.custom_fields)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.put("/personas/:id", requireLogin, (req, res) => {
|
app.put("/personas/:id", requireLogin, (req, res) => {
|
||||||
@@ -559,14 +522,12 @@ app.put("/personas/:id", requireLogin, (req, res) => {
|
|||||||
const appearance = normalizePersonaField(req.body?.appearance);
|
const appearance = normalizePersonaField(req.body?.appearance);
|
||||||
const background = normalizePersonaField(req.body?.background);
|
const background = normalizePersonaField(req.body?.background);
|
||||||
const details = normalizePersonaField(req.body?.details);
|
const details = normalizePersonaField(req.body?.details);
|
||||||
const customFields = normalizeCustomFields(req.body?.customFields);
|
|
||||||
const result = updatePersonaStmt.run(
|
const result = updatePersonaStmt.run(
|
||||||
name,
|
name,
|
||||||
pronouns,
|
pronouns,
|
||||||
appearance,
|
appearance,
|
||||||
background,
|
background,
|
||||||
details,
|
details,
|
||||||
customFields,
|
|
||||||
personaId,
|
personaId,
|
||||||
user
|
user
|
||||||
);
|
);
|
||||||
@@ -574,12 +535,7 @@ app.put("/personas/:id", requireLogin, (req, res) => {
|
|||||||
return res.status(404).json({error: "Persona not found"});
|
return res.status(404).json({error: "Persona not found"});
|
||||||
}
|
}
|
||||||
const persona = getPersonaStmt.get(personaId, user);
|
const persona = getPersonaStmt.get(personaId, user);
|
||||||
res.json({
|
res.json({persona});
|
||||||
persona: {
|
|
||||||
...persona,
|
|
||||||
customFields: parseCustomFields(persona.custom_fields)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.delete("/personas/:id", requireLogin, (req, res) => {
|
app.delete("/personas/:id", requireLogin, (req, res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user