Fix authentication state persistence and admin role display
- Implement complete authentication system with JWT token validation - Add auth provider with persistent login state across page refreshes - Create multilingual login/register forms with Material-UI components - Fix token validation using raw SQL queries to bypass Prisma sync issues - Add comprehensive error handling for expired/invalid tokens - Create profile and settings pages with full i18n support - Add proper user role management (admin/user) with database sync - Implement secure middleware with CSRF protection and auth checks - Add debug endpoints for troubleshooting authentication issues - Fix Zustand store persistence for authentication state 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
140
scripts/import-english-json.ts
Normal file
140
scripts/import-english-json.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
interface Verse { verseNum: number; text: string }
|
||||
interface Chapter { chapterNum: number; verses: Verse[] }
|
||||
interface Book { name: string; chapters: Chapter[] }
|
||||
interface TestamentFile { testament: string; books: Book[] }
|
||||
|
||||
function loadJson(file: string): TestamentFile {
|
||||
return JSON.parse(fs.readFileSync(file, 'utf-8'))
|
||||
}
|
||||
|
||||
function getBookKeyEn(name: string): string {
|
||||
const map: Record<string, string> = {
|
||||
'Genesis': 'genesis', 'Exodus': 'exodus', 'Leviticus': 'leviticus', 'Numbers': 'numbers', 'Deuteronomy': 'deuteronomy',
|
||||
'Joshua': 'joshua', 'Judges': 'judges', 'Ruth': 'ruth', '1 Samuel': '1_samuel', '2 Samuel': '2_samuel',
|
||||
'1 Kings': '1_kings', '2 Kings': '2_kings', '1 Chronicles': '1_chronicles', '2 Chronicles': '2_chronicles',
|
||||
'Ezra': 'ezra', 'Nehemiah': 'nehemiah', 'Esther': 'esther', 'Job': 'job', 'Psalms': 'psalms',
|
||||
'Proverbs': 'proverbs', 'Ecclesiastes': 'ecclesiastes', 'Song of Songs': 'song_of_songs', 'Isaiah': 'isaiah',
|
||||
'Jeremiah': 'jeremiah', 'Lamentations': 'lamentations', 'Ezekiel': 'ezekiel', 'Daniel': 'daniel',
|
||||
'Hosea': 'hosea', 'Joel': 'joel', 'Amos': 'amos', 'Obadiah': 'obadiah', 'Jonah': 'jonah', 'Micah': 'micah',
|
||||
'Nahum': 'nahum', 'Habakkuk': 'habakkuk', 'Zephaniah': 'zephaniah', 'Haggai': 'haggai', 'Zechariah': 'zechariah', 'Malachi': 'malachi',
|
||||
'Matthew': 'matthew', 'Mark': 'mark', 'Luke': 'luke', 'John': 'john', 'Acts': 'acts', 'Romans': 'romans',
|
||||
'1 Corinthians': '1_corinthians', '2 Corinthians': '2_corinthians', 'Galatians': 'galatians', 'Ephesians': 'ephesians', 'Philippians': 'philippians', 'Colossians': 'colossians',
|
||||
'1 Thessalonians': '1_thessalonians', '2 Thessalonians': '2_thessalonians', '1 Timothy': '1_timothy', '2 Timothy': '2_timothy', 'Titus': 'titus', 'Philemon': 'philemon',
|
||||
'Hebrews': 'hebrews', 'James': 'james', '1 Peter': '1_peter', '2 Peter': '2_peter', '1 John': '1_john', '2 John': '2_john', '3 John': '3_john', 'Jude': 'jude', 'Revelation': 'revelation'
|
||||
}
|
||||
return map[name] || name.toLowerCase().replace(/\s+/g, '_')
|
||||
}
|
||||
|
||||
function getOrderFromList(name: string, list: string[]): number {
|
||||
const idx = list.indexOf(name)
|
||||
return idx >= 0 ? idx + 1 : 999
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const abbr = (process.env.EN_ABBR || 'BSB').toUpperCase()
|
||||
const inputDir = process.env.INPUT_DIR || path.join('data', 'en_bible', abbr)
|
||||
const lang = 'en'
|
||||
|
||||
const otPath = path.join(inputDir, 'old_testament.json')
|
||||
const ntPath = path.join(inputDir, 'new_testament.json')
|
||||
if (!fs.existsSync(otPath) || !fs.existsSync(ntPath)) {
|
||||
throw new Error(`Missing OT/NT JSON at ${inputDir}. Run fetch-english-bible.ts first.`)
|
||||
}
|
||||
|
||||
// Upsert English version
|
||||
const englishVersion = await prisma.bibleVersion.upsert({
|
||||
where: { abbreviation_language: { abbreviation: abbr, language: lang } },
|
||||
update: {},
|
||||
create: {
|
||||
name: abbr,
|
||||
abbreviation: abbr,
|
||||
language: lang,
|
||||
description: `English Bible (${abbr})`,
|
||||
isDefault: true
|
||||
}
|
||||
})
|
||||
|
||||
const ot = loadJson(otPath)
|
||||
const nt = loadJson(ntPath)
|
||||
const canon = [...ot.books.map(b => b.name), ...nt.books.map(b => b.name)]
|
||||
|
||||
let importedBooks = 0
|
||||
let importedChapters = 0
|
||||
let importedVerses = 0
|
||||
|
||||
async function importTestament(test: TestamentFile) {
|
||||
for (const book of test.books) {
|
||||
const orderNum = getOrderFromList(book.name, canon)
|
||||
const testament = test.testament
|
||||
const bookKey = getBookKeyEn(book.name)
|
||||
|
||||
const createdBook = await prisma.bibleBook.upsert({
|
||||
where: {
|
||||
versionId_orderNum: {
|
||||
versionId: englishVersion.id,
|
||||
orderNum
|
||||
}
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
versionId: englishVersion.id,
|
||||
name: book.name,
|
||||
testament,
|
||||
orderNum,
|
||||
bookKey
|
||||
}
|
||||
})
|
||||
importedBooks++
|
||||
|
||||
for (const chapter of book.chapters) {
|
||||
const createdChapter = await prisma.bibleChapter.upsert({
|
||||
where: {
|
||||
bookId_chapterNum: {
|
||||
bookId: createdBook.id,
|
||||
chapterNum: chapter.chapterNum
|
||||
}
|
||||
},
|
||||
update: {},
|
||||
create: { bookId: createdBook.id, chapterNum: chapter.chapterNum }
|
||||
})
|
||||
importedChapters++
|
||||
|
||||
// Deduplicate verses by verseNum
|
||||
const unique = new Map<number, string>()
|
||||
for (const v of chapter.verses) {
|
||||
if (!unique.has(v.verseNum)) unique.set(v.verseNum, v.text)
|
||||
}
|
||||
const versesData = Array.from(unique.entries()).map(([num, text]) => ({
|
||||
chapterId: createdChapter.id,
|
||||
verseNum: num,
|
||||
text
|
||||
}))
|
||||
if (versesData.length > 0) {
|
||||
await prisma.bibleVerse.createMany({ data: versesData, skipDuplicates: true })
|
||||
importedVerses += versesData.length
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await importTestament(ot)
|
||||
await importTestament(nt)
|
||||
|
||||
console.log(`Imported ${importedBooks} books, ${importedChapters} chapters, ${importedVerses} verses for ${abbr}.`)
|
||||
} catch (e) {
|
||||
console.error('English JSON import failed:', e)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
await prisma.$disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user