Skip to content

Commit be493e8

Browse files
WIP sprint
1 parent a89e5f8 commit be493e8

26 files changed

Lines changed: 1315 additions & 782 deletions

File tree

docs/model_relations/school_data_hub_server.svg

Lines changed: 1 addition & 0 deletions
Loading

school_data_hub_flutter/lib/common/widgets/custom_expansion_tile/custom_expansion_tile_switch.dart

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,22 @@ class CustomExpansionTileSwitch extends WatchingWidget {
3737
children: [
3838
expansionSwitchWidget!,
3939
const Gap(10),
40-
Icon(
41-
isExpanded
42-
? Icons.keyboard_arrow_up
43-
: Icons.keyboard_arrow_down,
44-
color: switchColor!,
40+
AnimatedRotation(
41+
turns: isExpanded ? 0.5 : 0.0,
42+
duration: const Duration(milliseconds: 200),
43+
child: Icon(Icons.keyboard_arrow_down, color: switchColor!),
4544
),
4645
],
4746
)
4847
: expansionSwitchWidget != null && includeSwitch != true
4948
? expansionSwitchWidget
50-
: Icon(
51-
isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
52-
color: switchColor ?? Colors.white,
49+
: AnimatedRotation(
50+
turns: isExpanded ? 0.5 : 0.0,
51+
duration: const Duration(milliseconds: 200),
52+
child: Icon(
53+
Icons.keyboard_arrow_down,
54+
color: switchColor ?? Colors.white,
55+
),
5356
),
5457
);
5558
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:flutter_it/flutter_it.dart';
2+
import 'package:school_data_hub_flutter/core/session/hub_session_manager.dart';
3+
import 'package:school_data_hub_flutter/features/pupil/domain/models/pupil_proxy.dart';
4+
5+
enum Clearance { none, developer, admin, tester }
6+
7+
class AuthClearanceHelper {
8+
static bool isAuthorized(Clearance clearanceLevel, {String? createdBy}) {
9+
final currentUser = di<HubSessionManager>().user!;
10+
11+
switch (clearanceLevel) {
12+
case Clearance.none:
13+
return true; // No clearance required, allow access
14+
case Clearance.developer:
15+
return currentUser.userInfo!.scopeNames.any(
16+
(scope) => scope.contains('developer'),
17+
);
18+
case Clearance.admin:
19+
return di<HubSessionManager>().isAdmin;
20+
case Clearance.tester:
21+
return currentUser.userFlags.isTester;
22+
}
23+
}
24+
25+
static bool isAdmin() {
26+
return di<HubSessionManager>().isAdmin;
27+
}
28+
29+
static bool isTutorOrAdmin(PupilProxy pupil) {
30+
final currentUser = di<HubSessionManager>().user!;
31+
return pupil.groupTutor == currentUser.userInfo!.userName ||
32+
di<HubSessionManager>().isAdmin;
33+
}
34+
35+
static bool isCreatorOrAdmin(String? createdBy) {
36+
final currentUser = di<HubSessionManager>().user!;
37+
if (createdBy == null) return false;
38+
return currentUser.userInfo!.scopeNames.contains('serverpod.admin') ||
39+
currentUser.userInfo!.userName == createdBy;
40+
}
41+
}

school_data_hub_flutter/lib/features/app_main_navigation/tools_page.dart

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:convert';
12
import 'dart:io';
23

34
import 'package:flutter/material.dart';
@@ -10,6 +11,8 @@ import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
1011
import 'package:school_data_hub_flutter/common/widgets/dialogs/confirmation_dialog.dart';
1112
import 'package:school_data_hub_flutter/common/widgets/dialogs/short_textfield_dialog.dart';
1213
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_app_bar.dart';
14+
import 'package:school_data_hub_flutter/common/widgets/qr/qr_utilites.dart';
15+
import 'package:school_data_hub_flutter/core/env/env_manager.dart';
1316
import 'package:school_data_hub_flutter/core/session/hub_session_manager.dart';
1417
import 'package:school_data_hub_flutter/features/matrix/domain/matrix_policy_manager.dart';
1518
import 'package:school_data_hub_flutter/features/matrix/presentation/set_matrix_environment_page/set_matrix_environment_controller.dart';
@@ -240,6 +243,16 @@ class ToolsPage extends WatchingWidget {
240243
icon: Icons.mobile_screen_share,
241244
label: 'Ids teilen',
242245
),
246+
_ToolsMenuButton(
247+
onPressed: () {
248+
Navigator.pop(context);
249+
_importUnencryptedPupilIdentitySourceFile(
250+
'pupil_identities',
251+
);
252+
},
253+
icon: Icons.file_open_rounded,
254+
label: 'aus Datei',
255+
),
243256
// Desktop-only admin tools for pupil identity import
244257
if (_hubSessionManager.isAdmin &&
245258
(Platform.isWindows || Platform.isMacOS)) ...[
@@ -261,16 +274,6 @@ class ToolsPage extends WatchingWidget {
261274
icon: Icons.school,
262275
label: 'SchiLD Import',
263276
),
264-
_ToolsMenuButton(
265-
onPressed: () {
266-
Navigator.pop(context);
267-
_importUnencryptedPupilIdentitySourceFile(
268-
'pupil_identities',
269-
);
270-
},
271-
icon: Icons.people,
272-
label: 'ID-Liste',
273-
),
274277
],
275278
],
276279
),
@@ -327,6 +330,19 @@ class ToolsPage extends WatchingWidget {
327330
label: 'Statistik',
328331
),
329332

