fix: correct member counts and member removal flow
This commit is contained in:
parent
c412eda221
commit
bb389d6f78
2 changed files with 49 additions and 25 deletions
7
VIEWER_ROLE_MIGRATION.sql
Normal file
7
VIEWER_ROLE_MIGRATION.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Run this in Supabase SQL Editor to allow a read-only viewer role.
|
||||||
|
alter table public.collection_members
|
||||||
|
drop constraint if exists collection_members_role_check;
|
||||||
|
|
||||||
|
alter table public.collection_members
|
||||||
|
add constraint collection_members_role_check
|
||||||
|
check (role in ('owner', 'member', 'viewer'));
|
||||||
|
|
@ -115,17 +115,33 @@ class CollectionService {
|
||||||
itemCounts[collectionId] = (itemCounts[collectionId] ?? 0) + 1;
|
itemCounts[collectionId] = (itemCounts[collectionId] ?? 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all members for these collections in a single query and count them in memory.
|
final memberCounts = <String, int>{};
|
||||||
|
await Future.wait(collectionIdList.map((collectionId) async {
|
||||||
|
try {
|
||||||
|
final rows = await supabase.rpc('get_collection_members', params: {
|
||||||
|
'p_collection_id': collectionId,
|
||||||
|
});
|
||||||
|
memberCounts[collectionId] = (rows as List).length;
|
||||||
|
} catch (_) {
|
||||||
|
// Keep fallback below when RPC fails.
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Fallback member count for collections where RPC did not return data.
|
||||||
|
final unresolvedIds = collectionIdList
|
||||||
|
.where((id) => !memberCounts.containsKey(id))
|
||||||
|
.toList(growable: false);
|
||||||
|
if (unresolvedIds.isNotEmpty) {
|
||||||
final members = await supabase
|
final members = await supabase
|
||||||
.from('collection_members')
|
.from('collection_members')
|
||||||
.select('id, collection_id')
|
.select('id, collection_id')
|
||||||
.inFilter('collection_id', collectionIdList);
|
.inFilter('collection_id', unresolvedIds);
|
||||||
|
|
||||||
final memberCounts = <String, int>{};
|
|
||||||
for (final member in members) {
|
for (final member in members) {
|
||||||
final collectionId = member['collection_id'] as String;
|
final collectionId = member['collection_id'] as String;
|
||||||
memberCounts[collectionId] = (memberCounts[collectionId] ?? 0) + 1;
|
memberCounts[collectionId] = (memberCounts[collectionId] ?? 0) + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final collections = <Collection>[];
|
final collections = <Collection>[];
|
||||||
|
|
||||||
|
|
@ -316,11 +332,22 @@ class CollectionService {
|
||||||
throw Exception('This user is already a member of this collection.');
|
throw Exception('This user is already a member of this collection.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
await supabase.from('collection_members').insert({
|
await supabase.from('collection_members').insert({
|
||||||
'collection_id': collectionId,
|
'collection_id': collectionId,
|
||||||
'user_id': userId,
|
'user_id': userId,
|
||||||
'role': normalizedRole,
|
'role': normalizedRole,
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
final message = e.toString();
|
||||||
|
if (normalizedRole == 'viewer' &&
|
||||||
|
message.contains('collection_members_role_check')) {
|
||||||
|
throw Exception(
|
||||||
|
'Viewer role is not enabled in your database yet. Please apply the viewer-role migration first.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a member from a collection.
|
/// Remove a member from a collection.
|
||||||
|
|
@ -343,17 +370,7 @@ class CollectionService {
|
||||||
throw Exception('Only the collection owner can remove members.');
|
throw Exception('Only the collection owner can remove members.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final target = await supabase
|
if (memberUserId == collection['owner_id']) {
|
||||||
.from('collection_members')
|
|
||||||
.select('role, user_id')
|
|
||||||
.eq('user_id', memberUserId)
|
|
||||||
.eq('collection_id', collectionId)
|
|
||||||
.maybeSingle();
|
|
||||||
|
|
||||||
if (target == null) {
|
|
||||||
throw Exception('Member not found.');
|
|
||||||
}
|
|
||||||
if (target['role'] == 'owner') {
|
|
||||||
throw Exception('Collection owner cannot be removed.');
|
throw Exception('Collection owner cannot be removed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue