이전 작업
2022.10.22 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기 #4. 로그인 시스템 구성
무언가 잘못되어 로그인이 되지 않을 때 사용자가 보고할 수 있는 페이지를 제작했고 그에 맞춰 firestore에 내용을 저장할 수 있도록 했어.
먼저 firebase firestore 데이터베이스를 asia-northeast3(서울지역인데 비싼걸로 알고 있음.)에 생성했어. 그리고 유저가 로그인하지 않은 상태이므로 아무나 database에 내용을 쓸 수 있도록 rule을 변경해야해. firestore의 규칙 탭에서 변경하고 테스트 가능해.
처음에 프러덕션으로 데이터베이스를 만들면 모든 문서에 대해서 접근이 불가하도록 설정이 되어 있는데 그걸 아래 처럼 변경👇👇
//첫번째
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {//DB root
match /userReports/{userReport}{//룰 적용할 collection
allow write: if true;//모두 허용함
allow read: if request.auth != null;//인증된 사람만 허용함.
//=>>>> 인증된 모든 사람이 볼 수 있는 문제!!
}
}
}
//두번째
rules_version = '3';
service cloud.firestore {
match /databases/{database}/documents {//DB root
match /userReports/{userReport}{//룰 적용할 collection
allow read, update, delete: if request.auth != null && //인증된 사람과
request.auth.token.email == resource.data.userEmail;//작성한 사람만 볼 수 있음.
}
}
}
첫번째 예는 모든 사람에게 쓰기를 허용하고 읽기는 로그인한 사람에게만 허용하는 규칙이고 두번째는 마찬가지로 쓰기는 모든 사람에게 허용, 읽기, 수정, 삭제는 로그인한 사람이고 로그인한 이메일이 문서의 이메일과 동일한 사람(작성자)만 볼 수 있게 하는 규칙이야. 주석을 보면 쉽게 알 수 있을 거야.
그 다음은 Flutter 앱에서 화면 만들고👇 입력은 TextFormField를 사용했어.
그리고 Firebase 저장할 Data model을 만들자. Model 폴더를 하나 만들고 그 안에 userReport.dart를 생성.
Model 파일은 사실 별거 없어. Firebase에서 Json 객체를 던져주는데 flutter에서는 그걸 Map<String, dynamic?>으로 인식해서 접근하려면 userReport["userEmail"] 이렇게 등신처럼 접근해야 해.. 근데 그걸 flutter에서 쉽게 사용가능한 객체로 만들어 주는 것뿐!
//userReport.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class UserReport {
const UserReport({
required this.userEmail,
required this.userMessage,
required this.createdAt,
this.isReplied,
this.replyMessage,
});
final String userEmail; //user email
final String userMessage; // user text reported
final Timestamp createdAt; //creation time
final bool? isReplied;
final String? replyMessage;
UserReport.fromJson(Map<String, Object?> json)
: this(
userMessage: json['userMessage']! as String,
createdAt: json['createdAt']! as Timestamp,
userEmail: json['userEmail']! as String,
isReplied: json['isReplied']! as bool,
replyMessage: json['replyMessage'] as String,
);
Map<String, Object?> toJson() {
return {
'userMessage': userMessage,
'userEmail': userEmail,
'createdAt': createdAt,
'isReplied': isReplied,
'replyMessage': replyMessage,
};
}
}
2022.10.15 - [Flutter/Flutter Study] - [Flutter] JSON, 직렬화???, Model, Firestore withConverter
Model과 관련한 자세한 사항은 👆👆를 참고하고!
그리고 Controller 폴더에 reportController.dart 파일을 생성해서 GetXController 클래스를 하나 만들었어. 뭐 파일 위치같은 건 좀 합리적으로 바꿀 필요가 있을 것 같고... 암튼 동작은 하니까 이렇게 하는데;; 너무 등신같이 하는 거면;;; 좀 알려줘(제발!)😣😣😣
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
import 'package:socialchart/models/userReport.dart';
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseFirestore firestore = FirebaseFirestore.instance;
class ReportController extends GetxController {
static ReportController get to => Get.find();
final userReportColRef = firestore.collection("userReports").withConverter(
fromFirestore: (snapshot, options) =>
UserReport.fromJson(snapshot.data()!),
toFirestore: ((value, options) => value.toJson()));
Future<void> sendReport(String userEmail, userMessage) {
return userReportColRef
.add(UserReport(
userEmail: userEmail,
userMessage: userMessage,
createdAt: Timestamp.now(),
isReplied: false))
.then((value) => print("send complete"))
.catchError((onError) {
print("에러요!, ${onError}");
throw (onError);
});
}
}
특별한 건 없지만 굳이 설명하자면 collection reference 선언할 때 withConverter를 함께 사용하면 firestore 다큐먼트가 JSON 형식이 아니라 위의 model에서 선언한 모양대로 넘어와. 자동 완성도 되고 실수할 일도 없지!! 개강추!
그리고 나머지는 Form 버튼의 onPressed 에서 적당히 사용!👇
onPressed: () {
IsLoadingController.to.isLoading = true;
if (_formKey.currentState!.validate()) {
//todo 전송
ReportController.to
.sendReport(_emailController.text, _textController.text)
.then((value) {
IsLoadingController.to.isLoading = false;
Get.snackbar("전송 완료", "말씀해주신 내용이 전송되었어요.");
}).catchError((onError) {
print("에러요!${onError}");
Get.snackbar("에러요!", "죄송해요. 뭔가 잘못되었어요.");
IsLoadingController.to.isLoading = false;
});
} else {
IsLoadingController.to.isLoading = false;
if (!Get.isSnackbarOpen) {
Get.snackbar("오류", "입력에 오류가 있어요.", isDismissible: true);
}
}
},
음 이걸로 model은 1%정도 완료된 듯! ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 언제 다 하지?? ㅋㅋㅋ
아자아자앚아자아아아자아앙자앚!!!!!
이 글은 말 그대로 제작기야! 그래서 설명이 부족할 수 있는데! 그래서 열받고 막 그러면 댓글 남겨. 그럼 ㅈㄴ 친절하게 답변해줄게. 안녕!
'Flutter > Flutter Project' 카테고리의 다른 글
[소셜차트] 앱 제작기 #8. 글쓰는 페이지 (0) | 2022.11.05 |
---|---|
[소셜차트] 앱 제작기 #6. Profile & Notice Screen Layout (1) | 2022.10.26 |
[소셜차트] 앱 제작기 #4. 로그인 시스템 구성 (0) | 2022.10.22 |
[소셜차트] 앱 제작기 #3. Navigation 시스템 구성 (0) | 2022.10.21 |
[소셜차트] 앱 제작기 #2. 기본 설정 (0) | 2022.10.14 |