From 253311bbd70e30e0f78ce17c23221e911514dcb3 Mon Sep 17 00:00:00 2001 From: monoid Date: Wed, 29 Jun 2022 21:14:39 +0900 Subject: [PATCH] add tag api --- src/config.ts | 10 ++++++++-- src/database.ts | 19 ++++++++++++++++--- src/db/doc.ts | 2 +- src/db/tag.ts | 10 ++++++++-- src/model/tag.ts | 18 ++++++++++++------ src/route/tags.ts | 32 ++++++++++++++++++++++++++++++++ src/server.ts | 37 ++++++++++++++++++++++++++----------- 7 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 src/route/tags.ts diff --git a/src/config.ts b/src/config.ts index 35d0f78..44d381c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,10 +1,16 @@ +import {Knex as k} from "knex"; + export namespace Knex { - export const config = { + export const config: { + development: k.Config, + production: k.Config + } = { development: { client: 'sqlite3', connection: { filename: './devdb.sqlite3' - } + }, + debug: true, }, production: { client: 'sqlite3', diff --git a/src/database.ts b/src/database.ts index e13afde..b779352 100644 --- a/src/database.ts +++ b/src/database.ts @@ -4,10 +4,23 @@ import {Knex as KnexConfig} from './config'; import { get_setting } from './SettingConfig'; export async function connectDB(){ - const config = KnexConfig.config; const env = get_setting().mode; - const init_need = !existsSync(config[env].connection.filename); - const knex = Knex(config[env]); + const config = KnexConfig.config[env]; + if(!config.connection){ + throw new Error("connection options required."); + } + const connection = config.connection + if(typeof connection === "string"){ + throw new Error("unknown connection options"); + } + if(typeof connection === "function"){ + throw new Error("connection provider not supported..."); + } + if(!("filename" in connection) ){ + throw new Error("sqlite3 config need"); + } + const init_need = !existsSync(connection.filename); + const knex = Knex(config); let tries = 0; for(;;){ try{ diff --git a/src/db/doc.ts b/src/db/doc.ts index 02731db..44cbab7 100644 --- a/src/db/doc.ts +++ b/src/db/doc.ts @@ -3,7 +3,7 @@ import {Knex} from 'knex'; import {createKnexTagController} from './tag'; import { TagAccessor } from '../model/tag'; -type DBTagContentRelation = { +export type DBTagContentRelation = { doc_id:number, tag_name:string } diff --git a/src/db/tag.ts b/src/db/tag.ts index 0f4d49c..2754223 100644 --- a/src/db/tag.ts +++ b/src/db/tag.ts @@ -1,5 +1,6 @@ -import {Tag, TagAccessor} from '../model/tag'; +import {Tag, TagAccessor, TagCount} from '../model/tag'; import {Knex} from 'knex'; +import {DBTagContentRelation} from './doc'; type DBTags = { name: string, @@ -11,7 +12,12 @@ class KnexTagAccessor implements TagAccessor{ constructor(knex:Knex){ this.knex = knex; } - async getTagAllList(onlyname?:boolean){ + async getAllTagCount(): Promise { + const result = await this.knex("doc_tag_relation").select("tag_name") + .count("*",{as:"occurs"}).groupBy("tag_name"); + return result; + } + async getAllTagList(onlyname?:boolean){ onlyname = onlyname ?? false; const t:DBTags[] = await this.knex.select(onlyname ? "*" : "name").from("tags") return t; diff --git a/src/model/tag.ts b/src/model/tag.ts index 5071e8d..caa6943 100644 --- a/src/model/tag.ts +++ b/src/model/tag.ts @@ -3,10 +3,16 @@ export interface Tag{ description?: string } -export interface TagAccessor{ - getTagAllList: (onlyname?:boolean)=> Promise - getTagByName: (name:string)=>Promise, - addTag: (tag:Tag)=>Promise, - delTag: (name:string) => Promise, - updateTag: (name:string,tag:string) => Promise +export interface TagCount{ + tagname: string; + occurs: number; +} + +export interface TagAccessor{ + getAllTagList: (onlyname?:boolean)=> Promise; + getAllTagCount(): Promise; + getTagByName: (name:string)=>Promise; + addTag: (tag:Tag)=>Promise; + delTag: (name:string) => Promise; + updateTag: (name:string,tag:string) => Promise; } diff --git a/src/route/tags.ts b/src/route/tags.ts new file mode 100644 index 0000000..2d243bb --- /dev/null +++ b/src/route/tags.ts @@ -0,0 +1,32 @@ +import {Context, Next} from "koa"; +import Router,{RouterContext} from "koa-router"; +import { TagAccessor } from "../model/tag"; +import { sendError } from "./error_handler"; +import { createPermissionCheckMiddleware as PerCheck, Permission } from "../permission/permission"; + +export function getTagRounter(tagController: TagAccessor){ + let router = new Router(); + router.get("/",PerCheck(Permission.QueryContent), + async (ctx: Context)=>{ + if(ctx.query["withCount"]){ + const c = await tagController.getAllTagCount(); + ctx.body = c; + } + else { + const c = await tagController.getAllTagList(); + ctx.body = c; + } + ctx.type = "json"; + }); + router.get("/:tag_name", PerCheck(Permission.QueryContent), + async (ctx: RouterContext)=>{ + const tag_name = ctx.params["tag_name"]; + const c = await tagController.getTagByName(tag_name); + if (!c){ + sendError(404, "tags not found"); + } + ctx.body = c; + ctx.type = "json"; + }); + return router; +} \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 4d335bd..9cfdcc7 100644 --- a/src/server.ts +++ b/src/server.ts @@ -7,25 +7,31 @@ import {DiffManager, createDiffRouter} from './diff/mod'; import { createReadStream, readFileSync } from 'fs'; import getContentRouter from './route/contents'; -import { createKnexDocumentAccessor, createKnexUserController } from './db/mod'; +import { createKnexDocumentAccessor, createKnexTagController, createKnexUserController } from './db/mod'; import bodyparser from 'koa-bodyparser'; import {error_handler} from './route/error_handler'; import {createUserMiddleWare, createLoginRouter, isAdminFirst, getAdmin} from './login'; import {createInterface as createReadlineInterface} from 'readline'; -import { DocumentAccessor, UserAccessor } from './model/mod'; +import { DocumentAccessor, UserAccessor, TagAccessor } from './model/mod'; import { createComicWatcher } from './diff/watcher/comic_watcher'; - +import { getTagRounter } from './route/tags'; class ServerApplication{ readonly userController: UserAccessor; readonly documentController: DocumentAccessor; - readonly diffManger; + readonly tagController: TagAccessor; + readonly diffManger: DiffManager; readonly app: Koa; private index_html:Buffer; - private constructor(userController: UserAccessor,documentController:DocumentAccessor){ - this.userController = userController; - this.documentController = documentController; - this.diffManger = new DiffManager(documentController); + private constructor(controller:{ + userController: UserAccessor, + documentController:DocumentAccessor, + tagController: TagAccessor}){ + this.userController = controller.userController; + this.documentController = controller.documentController; + this.tagController = controller.tagController; + + this.diffManger = new DiffManager(this.documentController); this.app = new Koa(); this.index_html = readFileSync("index.html"); } @@ -66,6 +72,11 @@ class ServerApplication{ const content_router = getContentRouter(this.documentController); router.use('/api/doc',content_router.routes()); router.use('/api/doc',content_router.allowedMethods()); + + const tags_router = getTagRounter(this.tagController); + router.use("/api/tags",tags_router.routes()); + router.use("/api/tags",tags_router.allowedMethods()); + const login_router = createLoginRouter(this.userController); router.use('/user',login_router.routes()); router.use('/user',login_router.allowedMethods()); @@ -75,7 +86,8 @@ class ServerApplication{ let mm_count = 0; app.use(async (ctx,next)=>{ console.log(`==========================${mm_count++}`); - const fromClient = ctx.state['user'].username === "" ? ctx.ip : ctx.state['user'].username; + const ip = (ctx.get("X-Real-IP")) ?? ctx.ip; + const fromClient = ctx.state['user'].username === "" ? ip : ctx.state['user'].username; console.log(`${fromClient} : ${ctx.method} ${ctx.url}`); await next(); //console.log(`404`); @@ -136,8 +148,11 @@ class ServerApplication{ const setting = get_setting(); let db = await connectDB(); - const app = new ServerApplication(createKnexUserController(db) - ,createKnexDocumentAccessor(db)); + const app = new ServerApplication({ + userController:createKnexUserController(db), + documentController: createKnexDocumentAccessor(db), + tagController: createKnexTagController(db), + }); await app.setup(); return app; }