Shurem commited on
Commit
8d7eca6
·
1 Parent(s): 228008d

resolve missings chapter

Browse files
Files changed (1) hide show
  1. src/routes/personalize.ts +26 -25
src/routes/personalize.ts CHANGED
@@ -1,5 +1,7 @@
1
  import { Hono } from 'hono';
2
  import { eq } from 'drizzle-orm';
 
 
3
  import { db } from '../db/client.js';
4
  import { userProfiles } from '../db/schema.js';
5
  import { requireAuth, getAuthContext } from '../middleware/auth.js';
@@ -90,40 +92,34 @@ function validateProfileCompleteness(profile: ProfileResponse | null): ProfileVa
90
  // =============================================================================
91
 
92
  /**
93
- * Get the base URL for fetching chapter content
94
- * Uses the deployed Docusaurus site's raw markdown from GitHub
95
  */
96
- function getChapterContentBaseUrl(): string {
97
- // Fetch raw markdown from GitHub repository
98
- return process.env.CHAPTER_CONTENT_URL ||
99
- 'https://raw.githubusercontent.com/shuremali02/AI_Spec-Driven_Online_Hackathon_1/main/book-write/docs';
100
  }
101
 
102
  /**
103
- * Fetch chapter content from GitHub raw URL
104
  * Supports both `chapter-01.md` and `chapter-01/index.md` patterns
105
  */
106
  async function fetchChapterContent(chapterId: string): Promise<string | null> {
107
- const baseUrl = getChapterContentBaseUrl();
108
 
109
  // Sanitize chapter ID to prevent directory traversal
110
  const sanitizedId = chapterId.replace(/\.\./g, '').replace(/^\/+/, '');
111
 
112
  // Try different file patterns
113
  const patterns = [
114
- `${baseUrl}/${sanitizedId}.md`,
115
- `${baseUrl}/${sanitizedId}.mdx`,
116
- `${baseUrl}/${sanitizedId}/index.md`,
117
- `${baseUrl}/${sanitizedId}/index.mdx`,
118
  ];
119
 
120
- for (const url of patterns) {
121
  try {
122
- const response = await fetch(url);
123
- if (!response.ok) {
124
- continue;
125
- }
126
- const content = await response.text();
127
  // Strip frontmatter
128
  const frontmatterMatch = content.match(/^---\n[\s\S]*?\n---\n/);
129
  if (frontmatterMatch) {
@@ -131,7 +127,7 @@ async function fetchChapterContent(chapterId: string): Promise<string | null> {
131
  }
132
  return content;
133
  } catch {
134
- // URL doesn't work, try next pattern
135
  continue;
136
  }
137
  }
@@ -378,13 +374,18 @@ personalize.post('/personalize', async (c) => {
378
  }
379
 
380
  // Fetch chapter content (TASK-005)
381
- const chapterContent = await fetchChapterContent(body.chapter_id);
 
382
  if (!chapterContent) {
383
- return c.json({
384
- success: false,
385
- error: 'CHAPTER_NOT_FOUND',
386
- message: 'Chapter not found',
387
- }, 404);
 
 
 
 
388
  }
389
 
390
  // Log personalization request
 
1
  import { Hono } from 'hono';
2
  import { eq } from 'drizzle-orm';
3
+ import { readFile } from 'fs/promises';
4
+ import { join, resolve } from 'path';
5
  import { db } from '../db/client.js';
6
  import { userProfiles } from '../db/schema.js';
7
  import { requireAuth, getAuthContext } from '../middleware/auth.js';
 
92
  // =============================================================================
93
 
94
  /**
95
+ * Get the path to chapter content directory
 
96
  */
97
+ function getChapterContentPath(): string {
98
+ // Use environment variable or default to relative path from auth service
99
+ return process.env.CHAPTER_CONTENT_PATH || resolve(process.cwd(), '..', 'book-write', 'docs');
 
100
  }
101
 
102
  /**
103
+ * Fetch chapter content from filesystem
104
  * Supports both `chapter-01.md` and `chapter-01/index.md` patterns
105
  */
106
  async function fetchChapterContent(chapterId: string): Promise<string | null> {
107
+ const basePath = getChapterContentPath();
108
 
109
  // Sanitize chapter ID to prevent directory traversal
110
  const sanitizedId = chapterId.replace(/\.\./g, '').replace(/^\/+/, '');
111
 
112
  // Try different file patterns
113
  const patterns = [
114
+ join(basePath, `${sanitizedId}.md`),
115
+ join(basePath, `${sanitizedId}.mdx`),
116
+ join(basePath, sanitizedId, 'index.md'),
117
+ join(basePath, sanitizedId, 'index.mdx'),
118
  ];
119
 
120
+ for (const filePath of patterns) {
121
  try {
122
+ const content = await readFile(filePath, 'utf-8');
 
 
 
 
123
  // Strip frontmatter
124
  const frontmatterMatch = content.match(/^---\n[\s\S]*?\n---\n/);
125
  if (frontmatterMatch) {
 
127
  }
128
  return content;
129
  } catch {
130
+ // File doesn't exist, try next pattern
131
  continue;
132
  }
133
  }
 
374
  }
375
 
376
  // Fetch chapter content (TASK-005)
377
+ // For deployment compatibility, allow frontend to provide content directly
378
+ let chapterContent = body.chapter_content;
379
  if (!chapterContent) {
380
+ // Fallback to filesystem fetch if content not provided
381
+ chapterContent = await fetchChapterContent(body.chapter_id);
382
+ if (!chapterContent) {
383
+ return c.json({
384
+ success: false,
385
+ error: 'CHAPTER_NOT_FOUND',
386
+ message: 'Chapter not found and no content provided',
387
+ }, 404);
388
+ }
389
  }
390
 
391
  // Log personalization request