Persist versioned document text reviews against source file hashes
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import {createHash} from 'node:crypto';
|
||||
import {openDb,BELGE_DIR} from './user-store.mjs';
|
||||
const hash=value=>createHash('sha256').update(value).digest('hex');
|
||||
const fail=(status,message)=>Object.assign(new Error(message),{status});
|
||||
function source(db,email,id) {
|
||||
const record=db.prepare('SELECT * FROM belgeler WHERE id=? AND email=?').get(id,email);
|
||||
if(!record || record.tur !== 'ihale') throw fail(404,'İhale dokümanı bulunamadı.');
|
||||
let bytes;
|
||||
try {bytes=fs.readFileSync(path.join(BELGE_DIR,record.dosya));}
|
||||
catch {throw fail(409,'Kaynak dosya okunamıyor; inceleme kaydedilemez.');}
|
||||
return hash(bytes);
|
||||
}
|
||||
function latest(db,email,id) {
|
||||
return db.prepare('SELECT revision,file_hash,text_hash,corrected_text,review_note,reviewed_at FROM document_text_reviews WHERE document_id=? AND email=? ORDER BY revision DESC LIMIT 1').get(id,email) || null;
|
||||
}
|
||||
export function documentReview(email,id) {
|
||||
const db=openDb();
|
||||
try {
|
||||
const fileHash=source(db,email,id), review=latest(db,email,id);
|
||||
return {documentId:id,fileHash,review,stale:Boolean(review && review.file_hash!==fileHash)};
|
||||
} finally {db.close();}
|
||||
}
|
||||
export function saveDocumentReview(email,id,input) {
|
||||
if(typeof input.correctedText !== 'string' || input.correctedText.trim().length<40 || Buffer.byteLength(input.correctedText)>1024*1024)
|
||||
throw fail(400,'Kontrol edilen metin 40 karakter ile 1 MB arasında olmalı.');
|
||||
if(typeof input.note !== 'string' || input.note.trim().length<20 || input.note.length>2000)
|
||||
throw fail(400,'Karşılaştırılan sayfaları ve yapılan düzeltmeleri en az 20 karakterle açıklayın.');
|
||||
if(input.allPagesCompared !== true) throw fail(400,'Tüm kaynak sayfalarıyla karşılaştırma gerekli.');
|
||||
if(!Number.isInteger(input.expectedRevision) || input.expectedRevision<0) throw fail(400,'Geçerli inceleme sürümü gerekli.');
|
||||
const db=openDb();
|
||||
try {
|
||||
db.exec('BEGIN IMMEDIATE');
|
||||
const fileHash=source(db,email,id), previous=latest(db,email,id);
|
||||
if(input.fileHash!==fileHash || input.expectedRevision!==(previous?.revision || 0)) throw fail(409,'Dosya veya inceleme sürümü değişti. Güncel kaydı yeniden açın.');
|
||||
const text=input.correctedText.trim();
|
||||
db.prepare('INSERT INTO document_text_reviews VALUES (?,?,?,?,?,?,?,?)').run(id,email,input.expectedRevision+1,fileHash,hash(text),text,input.note.trim(),new Date().toISOString());
|
||||
const review=latest(db,email,id);
|
||||
db.exec('COMMIT');return {documentId:id,fileHash,review,stale:false};
|
||||
} catch(error) {try {db.exec('ROLLBACK');} catch {} throw error;}
|
||||
finally {db.close();}
|
||||
}
|
||||
Reference in New Issue
Block a user