project-nomad/admin/app/controllers/zim_controller.ts
Chris Sherwood 2c4fc59428 feat(ContentManager): Display friendly names instead of filenames
Content Manager now shows Title and Summary columns from Kiwix metadata
instead of just raw filenames. Metadata is captured when files are
downloaded from Content Explorer and stored in a new zim_file_metadata
table. Existing files without metadata gracefully fall back to showing
the filename.

Changes:
- Add zim_file_metadata table and model for storing title, summary, author
- Update download flow to capture and store metadata from Kiwix library
- Update Content Manager UI to display Title and Summary columns
- Clean up metadata when ZIM files are deleted

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 23:14:28 -08:00

95 lines
2.8 KiB
TypeScript

import { ZimService } from '#services/zim_service'
import {
downloadCollectionValidator,
filenameParamValidator,
remoteDownloadWithMetadataValidator,
saveInstalledTierValidator,
selectWikipediaValidator,
} from '#validators/common'
import { listRemoteZimValidator } from '#validators/zim'
import { inject } from '@adonisjs/core'
import type { HttpContext } from '@adonisjs/core/http'
@inject()
export default class ZimController {
constructor(private zimService: ZimService) {}
async list({}: HttpContext) {
return await this.zimService.list()
}
async listRemote({ request }: HttpContext) {
const payload = await request.validateUsing(listRemoteZimValidator)
const { start = 0, count = 12, query } = payload
return await this.zimService.listRemote({ start, count, query })
}
async downloadRemote({ request }: HttpContext) {
const payload = await request.validateUsing(remoteDownloadWithMetadataValidator)
const { filename, jobId } = await this.zimService.downloadRemote(payload.url, payload.metadata)
return {
message: 'Download started successfully',
filename,
jobId,
url: payload.url,
}
}
async downloadCollection({ request }: HttpContext) {
const payload = await request.validateUsing(downloadCollectionValidator)
const resources = await this.zimService.downloadCollection(payload.slug)
return {
message: 'Download started successfully',
slug: payload.slug,
resources,
}
}
async listCuratedCollections({}: HttpContext) {
return this.zimService.listCuratedCollections()
}
async fetchLatestCollections({}: HttpContext) {
const success = await this.zimService.fetchLatestCollections()
return { success }
}
async saveInstalledTier({ request }: HttpContext) {
const payload = await request.validateUsing(saveInstalledTierValidator)
await this.zimService.saveInstalledTier(payload.categorySlug, payload.tierSlug)
return { success: true }
}
async delete({ request, response }: HttpContext) {
const payload = await request.validateUsing(filenameParamValidator)
try {
await this.zimService.delete(payload.params.filename)
} catch (error) {
if (error.message === 'not_found') {
return response.status(404).send({
message: `ZIM file with key ${payload.params.filename} not found`,
})
}
throw error // Re-throw any other errors and let the global error handler catch
}
return {
message: 'ZIM file deleted successfully',
}
}
// Wikipedia selector endpoints
async getWikipediaState({}: HttpContext) {
return this.zimService.getWikipediaState()
}
async selectWikipedia({ request }: HttpContext) {
const payload = await request.validateUsing(selectWikipediaValidator)
return this.zimService.selectWikipedia(payload.optionId)
}
}