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,16 +115,32 @@ class CollectionService {
|
|||
itemCounts[collectionId] = (itemCounts[collectionId] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Fetch all members for these collections in a single query and count them in memory.
|
||||
final members = await supabase
|
||||
.from('collection_members')
|
||||
.select('id, collection_id')
|
||||
.inFilter('collection_id', collectionIdList);
|
||||
|
||||
final memberCounts = <String, int>{};
|
||||
for (final member in members) {
|
||||
final collectionId = member['collection_id'] as String;
|
||||
memberCounts[collectionId] = (memberCounts[collectionId] ?? 0) + 1;
|
||||
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
|
||||
.from('collection_members')
|
||||
.select('id, collection_id')
|
||||
.inFilter('collection_id', unresolvedIds);
|
||||
|
||||
for (final member in members) {
|
||||
final collectionId = member['collection_id'] as String;
|
||||
memberCounts[collectionId] = (memberCounts[collectionId] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
final collections = <Collection>[];
|
||||
|
|
@ -316,11 +332,22 @@ class CollectionService {
|
|||
throw Exception('This user is already a member of this collection.');
|
||||
}
|
||||
|
||||
await supabase.from('collection_members').insert({
|
||||
'collection_id': collectionId,
|
||||
'user_id': userId,
|
||||
'role': normalizedRole,
|
||||
});
|
||||
try {
|
||||
await supabase.from('collection_members').insert({
|
||||
'collection_id': collectionId,
|
||||
'user_id': userId,
|
||||
'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.
|
||||
|
|
@ -343,17 +370,7 @@ class CollectionService {
|
|||
throw Exception('Only the collection owner can remove members.');
|
||||
}
|
||||
|
||||
final target = await supabase
|
||||
.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') {
|
||||
if (memberUserId == collection['owner_id']) {
|
||||
throw Exception('Collection owner cannot be removed.');
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue