add modified_at

This commit is contained in:
monoid 2022-07-19 23:41:50 +09:00
parent 6dd1d4d83a
commit e889f98530
7 changed files with 4418 additions and 13 deletions

View File

@ -1,6 +1,11 @@
import {Knex} from 'knex'; import {Knex} from 'knex';
export async function up(knex:Knex) { export async function up(knex:Knex) {
await knex.schema.createTable("schema_migration",(b)=>{
b.string("version");
b.boolean("dirty");
});
await knex.schema.createTable("users",(b)=>{ await knex.schema.createTable("users",(b)=>{
b.string("username").primary().comment("user's login id"); b.string("username").primary().comment("user's login id");
b.string("password_hash",64).notNullable(); b.string("password_hash",64).notNullable();
@ -15,6 +20,7 @@ export async function up(knex:Knex) {
b.string("content_hash").nullable(); b.string("content_hash").nullable();
b.json("additional").nullable(); b.json("additional").nullable();
b.integer("created_at").notNullable(); b.integer("created_at").notNullable();
b.integer("modified_at").notNullable();
b.integer("deleted_at"); b.integer("deleted_at");
b.index("content_type","content_type_index"); b.index("content_type","content_type_index");
}); });
@ -44,10 +50,5 @@ export async function up(knex:Knex) {
}; };
export async function down(knex:Knex) { export async function down(knex:Knex) {
//throw new Error('Downward migrations are not supported. Restore from backup.'); throw new Error('Downward migrations are not supported. Restore from backup.');
await knex.schema.dropTable("users");
await knex.schema.dropTable("document");
await knex.schema.dropTable("tags");
await knex.schema.dropTable("document_tag_relation");
await knex.schema.dropTable("permissions");
}; };

View File

@ -40,4 +40,10 @@
- ~~hash~~ - ~~hash~~
- search - search
- client tag add and delete - client tag add and delete
- pagination - ~~pagination~~
add URL Render page 바꾸기
add modified_time
add support robots.txt
add vite ssr

3319
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

1068
src/client/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
import {Context, DefaultState, DefaultContext, Middleware, Next} from 'koa'; import {Context, DefaultState, DefaultContext, Middleware, Next} from 'koa';
import Router from 'koa-router'; import Router from 'koa-router';
import {createHash} from 'crypto'; import {createHash} from 'crypto';
import {promises} from 'fs' import {promises, Stats} from 'fs'
import {extname} from 'path'; import {extname} from 'path';
import { DocumentBody } from '../model/mod'; import { DocumentBody } from '../model/mod';
import path from 'path'; import path from 'path';
@ -15,7 +15,7 @@ export interface ContentFile{
readonly type: string; readonly type: string;
} }
export type ContentConstructOption = { export type ContentConstructOption = {
hash: string hash: string,
} }
type ContentFileConstructor = (new (path:string,option?:ContentConstructOption) => ContentFile)&{content_type:string}; type ContentFileConstructor = (new (path:string,option?:ContentConstructOption) => ContentFile)&{content_type:string};
export const createDefaultClass = (type:string):ContentFileConstructor=>{ export const createDefaultClass = (type:string):ContentFileConstructor=>{
@ -24,13 +24,16 @@ export const createDefaultClass = (type:string):ContentFileConstructor=>{
//type = type; //type = type;
static content_type = type; static content_type = type;
protected hash: string| undefined; protected hash: string| undefined;
protected stat: Stats| undefined;
constructor(path:string,option?:ContentConstructOption){ constructor(path:string,option?:ContentConstructOption){
this.path = path; this.path = path;
this.hash = option?.hash; this.hash = option?.hash;
this.stat = undefined;
} }
async createDocumentBody(): Promise<DocumentBody> { async createDocumentBody(): Promise<DocumentBody> {
const {base,dir, name} = path.parse(this.path); const {base,dir, name} = path.parse(this.path);
const ret = { const ret = {
title : name, title : name,
basepath : dir, basepath : dir,
@ -38,7 +41,8 @@ export const createDefaultClass = (type:string):ContentFileConstructor=>{
content_type: cons.content_type, content_type: cons.content_type,
filename: base, filename: base,
tags: [], tags: [],
content_hash: this.hash ?? await this.getHash(), content_hash: await this.getHash(),
modified_at: await this.getMtime(),
} as DocumentBody; } as DocumentBody;
return ret; return ret;
} }
@ -47,16 +51,21 @@ export const createDefaultClass = (type:string):ContentFileConstructor=>{
} }
async getHash():Promise<string>{ async getHash():Promise<string>{
if(this.hash !== undefined) return this.hash; if(this.hash !== undefined) return this.hash;
const stat = await promises.stat(this.path); this.stat = await promises.stat(this.path);
const hash = createHash("sha512"); const hash = createHash("sha512");
hash.update(extname(this.path)); hash.update(extname(this.path));
hash.update(stat.mode.toString()); hash.update(this.stat.mode.toString());
//if(this.desc !== undefined) //if(this.desc !== undefined)
// hash.update(JSON.stringify(this.desc)); // hash.update(JSON.stringify(this.desc));
hash.update(stat.size.toString()); hash.update(this.stat.size.toString());
this.hash = hash.digest("base64"); this.hash = hash.digest("base64");
return this.hash; return this.hash;
} }
async getMtime():Promise<number>{
if(this.stat !== undefined) return this.stat.mtimeMs;
await this.getHash();
return this.stat!.mtimeMs;
}
}; };
return cons; return cons;
} }

View File

@ -7,6 +7,7 @@ export interface DocumentBody{
content_type : string, content_type : string,
basepath : string, basepath : string,
filename : string, filename : string,
modified_at : number,
content_hash : string, content_hash : string,
additional : JSONMap, additional : JSONMap,
tags : string[],//eager loading tags : string[],//eager loading

View File

@ -16,6 +16,7 @@ import {createInterface as createReadlineInterface} from 'readline';
import { DocumentAccessor, UserAccessor, TagAccessor } from './model/mod'; import { DocumentAccessor, UserAccessor, TagAccessor } from './model/mod';
import { createComicWatcher } from './diff/watcher/comic_watcher'; import { createComicWatcher } from './diff/watcher/comic_watcher';
import { getTagRounter } from './route/tags'; import { getTagRounter } from './route/tags';
class ServerApplication{ class ServerApplication{
readonly userController: UserAccessor; readonly userController: UserAccessor;
readonly documentController: DocumentAccessor; readonly documentController: DocumentAccessor;