tfrere HF Staff commited on
Commit
0784389
·
1 Parent(s): 3616e87

feat: clean routing - /editor for auth, / for published article

Browse files

- GET / serves published HTML if available, otherwise login page
- GET /editor requires HF OAuth, serves the SPA editor
- In dev mode (no SPACE_ID), / serves the editor directly
- Cleaner login page with styled "Sign in with HF" button

Made-with: Cursor

Files changed (1) hide show
  1. backend/src/server.ts +66 -31
backend/src/server.ts CHANGED
@@ -260,50 +260,85 @@ const staticDir =
260
  ? join(__dirname, "..", "frontend-dist")
261
  : join(__dirname, "..", "..", "frontend", "dist");
262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  if (existsSync(staticDir)) {
264
  app.use(express.static(staticDir));
265
 
266
- app.get("*", async (req, res) => {
267
- // If OAuth is enabled, serve published HTML to unauthenticated visitors
268
  if (oauthEnabled) {
269
  const token = extractToken(req.headers.cookie);
270
  const user = await resolveUser(token);
271
 
272
  if (!user || !user.canEdit) {
273
- // Try to serve published version
274
- const docMatch = req.query.doc as string | undefined;
275
- const docName = docMatch || "default";
276
- const safeName = docName.replace(/[^a-zA-Z0-9_-]/g, "_");
277
- const publishedPath = join(DATA_DIR, "published", safeName, "index.html");
278
-
279
- if (existsSync(publishedPath)) {
280
- res.sendFile(publishedPath);
281
- return;
282
- }
283
-
284
- // No published version: show a simple message
285
- if (!user) {
286
- res.status(200).send(`
287
- <!DOCTYPE html>
288
- <html>
289
- <head><title>Collab Editor</title></head>
290
- <body style="display:flex;align-items:center;justify-content:center;height:100vh;margin:0;font-family:system-ui;background:#0a0a0a;color:#aaa;">
291
- <div style="text-align:center;">
292
- <h1 style="color:#fff;">This article is not yet published</h1>
293
- <p>Log in with your Hugging Face account to edit.</p>
294
- <a href="/oauth/authorize" style="color:#958DF1;">Log in</a>
295
- </div>
296
- </body>
297
- </html>
298
- `);
299
- return;
300
- }
301
  }
302
  }
303
 
304
- // Authenticated editors get the SPA
305
  res.sendFile(join(staticDir, "index.html"));
306
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  }
308
 
309
  // ---------- Start ----------
 
260
  ? join(__dirname, "..", "frontend-dist")
261
  : join(__dirname, "..", "..", "frontend", "dist");
262
 
263
+ function getDocName(req: express.Request): string {
264
+ const raw = (req.query.doc as string) || "default";
265
+ return raw.replace(/[^a-zA-Z0-9_-]/g, "_");
266
+ }
267
+
268
+ function getPublishedPath(docName: string): string {
269
+ return join(DATA_DIR, "published", docName, "index.html");
270
+ }
271
+
272
+ function sendLoginPage(res: express.Response) {
273
+ res.status(200).send(`<!DOCTYPE html>
274
+ <html lang="en">
275
+ <head>
276
+ <meta charset="utf-8" />
277
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
278
+ <title>Collab Editor</title>
279
+ <style>
280
+ * { margin: 0; padding: 0; box-sizing: border-box; }
281
+ body { display: flex; align-items: center; justify-content: center; height: 100vh;
282
+ font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #aaa; }
283
+ .card { text-align: center; max-width: 420px; padding: 2rem; }
284
+ h1 { color: #fff; font-size: 1.5rem; margin-bottom: 0.5rem; }
285
+ p { margin-bottom: 1.5rem; line-height: 1.5; }
286
+ a.btn { display: inline-block; padding: 0.6rem 1.5rem; border-radius: 8px;
287
+ background: #958DF1; color: #fff; text-decoration: none; font-weight: 500;
288
+ transition: opacity 0.15s; }
289
+ a.btn:hover { opacity: 0.85; }
290
+ </style>
291
+ </head>
292
+ <body>
293
+ <div class="card">
294
+ <h1>This article is not yet published</h1>
295
+ <p>Log in with your Hugging Face account to access the editor.</p>
296
+ <a class="btn" href="/oauth/authorize">Sign in with Hugging Face</a>
297
+ </div>
298
+ </body>
299
+ </html>`);
300
+ }
301
+
302
  if (existsSync(staticDir)) {
303
  app.use(express.static(staticDir));
304
 
305
+ // GET /editor → requires auth, serves the SPA
306
+ app.get("/editor", async (req, res) => {
307
  if (oauthEnabled) {
308
  const token = extractToken(req.headers.cookie);
309
  const user = await resolveUser(token);
310
 
311
  if (!user || !user.canEdit) {
312
+ // Not logged in or no write access → redirect to OAuth login
313
+ const docParam = req.query.doc ? `?doc=${req.query.doc}` : "";
314
+ res.redirect(`/oauth/authorize`);
315
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  }
317
  }
318
 
 
319
  res.sendFile(join(staticDir, "index.html"));
320
  });
321
+
322
+ // GET / (and all other paths) → public article or login prompt
323
+ app.get("*", async (req, res) => {
324
+ if (!oauthEnabled) {
325
+ // Dev mode: serve editor directly
326
+ res.sendFile(join(staticDir, "index.html"));
327
+ return;
328
+ }
329
+
330
+ // In production with OAuth: serve the published article if it exists
331
+ const docName = getDocName(req);
332
+ const publishedPath = getPublishedPath(docName);
333
+
334
+ if (existsSync(publishedPath)) {
335
+ res.sendFile(publishedPath);
336
+ return;
337
+ }
338
+
339
+ // No published version → login page
340
+ sendLoginPage(res);
341
+ });
342
  }
343
 
344
  // ---------- Start ----------