Use user name for tasks lookup with robust fallbacks

This commit is contained in:
2026-03-29 02:51:14 +00:00
parent d042f00230
commit 6abaf6c778
2 changed files with 86 additions and 22 deletions
+71 -11
View File
@@ -495,39 +495,98 @@ app.get('/api/tasks/list', async (c) => {
try { try {
const me = pb.authStore.model; const me = pb.authStore.model;
const meId = String(me?.id || '').trim(); const meId = String(me?.id || '').trim();
const meName = String(me?.name || me?.username || me?.email || '').trim();
const requestedUserName = String(c.req.query('userName') || '').trim();
const requestedUserId = String(c.req.query('userId') || '').trim(); const requestedUserId = String(c.req.query('userId') || '').trim();
const targetUserId = requestedUserId || meId; const targetUserName = requestedUserName || meName;
if (!targetUserId) return c.json({ success: false, message: 'No target user available' }, 400); if (!targetUserName && !requestedUserId && !meId) {
return c.json({ success: false, message: 'No target user available' }, 400);
}
const fetchTasks = async (userId: string) => { const baseFields = 'id,user,title,startDate,dueDate,priority,completed,content,size,status,expand.user.id,expand.user.email,expand.user.name,expand.user.username';
const filter = `user = "${userId.replace(/"/g, '\\"')}"`; const fetchTasksWithFilter = async (filter: string) => {
return pb.collection(PB_TASKS_COLLECTION).getFullList({ return pb.collection(PB_TASKS_COLLECTION).getFullList({
filter, filter,
sort: '-startDate,-created', sort: '-startDate,-created',
expand: 'user', expand: 'user',
fields: 'id,user,title,startDate,dueDate,priority,completed,content,size,status,expand.user.id,expand.user.email,expand.user.name,expand.user.username', fields: baseFields,
}); });
}; };
const fetchAllTasks = async () => {
return pb.collection(PB_TASKS_COLLECTION).getFullList({
sort: '-startDate,-created',
expand: 'user',
fields: baseFields,
});
};
const matchTaskByName = (task: any, name: string): boolean => {
const target = String(name || '').trim().toLowerCase();
if (!target) return false;
const taskUserDisplay = String(task?.expand?.user?.name || task?.expand?.user?.username || task?.expand?.user?.email || '').trim().toLowerCase();
const taskUserRaw = String(task?.user || '').trim().toLowerCase();
const owner = String(task?.owner || '').trim().toLowerCase();
const assignedTo = String(task?.assigned_to || '').trim().toLowerCase();
const userName = String(task?.user_name || task?.Username || '').trim().toLowerCase();
return [taskUserDisplay, taskUserRaw, owner, assignedTo, userName].some((v) => v && v === target);
};
let records: any[] = []; let records: any[] = [];
let warning = ''; let warning = '';
let effectiveUserId = targetUserId; let effectiveUserId = requestedUserId || meId;
let effectiveUserName = targetUserName;
try { try {
records = await fetchTasks(targetUserId); const escapedName = targetUserName.replace(/"/g, '\\"');
} catch (listErr) { const escapedUserId = (requestedUserId || meId).replace(/"/g, '\\"');
if (targetUserId !== meId && meId) { const candidateFilters = [
targetUserName ? `user = "${escapedName}"` : '',
targetUserName ? `user_name = "${escapedName}"` : '',
targetUserName ? `Username = "${escapedName}"` : '',
targetUserName ? `assigned_to = "${escapedName}"` : '',
targetUserName ? `owner = "${escapedName}"` : '',
escapedUserId ? `user = "${escapedUserId}"` : '',
].filter(Boolean);
for (const filter of candidateFilters) {
try { try {
records = await fetchTasks(meId); const found = await fetchTasksWithFilter(filter);
if (Array.isArray(found) && found.length) {
records = found;
break;
}
} catch {
}
}
if (!records.length) {
const all = await fetchAllTasks();
if (targetUserName) {
records = all.filter((task: any) => matchTaskByName(task, targetUserName));
} else if (escapedUserId) {
records = all.filter((task: any) => String(task?.user || '') === escapedUserId);
} else {
records = all;
}
}
} catch (listErr) {
if (targetUserName && meName && targetUserName !== meName) {
try {
const all = await fetchAllTasks();
records = all.filter((task: any) => matchTaskByName(task, meName));
effectiveUserId = meId; effectiveUserId = meId;
effectiveUserName = meName;
warning = 'Requested user tasks are restricted by PocketBase rules; showing your tasks instead.'; warning = 'Requested user tasks are restricted by PocketBase rules; showing your tasks instead.';
} catch { } catch {
records = []; records = [];
effectiveUserId = meId; effectiveUserId = meId;
effectiveUserName = meName;
warning = 'Task list is restricted by PocketBase rules; no accessible tasks for current user.'; warning = 'Task list is restricted by PocketBase rules; no accessible tasks for current user.';
} }
} else { } else {
records = []; records = [];
effectiveUserId = meId || targetUserId; effectiveUserId = meId || requestedUserId;
effectiveUserName = targetUserName || meName;
warning = 'Task list is restricted by PocketBase rules; no accessible tasks for current user.'; warning = 'Task list is restricted by PocketBase rules; no accessible tasks for current user.';
} }
} }
@@ -535,6 +594,7 @@ app.get('/api/tasks/list', async (c) => {
return c.json({ return c.json({
success: true, success: true,
userId: effectiveUserId, userId: effectiveUserId,
userName: effectiveUserName,
count: records.length, count: records.length,
warning: warning || undefined, warning: warning || undefined,
tasks: records.map((task: any) => ({ tasks: records.map((task: any) => ({
+15 -11
View File
@@ -317,22 +317,25 @@
usersCache = Array.isArray(data.users) ? data.users : []; usersCache = Array.isArray(data.users) ? data.users : [];
const meId = String(data?.me?.id || '').trim(); const meId = String(data?.me?.id || '').trim();
const meName = data?.me?.name || data?.me?.email || 'Me'; const meName = data?.me?.name || data?.me?.email || 'Me';
const meLookupName = String(data?.me?.name || data?.me?.email || '').trim();
taskUserSelect.innerHTML = ''; taskUserSelect.innerHTML = '';
for (const user of usersCache) { for (const user of usersCache) {
const opt = document.createElement('option'); const opt = document.createElement('option');
opt.value = user.id; const lookupName = String(user.name || user.email || user.id || '').trim();
opt.value = lookupName;
opt.dataset.userId = user.id;
opt.textContent = `${user.name || user.email || user.id}${user.id === meId ? ' (Me)' : ''}`; opt.textContent = `${user.name || user.email || user.id}${user.id === meId ? ' (Me)' : ''}`;
taskUserSelect.appendChild(opt); taskUserSelect.appendChild(opt);
} }
if (meId) { if (meLookupName) {
taskUserSelect.value = meId; taskUserSelect.value = meLookupName;
} }
writeOutput({ message: `Loaded ${usersCache.length} users`, me: { id: meId, name: meName } }); writeOutput({ message: `Loaded ${usersCache.length} users`, me: { id: meId, name: meName, lookupName: meLookupName } });
if (data?.warning) { if (data?.warning) {
writeOutput({ message: `Loaded ${usersCache.length} users`, warning: data.warning, me: { id: meId, name: meName } }); writeOutput({ message: `Loaded ${usersCache.length} users`, warning: data.warning, me: { id: meId, name: meName, lookupName: meLookupName } });
} }
} }
@@ -367,9 +370,9 @@
async function loadTasks() { async function loadTasks() {
await ensurePocketBaseClient(); await ensurePocketBaseClient();
const token = getCurrentToken(); const token = getCurrentToken();
const userId = String(taskUserSelect.value || '').trim(); const userName = String(taskUserSelect.value || '').trim();
const url = userId const url = userName
? `/api/tasks/list?userId=${encodeURIComponent(userId)}` ? `/api/tasks/list?userName=${encodeURIComponent(userName)}`
: '/api/tasks/list'; : '/api/tasks/list';
const resp = await fetch(url, { const resp = await fetch(url, {
headers: { 'x-pb-token': token }, headers: { 'x-pb-token': token },
@@ -378,13 +381,14 @@
if (!resp.ok || !data?.success) { if (!resp.ok || !data?.success) {
throw new Error(data?.message || 'Failed to load tasks'); throw new Error(data?.message || 'Failed to load tasks');
} }
if (data?.userId && taskUserSelect.value !== data.userId) { if (data?.userName && taskUserSelect.value !== data.userName) {
taskUserSelect.value = data.userId; taskUserSelect.value = data.userName;
} }
renderTasks(data.tasks || []); renderTasks(data.tasks || []);
writeOutput({ writeOutput({
message: `Loaded ${data?.count ?? 0} task(s)`, message: `Loaded ${data?.count ?? 0} task(s)`,
userId: data?.userId || userId, userName: data?.userName || userName,
userId: data?.userId || undefined,
warning: data?.warning || undefined, warning: data?.warning || undefined,
tasks: data.tasks || [], tasks: data.tasks || [],
}); });