Skip to content

Commit

Permalink
fix issue
Browse files Browse the repository at this point in the history
  • Loading branch information
jwson-automation committed Aug 31, 2024
2 parents 811f1e4 + 66b3a89 commit e94bf9b
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 229 deletions.
29 changes: 23 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
ROOT := $(shell git rev-parse --show-toplevel)

# Detect operating system
ifeq ($(OS), Windows_NT)
DETECTED_OS := Windows
Expand All @@ -12,10 +11,23 @@ else
FLUTTER := $(shell which flutter)
endif
endif

# Define the default target to call all necessary targets
all: init analyze apply format buildRunner

# Define the init target to initialize the project
first : create init analyze buildRunner env
setting : init buildRunner
lint : analyze apply format

# Define the init target
create:
@echo "Create ios and android floder..."
ifeq ($(DETECTED_OS), Windows)
@flutter create .
else
@$(FLUTTER) create .
endif

# Define the init target
init:
@echo "Initializing Flutter project..."
Expand All @@ -24,7 +36,6 @@ ifeq ($(DETECTED_OS), Windows)
else
@$(FLUTTER) pub get
endif

# Define the analyze target
analyze:
@echo "Analyzing Flutter project..."
Expand All @@ -33,7 +44,6 @@ ifeq ($(DETECTED_OS), Windows)
else
-@$(FLUTTER) analyze
endif

# Define the apply target
apply:
@echo "Applying dart fixes..."
Expand All @@ -42,7 +52,6 @@ ifeq ($(DETECTED_OS), Windows)
else
@dart fix --apply
endif

# Define the apply target
format:
@echo "format dart fixes..."
Expand All @@ -51,7 +60,6 @@ ifeq ($(DETECTED_OS), Windows)
else
@dart format .
endif

# Define the buildRunner target
buildRunner:
@echo "Freezed Running build runner..."
Expand All @@ -61,3 +69,12 @@ else
@$(FLUTTER) pub run build_runner build --delete-conflicting-outputs
endif

# Define the env target for Unix-like systems
env:
ifeq ($(DETECTED_OS), Windows)
@echo "Using PowerShell script to create .env file."
@powershell -ExecutionPolicy Bypass -File generate_env.ps1
else
@echo "Using bash script to create .env file."
@bash generate_env.sh
endif
19 changes: 19 additions & 0 deletions generate_env.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# PowerShell 스크립트로 .env 파일 생성

# 현재 작업 중인 디렉터리 경로 가져오기
$TargetDir = Get-Location

# .env 파일 내용
$envContent = @"
# please replace 'your_api_key_here' with your actual API key
GOOGLE_API_KEY=your_api_key_here
GPT_API_KEY=your_api_key_here
# Other environment variables can be added here
"@

# .env 파일 생성
$envFilePath = Join-Path -Path $TargetDir -ChildPath ".env"
Write-Output "Creating .env file at: $envFilePath"

# UTF-8 인코딩으로 파일 생성
$envContent | Out-File -FilePath $envFilePath -Encoding utf8
5 changes: 5 additions & 0 deletions generate_env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# .env 파일 생성
echo "# please replace 'your_api_key_here' with your actual API key" > ".env"
echo "GOOGLE_API_KEY=your_api_key_here" >> ".env"
echo "GPT_API_KEY=your_api_key_here" >> ".env"
echo "# Other environment variables can be added here" >> ".env"
46 changes: 46 additions & 0 deletions integration_test/app_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:blueberry_flutter_template/firebase_options.dart';
import 'package:blueberry_flutter_template/model/PetProfileModel.dart';
import 'package:blueberry_flutter_template/model/PostModel.dart';
import 'package:blueberry_flutter_template/model/UserModel.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down Expand Up @@ -39,5 +41,49 @@ void main() {
// Then: 매핑된 데이터 검증
expect(fetchedData, isNotNull, reason: 'fetchedData는 null이 아니어야 합니다.');
});

