Broaden Tasgird task lookup fallbacks

This commit is contained in:
2026-03-29 03:19:52 +00:00
parent 69c8d80ef2
commit a34b362683
2 changed files with 100 additions and 12 deletions
+90 -7
View File
@@ -533,16 +533,88 @@ app.get('/api/tasks/list', async (c) => {
}
const baseFields = 'id,user,title,startDate,dueDate,priority,completed,content,size,status,owner,assigned_to,user_name,Username,expand.user.id,expand.user.email,expand.user.name,expand.user.username';
const fetchTasksByRelationIds = async (userIds: string[]) => {
const uniqueById = (records: any[]) => {
const seen = new Map<string, any>();
for (const record of Array.isArray(records) ? records : []) {
const id = String(record?.id || '').trim();
if (!id || seen.has(id)) continue;
seen.set(id, record);
}
return Array.from(seen.values());
};
const taskMatchesTarget = (task: any, userIds: string[], nameHints: string[]) => {
const idSet = new Set(userIds.map((id) => String(id || '').trim()).filter(Boolean));
const lowerHints = nameHints.map((value) => String(value || '').trim().toLowerCase()).filter(Boolean);
const directUsers = Array.isArray(task?.user)
? task.user
: (task?.user ? [task.user] : []);
if (directUsers.some((value: any) => idSet.has(String(value || '').trim()))) {
return true;
}
const expandedUsers = Array.isArray(task?.expand?.user)
? task.expand.user
: (task?.expand?.user ? [task.expand.user] : []);
if (expandedUsers.some((user: any) => idSet.has(String(user?.id || '').trim()))) {
return true;
}
const textFields = [task?.user_name, task?.Username, task?.owner, task?.assigned_to]
.map((value) => String(value || '').trim().toLowerCase())
.filter(Boolean);
return lowerHints.some((hint) => textFields.some((value) => value === hint || value.includes(hint)));
};
const fetchTasksByRelationIds = async (userIds: string[], nameHints: string[]) => {
const ids = Array.from(new Set(userIds.map((id) => String(id || '').trim()).filter(Boolean)));
if (!ids.length) return [];
const relationFilter = ids.map((id) => `user = "${id.replace(/"/g, '\\"')}"`).join(' || ');
return taskPb.collection(PB_TASKS_COLLECTION).getFullList({
filter: relationFilter,
if (!ids.length) return { records: [], lookupMethod: 'no_user_ids' };
const filterAttempts = [
{
lookupMethod: 'relation_eq',
filter: ids.map((id) => `user = "${id.replace(/"/g, '\\"')}"`).join(' || '),
},
{
lookupMethod: 'relation_any_eq',
filter: ids.map((id) => `user ?= "${id.replace(/"/g, '\\"')}"`).join(' || '),
},
];
let lastError: unknown = null;
for (const attempt of filterAttempts) {
try {
const records = await taskPb.collection(PB_TASKS_COLLECTION).getFullList({
filter: attempt.filter,
sort: '-startDate,-created',
expand: 'user',
fields: baseFields,
});
if (records.length) {
return { records: uniqueById(records), lookupMethod: attempt.lookupMethod };
}
} catch (error) {
lastError = error;
}
}
try {
const accessibleTasks = await taskPb.collection(PB_TASKS_COLLECTION).getFullList({
sort: '-startDate,-created',
expand: 'user',
fields: baseFields,
});
const filtered = accessibleTasks.filter((task: any) => taskMatchesTarget(task, ids, nameHints));
return {
records: uniqueById(filtered),
lookupMethod: 'accessible_fallback',
};
} catch (error) {
if (lastError) throw lastError;
throw error;
}
};
const resolveUserIdsByName = async (name: string): Promise<string[]> => {
@@ -587,6 +659,7 @@ app.get('/api/tasks/list', async (c) => {
let warning = '';
let effectiveUserId = requestedUserId || meId;
let effectiveUserName = targetUserName;
let lookupMethod = 'unresolved';
try {
if (targetUserName) {
const targetUserIds = Array.from(new Set([
@@ -598,7 +671,9 @@ app.get('/api/tasks/list', async (c) => {
warning = `No Users record matched name "${targetUserName}".`;
records = [];
} else {
records = await fetchTasksByRelationIds(targetUserIds);
const result = await fetchTasksByRelationIds(targetUserIds, [targetUserName, meName]);
records = result.records;
lookupMethod = result.lookupMethod;
if (!records.length) {
warning = `No accessible Tasgird tasks matched Users.name "${targetUserName}".`;
}
@@ -606,7 +681,9 @@ app.get('/api/tasks/list', async (c) => {
}
} else if (requestedUserId || meId) {
const fallbackId = String(requestedUserId || meId).trim();
records = await fetchTasksByRelationIds([fallbackId]);
const result = await fetchTasksByRelationIds([fallbackId], [meName]);
records = result.records;
lookupMethod = result.lookupMethod;
if (!records.length) {
warning = 'No accessible Tasgird tasks matched the current user relation.';
}
@@ -628,7 +705,13 @@ app.get('/api/tasks/list', async (c) => {
success: true,
userId: effectiveUserId,
userName: effectiveUserName,
authUser: {
id: meId,
email: meRecord?.email || '',
name: meName,
},
count: records.length,
lookupMethod,
warning: warning || undefined,
tasks: records.map((task: any) => ({
id: task.id,
+6 -1
View File
@@ -387,7 +387,10 @@
});
const data = await resp.json().catch(() => ({}));
if (!resp.ok || !data?.success) {
throw new Error(data?.message || 'Failed to load tasks');
const details = data?.details
? (typeof data.details === 'string' ? data.details : JSON.stringify(data.details))
: '';
throw new Error(details ? `${data?.message || 'Failed to load tasks'}: ${details}` : (data?.message || 'Failed to load tasks'));
}
if (data?.userName && taskUserSelect.value !== data.userName) {
taskUserSelect.value = data.userName;
@@ -397,6 +400,8 @@
message: `Loaded ${data?.count ?? 0} task(s)`,
userName: data?.userName || userName,
userId: data?.userId || undefined,
authUser: data?.authUser || undefined,
lookupMethod: data?.lookupMethod || undefined,
warning: data?.warning || undefined,
tasks: data.tasks || [],
});