mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 15:36:33 +00:00
fix(ci): typed card points, the managed take route, and the failing card tests and ratchets
This commit is contained in:
@@ -51,26 +51,29 @@ export class TrekPhotoSignalsRepository extends TrekRepository<TrekPhotoSignals>
|
||||
|
||||
/** The measurements stored for these photos, whatever version made them; a photo without one is left out. */
|
||||
async listForPhotos(photoIds: number[]): Promise<TrekPhotoSignalRow[]> {
|
||||
const out: TrekPhotoSignalRow[] = [];
|
||||
for (let i = 0; i < photoIds.length; i += IN_CHUNK) {
|
||||
const rows = await this.db()
|
||||
.selectFrom('trek_photo_signals')
|
||||
.select([
|
||||
'photo_id',
|
||||
'algo',
|
||||
'phash',
|
||||
'sharpness',
|
||||
'luma',
|
||||
'clipped',
|
||||
'orig_width',
|
||||
'orig_height',
|
||||
'computed_at',
|
||||
])
|
||||
.where('photo_id', 'in', photoIds.slice(i, i + IN_CHUNK))
|
||||
.execute();
|
||||
out.push(...rows);
|
||||
}
|
||||
return out;
|
||||
const chunks = Array.from({ length: Math.ceil(photoIds.length / IN_CHUNK) }, (_, i) =>
|
||||
photoIds.slice(i * IN_CHUNK, (i + 1) * IN_CHUNK),
|
||||
);
|
||||
const found = await Promise.all(
|
||||
chunks.map((chunk) =>
|
||||
this.db()
|
||||
.selectFrom('trek_photo_signals')
|
||||
.select([
|
||||
'photo_id',
|
||||
'algo',
|
||||
'phash',
|
||||
'sharpness',
|
||||
'luma',
|
||||
'clipped',
|
||||
'orig_width',
|
||||
'orig_height',
|
||||
'computed_at',
|
||||
])
|
||||
.where('photo_id', 'in', chunk)
|
||||
.execute(),
|
||||
),
|
||||
);
|
||||
return found.flat();
|
||||
}
|
||||
|
||||
/** Stores a measurement, replacing the photo's earlier one. */
|
||||
|
||||
@@ -11,6 +11,9 @@ import type { CollectionDetailResponse, CollectionItemsRequest, CollectionItemsR
|
||||
/** The most lists one lookup opens: 50 places and 20 labels can sit in no more than 70. */
|
||||
const MAX_LISTS = 70;
|
||||
|
||||
/** A list the lookup opened, with whether the user may take places out of it. */
|
||||
type OpenedList = CollectionDetailResponse & { canDelete: boolean };
|
||||
|
||||
/**
|
||||
* Saved places and labels by their own ids, wherever they are filed (the
|
||||
* get_collection_items tool): what an assistant's card needs to name a place
|
||||
@@ -30,23 +33,13 @@ export class CollectionsItemsService {
|
||||
async getItems(userId: number, request: CollectionItemsRequest): Promise<CollectionItemsResponse> {
|
||||
const placeIds = [...new Set(request.placeIds ?? [])];
|
||||
const labelIds = [...new Set(request.labelIds ?? [])];
|
||||
const listIds = new Set<number>();
|
||||
for (const placeId of placeIds) {
|
||||
const listId = await this.collectionsRepo.collectionIdOfPlace(placeId);
|
||||
if (listId !== undefined) listIds.add(listId);
|
||||
}
|
||||
for (const labelId of labelIds) {
|
||||
const listId = await this.labels.collectionIdOf(labelId);
|
||||
if (listId !== undefined) listIds.add(listId);
|
||||
}
|
||||
const read: Array<CollectionDetailResponse & { canDelete: boolean }> = [];
|
||||
for (const listId of [...listIds].slice(0, MAX_LISTS)) {
|
||||
const detail = await this.readable(userId, listId);
|
||||
if (!detail) continue;
|
||||
// Places leave a list only by its owner or an admin (assertCanDelete); an editor adds.
|
||||
const role = await this.collections.roleOf(userId, listId);
|
||||
read.push({ ...detail, canDelete: role === 'owner' || role === 'admin' });
|
||||
}
|
||||
const [ofPlaces, ofLabels] = await Promise.all([
|
||||
Promise.all(placeIds.map((placeId) => this.collectionsRepo.collectionIdOfPlace(placeId))),
|
||||
Promise.all(labelIds.map((labelId) => this.labels.collectionIdOf(labelId))),
|
||||
]);
|
||||
const listIds = new Set([...ofPlaces, ...ofLabels].filter((listId): listId is number => listId !== undefined));
|
||||
const opened = await Promise.all([...listIds].slice(0, MAX_LISTS).map((listId) => this.withDelete(userId, listId)));
|
||||
const read = opened.filter((list): list is OpenedList => list !== null);
|
||||
const wantedPlaces = new Set(placeIds);
|
||||
const wantedLabels = new Set(labelIds);
|
||||
return {
|
||||
@@ -71,6 +64,15 @@ export class CollectionsItemsService {
|
||||
};
|
||||
}
|
||||
|
||||
/** One list as its members read it, with whether the user may take places out of it. */
|
||||
private async withDelete(userId: number, listId: number): Promise<OpenedList | null> {
|
||||
const detail = await this.readable(userId, listId);
|
||||
if (!detail) return null;
|
||||
// Places leave a list only by its owner or an admin (assertCanDelete); an editor adds.
|
||||
const role = await this.collections.roleOf(userId, listId);
|
||||
return { ...detail, canDelete: role === 'owner' || role === 'admin' };
|
||||
}
|
||||
|
||||
/** One list as its members read it; null for one the user may not see or that is gone. */
|
||||
private async readable(userId: number, listId: number): Promise<CollectionDetailResponse | null> {
|
||||
try {
|
||||
|
||||
@@ -93,6 +93,7 @@ export const MANAGED_ROUTE_ALLOW_LIST: string[] = [
|
||||
'AssistantController.deleteThread',
|
||||
'AssistantController.share',
|
||||
'AssistantController.stop',
|
||||
'AssistantController.takeProposal',
|
||||
'AssistantController.thread',
|
||||
'AssistantController.threads',
|
||||
'AssistantController.undo',
|
||||
|
||||
Reference in New Issue
Block a user