Files
f0ckm/src/inc/settings.mjs
T
2026-09-19 06:20:37 +02:00

258 lines
10 KiB
JavaScript

import cfg from "./config.mjs";
import db from "./sql.mjs";
import lib from "./lib.mjs";
let manual_approval = true;
let min_tags = 3;
let registration_open = false;
let trusted_uploads = 0;
let bypass_duplicate_check = false;
let protect_files = false;
let private_messages = true;
let dm_attachments = true;
let dm_unencrypted = false;
let default_layout = 'modern';
let enable_pdf = false;
let enable_cleanup = false;
let cleanup_start_date = '';
let cleanup_end_date = '';
let cleanup_include_engaged = false;
export const getShitpostMode = () => !!cfg.websrv.shitpost_mode;
export const setShitpostMode = (val) => {}; // No-op, strictly config-based
export const getEnableExpiringUploads = () => {
if (cfg.enable_expiring_uploads === false || cfg.websrv?.enable_expiring_uploads === false) return false;
return true;
};
export const getEnableItemSlugs = () => {
if (cfg.enable_item_slugs === false || cfg.websrv?.enable_item_slugs === false) return false;
return true;
};
export const getEnableAnonymousAccess = () => {
if (cfg.enable_anonymous_access === false || cfg.anonymous_access === false || cfg.websrv?.enable_anonymous_access === false || cfg.websrv?.anonymous_access === false) return false;
return true;
};
export const DEFAULT_ANON_PERMISSIONS = Object.freeze({
upload: false,
comment: true,
comment_attachments: false,
comment_vote: true,
poll_vote: true,
tag: true,
tag_vote: true,
favorite: true,
rate_item: false,
filter: true,
exclude_tags: true,
anonymize_users: false,
allowed_modes: ['sfw', 'nsfw', 'untagged', 'all', 'nsfl'],
allowed_mimes: ['image', 'video', 'audio', 'flash', 'pdf']
});
export const getAnonPermissions = () => {
const fromConfig = cfg.anonymous_permissions || cfg.websrv?.anonymous_permissions || {};
return {
...DEFAULT_ANON_PERMISSIONS,
...fromConfig
};
};
export const getAnonAnonymize = () => {
const perms = getAnonPermissions();
if (typeof perms.anonymize_users === 'boolean') return perms.anonymize_users;
if (typeof perms.anon_anonymize === 'boolean') return perms.anon_anonymize;
if (cfg.main && typeof cfg.main.anon_anonymize === 'boolean') return cfg.main.anon_anonymize;
if (cfg.main && typeof cfg.main.anonymous_anonymize === 'boolean') return cfg.main.anonymous_anonymize;
if (typeof cfg.anon_anonymize === 'boolean') return cfg.anon_anonymize;
if (typeof cfg.anonymous_anonymize === 'boolean') return cfg.anonymous_anonymize;
return false;
};
export const isAnonymizeSession = (session) => {
if (!session || typeof session !== 'object' || !session.user) {
return !!(cfg.main?.guest_anonymize ?? cfg.guest_anonymize);
}
if (session.is_anon || session.user === 'anonymous' || (typeof session.user === 'string' && session.user.startsWith('anon_'))) {
return getAnonAnonymize();
}
return false;
};
export const canAnonDo = (action) => {
if (!getEnableAnonymousAccess()) return false;
const perms = getAnonPermissions();
if (action === 'exclude_tags' || action === 'exclude_tag' || action === 'tag_exclude') {
if (perms.exclude_tags !== undefined) return !!perms.exclude_tags;
if (perms.exclude_tag !== undefined) return !!perms.exclude_tag;
if (perms.tag_exclude !== undefined) return !!perms.tag_exclude;
return perms.filter !== undefined ? !!perms.filter : true;
}
return perms[action] !== undefined ? !!perms[action] : !!DEFAULT_ANON_PERMISSIONS[action];
};
export const getAnonAllowedModes = () => {
const perms = getAnonPermissions();
return Array.isArray(perms.allowed_modes) ? perms.allowed_modes.map(m => String(m).toLowerCase()) : DEFAULT_ANON_PERMISSIONS.allowed_modes;
};
export const getAnonAllowedMimes = () => {
const perms = getAnonPermissions();
return Array.isArray(perms.allowed_mimes) ? perms.allowed_mimes.map(m => String(m).toLowerCase()) : DEFAULT_ANON_PERMISSIONS.allowed_mimes;
};
export const canAnonMode = (mode) => {
if (!canAnonDo('filter')) return false;
const allowed = getAnonAllowedModes();
const modeNames = ['sfw', 'nsfw', 'untagged', 'all', 'nsfl'];
const name = typeof mode === 'number' ? modeNames[mode] : String(mode).toLowerCase();
return allowed.includes(name);
};
export const canAnonMime = (mime) => {
if (!canAnonDo('filter')) return false;
const allowed = getAnonAllowedMimes();
return allowed.includes(String(mime).toLowerCase());
};
export const isAnonSession = (session) => {
if (!session) return true;
if (session === true) return false;
if (typeof session !== 'object' || !session.user) return true;
return !!(session.is_anon || session.user === 'anonymous' || (typeof session.user === 'string' && session.user.startsWith('anon_')));
};
export const checkAnonPermission = (session, action) => {
if (!isAnonSession(session)) return true;
return canAnonDo(action);
};
export const ensureAllItemsHaveSlugs = async () => {
try {
const rows = await db`SELECT id FROM items WHERE slug IS NULL OR slug = ''`;
if (!rows || rows.length === 0) return;
console.log(`[SLUG_BACKFILL] Found ${rows.length} item(s) missing slugs. Backfilling...`);
for (const row of rows) {
const newSlug = lib.generateSlug(11);
await db`UPDATE items SET slug = ${newSlug} WHERE id = ${row.id} AND (slug IS NULL OR slug = '')`;
}
console.log(`[SLUG_BACKFILL] Successfully backfilled ${rows.length} item slug(s).`);
} catch (err) {
console.error('[SLUG_BACKFILL] Error during slug backfill:', err.message);
}
};
export const ensureAllAlbumItemsHaveSlugs = async () => {
try {
const rows = await db`SELECT id FROM album_items WHERE slug IS NULL OR slug = ''`;
if (!rows || rows.length === 0) return;
console.log(`[ALBUM_SLUG_BACKFILL] Found ${rows.length} album item(s) missing slugs. Backfilling...`);
for (const row of rows) {
const newSlug = lib.generateSlug(11);
await db`UPDATE album_items SET slug = ${newSlug} WHERE id = ${row.id} AND (slug IS NULL OR slug = '')`;
}
console.log(`[ALBUM_SLUG_BACKFILL] Successfully backfilled ${rows.length} album item slug(s).`);
} catch (err) {
console.error('[ALBUM_SLUG_BACKFILL] Error during album item slug backfill:', err.message);
}
};
export const getEnableCleanup = () => {
if (cfg.websrv.enable_cleanup === false) return false;
return enable_cleanup;
};
export const setEnableCleanup = (val) => enable_cleanup = !!val;
export const getCleanupStartDate = () => cleanup_start_date;
export const setCleanupStartDate = (val) => cleanup_start_date = val || '';
export const getCleanupEndDate = () => cleanup_end_date;
export const setCleanupEndDate = (val) => cleanup_end_date = val || '';
export const getCleanupIncludeEngaged = () => cleanup_include_engaged;
export const setCleanupIncludeEngaged = (val) => cleanup_include_engaged = !!val;
export const getEnablePdf = () => enable_pdf;
export const setEnablePdf = (val) => enable_pdf = !!val;
export const getManualApproval = () => manual_approval;
export const setManualApproval = (val) => manual_approval = !!val;
export const getMinTags = () => min_tags;
export const setMinTags = (val) => {
const parsed = parseInt(val);
min_tags = isNaN(parsed) ? 3 : Math.max(0, parsed);
};
export const getRegistrationOpen = () => {
if (cfg.websrv.open_registration_web_toggle === false) {
return !!cfg.websrv.open_registration;
}
return registration_open;
};
export const setRegistrationOpen = (val) => registration_open = !!val;
// When false (default): open_registration=true means anyone can register with just username+password, activated immediately.
// When true: even in open registration, a valid email OR invite token is required.
export const getRegistrationRequireMailAndorToken = () => !!cfg.websrv.open_registration_require_mail_andor_token;
export const setRegistrationRequireMailAndorToken = (val) => {}; // No-op, strictly config-based
export const getTrustedUploads = () => trusted_uploads;
export const setTrustedUploads = (val) => trusted_uploads = Math.max(0, parseInt(val) ?? 3);
export const getBypassDuplicateCheck = () => bypass_duplicate_check;
export const setBypassDuplicateCheck = (val) => bypass_duplicate_check = !!val;
export const getProtectFiles = () => protect_files;
export const setProtectFiles = (val) => protect_files = !!val;
export const getPrivateMessages = () => private_messages;
export const setPrivateMessages = (val) => private_messages = !!val;
export const getDmAttachments = () => dm_attachments;
export const setDmAttachments = (val) => dm_attachments = !!val;
export const getDmUnencrypted = () => dm_unencrypted;
export const setDmUnencrypted = (val) => dm_unencrypted = !!val;
export const getDmAttachmentExpiryDays = () => {
const v = parseInt(cfg.websrv.dm_attachment_expiry_days);
return (Number.isFinite(v) && v > 0) ? v : 90;
};
export const getDefaultLayout = () => default_layout;
export const setDefaultLayout = (val) => default_layout = (val === 'legacy' ? 'legacy' : 'modern');
export const getLogUserIps = () => !!cfg.websrv.log_user_ips;
export const setLogUserIps = (val) => {}; // No-op, strictly config-based
export const getHashUserIps = () => !!cfg.websrv.hash_user_ips;
export const setHashUserIps = (val) => {}; // No-op, strictly config-based
export const getAllowCommentDeletion = () => !!cfg.websrv.allow_comment_deletion;
export const setAllowCommentDeletion = (val) => {}; // No-op, strictly config-based
// Live-editable NSFP tag ID list — seeded from config.json, can be overridden by DB setting
let nsfp_ids = Array.isArray(cfg.nsfp) ? [...cfg.nsfp.map(Number).filter(n => !isNaN(n))] : [];
export const getNsfpIds = () => nsfp_ids;
export const setNsfpIds = (ids) => {
nsfp_ids = Array.isArray(ids) ? ids.map(Number).filter(n => !isNaN(n) && n > 0) : [];
// Also sync to cfg.nsfp so all code reading cfg.nsfp directly still works
cfg.nsfp = [...nsfp_ids];
};
// Brand image URL — stored in site_settings DB, not config.json
// Falls back to cfg.websrv.custom_brand_image (array or string) on first boot
let brand_image_url = (() => {
const raw = cfg.websrv?.custom_brand_image;
return Array.isArray(raw) ? (raw[0] || '') : (raw || '');
})();
export const getBrandImageUrl = () => brand_image_url;
export const setBrandImageUrl = (val) => { brand_image_url = val || ''; };