MIF_E31222656/lib/screens/community/services/group_management_service.dart

393 lines
11 KiB
Dart

import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group_member.dart';
class GroupManagementService {
final _supabase = Supabase.instance.client;
// Get current user ID
String? get currentUserId => _supabase.auth.currentUser?.id;
// Check if the current user is an admin
Future<bool> isUserAdmin() async {
if (currentUserId == null) return false;
try {
final response =
await _supabase
.from('user_roles')
.select('role')
.eq('user_id', currentUserId!)
.maybeSingle();
if (response == null) return false;
return response['role'] == 'admin';
} catch (e) {
print('[ERROR] Failed to check if user is admin: $e');
return false;
}
}
// Get all groups (admin only)
Future<List<Group>> getAllGroups() async {
print('[DEBUG] Starting getAllGroups()');
final bool isAdmin = await isUserAdmin();
print('[DEBUG] isUserAdmin result: $isAdmin');
if (!isAdmin) {
print('[ERROR] Unauthorized access to admin function');
return [];
}
try {
print('[DEBUG] Fetching groups from database...');
final response = await _supabase
.from('groups')
.select('*, group_members(count)')
.order('created_at');
print('[DEBUG] Raw response from groups query: $response');
if (response.isEmpty) {
print('[DEBUG] No groups found in response');
return [];
}
final List<Group> groups = [];
for (final item in response) {
print('[DEBUG] Processing group: ${item['name']} (${item['id']})');
final memberCount = item['group_members']?[0]?['count'] ?? 0;
final groupData = Map<String, dynamic>.from(item);
groupData['member_count'] = memberCount;
final group = Group.fromMap(groupData);
groups.add(group);
}
print('[DEBUG] Returned ${groups.length} groups');
return groups;
} catch (e) {
print('[ERROR] Failed to load all groups: $e');
return [];
}
}
// Create a new group (admin only)
Future<Group?> createGroup(Group group) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return null;
}
try {
// Insert group dengan id dari group parameter
final response =
await _supabase
.from('groups')
.insert({
'id': group.id,
'name': group.name,
'description': group.description,
'created_by': group.createdBy,
'created_at': group.createdAt.toIso8601String(),
'is_default': group.isDefault,
'is_public': group.isPublic,
'icon_url': group.iconUrl,
})
.select('id')
.single();
print('[INFO] Group created successfully: ${response['id']}');
// Ensure we use the ID from response in case it's different
final createdGroupId = response['id'] as String;
// Add creator as admin member
final member = GroupMember(
groupId: createdGroupId,
userId: currentUserId!,
role: 'admin',
);
await _supabase.from('group_members').insert(member.toMap());
// Return group with proper ID
return group.copyWith(id: createdGroupId);
} catch (e) {
print('[ERROR] Failed to create group: $e');
return null;
}
}
// Update an existing group (admin only)
Future<bool> updateGroup(Group group) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return false;
}
try {
await _supabase.from('groups').update(group.toMap()).eq('id', group.id);
return true;
} catch (e) {
print('[ERROR] Failed to update group: $e');
return false;
}
}
// Delete a group (admin only)
Future<bool> deleteGroup(String groupId) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return false;
}
try {
// Check if this is the default group
final response =
await _supabase
.from('groups')
.select('is_default')
.eq('id', groupId)
.single();
if (response['is_default'] == true) {
// Cannot delete default group
return false;
}
// Delete group members first (due to foreign key constraints)
await _supabase.from('group_members').delete().eq('group_id', groupId);
// Delete the group
await _supabase.from('groups').delete().eq('id', groupId);
return true;
} catch (e) {
print('[ERROR] Failed to delete group: $e');
return false;
}
}
// Get all members of a group (admin only)
Future<List<GroupMemberDetail>> getGroupMembers(String groupId) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return [];
}
try {
final response = await _supabase
.from('group_members')
.select('*, profiles:user_id(username, avatar_url, email)')
.eq('group_id', groupId)
.eq('is_active', true)
.order('joined_at');
final List<GroupMemberDetail> members = [];
for (final item in response) {
final member = GroupMember.fromMap(item);
final profile = item['profiles'] as Map<String, dynamic>?;
members.add(
GroupMemberDetail(
member: member,
username: profile?['username'] as String? ?? 'Unknown User',
email: profile?['email'] as String?,
avatarUrl: profile?['avatar_url'] as String?,
),
);
}
return members;
} catch (e) {
print('[ERROR] Failed to load group members: $e');
return [];
}
}
// Remove a user from a group (admin only)
Future<bool> removeGroupMember(String groupId, String userId) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return false;
}
try {
// Mark as inactive instead of deleting
await _supabase
.from('group_members')
.update({'is_active': false})
.eq('group_id', groupId)
.eq('user_id', userId);
return true;
} catch (e) {
print('[ERROR] Failed to remove group member: $e');
return false;
}
}
// Change a member's role (admin only)
Future<bool> changeGroupMemberRole(
String groupId,
String userId,
String newRole,
) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return false;
}
// Validate role
if (!['admin', 'moderator', 'member'].contains(newRole)) {
print('[ERROR] Invalid role: $newRole');
return false;
}
try {
await _supabase
.from('group_members')
.update({'role': newRole})
.eq('group_id', groupId)
.eq('user_id', userId);
return true;
} catch (e) {
print('[ERROR] Failed to change member role: $e');
return false;
}
}
// Add all users to a default group (admin only)
Future<bool> addAllUsersToDefaultGroup(String defaultGroupId) async {
if (!await isUserAdmin()) {
print('[ERROR] Unauthorized access to admin function');
return false;
}
try {
// Cara langsung menggunakan RPC untuk menghindari masalah RLS
final result = await _supabase.rpc(
'add_all_users_to_group',
params: {'group_id_param': defaultGroupId},
);
print('[INFO] Added users to default group: $result');
return result == true;
} catch (e) {
print('[ERROR] Failed to add all users to default group: $e');
// Fallback jika RPC tidak tersedia
try {
// Get all user IDs
final usersResponse = await _supabase
.from('profiles')
.select('user_id');
// Get existing members of the group
final membersResponse = await _supabase
.from('group_members')
.select('user_id')
.eq('group_id', defaultGroupId);
final existingMemberIds =
membersResponse.map((m) => m['user_id'] as String).toSet();
// Create members for users who aren't already in the group
final List<Map<String, dynamic>> newMembers = [];
for (final user in usersResponse) {
final userId = user['user_id'] as String;
if (!existingMemberIds.contains(userId)) {
newMembers.add(
GroupMember(groupId: defaultGroupId, userId: userId).toMap(),
);
}
}
if (newMembers.isNotEmpty) {
await _supabase.from('group_members').insert(newMembers);
}
print(
'[INFO] Added ${newMembers.length} users to default group (fallback method)',
);
return true;
} catch (fallbackError) {
print('[ERROR] Fallback method also failed: $fallbackError');
return false;
}
}
}
// Create a new group (admin only) menggunakan RPC
Future<Group?> createGroupViaRPC({
required String name,
required String description,
required bool isPublic,
required bool isDefault,
String? iconUrl,
}) async {
if (currentUserId == null) {
print('[ERROR] User not authenticated');
return null;
}
try {
// Panggil fungsi RPC di database
final response = await _supabase.rpc(
'create_group_with_creator',
params: {
'name': name,
'description': description,
'created_by': currentUserId,
'is_public': isPublic,
'is_default': isDefault,
'icon_url': iconUrl,
},
);
print('[INFO] Group created via RPC: $response');
if (response != null) {
// Buat objek Group dari hasil
final createdGroup = Group(
id: response as String,
name: name,
description: description,
createdBy: currentUserId!,
isPublic: isPublic,
isDefault: isDefault,
iconUrl: iconUrl,
);
return createdGroup;
}
return null;
} catch (e) {
print('[ERROR] Failed to create group via RPC: $e');
return null;
}
}
}
// Helper class for group member details
class GroupMemberDetail {
final GroupMember member;
final String username;
final String? email;
final String? avatarUrl;
GroupMemberDetail({
required this.member,
required this.username,
this.email,
this.avatarUrl,
});
}