test('user 컬렉션이 있을 때, 첫 번째 문서를 가져와 fromJson 메서드로 매핑하면, 오류 없이 매핑된다',
() async {
UserModel? fetchedData;

// Given: 컬렉션 이름 설정
collectionName = 'users';

// When: 첫 번째 문서 가져오기 및 fromJson 매핑
final querySnapshot =
await firestore.collection(collectionName).limit(1).get();

if (querySnapshot.docs.isNotEmpty) {
final data = querySnapshot.docs.first.data();
fetchedData = UserModel.fromJson(data);
} else {
throw Exception('$collectionName 컬렉션 안에 다큐먼트가 존재하지 않습니다');
}

// Then: 매핑된 데이터 검증
expect(fetchedData, isNotNull, reason: 'fetchedData는 null이 아니어야 합니다.');
});

test('posts 컬렉션이 있을 때, 첫 번째 문서를 가져와 fromJson 메서드로 매핑하면, 오류 없이 매핑된다',
() async {
PostModel? fetchedPost;

// Given: 컬렉션 이름 설정
collectionName = 'posts';

// When: 첫 번째 문서 가져오기 및 fromJson 매핑
final querySnapshot =
await firestore.collection(collectionName).limit(1).get();

if (querySnapshot.docs.isNotEmpty) {
final data = querySnapshot.docs.first.data();
fetchedPost = PostModel.fromJson(data);
} else {
throw Exception('$collectionName 컬렉션 안에 다큐먼트가 존재하지 않습니다');
}

// Then: 매핑된 데이터 검증
expect(fetchedPost, isNotNull, reason: 'fetchedPost는 null이 아니어야 합니다.');
});
});
}
140 changes: 83 additions & 57 deletions lib/feature/rank/provider/UserRankProvider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,21 @@ import 'package:blueberry_flutter_template/utils/AppStrings.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

