$product]); } public static function show($id) { $doc = new Document($id); $doc->load(); return blade("document", [ "doc" => $doc ]); } public static function api_get($id) { return new Document($id); } public static function api_set($id) { $doc = new Document($id); if ($doc->valid()) { foreach ($_POST as $k=>$v) { if ($k != "products") { $doc->$k = trim($v); } } $doc->save(); $pids = explode(",", $_POST['products']); $dpl = DocProduct::find([["document", "=", $id]])->all();; foreach ($dpl as $dp) { $e = array_search($dp->product, $pids); if ($e !== false) { unset($pids[$e]); continue; } $dp->delete(); } foreach ($pids as $pid) { $dp = new DocProduct; $dp->document = $id; $dp->product = $pid; $dp->save(); } $doc->cache_invalidate("products"); } return $doc; } public static function api_get_products($id) { $doc = new Document($id); return $doc->products; } public static function api_move($id) { $doc = new Document($id); $from = $_POST['from']; $to = $_POST['to']; $dp = DocProduct([["document", "=", $id], ["product", "=", $from]])->first(); if ($dp) { $dp->product = $to; $dp->save(); } $doc->cache_invalidate("products"); return []; } public static function del_docproduct($doc, $prod) { $dp = DocProduct::find([["document", "=", $doc], ["product", "=", $prod]])->first(); if ($dp) { $dp->delete(); } return back(); } public static function get_by_id($id) { return Document::find([["internal_id", "=", trim($id)]])->first(); } public static function api_merge($id) { $from = new Document($id); $to = new Document($_POST['to']); if ($from->id == $to->id) return []; if ($from && $to) { $revs = Revision::find([["document", "=", $from->id]]); for ($rev = $revs->first(); $rev = $revs->next(); ) { $rev->document = $to->id; $rev->save(); } $from->delete(); } return new Document($to->id); // Force refresh } public static function api_drag_drop($_request) { $src_id = $_request->post("src_id"); $dst_id = $_request->post("dst_id"); $src_type = $_request->post("src_type"); $dst_type = $_request->post("dst_type"); $src_extra = $_request->post("src_extra"); $dst_extra = $_request->post("dst_extra"); $copy = $_request->post("copy") == "true"; if (($src_type == "document") && ($dst_type == "document")) { // Merge src into dst $src = new Document($src_id); $dst = new Document($dst_id); if ($src->id == $dst->id) return []; foreach ($src->revisions as $r) { $r->document = $dst->id; $r->save(); } $src->delete(); $dst->cache_invalidate("revisions"); } if (($src_type == "document") && ($dst_type == "product")) { if ($copy) { $dp = new DocProduct(); $dp->document = $src_id; $dp->product = $dst_id; $dp->save(); } else { // Move document into product $dpl = DocProduct::find([["document", "=", $src_id], ["product", "=", $src_extra]])->all(); foreach ($dpl as $dp) { $dp->product = $dst_id; $dp->save(); } $prod = new Product($src_extra); $prod->cache_invalidate("documents"); } $doc = new Document($src_id); $doc->cache_invalidate("products"); $prod = new Product($dst_id); $prod->cache_invalidate("documents"); } if (($src_type == "product") && ($dst_type == "product")) { if ($src_id == $dst_id) return []; // Move product into product $sp = new Product($src_id); $dp = new Product($dst_id); $sp->parent = $dp->id; $sp->save(); $sp->cache_invalidate("parent"); $sp->cache_invalidate("children"); $dp->cache_invalidate("parent"); $dp->cache_invalidate("children"); } return [200, ["didit" => "true"]]; } public static function merge($id) { $doc = new Document($id); $proc = new Process("pdftk"); foreach ($doc->revisions as $rev) { $proc->arg($rev->path() . "/doc.pdf"); } $nr = new Revision; $nr->document = $doc->id; $nr->revno = "NEW"; $nr->save(); $out = new File($nr->path() . "/doc.pdf"); $out->parent()->mkdir(); $proc->arg("output"); $proc->arg((string)$out); $r = $proc->execute(); if ($r != 0) { print("
");
			print_r($proc->stderr());
			print("
"); exit(0); } return redirect("/document/" . $doc->id); } public static function create_overview($id, $move) { $job = new GeminiJob($id, "document:$id"); $job->move = ($move == "move"); $jobid = $job->queue(); flash("success", "Job queued as ID " . $jobid); return redirect("/document/" . $id); } public static function api_get_title_fragment($_request) { $q = $_request->post("title"); $db = DB::getInstance(); $q1 = $db->query(" SELECT DISTINCT title FROM ( SELECT DISTINCT title FROM document WHERE title LIKE :s UNION SELECT DISTINCT subtitle AS title FROM document WHERE subtitle LIKE :s UNION SELECT DISTINCT subsubtitle AS title FROM document WHERE subsubtitle LIKE :s ) AS DERIVED", ["s" => $q . "%"]); $o = $db->all($q1); if ($o->count() == 0) { return [404, "Not Found"]; } if ($o->count() != 1) { return [413, "Content Too Large"]; } return $o[0]->title; } public static function separate($id) { $doc = new Document($id); $firstprod = $doc->products[0]; $count = 0; foreach ($doc->revisions as $rev) { $count++; if ($count == 1) { continue; } $newdoc = $doc->duplicate(); $newdoc->subsubtitle .= " - $count"; $rev->document = $newdoc->id; $rev->save(); } return redirect("/documents/" . $firstprod); } public static function api_get_metadata($id) { return DocMeta::find([["document", "=", $id]])->orderBy("metadata")->all(); } public static function api_new_metadata($_request, $id) { $doc = new Document($id); $doc->set_metadata($_request->put("item_id"), ""); return DocMeta::find([["document", "=", $id]])->orderBy("metadata")->all(); } public static function api_set_metadata($_request, $id, $metadata) { $doc = new Document($id); $doc->set_metadata($metadata, $_request->post('data')); return DocMeta::find([["document", "=", $id]])->orderBy("metadata")->all(); } public static function api_delete_metadata($id, $metadata) { $doc = new Document($id); $doc->remove_metadata($metadata); return DocMeta::find([["document", "=", $id]])->orderBy("metadata")->all(); } public static function api_available_metadata($id) { $exist = DocMeta::find([["document", "=", $id]])->orderBy("metadata")->all(); $metas = MetaType::find()->all(); $out = new Collection(); foreach ($metas as $meta) { $e = false; foreach ($exist as $ex) { if ($ex->metadata == $meta->id) { $e = true; break; } } if (!$e) { $cl = new stdClass; $cl->key = $meta->id; $cl->value = $meta->name; $out->push($cl); } } $out->sort("value"); return $out; } public static function delete_metadata($id, $metadata) { $doc = new Document($id); $doc->remove_metadata($metadata); return redirect("/document/" . $id); } public static function api_guess_docid($id) { $doc = new Document($id); $docid = $doc->guess_docid(); return new Collection(["id" => $id, "docid" => $docid]); } public static function download_attachment($id, $filename) { $doc = new Document($id); $atts = $doc->get_attachments(); foreach ($atts as $f) { if ($f->basename() == $filename) { $f->set_header("Content-Disposition", "attachment; filename=\"$filename\""); return $f; } } return false; } public static function upload_attachment($id) { $doc = new Document($id); return blade("upload.attachment", ["doc" => $doc]); } public static function do_upload_attachment($_request, $id) { $doc = new Document($id); mkdir(ROOT . "/attachments/" . $doc->id, 0777); $f = 0; while (($file = $_request->file("file", $f)) !== false) { $nf = new File($file['tmp_name']); $nf->rename(ROOT . "/attachments/" . $doc->id . "/" . $file['name']); $f++; } return redirect("/document/" . $doc->id); } public static function upload_document($_request) { return blade("upload.document"); } public static function do_upload_document($_request) { $i = 0; while ($f = $_request->file("file", $i)) { $file = new File($f['tmp_name']); $sha256 = $file->hash(); $rev = Revision::find([["sha256", "=", $sha256]])->first(); if ($rev) { return redirect("/uploads/duplicate/" . $rev->id); } $u = new Upload(); $u->filename = $f['name']; $u->sha256 = $sha256; $u->ocr = "N"; $u->ai = "N"; $u->owner = get_user()->id; $u->save(); copy($f['tmp_name'], ROOT . "/uploads/" . $u->id . ".pdf"); $j = new ImportGeminiJob($u->id); $j->queue(); $j = new ImportOCRJob($u->id); $j->queue(); $i++; } return redirect("/uploads"); } public static function rerun_upload($id) { $u = new Upload($id); if ($u->ocr == "F") { $u->ocr = "N"; $u->save(); $j = new ImportOCRJob($u->id); $j->queue(); } if ($u->ai == "F") { $u->ai = "N"; $u->save(); $j = new ImportGeminiJob($u->id); $j->queue(); } return redirect("/uploads"); } public static function rerun_all() { $ai = Upload::find([["ai", "=", "F"], ["owner", "=", get_user()->id]])->all(); foreach ($ai as $u) { $u->ai = "N"; $u->save(); $j = new ImportGeminiJob($u->id); $j->queue(); } $ocr = Upload::find([["ocr", "=", "F"], ["owner", "=", get_user()->id]])->all(); foreach ($ocr as $u) { $u->ocr = "N"; $u->save(); $j = new ImportOCRJob($u->id); $j->queue(); } return redirect("/uploads"); } public static function uploads($_request) { return DocumentController::uploads_page($_request, 0); } public static function uploads_page($_request, $page) { $uploads = Upload::find([["owner", "=", get_user()->id]])->orderBy("id")->limit($page * 20, 20)->all(); return blade("upload.list", ["uploads" => $uploads, "page" => $page]); } public static function discard_upload($_request, $id) { $u = new Upload($id); if ($u->owner != get_user()->id) { return [403, "Not yours, punk!"]; } DB::getInstance()->query("delete from job where source=:source", ["source" => "upload:" . $u->id]); unlink($u->getPDF()); $u->delete(); return redirect("/uploads"); } public static function import($_request, $id, $source) { $u = new Upload($id); if ($u->owner != get_user()->id) { return [403, "Not yours, punk!"]; } $doc = false; if ($source == "ai") { $doc = Document::find_by_docid($u->ai_docid); } else if ($source == "ocr") { $doc = Document::find_by_docid($u->ocr_docid); } if (!$doc) { $doc = new Document; if ($source == "ai") { $doc->internal_id = $u->ai_docid; } else if ($source == "ocr") { $doc->internal_id = $u->ocr_docid; } else { $doc->internal_id = "XX-XXXXX-XX"; } $doc->title = $u->title; $doc->subtitle = $u->subtitle; $doc->subsubtitle = $u->subsubtitle; $doc->overview = $u->overview; $doc->save(); $incoming = Product::find([["title", "=", "Incoming"]])->first(); $dp = new DocProduct(); $dp->document = $doc->id; $dp->product = $incoming->id; $dp->save(); } $rev = new Revision(); $rev->document = $doc->id; $rev->revid=""; $rev->sha256 = $u->sha256; $rev->origtitle = $u->source; $rev->save(); $ocr = new OCR(); $ocr->revision = $rev->id; $ocr->body = $u->body; $ocr->save(); $out = new File($rev->path() . "/doc.pdf"); $out->parent()->mkdir(); $pdf = $u->getPDF(); $pdf->rename($out->path()); $db = DB::getInstance(); $db->query("DELETE FROM job WHERE source=:source", ["source" => "upload:" . $u->id]); $u->delete(); $rev->info = $rev->getPDF()->info(); $rev->save(); $j = new IndexJob($rev->id); $j->queue(); //return redirect("/uploads"); return redirect("/document/" . $doc->id); } public static function delete_upload($_request, $id) { $u = new Upload($id); if ($u->owner != get_user()->id) { return [403, "Not yours, punk!"]; } } public static function upload_duplicate($id) { $r = new Revision($id); return blade("upload.duplicate", ["rev" => $r]); } public static function view_upload($id) { $u = new Upload($id); return $u->getPDF(); } }