Reputation: 461
I am a beginner in Flutter x Firebase and been stuck here for last three days. Pls help me resolve this, and explain the reason as well
/Firestore(30190): (25.0.0) [Firestore]: Listen for Query(target=Query( collectionGroup=leaves where status==pending order by name);limitType=LIMIT_TO_FIRST) failed: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null}
my code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class AdminDashboardScreen extends StatefulWidget {
const AdminDashboardScreen({super.key});
@override
_AdminDashboardScreenState createState() => _AdminDashboardScreenState();
}
class _AdminDashboardScreenState extends State<AdminDashboardScreen> {
bool isAdmin = false;
Future<bool> _isAdmin(String uid) async {
var doc = await FirebaseFirestore.instance.collection('admins').doc(uid).get();
return doc.exists;
}
@override
void initState() {
super.initState();
_checkIfAdmin();
}
Future<void> _checkIfAdmin() async {
String uid = FirebaseAuth.instance.currentUser!.uid;
bool admin = await _isAdmin(uid);
setState(() {
isAdmin = admin;
});
}
@override
Widget build(BuildContext context) {
if (!isAdmin) {
return Scaffold(
appBar: AppBar(
title: Text('Admin Panel'),
),
body: Center(child: Text('You do not have admin privileges.')),
);
}
return Scaffold(
appBar: AppBar(
title: Text('Admin Panel'),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collectionGroup('leaves')
.where('status', isEqualTo: 'pending').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return Center(child: Text('No pending leave requests.'));
}
var leaveRequests = snapshot.data!.docs;
return ListView.builder(
itemCount: leaveRequests.length,
itemBuilder: (context, index) {
var leave = leaveRequests[index];
return ListTile(
title: Text('${leave['studentName']} is requesting for a leave'),
subtitle: Text('Reason: ${leave['reason']}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.check),
onPressed: () => _updateLeaveStatus(leave, 'approved'),
),
IconButton(
icon: Icon(Icons.close),
onPressed: () => _updateLeaveStatus(leave, 'rejected'),
),
],
),
);
},
);
},
),
);
}
void _updateLeaveStatus(QueryDocumentSnapshot leave, String status) async {
try {
await leave.reference.update({'status': status});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Leave request $status')));
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error updating status: $e')));
}
}
}
my database security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated users to read/write their own documents
match /students/{studentId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid == studentId;
}
// Admin collection
match /admins/{adminId} {
allow read, write: if request.auth != null && request.auth.uid == adminId;
}
// Allow admins to read and write any student data
match /students/{studentId}/{documents=**} {
allow read, write: if request.auth != null && isAdmin(request.auth.uid);
}
}
}
Upvotes: 0
Views: 49
Reputation: 599716
Your security rules are also calling an isAdmin
function here:
match /students/{studentId}/{documents=**} {
allow read, write: if request.auth != null && isAdmin(request.auth.uid);
}
That isAdmin
isn't defined inside the security rules that you show, so that call will fail. Keep in mind that your security rules run somewhere else than your Flutter code, so the rules can't call the function in your Flutter code.
If you want the security rules to be able to test if somebody is an admin, you will have to write an isAdmin
implementation in the rules too.
Upvotes: 0