Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Flutter/Flutter Project

[소셜차트] 앱 제작기 #5. Model and Firestore 1%

방피터 2022. 10. 24. 18:50

이전 작업

2022.10.22 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기 #4. 로그인 시스템 구성

 

[소셜차트] 앱 제작기 #4. 로그인 시스템 구성

2022.10.21 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기 #3. Navigation 시스템 구성 [소셜차트] 앱 제작기 #3. Navigation 시스템 구성 2022.10.14 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기..

engschool.tistory.com

무언가 잘못되어 로그인이 되지 않을 때 사용자가 보고할 수 있는 페이지를 제작했고 그에 맞춰 firestore에 내용을 저장할 수 있도록 했어.

사용자 문제 보고 화면 + firebase

먼저 firebase firestore 데이터베이스를 asia-northeast3(서울지역인데 비싼걸로 알고 있음.)에 생성했어. 그리고 유저가 로그인하지 않은 상태이므로 아무나 database에 내용을 쓸 수 있도록 rule을 변경해야해. firestore의 규칙 탭에서 변경하고 테스트 가능해.

Firebase rule

처음에 프러덕션으로 데이터베이스를 만들면 모든 문서에 대해서 접근이 불가하도록 설정이 되어 있는데 그걸 아래 처럼 변경👇👇

//첫번째
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를 사용했어.

TextFormField

그리고 Firebase 저장할 Data model을 만들자. Model 폴더를 하나 만들고 그 안에 userReport.dart를 생성.

지금 사용중인 폴더 구조에 Model과 Controller 추가

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

 

[Flutter] JSON, 직렬화???, Model, Firestore withConverter

2022.10.12 - [Flutter/Flutter Study] - [Flutter] - Firebase firestore [Flutter] - Firebase firestore React native에서는 React Query가 있어서 디따 편하게 했는데;;; 찾아보니까 Flutter에는 대표적으로..

engschool.tistory.com

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%정도 완료된 듯! ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 언제 다 하지?? ㅋㅋㅋ

아자아자앚아자아아아자아앙자앚!!!!!

이 글은 말 그대로 제작기야! 그래서 설명이 부족할 수 있는데! 그래서 열받고 막 그러면 댓글 남겨. 그럼 ㅈㄴ 친절하게 답변해줄게. 안녕!

 

 

반응형