333+
// --- Calendar section ---
334+
_ToolsCategoryButton(
335+
onPressed: () {
336+
Navigator.of(context).push(
337+
MaterialPageRoute(
338+
builder: (_) => const SchooldaysCalendarPage(),
339+
),
340+
);
341+
},
342+
icon: Icons.calendar_month_rounded,
343+
label: 'Schultage-\nKalender',
344+
),
345+
330346
// --- Admin sections ---
331347
if (_hubSessionManager.isAdmin) ...[
332348
// User-Verwaltung
@@ -375,7 +391,7 @@ class ToolsPage extends WatchingWidget {
375391
],
376392
),
377393
icon: Icons.people_rounded,
378-
label: 'User',
394+
label: 'Personal',
379395
),
380396

381397
// Admin (Schuldaten + Kalender + Stundenplan + Matrix)
@@ -409,18 +425,7 @@ class ToolsPage extends WatchingWidget {
409425
icon: Icons.schedule,
410426
label: 'Stundenplan',
411427
),
412-
_ToolsMenuButton(
413-
onPressed: () {
414-
Navigator.pop(context);
415-
Navigator.of(context).push(
416-
MaterialPageRoute(
417-
builder: (_) => const SchooldaysCalendarPage(),
418-
),
419-
);
420-
},
421-
icon: Icons.calendar_month_rounded,
422-
label: 'Schultage-\nKalender',
423-
),
428+
424429
_ToolsMenuButton(
425430
onPressed: () {
426431
Navigator.pop(context);
@@ -456,6 +461,20 @@ class ToolsPage extends WatchingWidget {
456461
? 'Matrix\ninitialisiert'
457462
: 'Matrix\ninitialisieren',
458463
),
464+
_ToolsMenuButton(
465+
onPressed: () {
466+
Navigator.pop(context);
467+
final Map<String, dynamic> json = di<EnvManager>()
468+
.activeEnv!
469+
.toJson();
470+
471+
final String jsonString = jsonEncode(json);
472+
473+
showQrCode(jsonString, context);
474+
},
475+
icon: Icons.key_rounded,
476+
label: 'Schulschlüssel\nzeigen',
477+
),
459478
_ToolsMenuButton(
460479
onPressed: () async {
461480
Navigator.pop(context);

school_data_hub_flutter/lib/features/app_settings/settings_page/settings_page.dart

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter_it/flutter_it.dart';
23
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
34
import 'package:school_data_hub_flutter/app_utils/logger/presentation/logs_page/logs_page.dart';
45
import 'package:school_data_hub_flutter/app_utils/shorebird_code_push_page.dart';
56
import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
67
import 'package:school_data_hub_flutter/common/theme/styles.dart';
8+
import 'package:school_data_hub_flutter/core/auth/auth_clearance_helper.dart';
79
import 'package:school_data_hub_flutter/core/env/env_manager.dart';
810
import 'package:school_data_hub_flutter/core/session/hub_session_manager.dart';
911
import 'package:school_data_hub_flutter/core/updater/shorebird_update_manager.dart';
1012
import 'package:school_data_hub_flutter/features/app_settings/settings_page/widgets/settings_account_section.dart';
1113
import 'package:school_data_hub_flutter/features/app_settings/settings_page/widgets/settings_admin_section.dart';
1214
import 'package:school_data_hub_flutter/features/app_settings/settings_page/widgets/settings_session_section.dart';
15+
import 'package:school_data_hub_flutter/features/server_logs/presentation/server_logs_page.dart';
1316
import 'package:school_data_hub_flutter/l10n/app_localizations.dart';
14-
import 'package:flutter_it/flutter_it.dart';
1517

1618
class SettingsPage extends WatchingWidget {
1719
const SettingsPage({super.key});
@@ -69,10 +71,23 @@ class SettingsPage extends WatchingWidget {
6971
SettingsTile.navigation(
7072
leading: const Icon(Icons.bug_report_rounded),
7173
title: const Text('Logs'),
72-
onPressed: (context) => Navigator.of(
73-
context,
74-
).push(MaterialPageRoute(builder: (ctx) => const LogsPage())),
74+
onPressed: (context) => Navigator.of(context).push(
75+
MaterialPageRoute(builder: (ctx) => const LogsPage()),
76+
),
7577
),
78+
if (AuthClearanceHelper.isAdmin())
79+
SettingsTile.navigation(
80+
leading: const Icon(Icons.dns_outlined),
81+
title: const Text('Server-Logs'),
82+
onPressed: (context) {
83+
Navigator.push(
84+
context,
85+
MaterialPageRoute(
86+
builder: (_) => const ServerLogsPage(),
87+
),
88+
);
89+
},
90+
),
7691
SettingsTile.navigation(
7792
leading: const Icon(Icons.info_rounded),
7893
title: const Text('App Infos'),

school_data_hub_flutter/lib/features/app_settings/settings_page/widgets/settings_admin_section.dart

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import 'dart:convert';
2-
31
import 'package:flutter/material.dart';
42
import 'package:flutter_it/flutter_it.dart';
53
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
64
import 'package:school_data_hub_flutter/app_utils/app_helpers.dart';
75
import 'package:school_data_hub_flutter/common/services/notification_service.dart';
86
import 'package:school_data_hub_flutter/common/widgets/dialogs/confirmation_dialog.dart';
9-
import 'package:school_data_hub_flutter/common/widgets/qr/qr_utilites.dart';
107
import 'package:school_data_hub_flutter/core/env/env_manager.dart';
118
import 'package:school_data_hub_flutter/core/session/hub_session_manager.dart';
129
import 'package:school_data_hub_flutter/features/books/utils/book_ids_pdf_generator.dart';
@@ -39,18 +36,6 @@ class SettingsAdminSection extends AbstractSettingsSection with WatchItMixin {
3936
),
4037
),
4138
tiles: <SettingsTile>[
42-
SettingsTile.navigation(
43-
leading: const Icon(Icons.dns_outlined),
44-
title: const Text('Server-Logs'),
45-
onPressed: (context) {
46-
Navigator.push(
47-
context,
48-
MaterialPageRoute(
49-
builder: (_) => const ServerLogsPage(),
50-
),
51-
);
52-
},
53-
),
5439
SettingsTile.navigation(
5540
title: const Text('Buch IDs generieren'),
5641
leading: const Icon(Icons.qr_code_rounded),
@@ -87,17 +72,6 @@ class SettingsAdminSection extends AbstractSettingsSection with WatchItMixin {
8772
await userManager.increaseUsersCredit();
8873
},
8974
),
90-
SettingsTile.navigation(
91-
leading: const Icon(Icons.qr_code_rounded),
92-
title: const Text('Schulschlüssel zeigen'),
93-
onPressed: (context) {
94-
final Map<String, dynamic> json = envManager.activeEnv!.toJson();
95-
96-
final String jsonString = jsonEncode(json);
97-
98-
showQrCode(jsonString, context);
99-
},
100-
),
10175

10276
SettingsTile.navigation(
10377
onPressed: (context) async {

0 commit comments

Comments
 (0)