feat: add POST /api/cases/parties to store UYAP taraf bilgileri
The UYAP extension now captures the davaci/davali/sanik + vekil data from the "Taraf Bilgileri" tab and sends it once per case. This endpoint finds/creates the matching case by title (same lookup used by registerLocalDocument, now shared via lib/caseLookup.ts) and stores it in a new cases.parties column - a much more reliable source for the case detail screen's "Taraflar" info than the AI's own guess from OCR'd document text. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9f5c5c1e45
commit
99d4d770d5
@@ -2,6 +2,7 @@ import { Response } from 'express';
|
|||||||
import { supabase } from '../lib/supabase';
|
import { supabase } from '../lib/supabase';
|
||||||
import { AuthenticatedRequest } from '../middleware/auth';
|
import { AuthenticatedRequest } from '../middleware/auth';
|
||||||
import { runDocumentAnalysis } from './document.controller';
|
import { runDocumentAnalysis } from './document.controller';
|
||||||
|
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
|
||||||
|
|
||||||
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
|
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@@ -72,6 +73,36 @@ export const summarizeCase = async (req: AuthenticatedRequest, res: Response) =>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// UYAP Evrak İndirici eklentisinin "Taraf Bilgileri" sekmesinden yakaladığı
|
||||||
|
// davacı/davalı/sanık + vekil bilgisini kaydeder. AI'nin OCR metninden tahmin
|
||||||
|
// ettiği "Taraflar" alanından çok daha güvenilir — doğrudan UYAP'ın yapılandırılmış
|
||||||
|
// verisi. case_title ile eşleştirme registerLocalDocument ile aynı mantık.
|
||||||
|
export const updateCaseParties = async (req: AuthenticatedRequest, res: Response) => {
|
||||||
|
try {
|
||||||
|
const userId = req.user?.id;
|
||||||
|
const { case_title, parties } = req.body || {};
|
||||||
|
|
||||||
|
if (!case_title || !Array.isArray(parties) || parties.length === 0) {
|
||||||
|
return res.status(400).json({ error: 'case_title ve parties zorunludur.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const caseId = await findOrCreateCaseByTitle(userId as string, case_title);
|
||||||
|
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('cases')
|
||||||
|
.update({ parties })
|
||||||
|
.eq('id', caseId)
|
||||||
|
.select('id, title, parties')
|
||||||
|
.single();
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
res.json({ case: data });
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Update Case Parties Error:', error);
|
||||||
|
res.status(500).json({ error: error.message || 'Internal Server Error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const deleteCase = async (req: AuthenticatedRequest, res: Response) => {
|
export const deleteCase = async (req: AuthenticatedRequest, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { caseId } = req.params;
|
const { caseId } = req.params;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { supabase } from '../lib/supabase';
|
|||||||
import { AuthenticatedRequest } from '../middleware/auth';
|
import { AuthenticatedRequest } from '../middleware/auth';
|
||||||
import * as officeParser from 'officeparser';
|
import * as officeParser from 'officeparser';
|
||||||
import Tesseract from 'tesseract.js';
|
import Tesseract from 'tesseract.js';
|
||||||
|
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
|
||||||
const heicConvert = require('heic-convert');
|
const heicConvert = require('heic-convert');
|
||||||
|
|
||||||
const ANALYSIS_SYSTEM_PROMPT = `
|
const ANALYSIS_SYSTEM_PROMPT = `
|
||||||
@@ -65,27 +66,7 @@ export const registerLocalDocument = async (req: AuthenticatedRequest, res: Resp
|
|||||||
return res.status(400).json({ error: 'case_title, filename ve extracted_text zorunludur.' });
|
return res.status(400).json({ error: 'case_title, filename ve extracted_text zorunludur.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dava başlığına göre mevcut case'i bul (case-insensitive), yoksa oluştur.
|
const caseId = await findOrCreateCaseByTitle(userId as string, case_title);
|
||||||
const { data: existing } = await supabase
|
|
||||||
.from('cases')
|
|
||||||
.select('id, title')
|
|
||||||
.eq('user_id', userId)
|
|
||||||
.ilike('title', case_title)
|
|
||||||
.limit(1)
|
|
||||||
.maybeSingle();
|
|
||||||
|
|
||||||
let caseId: string;
|
|
||||||
if (existing) {
|
|
||||||
caseId = existing.id;
|
|
||||||
} else {
|
|
||||||
const { data: newCase, error: caseError } = await supabase
|
|
||||||
.from('cases')
|
|
||||||
.insert([{ title: String(case_title).slice(0, 200), user_id: userId }])
|
|
||||||
.select('id')
|
|
||||||
.single();
|
|
||||||
if (caseError) throw caseError;
|
|
||||||
caseId = newCase.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data: documentRecord, error: docError } = await supabase
|
const { data: documentRecord, error: docError } = await supabase
|
||||||
.from('documents')
|
.from('documents')
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { supabase } from './supabase';
|
||||||
|
|
||||||
|
// UYAP'tan gelen dava başlığına göre (case-insensitive) kullanıcının mevcut case'ini
|
||||||
|
// bulur, yoksa oluşturur. registerLocalDocument ve updateCaseParties'in ortak kullandığı
|
||||||
|
// eşleştirme mantığı — ikisi de aynı case_title string'iyle çalışıyor.
|
||||||
|
export async function findOrCreateCaseByTitle(userId: string, caseTitle: string): Promise<string> {
|
||||||
|
const { data: existing } = await supabase
|
||||||
|
.from('cases')
|
||||||
|
.select('id')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.ilike('title', caseTitle)
|
||||||
|
.limit(1)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
if (existing) return existing.id;
|
||||||
|
|
||||||
|
const { data: newCase, error } = await supabase
|
||||||
|
.from('cases')
|
||||||
|
.insert([{ title: String(caseTitle).slice(0, 200), user_id: userId }])
|
||||||
|
.select('id')
|
||||||
|
.single();
|
||||||
|
if (error) throw error;
|
||||||
|
return newCase.id;
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { requireAuth } from '../middleware/auth';
|
import { requireAuth } from '../middleware/auth';
|
||||||
import { createCase, deleteCase, summarizeCase } from '../controllers/case.controller';
|
import { createCase, deleteCase, summarizeCase, updateCaseParties } from '../controllers/case.controller';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.post('/', requireAuth, createCase);
|
router.post('/', requireAuth, createCase);
|
||||||
router.delete('/:caseId', requireAuth, deleteCase);
|
router.delete('/:caseId', requireAuth, deleteCase);
|
||||||
router.post('/:caseId/summarize', requireAuth, summarizeCase);
|
router.post('/:caseId/summarize', requireAuth, summarizeCase);
|
||||||
|
router.post('/parties', requireAuth, updateCaseParties);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user