diff --git a/lib/store.js b/lib/store.js index 9396244..0cbe80a 100644 --- a/lib/store.js +++ b/lib/store.js @@ -241,6 +241,14 @@ async function applyLicenseRuleToModels(name, commercial) { await db.query('UPDATE models SET commercial_use = $2 WHERE license = $1', [name, commercial ?? null]); } +// Align every model's commercial_use to its license rule (license = source of truth). +async function reconcileModelsToRules() { + await db.query(` + UPDATE models m SET commercial_use = lr.commercial + FROM license_rules lr + WHERE m.license = lr.name AND m.commercial_use IS DISTINCT FROM lr.commercial`); +} + // ---------------------------------------------------------------- users / auth async function countUsers() { const { rows } = await db.query('SELECT COUNT(*)::int AS n FROM users'); @@ -321,4 +329,5 @@ module.exports = { countUsers, getUserByEmail, getUserById, createUser, updateUserPassword, createPasswordReset, getValidReset, markResetUsed, getLicenseRule, upsertLicenseRule, listLicenseRules, distinctModelLicenses, applyLicenseRuleToModels, + reconcileModelsToRules, }; diff --git a/public/app.js b/public/app.js index bb59b54..5bff932 100644 --- a/public/app.js +++ b/public/app.js @@ -557,8 +557,6 @@ function openEditModal() { document.getElementById('editDescription').value = model.description || ''; document.getElementById('editTags').value = (model.tags || []).join(', '); document.getElementById('editLicense').value = model.license || ''; - document.getElementById('editCommercial').value = - model.commercial_use === true ? 'true' : model.commercial_use === false ? 'false' : ''; const ps = model.print_settings || {}; document.getElementById('editMaterial').value = ps.material || ''; @@ -577,12 +575,10 @@ function openEditModal() { async function handleEditModel(e) { e.preventDefault(); const id = editModal.dataset.editId; - const commercial = document.getElementById('editCommercial').value; const body = { name: document.getElementById('editName').value, description: document.getElementById('editDescription').value, license: document.getElementById('editLicense').value || null, - commercial_use: commercial === '' ? null : commercial === 'true', tags: splitTags(document.getElementById('editTags').value), projects: Array.from(document.getElementById('editProjects').selectedOptions).map((o) => Number(o.value)), print_settings: { diff --git a/public/index.html b/public/index.html index 9e17d16..ef25bf0 100644 --- a/public/index.html +++ b/public/index.html @@ -433,14 +433,7 @@
-
-
- - +

Sellable/non-commercial is set per license in Settings → License types.

diff --git a/server.js b/server.js index 05dcb1c..4e00f5b 100644 --- a/server.js +++ b/server.js @@ -253,6 +253,7 @@ app.get('/api/licenses', async (req, res, next) => { for (const name of await store.distinctModelLicenses()) { if (!(await store.getLicenseRule(name))) await store.upsertLicenseRule(name, licenses.inferCommercial(name)); } + await store.reconcileModelsToRules(); // keep old imports aligned to current policy res.json(await store.listLicenseRules()); } catch (e) { next(e); } }); @@ -337,7 +338,11 @@ app.post('/api/models/:id/files', upload.array('files'), async (req, res, next) app.put('/api/models/:id', async (req, res, next) => { try { - const model = await store.updateModel(req.params.id, req.body); + const updates = { ...req.body }; + // Sellability is derived from the license rule, so re-resolve it if the + // license changed (registers the new license if it's not seen before). + if (updates.license !== undefined) updates.commercial_use = await resolveCommercial(updates.license); + const model = await store.updateModel(req.params.id, updates); if (!model) return res.status(404).json({ error: 'Model not found' }); res.json(publicModel(model)); } catch (e) { next(e); }