Merge commit 'c70495e5252af7e5c43bc566a5dcdb44c0da4bd4'
This commit is contained in:
+24
-9
@@ -12,7 +12,7 @@
|
|||||||
`api/src/plugin-manager.js`, `api/src/plugins/dialog/index.js` + their tests.
|
`api/src/plugin-manager.js`, `api/src/plugins/dialog/index.js` + their tests.
|
||||||
- **Run tests:** `cd api && npm install && node --test` → **44 green**. `node_modules`
|
- **Run tests:** `cd api && npm install && node --test` → **44 green**. `node_modules`
|
||||||
is git-ignored; the fresh clone needs `npm install` once.
|
is git-ignored; the fresh clone needs `npm install` once.
|
||||||
- **Status:** stages 1–8 (+5.5) DONE; stage 6 partial (schema/system/System-panel done, editor-from-schema deferred). openbureau runs on core on dev CT 134, verified. **Next = stage 9** (onboard kgva: DB-less, auth:local, no plugins) — and finish stage 6's editor-from-schema there. Original stage-5 note kept below for history.
|
- **Status:** stages 1–9 DONE; openbureau + kgva BOTH LIVE on core. openbureau on dev CT134 (schema editor + supabase); kgva LIVE at karimgabrielevarano.xyz via core (Variant A: CMS serves the site; CT130 rebuilt in-place — Docker + kgva-cms on :8081, nginx :80 proxies to it and keeps /media, static timer disabled, Caddy untouched). CAVEAT: kgva GIT_PUBLISH=false → edits on CT130 disk, not git-backed (enable GIT_PUBLISH + creds to fix). Rollback for kgva: restore nginx .static.bak + re-enable kgva-deploy.timer + stop kgva-cms. Original stage-5 note kept below for history.
|
||||||
- **Immediate next action (historic):** stage 5 + 5.5 **DONE** on the branch (commits `c4230a4`
|
- **Immediate next action (historic):** stage 5 + 5.5 **DONE** on the branch (commits `c4230a4`
|
||||||
cutover, `5e06337` DDL, `a93d11a` migration runner). Plugin-manager singleton
|
cutover, `5e06337` DDL, `a93d11a` migration runner). Plugin-manager singleton
|
||||||
(`api/src/plugins.js`) wired into `index.js`/`stats.js`/`publish.js`, hard-coded
|
(`api/src/plugins.js`) wired into `index.js`/`stats.js`/`publish.js`, hard-coded
|
||||||
@@ -126,12 +126,16 @@ openbureau's extras become plugins (first: `dialog`); kgva enables none.
|
|||||||
`pg` against `DATABASE_URL`, warning-and-skipping if unset. Needs `DATABASE_URL`
|
`pg` against `DATABASE_URL`, warning-and-skipping if unset. Needs `DATABASE_URL`
|
||||||
wired into the cms service env for openbureau (stage 8). Tested: migrate.test.js +
|
wired into the cms service env for openbureau (stage 8). Tested: migrate.test.js +
|
||||||
tracking SQL proven on the live dev Postgres (throwaway DB).
|
tracking SQL proven on the live dev Postgres (throwaway DB).
|
||||||
6. [PARTLY DONE, commit f709b5d] `GET /api/schema` (site/auth/plugins/collections)
|
6. [DONE, commits f709b5d + f8f4131 + 59b9e20] schema-driven admin. `GET /api/schema`
|
||||||
+ `GET /api/system` (admin: core version, plugins, content model, hugo, auth) +
|
+ `GET /api/system` + a System panel; AND the editor now renders sidebar groups +
|
||||||
an admin **System panel** — all additive, the editor is untouched (stays 1:1).
|
fields from the site's collections (admin/src/fields.jsx: per-type controls
|
||||||
DEFERRED by design: making the editor itself render its fields from the schema —
|
string/text/slug/number/date/bool/select/list/image/color/markdown; form↔frontmatter
|
||||||
that needs a 2nd content model (kgva) + visual verification, not a blind rewrite
|
+ path building). One admin serves any site. Unknown frontmatter is PRESERVED on
|
||||||
of the live editor. Do it when onboarding kgva (stage 9).
|
save (__raw) — no data loss. Verified working via kgva (stage 9). NOTE: openbureau
|
||||||
|
is NOT yet redeployed with the schema editor (its running image keeps the bespoke
|
||||||
|
one); when it is, its config field types (color→swatch, layout opts) are already
|
||||||
|
tuned. Visual review of the openbureau editor by Karim still recommended before
|
||||||
|
redeploying it.
|
||||||
7. [DONE, commit 86f9f57] **auth provider** (`config.auth` = `supabase` | `local`).
|
7. [DONE, commit 86f9f57] **auth provider** (`config.auth` = `supabase` | `local`).
|
||||||
`api/src/auth-local.js` = file-based users (bcryptjs) + self-signed HS256 JWTs of
|
`api/src/auth-local.js` = file-based users (bcryptjs) + self-signed HS256 JWTs of
|
||||||
the SAME claim shape; `routes/auth.js` POST /api/auth/login (mounted only when
|
the SAME claim shape; `routes/auth.js` POST /api/auth/login (mounted only when
|
||||||
@@ -149,8 +153,19 @@ openbureau's extras become plugins (first: `dialog`); kgva enables none.
|
|||||||
stack's migrate service owns db/schema.sql incl. dialog). Deployed to dev CT 134
|
stack's migrate service owns db/schema.sql incl. dialog). Deployed to dev CT 134
|
||||||
and FULL write-verified: login/list/edit/preview/publish/dialog all identical, no
|
and FULL write-verified: login/list/edit/preview/publish/dialog all identical, no
|
||||||
git divergence (GIT_PUBLISH=false). Rollback image `cms-cms:rollback` kept.
|
git divergence (GIT_PUBLISH=false). Rollback image `cms-cms:rollback` kept.
|
||||||
9. onboard kgva (`CMS_CONFIG=…/kgva.config.js`, `auth: 'local'`, no plugins) as the
|
9. [DONE — LIVE on core (Variant A)] kgva consumes core. In
|
||||||
2nd consumer — DB-less.
|
`karim/kgva` (git.kgva.ch, main 51a94b8): `cms/core` = core subtree, `cms/kgva.config.js`
|
||||||
|
(project/page/section, auth:'local', no plugins), `docker-compose.yml` builds the core
|
||||||
|
image (Hugo 0.163.3, no VITE_SUPABASE_URL → local-auth admin), `cms/seed-admin.mjs`,
|
||||||
|
updated deploy/provision-lxc.sh + ADMIN.md. VERIFIED DB-less end-to-end on real content
|
||||||
|
(staged on CT134): local login → schema editor → 42 entries (de/en) → stats →
|
||||||
|
create/preview/cleanup; image galleries preserved. The LIVE site is UNCHANGED — CT130
|
||||||
|
still deploys statically (timer → `hugo` → nginx; hugo ignores cms/); the CMS is dormant.
|
||||||
|
PENDING (deliberate, his call — repoints a live domain): provision a kgva-core container
|
||||||
|
(deploy/provision-lxc.sh, free CTID + temp IP) and decide topology — CMS serves the site
|
||||||
|
(Caddy → it) OR CMS edits + GIT_PUBLISH=true commits to git and the CT130 static timer
|
||||||
|
keeps serving. Then Caddy cutover per deploy/README. openbureau also not yet redeployed
|
||||||
|
with the schema editor (stage 6 note).
|
||||||
|
|
||||||
## How to run / test
|
## How to run / test
|
||||||
openbureau CMS stack: `OPENBUREAU/cms/docker-compose.yml` (Node api + Hugo +
|
openbureau CMS stack: `OPENBUREAU/cms/docker-compose.yml` (Node api + Hugo +
|
||||||
|
|||||||
@@ -389,6 +389,31 @@ function Profile({ onMsg }) {
|
|||||||
<label>Über mich<textarea value={p.bio} onChange={set('bio')} rows={5} placeholder="Kurzer Text über dich…" /></label>
|
<label>Über mich<textarea value={p.bio} onChange={set('bio')} rows={5} placeholder="Kurzer Text über dich…" /></label>
|
||||||
<div className="actions"><button className="primary" onClick={save} disabled={busy}>Speichern</button></div>
|
<div className="actions"><button className="primary" onClick={save} disabled={busy}>Speichern</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
<PasswordChange onMsg={onMsg} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PasswordChange({ onMsg }) {
|
||||||
|
const [cur, setCur] = useState('');
|
||||||
|
const [nxt, setNxt] = useState('');
|
||||||
|
const [busy, setBusy] = useState(false);
|
||||||
|
async function submit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (nxt.length < 6) { onMsg({ type: 'err', text: 'Neues Passwort zu kurz (min. 6 Zeichen).' }); return; }
|
||||||
|
setBusy(true);
|
||||||
|
try { await api.changePassword(cur, nxt); onMsg({ type: 'ok', text: 'Passwort geändert.' }); setCur(''); setNxt(''); }
|
||||||
|
catch (e) { onMsg({ type: 'err', text: e.message }); }
|
||||||
|
finally { setBusy(false); }
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="profile-card">
|
||||||
|
<h2>Passwort ändern</h2>
|
||||||
|
<form onSubmit={submit}>
|
||||||
|
<label>Aktuelles Passwort<input type="password" value={cur} onChange={(e) => setCur(e.target.value)} autoComplete="current-password" /></label>
|
||||||
|
<label>Neues Passwort<input type="password" value={nxt} onChange={(e) => setNxt(e.target.value)} autoComplete="new-password" /></label>
|
||||||
|
<div className="actions"><button className="primary" disabled={busy}>Passwort setzen</button></div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -431,6 +456,49 @@ function Overview({ onMsg, go }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── System (nur Admin): core-Version, Update-Check, Admins, Plugins, Modell ──
|
||||||
|
function System({ onMsg }) {
|
||||||
|
const [s, setS] = useState(null);
|
||||||
|
const [upd, setUpd] = useState(null);
|
||||||
|
useEffect(() => {
|
||||||
|
api.system().then(setS).catch((e) => onMsg({ type: 'err', text: e.message }));
|
||||||
|
api.systemUpdate().then(setUpd).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
if (!s) return <div className="empty">…</div>;
|
||||||
|
const badge = !upd ? null
|
||||||
|
: upd.available ? <span className="status draft">core v{upd.vendored} bereit — Rebuild nötig</span>
|
||||||
|
: upd.vendored ? <span className="status live">aktuell</span>
|
||||||
|
: <span className="muted">(kein Subtree)</span>;
|
||||||
|
return (
|
||||||
|
<div className="profile">
|
||||||
|
<div className="profile-card wide">
|
||||||
|
<h2>System</h2>
|
||||||
|
<div className="sysgrid">
|
||||||
|
<div><span className="muted">Core</span><b>{s.core.name} <span className="ver">v{s.core.version}</span></b> {badge}</div>
|
||||||
|
<div><span className="muted">Site</span><b>{s.site || '—'}</b></div>
|
||||||
|
<div><span className="muted">Auth</span><b>{s.auth}</b></div>
|
||||||
|
<div><span className="muted">Hugo</span><b>{s.hugo}</b></div>
|
||||||
|
</div>
|
||||||
|
<h3>Admins <span className="count-pill">{(s.admins || []).length}</span></h3>
|
||||||
|
<ul className="syslist">{(s.admins || []).map((a) => (
|
||||||
|
<li key={a}><b>{a}</b><span className="muted">aus Config (fix)</span></li>
|
||||||
|
))}</ul>
|
||||||
|
<h3>Plugins <span className="count-pill">{s.plugins.length}</span></h3>
|
||||||
|
{s.plugins.length
|
||||||
|
? <ul className="syslist">{s.plugins.map((p) => (
|
||||||
|
<li key={p.name}><b>{p.name}</b><span className="muted">{p.routes} Routen · {p.migrations} Migration(en)</span></li>
|
||||||
|
))}</ul>
|
||||||
|
: <p className="muted">Keine Plugins aktiv.</p>}
|
||||||
|
<h3>Content-Modell <span className="count-pill">{s.collections.length}</span></h3>
|
||||||
|
<ul className="syslist">{s.collections.map((c) => (
|
||||||
|
<li key={c.kind}><b>{c.label}</b><span className="muted">{c.kind} · {c.fields} Felder{c.statKey ? ` · ${c.statKey}` : ''}</span></li>
|
||||||
|
))}</ul>
|
||||||
|
<p className="muted who-mail">openbureau-core fährt diese Site. Updates werden serverseitig eingespielt (Update-Skript).</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Autor:innen-Verwaltung (nur Admin) ──────────────────────────────────────
|
// ── Autor:innen-Verwaltung (nur Admin) ──────────────────────────────────────
|
||||||
function Users({ onMsg, currentEmail }) {
|
function Users({ onMsg, currentEmail }) {
|
||||||
const [list, setList] = useState(null);
|
const [list, setList] = useState(null);
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export const api = {
|
|||||||
getMe: () => call('/me'),
|
getMe: () => call('/me'),
|
||||||
stats: () => call('/stats'),
|
stats: () => call('/stats'),
|
||||||
system: () => call('/system'),
|
system: () => call('/system'),
|
||||||
|
systemUpdate: () => call('/system/update'),
|
||||||
schema: () => call('/schema'),
|
schema: () => call('/schema'),
|
||||||
|
changePassword: (current, next) => call('/account/password', { method: 'POST', body: JSON.stringify({ current, next }) }),
|
||||||
listUsers: () => call('/users'),
|
listUsers: () => call('/users'),
|
||||||
createUser: (email, password, role) => call('/users', { method: 'POST', body: JSON.stringify({ email, password, role }) }),
|
createUser: (email, password, role) => call('/users', { method: 'POST', body: JSON.stringify({ email, password, role }) }),
|
||||||
setPassword: (id, password) => call(`/users/${id}`, { method: 'PUT', body: JSON.stringify({ password }) }),
|
setPassword: (id, password) => call(`/users/${id}`, { method: 'PUT', body: JSON.stringify({ password }) }),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openbureau-cms-api",
|
"name": "openbureau-cms-api",
|
||||||
"version": "0.6.0",
|
"version": "0.7.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Headless CMS backend für OPENBUREAU — schreibt Supabase-Posts in Hugo-content/, baut und serviert die Site.",
|
"description": "Headless CMS backend für OPENBUREAU — schreibt Supabase-Posts in Hugo-content/, baut und serviert die Site.",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import profile from './routes/profile.js';
|
|||||||
import users from './routes/users.js';
|
import users from './routes/users.js';
|
||||||
import stats from './routes/stats.js';
|
import stats from './routes/stats.js';
|
||||||
import system from './routes/system.js';
|
import system from './routes/system.js';
|
||||||
|
import account from './routes/account.js';
|
||||||
import history from './routes/history.js';
|
import history from './routes/history.js';
|
||||||
import authRoute from './routes/auth.js';
|
import authRoute from './routes/auth.js';
|
||||||
import { requireAuth, requireAdmin } from './auth.js';
|
import { requireAuth, requireAdmin } from './auth.js';
|
||||||
@@ -100,6 +101,7 @@ app.route('/api/profile', profile);
|
|||||||
app.route('/api/users', users);
|
app.route('/api/users', users);
|
||||||
app.route('/api/stats', stats);
|
app.route('/api/stats', stats);
|
||||||
app.route('/api/system', system);
|
app.route('/api/system', system);
|
||||||
|
app.route('/api/account', account);
|
||||||
// Content-Modell der Site fürs Admin (schema-getriebenes Rendern). Jede:r
|
// Content-Modell der Site fürs Admin (schema-getriebenes Rendern). Jede:r
|
||||||
// eingeloggte Nutzer:in darf es lesen — der Editor braucht es zum Aufbauen.
|
// eingeloggte Nutzer:in darf es lesen — der Editor braucht es zum Aufbauen.
|
||||||
app.get('/api/schema', (c) => c.json({
|
app.get('/api/schema', (c) => c.json({
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Hono } from 'hono';
|
||||||
|
import { config } from '../config.js';
|
||||||
|
import { supabase, supabaseAuth } from '../supabase.js';
|
||||||
|
import * as local from '../auth-local.js';
|
||||||
|
|
||||||
|
// Self-service for the logged-in user (after requireAuth). Currently: change own
|
||||||
|
// password — local provider edits the user file; supabase verifies the current
|
||||||
|
// password then updates via the admin API.
|
||||||
|
const account = new Hono();
|
||||||
|
|
||||||
|
account.post('/password', async (c) => {
|
||||||
|
let body = {};
|
||||||
|
try { body = await c.req.json(); } catch { /* 400 below */ }
|
||||||
|
const { current, next } = body;
|
||||||
|
if (!next || String(next).length < 6) return c.json({ error: 'Neues Passwort zu kurz (min. 6 Zeichen).' }, 400);
|
||||||
|
const email = (c.get('email') || '').toLowerCase();
|
||||||
|
const userId = c.get('user')?.id;
|
||||||
|
|
||||||
|
if (config.auth === 'local') {
|
||||||
|
const u = (await local.loadUsers()).find((x) => (x.email || '').toLowerCase() === email);
|
||||||
|
if (!u || !(await local.verifyPassword(current || '', u.password))) {
|
||||||
|
return c.json({ error: 'Aktuelles Passwort ist falsch.' }, 403);
|
||||||
|
}
|
||||||
|
await local.updateUser(u.id, { password: next });
|
||||||
|
return c.json({ ok: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// supabase: verify current via the dedicated auth client, then update via admin.
|
||||||
|
if (!supabaseAuth || !supabase) return c.json({ error: 'Auth nicht verfügbar' }, 500);
|
||||||
|
const { error: e1 } = await supabaseAuth.auth.signInWithPassword({ email, password: current || '' });
|
||||||
|
await supabaseAuth.auth.signOut().catch(() => {}); // Session sofort wieder lösen
|
||||||
|
if (e1) return c.json({ error: 'Aktuelles Passwort ist falsch.' }, 403);
|
||||||
|
const { error: e2 } = await supabase.auth.admin.updateUserById(userId, { password: next });
|
||||||
|
if (e2) return c.json({ error: e2.message }, 400);
|
||||||
|
return c.json({ ok: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
export default account;
|
||||||
@@ -1,21 +1,39 @@
|
|||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { execFile } from 'node:child_process';
|
||||||
|
import { promisify } from 'node:util';
|
||||||
import { config } from '../config.js';
|
import { config } from '../config.js';
|
||||||
import { manager } from '../plugins.js';
|
import { manager } from '../plugins.js';
|
||||||
import { requireAdmin } from '../auth.js';
|
import { requireAdmin } from '../auth.js';
|
||||||
|
|
||||||
// System-/Diagnose-Info für das Admin-Panel: welche core-Version läuft, welche
|
const execFileP = promisify(execFile);
|
||||||
// Plugins aktiv sind, welches Content-Modell die Site fährt. Rein lesend, Admin.
|
|
||||||
// Reine Builder-Funktion (testbar) — die Route hängt nur Version + Hugo dran.
|
let _version = null;
|
||||||
|
async function coreVersion() {
|
||||||
|
if (_version) return _version;
|
||||||
|
try { _version = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8')).version || '0.0.0'; }
|
||||||
|
catch { _version = '0.0.0'; }
|
||||||
|
return _version;
|
||||||
|
}
|
||||||
|
let _hugo = null;
|
||||||
|
async function hugoVersion() {
|
||||||
|
if (_hugo) return _hugo;
|
||||||
|
try { const { stdout } = await execFileP('hugo', ['version']); _hugo = (stdout.match(/v[0-9][0-9.]*[^\s]*/) || ['?'])[0]; }
|
||||||
|
catch { _hugo = '?'; }
|
||||||
|
return _hugo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// System-/Diagnose-Info fürs Admin-Panel. Reiner Builder (testbar); die Route hängt
|
||||||
|
// nur die zur Laufzeit ermittelten Versionen dran.
|
||||||
export function systemInfo({ version, hugo }) {
|
export function systemInfo({ version, hugo }) {
|
||||||
return {
|
return {
|
||||||
core: { name: 'openbureau-core', version },
|
core: { name: 'openbureau-core', version },
|
||||||
site: config.site || null,
|
site: config.site || null,
|
||||||
auth: config.auth || 'supabase',
|
auth: config.auth || 'supabase',
|
||||||
|
admins: config.admins || [],
|
||||||
plugins: manager.plugins.map((p) => ({
|
plugins: manager.plugins.map((p) => ({
|
||||||
name: p.name,
|
name: p.name, routes: (p.routes || []).length, migrations: (p.migrations || []).length,
|
||||||
routes: (p.routes || []).length,
|
|
||||||
migrations: (p.migrations || []).length,
|
|
||||||
})),
|
})),
|
||||||
collections: config.collections.map((c) => ({
|
collections: config.collections.map((c) => ({
|
||||||
kind: c.kind, label: c.label, statKey: c.statKey || null, fields: (c.fields || []).length,
|
kind: c.kind, label: c.label, statKey: c.statKey || null, fields: (c.fields || []).length,
|
||||||
@@ -26,13 +44,20 @@ export function systemInfo({ version, hugo }) {
|
|||||||
|
|
||||||
const system = new Hono();
|
const system = new Hono();
|
||||||
system.use('*', requireAdmin);
|
system.use('*', requireAdmin);
|
||||||
system.get('/', async (c) => {
|
|
||||||
let version = '0.0.0';
|
system.get('/', async (c) => c.json(systemInfo({ version: await coreVersion(), hugo: await hugoVersion() })));
|
||||||
try {
|
|
||||||
const pkg = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8'));
|
// Update-Check (token-frei): laufende Core-Version (Image, /app/package.json) vs. die
|
||||||
version = pkg.version || version;
|
// im Repo VENDORTE Version (SITE_DIR/cms/core/api/package.json). Ist die vendorte neuer,
|
||||||
} catch { /* package.json nicht lesbar → 0.0.0 */ }
|
// wurde core aktualisiert aber noch nicht neu gebaut → "Rebuild nötig" (Update-Skript).
|
||||||
return c.json(systemInfo({ version, hugo: '0.161.1+extended' }));
|
system.get('/update', async (c) => {
|
||||||
|
const running = await coreVersion();
|
||||||
|
const siteDir = process.env.SITE_DIR || '/site';
|
||||||
|
const vendorPath = path.join(siteDir, process.env.CORE_VENDOR_PATH || 'cms/core', 'api/package.json');
|
||||||
|
let vendored = null;
|
||||||
|
try { vendored = JSON.parse(await readFile(vendorPath, 'utf8')).version || null; }
|
||||||
|
catch { /* nicht als Subtree eingebunden → kein Vergleich möglich */ }
|
||||||
|
return c.json({ running, vendored, available: !!(vendored && vendored !== running) });
|
||||||
});
|
});
|
||||||
|
|
||||||
export default system;
|
export default system;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ test('systemInfo reflects core version, plugins and content model', () => {
|
|||||||
assert.equal(info.site, 'openbureau');
|
assert.equal(info.site, 'openbureau');
|
||||||
assert.equal(info.auth, 'supabase'); // openbureau.config.js sets auth: 'supabase'
|
assert.equal(info.auth, 'supabase'); // openbureau.config.js sets auth: 'supabase'
|
||||||
assert.equal(info.hugo, '0.161.1+extended');
|
assert.equal(info.hugo, '0.161.1+extended');
|
||||||
|
assert.deepEqual(info.admins, ['karim@gabrielevarano.ch']);
|
||||||
// dialog plugin is active with its routes + the one migration
|
// dialog plugin is active with its routes + the one migration
|
||||||
const dialog = info.plugins.find((p) => p.name === 'dialog');
|
const dialog = info.plugins.find((p) => p.name === 'dialog');
|
||||||
assert.ok(dialog, 'dialog plugin listed');
|
assert.ok(dialog, 'dialog plugin listed');
|
||||||
|
|||||||
Reference in New Issue
Block a user