Analyze server-resolved document reviews with revision checks
This commit is contained in:
@@ -41,3 +41,21 @@ export function saveDocumentReview(email,id,input) {
|
||||
} catch(error) {try {db.exec('ROLLBACK');} catch {} throw error;}
|
||||
finally {db.close();}
|
||||
}
|
||||
|
||||
/** Resolve a requested review to server-owned text; caller text/approval is never used. */
|
||||
export function reviewedAnalysisSource(email,reference,tenderKey) {
|
||||
if(!reference || typeof reference.documentId !== 'string' || !Number.isInteger(reference.revision))
|
||||
throw fail(400,'Geçerli belge ve inceleme sürümü gerekli.');
|
||||
const db=openDb();
|
||||
try {
|
||||
const fileHash=source(db,email,reference.documentId);
|
||||
const doc=db.prepare('SELECT ad,ikn FROM belgeler WHERE id=? AND email=?').get(reference.documentId,email);
|
||||
if(!doc.ikn || doc.ikn!==tenderKey) throw fail(409,'İnceleme bu ihaleye bağlı değil.');
|
||||
const review=latest(db,email,reference.documentId);
|
||||
if(!review || review.revision!==reference.revision || review.file_hash!==fileHash)
|
||||
throw fail(409,'İnceleme veya kaynak dosya değişti; güncel incelemeyi açın.');
|
||||
return {text:review.corrected_text,fileName:doc.ad,
|
||||
humanReview:{documentId:reference.documentId,revision:review.revision,fileHash,textHash:review.text_hash,
|
||||
reviewedBy:email,reviewedAt:review.reviewed_at,note:review.review_note}};
|
||||
} finally {db.close();}
|
||||
}
|
||||
|
||||
+13
-6
@@ -1,4 +1,4 @@
|
||||
import {documentReview,saveDocumentReview} from './document-review.mjs';
|
||||
import {documentReview,saveDocumentReview,reviewedAnalysisSource} from './document-review.mjs';
|
||||
import { documentMetadataPatch, decodeDocumentUpload } from './document-metadata.mjs';
|
||||
import { deadlineInfo } from '../src/services/tenderCalendar.js';
|
||||
import { exchangeRates } from './exchange-rates.mjs';
|
||||
@@ -1300,20 +1300,27 @@ const server = http.createServer(async (req, res) => {
|
||||
}
|
||||
try {
|
||||
const body = await readBody(req, 2 * 1024 * 1024);
|
||||
if (!body.text || String(body.text).trim().length < 40) {
|
||||
const reviewed=body.reviewedSource ? reviewedAnalysisSource(user.email,body.reviewedSource,body.tender?.ikn) : null;
|
||||
const sourceText=reviewed ? reviewed.text : body.text;
|
||||
if (!sourceText || String(sourceText).trim().length < 40) {
|
||||
return json(res, 400, { success: false, error: 'Analiz için yeterli metin yok (en az 40 karakter).' });
|
||||
}
|
||||
const out = await analyzeSpec({
|
||||
text: body.text,
|
||||
fileName: body.fileName,
|
||||
extraction: body.extraction,
|
||||
text: sourceText,
|
||||
fileName: reviewed?.fileName || body.fileName,
|
||||
extraction: reviewed ? {fileName:reviewed.fileName,complete:true,ocr:false} : body.extraction,
|
||||
tender: body.tender,
|
||||
chain: body.chain,
|
||||
mode: body.mode === 'derin' ? 'derin' : undefined,
|
||||
});
|
||||
if (reviewed) {
|
||||
const latest=reviewedAnalysisSource(user.email,body.reviewedSource,body.tender?.ikn);
|
||||
if(latest.humanReview.textHash!==reviewed.humanReview.textHash) throw Object.assign(new Error('İnceleme analiz sırasında değişti.'),{status:409});
|
||||
out.result.sourceReview={...out.result.sourceReview,humanReview:reviewed.humanReview};
|
||||
}
|
||||
return json(res, 200, { success: true, ...out, analyzedAt: new Date().toISOString() });
|
||||
} catch (e) {
|
||||
return json(res, 502, { success: false, error: e.message, attempts: e.attempts || null });
|
||||
return json(res, e.status || 502, { success: false, error: e.message, attempts: e.attempts || null });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user