Админка: колонка «Пользователь» в обработанных документах + FILES.web_account
- бот: @username / имя / tg:id; веб: аккаунт сессии или «аноним» - новая колонка FILES.web_account (tg:/yandex:/vk:/email:) — пишется в _finalize_submit из резолвнутого аккаунта, чтобы у залогиненных веб-юзеров атрибуция работала для любого способа входа (раньше только Telegram) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
23
app/main.py
23
app/main.py
@@ -138,7 +138,7 @@ def _convert_doc_to_pdf(src_path: str, dst_path: str) -> None:
|
||||
def _db_insert_job(
|
||||
name_or_f, stitching, title, numeration, flip_side,
|
||||
color, pdfa, quality, original_name, source_size_mb,
|
||||
ocr=0, web_owner_id=0,
|
||||
ocr=0, web_owner_id=0, web_account=None,
|
||||
):
|
||||
now = datetime.datetime.now()
|
||||
date_str = now.strftime("%Y.%m.%d")
|
||||
@@ -178,6 +178,9 @@ def _db_insert_job(
|
||||
if "web_owner_id" in cols:
|
||||
fields.append("web_owner_id")
|
||||
values.append(int(web_owner_id or 0))
|
||||
if "web_account" in cols:
|
||||
fields.append("web_account")
|
||||
values.append(web_account or "")
|
||||
|
||||
placeholders = ", ".join(["?"] * len(fields))
|
||||
sql = f"INSERT INTO FILES ({', '.join(fields)}) VALUES ({placeholders})"
|
||||
@@ -409,6 +412,9 @@ def _db_ensure_auth_table():
|
||||
con.execute("ALTER TABLE FILES ADD COLUMN ocr INTEGER DEFAULT 0")
|
||||
if "web_owner_id" not in have:
|
||||
con.execute("ALTER TABLE FILES ADD COLUMN web_owner_id INTEGER DEFAULT 0")
|
||||
if "web_account" not in have:
|
||||
# аккаунт сессии (tg:/yandex:/vk:/email:) — кто загрузил с сайта
|
||||
con.execute("ALTER TABLE FILES ADD COLUMN web_account TEXT DEFAULT ''")
|
||||
except Exception as _mig:
|
||||
print(f"FILES migrate error: {_mig}")
|
||||
# Авто-миграция WEB_ACCOUNTS: авто-продление подписки (сохранённый способ оплаты)
|
||||
@@ -1094,6 +1100,7 @@ def _finalize_submit(job_id, file_path, original_name, stitching, title,
|
||||
source_size_mb=size_mb,
|
||||
ocr=ocr,
|
||||
web_owner_id=owner,
|
||||
web_account=acc,
|
||||
)
|
||||
except Exception as exc:
|
||||
_safe_remove(file_path)
|
||||
@@ -3205,7 +3212,7 @@ _ADMIN_HTML = """<!doctype html>
|
||||
<h2 style="margin:0">Обработанные документы <span class="muted" id="docs-totals"></span></h2>
|
||||
<button class="ghost" onclick="downloadCsv()">Экспорт CSV</button>
|
||||
</div>
|
||||
<div class="scroll"><table><thead><tr><th>Дата</th><th>Файл</th><th class="num">Стр.</th><th class="num">Время</th><th class="num">Исходник</th><th class="num">Результат</th><th>Кач-во</th><th>Сшивка</th><th>OCR</th><th>Источник</th></tr></thead>
|
||||
<div class="scroll"><table><thead><tr><th>Дата</th><th>Файл</th><th class="num">Стр.</th><th class="num">Время</th><th class="num">Исходник</th><th class="num">Результат</th><th>Кач-во</th><th>Сшивка</th><th>OCR</th><th>Источник</th><th>Пользователь</th></tr></thead>
|
||||
<tbody id="t-docs"></tbody></table></div>
|
||||
</section>
|
||||
|
||||
@@ -3425,11 +3432,15 @@ _ADMIN_HTML = """<!doctype html>
|
||||
document.getElementById('t-docs').innerHTML = docs.length ? docs.map(function(f){
|
||||
var web = (f.user_id === wid);
|
||||
var srcPill = web ? '<span class="pill web">сайт</span>' : '<span class="pill bot">бот</span>';
|
||||
var who = web
|
||||
? (f.web_account || (f.web_owner_id ? 'tg:'+f.web_owner_id : ''))
|
||||
: ((f.username && f.username!=='webuser') ? '@'+f.username : (f.first_name || ('tg:'+f.user_id)));
|
||||
var whoCell = who ? esc(who) : '<span class="muted">аноним</span>';
|
||||
var dd = (f.date||'') + (f.time ? ' '+String(f.time).slice(0,5) : '');
|
||||
return '<tr><td>'+esc(dd)+'</td><td class="fname" title="'+esc(f.name)+'">'+esc(f.name)+'</td><td class="num">'+(f.pages||'—')+
|
||||
'</td><td class="num">'+psec(f.secs)+'</td><td class="num">'+size(f.source_size_mb)+'</td><td class="num">'+size(f.result_size_mb)+
|
||||
'</td><td>'+esc(f.quality||'—')+'</td><td>'+esc(f.stitching||'—')+'</td><td>'+(f.ocr?'✓':'')+'</td><td>'+srcPill+'</td></tr>';
|
||||
}).join('') : '<tr><td colspan="10" class="muted">Пока нет документов</td></tr>';
|
||||
'</td><td>'+esc(f.quality||'—')+'</td><td>'+esc(f.stitching||'—')+'</td><td>'+(f.ocr?'✓':'')+'</td><td>'+srcPill+'</td><td>'+whoCell+'</td></tr>';
|
||||
}).join('') : '<tr><td colspan="11" class="muted">Пока нет документов</td></tr>';
|
||||
}
|
||||
|
||||
function showGate(err){
|
||||
@@ -3743,9 +3754,11 @@ def _admin_collect_stats() -> dict:
|
||||
# Документы
|
||||
cols = {r[1] for r in con.execute("PRAGMA table_info(FILES)")}
|
||||
pages_expr = "COALESCE(NULLIF(pages_total,0), num_pages, 0)" if "pages_total" in cols else "COALESCE(num_pages,0)"
|
||||
wa_expr = "COALESCE(web_account,'')" if "web_account" in cols else "''"
|
||||
docs = [dict(r) for r in con.execute(
|
||||
f"SELECT date, time, COALESCE(NULLIF(original_name,''), name_or_f) AS name, {pages_expr} AS pages, "
|
||||
"source_size_mb, result_size_mb, quality, stitching, ocr, elapsed_time, user_id, url_res_f "
|
||||
"source_size_mb, result_size_mb, quality, stitching, ocr, elapsed_time, user_id, url_res_f, "
|
||||
f"username, first_name, COALESCE(web_owner_id,0) AS web_owner_id, {wa_expr} AS web_account "
|
||||
"FROM FILES ORDER BY rowid DESC LIMIT 150")]
|
||||
for _d in docs:
|
||||
_d["secs"] = _elapsed_to_sec(_d.get("elapsed_time"))
|
||||
|
||||
Reference in New Issue
Block a user