feat(admin): grant full admin permissions in app and security rules to nicolas@gruber.info
Build Android APK / Build Release APKs (push) Successful in 16m30s

This commit is contained in:
2026-09-14 11:35:40 +02:00
parent f9a88a5ba2
commit 2f2170573d
4 changed files with 52 additions and 29 deletions
+4 -1
View File
@@ -8,7 +8,10 @@ service cloud.firestore {
} }
function isAdmin() { function isAdmin() {
return request.auth != null && request.auth.token.admin == true; return request.auth != null && (
request.auth.token.admin == true ||
request.auth.token.email == 'nicolas@gruber.info'
);
} }
function isAuthorOrAdmin() { function isAuthorOrAdmin() {
+37 -27
View File
@@ -51,11 +51,13 @@ class InfoScreen extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
// Bürgerforum Access & Account Card // Bürgerforum Access & Account Card
Card( Card(
color: auth.isRegisteredUser color: auth.isAdmin
? Colors.green.shade50 ? Colors.indigo.shade50
: auth.isCommunityUnlocked : auth.isRegisteredUser
? Colors.teal.shade50 ? Colors.green.shade50
: Colors.blue.shade50, : auth.isCommunityUnlocked
? Colors.teal.shade50
: Colors.blue.shade50,
shape: shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding( child: Padding(
@@ -65,16 +67,20 @@ class InfoScreen extends StatelessWidget {
Row( Row(
children: [ children: [
Icon( Icon(
auth.isRegisteredUser auth.isAdmin
? Icons.account_circle ? Icons.admin_panel_settings
: auth.isCommunityUnlocked : auth.isRegisteredUser
? Icons.verified_user ? Icons.account_circle
: Icons.lock_outline, : auth.isCommunityUnlocked
color: auth.isRegisteredUser ? Icons.verified_user
? Colors.green.shade700 : Icons.lock_outline,
: auth.isCommunityUnlocked color: auth.isAdmin
? Colors.teal.shade800 ? Colors.indigo.shade700
: Colors.blue.shade800, : auth.isRegisteredUser
? Colors.green.shade700
: auth.isCommunityUnlocked
? Colors.teal.shade800
: Colors.blue.shade800,
size: 36, size: 36,
), ),
const SizedBox(width: 14), const SizedBox(width: 14),
@@ -83,23 +89,27 @@ class InfoScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
auth.isRegisteredUser auth.isAdmin
? (auth.displayName?.isNotEmpty == true ? 'Administrator'
? auth.displayName! : auth.isRegisteredUser
: 'Bürger-Konto') ? (auth.displayName?.isNotEmpty == true
: auth.isCommunityUnlocked ? auth.displayName!
? 'Bürgerzugang: Aktiv (Code)' : 'Bürger-Konto')
: 'Gastmodus (Nur Lesen)', : auth.isCommunityUnlocked
? 'Bürgerzugang: Aktiv (Code)'
: 'Gastmodus (Nur Lesen)',
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15), fontWeight: FontWeight.bold, fontSize: 15),
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Text( Text(
auth.isRegisteredUser auth.isAdmin
? auth.email ?? 'Angemeldet' ? '${auth.email ?? "Angemeldet"} (Admin-Rechte aktiv)'
: auth.isCommunityUnlocked : auth.isRegisteredUser
? 'Mängel & Ideen freigeschaltet' ? auth.email ?? 'Angemeldet'
: 'Anmelden oder Code eingeben zum Mitwirken.', : auth.isCommunityUnlocked
? 'Mängel & Ideen freigeschaltet'
: 'Anmelden oder Code eingeben zum Mitwirken.',
style: TextStyle( style: TextStyle(
fontSize: 12, color: Colors.grey.shade700), fontSize: 12, color: Colors.grey.shade700),
), ),
+9
View File
@@ -47,8 +47,17 @@ class AuthService extends ChangeNotifier {
_initAuth(); _initAuth();
} }
static const List<String> adminEmails = [
'nicolas@gruber.info',
];
Future<void> _checkAdminClaim(User? user) async { Future<void> _checkAdminClaim(User? user) async {
if (user != null && !user.isAnonymous) { if (user != null && !user.isAnonymous) {
final email = user.email?.trim().toLowerCase();
if (email != null && adminEmails.contains(email)) {
_isAdmin = true;
return;
}
try { try {
final tokenResult = await user.getIdTokenResult(); final tokenResult = await user.getIdTokenResult();
_isAdmin = tokenResult.claims?['admin'] == true; _isAdmin = tokenResult.claims?['admin'] == true;
+2 -1
View File
@@ -15,7 +15,8 @@ service firebase.storage {
// Nur der Verfasser oder ein Admin darf sein Foto löschen // Nur der Verfasser oder ein Admin darf sein Foto löschen
allow delete: if request.auth != null && ( allow delete: if request.auth != null && (
request.auth.uid == userId || request.auth.uid == userId ||
request.auth.token.admin == true request.auth.token.admin == true ||
request.auth.token.email == 'nicolas@gruber.info'
); );
} }
} }