/// User provider - Firestore에서 사용자 데이터를 가져오고 캐싱 처리
final userProvider = FutureProvider<List<UserModel>>((ref) async {
final cacheService = CacheService.instance;

// 한국 시간으로 매일 오전 9시 설정
final now = DateTime.now().toUtc().add(const Duration(hours: 9));
final tomorrowMorning = DateTime(now.year, now.month, now.day + 1, 9).toUtc();

// 캐시 정책 설정
final cacheConfig = CacheConfig(
cacheKey: AppStrings.userCacheKey,
expiryTime: tomorrowMorning, // 다음 날 오전 9시까지 유효
);
final cacheConfig = _createCacheConfig();

try {
// 캐시된 데이터 가져오기
// 1. 캐시된 데이터 가져오기 시도
final cachedUsers = await _getCachedUsers(cacheService, cacheConfig);
if (cachedUsers != null) return cachedUsers;

// Firestore에서 데이터 가져오기
// 2. Firestore에서 데이터 가져오기
final users = await _fetchUsersFromFirestore();

// 캐시에 저장
// 3. 캐시에 사용자 데이터 저장
await _cacheUsers(cacheService, cacheConfig, users);

return users;
Expand All @@ -36,72 +29,105 @@ final userProvider = FutureProvider<List<UserModel>>((ref) async {
}
});

/// 캐시 구성 생성 함수
CacheConfig _createCacheConfig() {
// 한국 시간으로 매일 오전 9시 설정
final now = DateTime.now().toUtc().add(const Duration(hours: 9));
final tomorrowMorning = DateTime(now.year, now.month, now.day + 1, 9).toUtc();

return CacheConfig(
cacheKey: AppStrings.userCacheKey,
expiryTime: tomorrowMorning, // 다음 날 오전 9시까지 유효
);
}

/// 캐시된 사용자 데이터를 가져오는 함수
Future<List<UserModel>?> _getCachedUsers(
CacheService cacheService, CacheConfig cacheConfig) async {
CacheService cacheService,
CacheConfig cacheConfig,
) async {
try {
final cachedData = await cacheService.getCachedData(cacheConfig);
if (cachedData != null) {
final cachedUsers = (json.decode(cachedData) as List<dynamic>)
.map((item) => UserModel.fromJson(item as Map<String, dynamic>))
.toList();
return cachedUsers;
// 캐시 만료 시간 확인
final now = DateTime.now().toUtc();
if (cacheConfig.expiryTime != null &&
now.isBefore(cacheConfig.expiryTime!)) {
return _decodeCachedUsers(cachedData);
} else {
// 만료되었으면 캐시 삭제
await cacheService.deleteCachedData(cacheConfig.cacheKey);
}
}
} catch (e) {
throw Exception('Failed to fetch user cached data');
}
return null;
}

/// 캐시된 사용자 데이터를 디코딩하는 함수
List<UserModel> _decodeCachedUsers(String cachedData) {
final List<dynamic> jsonData = json.decode(cachedData);
return jsonData
.map((item) => UserModel.fromJson(item as Map<String, dynamic>))
.toList();
}

/// Firestore에서 사용자 데이터를 가져오는 함수
Future<List<UserModel>> _fetchUsersFromFirestore() async {
try {
final fireStore = FirebaseFirestore.instance;

final likesSnapshot = await fireStore
.collection('likes')
.orderBy('likedUsers', descending: true)
.get();

final likedUserIds = likesSnapshot.docs
.expand((doc) => List<String>.from(doc['likedUsers']))
.toList();

final userDocs = await Future.wait(
likedUserIds
.map((userId) => fireStore.collection('users').doc(userId).get())
.toList(),
);

final users = userDocs.map((doc) {
if (doc.exists) {
final data = doc.data()!;
return UserModel(
userClass: data['userClass'] as String,
userId: doc.id,
name: data['name'] as String,
email: data['email'] as String,
age: data['age'] as int,
isMemberShip: data['isMemberShip'] as bool,
profileImageUrl: data['profilePicture'] as String?,
createdAt: DateTime.parse(data['createdAt'] as String),
socialLogin: data['socialLogin'] as bool,
socialCompany: data['socialCompany'] as String,
mbti: data['mbti'] as String,
fcmToken: data['fcmToken'] as String?,
likeGivens: data["likeGivens"] as List<String>,
);
} else {
throw Exception('User not found');
}
}).toList();
// 'likes' 컬렉션에서 좋아요 순으로 사용자 아이디 가져오기
final likedUserIds = await _fetchLikedUserIds(fireStore);

return users;
// 'users' 컬렉션에서 해당 사용자 문서들 가져오기
final userDocs = await _fetchUserDocs(fireStore, likedUserIds);

return _mapDocsToUsers(userDocs);
} catch (e) {
throw Exception('Failed to fetch users from Firestore');
}
}

Future<void> _cacheUsers(CacheService cacheService, CacheConfig cacheConfig,
List<UserModel> users) async {
/// Firestore에서 'likes' 컬렉션으로부터 사용자 아이디 목록을 가져오는 함수
Future<List<String>> _fetchLikedUserIds(FirebaseFirestore fireStore) async {
final likesSnapshot = await fireStore
.collection('likes')
.orderBy('likedUsers', descending: true)
.get();

return likesSnapshot.docs
.expand((doc) => List<String>.from(doc['likedUsers']))
.toList();
}

/// Firestore에서 사용자 문서들을 가져오는 함수
Future<List<DocumentSnapshot>> _fetchUserDocs(
FirebaseFirestore fireStore,
List<String> likedUserIds,
) async {
return await Future.wait(
likedUserIds
.map((userId) => fireStore.collection('users').doc(userId).get())
.toList(),
);
}

/// Firestore 문서 목록을 UserModel 객체로 매핑하는 함수
List<UserModel> _mapDocsToUsers(List<DocumentSnapshot> userDocs) {
return userDocs.where((doc) => doc.exists).map((doc) {
final data = doc.data() as Map<String, dynamic>;
return UserModel.fromJson(data);
}).toList();
}

/// 사용자 데이터를 캐시에 저장하는 함수
Future<void> _cacheUsers(
CacheService cacheService,
CacheConfig cacheConfig,
List<UserModel> users,
) async {
try {
final encodedData =
json.encode(users.map((user) => user.toJson()).toList());
Expand Down
23 changes: 0 additions & 23 deletions lib/feature/voiceOutput/VoiceOutputScreen.dart

This file was deleted.

11 changes: 0 additions & 11 deletions lib/feature/voiceOutput/provider/VoiceOutputProvider.dart

This file was deleted.

Loading

0 comments on commit e94bf9b

Please sign in to comment.