359 lines
10 KiB
Dart
359 lines
10 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import '../config/api_config.dart';
|
|
import '../models/admin_model.dart';
|
|
|
|
/// 관리자 기능 관련 서비스
|
|
class AdminService extends ChangeNotifier {
|
|
final String _baseUrl = ApiConfig.baseUrl;
|
|
final String _token;
|
|
final String _clubId;
|
|
|
|
List<MemberRole> _memberRoles = [];
|
|
ClubSettings? _clubSettings;
|
|
UserRole _currentUserRole = UserRole.member;
|
|
AdminPermission _currentUserPermissions = AdminPermission();
|
|
bool _isLoading = false;
|
|
String? _error;
|
|
|
|
AdminService(this._token, this._clubId) {
|
|
_initialize();
|
|
}
|
|
|
|
// 게터
|
|
List<MemberRole> get memberRoles => _memberRoles;
|
|
ClubSettings? get clubSettings => _clubSettings;
|
|
UserRole get currentUserRole => _currentUserRole;
|
|
AdminPermission get currentUserPermissions => _currentUserPermissions;
|
|
bool get isLoading => _isLoading;
|
|
String? get error => _error;
|
|
|
|
// 권한 확인 게터
|
|
bool get canManageMembers => _currentUserPermissions.canManageMembers;
|
|
bool get canManageEvents => _currentUserPermissions.canManageEvents;
|
|
bool get canManageScores => _currentUserPermissions.canManageScores;
|
|
bool get canManageSettings => _currentUserPermissions.canManageSettings;
|
|
bool get canManageSubscription => _currentUserPermissions.canManageSubscription;
|
|
bool get canManageRoles => _currentUserPermissions.canManageRoles;
|
|
bool get canViewFinancials => _currentUserPermissions.canViewFinancials;
|
|
bool get canExportData => _currentUserPermissions.canExportData;
|
|
|
|
/// 초기화 (현재 사용자 권한 및 클럽 설정 로드)
|
|
Future<void> _initialize() async {
|
|
await Future.wait([
|
|
fetchCurrentUserRole(),
|
|
fetchClubSettings(),
|
|
]);
|
|
}
|
|
|
|
/// 현재 사용자의 역할 및 권한 조회
|
|
Future<void> fetchCurrentUserRole() async {
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/my-role'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
final memberRole = MemberRole.fromJson(data);
|
|
_currentUserRole = memberRole.role;
|
|
_currentUserPermissions = memberRole.permissions;
|
|
} else {
|
|
// 기본값: 일반 회원
|
|
_currentUserRole = UserRole.member;
|
|
_currentUserPermissions = AdminPermission.fromRole(UserRole.member);
|
|
_error = '사용자 역할 정보를 불러오는데 실패했습니다. (${response.statusCode})';
|
|
}
|
|
} catch (e) {
|
|
_error = '사용자 역할 정보를 불러오는데 실패했습니다: $e';
|
|
// 기본값: 일반 회원
|
|
_currentUserRole = UserRole.member;
|
|
_currentUserPermissions = AdminPermission.fromRole(UserRole.member);
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 내 모든 회원의 역할 정보 조회
|
|
Future<void> fetchMemberRoles() async {
|
|
if (!canManageRoles) {
|
|
_error = '역할 관리 권한이 없습니다.';
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/roles'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final List<dynamic> data = jsonDecode(response.body);
|
|
_memberRoles = data.map((role) => MemberRole.fromJson(role)).toList();
|
|
} else {
|
|
_error = '회원 역할 정보를 불러오는데 실패했습니다. (${response.statusCode})';
|
|
}
|
|
} catch (e) {
|
|
_error = '회원 역할 정보를 불러오는데 실패했습니다: $e';
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 회원 역할 변경
|
|
Future<bool> updateMemberRole(String memberId, UserRole newRole) async {
|
|
if (!canManageRoles) {
|
|
_error = '역할 관리 권한이 없습니다.';
|
|
notifyListeners();
|
|
return false;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.put(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/members/$memberId/role'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
body: jsonEncode({
|
|
'role': newRole.toString().split('.').last,
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
// 역할 목록 갱신
|
|
await fetchMemberRoles();
|
|
return true;
|
|
} else {
|
|
_error = '회원 역할 변경에 실패했습니다. (${response.statusCode})';
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
_error = '회원 역할 변경에 실패했습니다: $e';
|
|
return false;
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 설정 조회
|
|
Future<void> fetchClubSettings() async {
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/settings'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
_clubSettings = ClubSettings.fromJson(data);
|
|
} else {
|
|
_error = '클럽 설정을 불러오는데 실패했습니다. (${response.statusCode})';
|
|
}
|
|
} catch (e) {
|
|
_error = '클럽 설정을 불러오는데 실패했습니다: $e';
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 설정 업데이트
|
|
Future<bool> updateClubSettings(ClubSettings updatedSettings) async {
|
|
if (!canManageSettings) {
|
|
_error = '설정 관리 권한이 없습니다.';
|
|
notifyListeners();
|
|
return false;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.put(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/settings'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
body: jsonEncode(updatedSettings.toJson()),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
_clubSettings = ClubSettings.fromJson(data);
|
|
notifyListeners();
|
|
return true;
|
|
} else {
|
|
_error = '클럽 설정 업데이트에 실패했습니다. (${response.statusCode})';
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
_error = '클럽 설정 업데이트에 실패했습니다: $e';
|
|
return false;
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 로고 업로드
|
|
Future<bool> uploadClubLogo(String filePath) async {
|
|
if (!canManageSettings) {
|
|
_error = '설정 관리 권한이 없습니다.';
|
|
notifyListeners();
|
|
return false;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
// 파일 업로드 로직 구현 (multipart/form-data)
|
|
// 실제 구현 시 http.MultipartRequest 사용
|
|
|
|
// 성공 시 설정 업데이트
|
|
await fetchClubSettings();
|
|
return true;
|
|
} catch (e) {
|
|
_error = '클럽 로고 업로드에 실패했습니다: $e';
|
|
return false;
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 데이터 내보내기
|
|
Future<String?> exportClubData(String dataType) async {
|
|
if (!canExportData) {
|
|
_error = '데이터 내보내기 권한이 없습니다.';
|
|
notifyListeners();
|
|
return null;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/export/$dataType'),
|
|
headers: {
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
// 다운로드 URL 또는 데이터 반환
|
|
final data = jsonDecode(response.body);
|
|
return data['downloadUrl'] ?? data['data'];
|
|
} else {
|
|
_error = '데이터 내보내기에 실패했습니다. (${response.statusCode})';
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
_error = '데이터 내보내기에 실패했습니다: $e';
|
|
return null;
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 클럽 통계 및 분석 데이터 조회
|
|
Future<Map<String, dynamic>?> fetchClubAnalytics() async {
|
|
if (!canViewFinancials) {
|
|
_error = '통계 조회 권한이 없습니다.';
|
|
notifyListeners();
|
|
return null;
|
|
}
|
|
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/api/clubs/$_clubId/analytics'),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $_token',
|
|
},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
return data;
|
|
} else {
|
|
_error = '클럽 통계 데이터를 불러오는데 실패했습니다. (${response.statusCode})';
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
_error = '클럽 통계 데이터를 불러오는데 실패했습니다: $e';
|
|
return null;
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// 특정 권한이 있는지 확인
|
|
bool hasPermission(String permissionName) {
|
|
switch (permissionName) {
|
|
case 'manageMembers':
|
|
return _currentUserPermissions.canManageMembers;
|
|
case 'manageEvents':
|
|
return _currentUserPermissions.canManageEvents;
|
|
case 'manageScores':
|
|
return _currentUserPermissions.canManageScores;
|
|
case 'manageSettings':
|
|
return _currentUserPermissions.canManageSettings;
|
|
case 'manageSubscription':
|
|
return _currentUserPermissions.canManageSubscription;
|
|
case 'manageRoles':
|
|
return _currentUserPermissions.canManageRoles;
|
|
case 'viewFinancials':
|
|
return _currentUserPermissions.canViewFinancials;
|
|
case 'exportData':
|
|
return _currentUserPermissions.canExportData;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|