UI: фамилия с инициалами в шапке, подпись автора у тестов

- Хедер: отображать Фамилия И. О., полное ФИО в title.
- Список тестов и карточка: «Автор: Вы» для своих, иначе «Автор: Фамилия И. О.».
- API: в каталоге и summary/versions — created_by, author full_name (camelCase в JSON).

Made-with: Cursor
This commit is contained in:
Константин Лебединский
2026-04-24 22:08:45 +05:00
parent 89da5b60b7
commit 4801ea9f19
6 changed files with 1898 additions and 173 deletions
+64
View File
@@ -0,0 +1,64 @@
/**
* Кто видит тест: автор цепочки и пользователи с назначением (target user = clinic user id).
*/
import { isTestAuthor } from '../config/devAuthor.js';
import { query } from '../db/db.js';
/**
* @param {string} userId
* @param {string} testId
* @returns {Promise<{ ok: boolean, isAuthor: boolean, notFound: boolean }>}
*/
export async function userHasTestAccess(userId, testId) {
const { rows } = await query(
`SELECT t.created_by FROM tests t WHERE t.id = $1`,
[testId]
);
if (!rows.length) {
return { ok: false, isAuthor: false, notFound: true };
}
if (isTestAuthor(rows[0].created_by, userId)) {
return { ok: true, isAuthor: true, notFound: false };
}
const { rows: ar } = await query(
`SELECT 1
FROM test_assignments ta
INNER JOIN test_versions tv_a ON tv_a.id = ta.test_version_id
INNER JOIN test_assignment_targets tat ON tat.assignment_id = ta.id
WHERE tv_a.test_id = $1
AND tat.target_type = 'user'
AND tat.target_id = $2
LIMIT 1`,
[testId, userId]
);
return { ok: ar.length > 0, isAuthor: false, notFound: false };
}
/**
* Список тестов в каталоге: только `is_active` цепочка + (автор OR назначен).
*/
export async function queryTestsVisibleToUser(userId) {
return query(
`SELECT DISTINCT t.id, t.title, t.description, t.is_active AS chain_active,
t.created_at, t.updated_at, tv.id AS active_version_id, tv.version,
t.created_by, u.full_name AS author_full_name
FROM tests t
INNER JOIN test_versions tv ON tv.test_id = t.id AND tv.is_active = true
INNER JOIN users u ON u.id = t.created_by
WHERE t.is_active = true
AND (
t.created_by = $1
OR EXISTS (
SELECT 1
FROM test_assignments ta
INNER JOIN test_versions tv2 ON tv2.id = ta.test_version_id
INNER JOIN test_assignment_targets tat ON tat.assignment_id = ta.id
WHERE tv2.test_id = t.id
AND tat.target_type = 'user'
AND tat.target_id = $1
)
)
ORDER BY t.updated_at DESC NULLS LAST, t.created_at DESC`,
[userId]
);
}