Skip to content

Commit 21d7eff

Browse files
force logout in deleted device, other fixes
1 parent debcd07 commit 21d7eff

21 files changed

Lines changed: 2743 additions & 2141 deletions

File tree

docs/model_relations/school_data_hub_server.svg

Lines changed: 1 addition & 1 deletion
Loading
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
2+
/* To generate run: "serverpod generate" */
3+
4+
// ignore_for_file: implementation_imports
5+
// ignore_for_file: library_private_types_in_public_api
6+
// ignore_for_file: non_constant_identifier_names
7+
// ignore_for_file: public_member_api_docs
8+
// ignore_for_file: type_literal_in_constant_pattern
9+
// ignore_for_file: use_super_parameters
10+
11+
// ignore_for_file: no_leading_underscores_for_library_prefixes
12+
import 'package:serverpod_client/serverpod_client.dart' as _i1;
13+
14+
abstract class ForceLogoutEvent implements _i1.SerializableModel {
15+
ForceLogoutEvent._({
16+
required this.userInfoId,
17+
required this.deviceId,
18+
});
19+
20+
factory ForceLogoutEvent({
21+
required int userInfoId,
22+
required String deviceId,
23+
}) = _ForceLogoutEventImpl;
24+
25+
factory ForceLogoutEvent.fromJson(Map<String, dynamic> jsonSerialization) {
26+
return ForceLogoutEvent(
27+
userInfoId: jsonSerialization['userInfoId'] as int,
28+
deviceId: jsonSerialization['deviceId'] as String,
29+
);
30+
}
31+
32+
int userInfoId;
33+
34+
String deviceId;
35+
36+
/// Returns a shallow copy of this [ForceLogoutEvent]
37+
/// with some or all fields replaced by the given arguments.
38+
@_i1.useResult
39+
ForceLogoutEvent copyWith({
40+
int? userInfoId,
41+
String? deviceId,
42+
});
43+
@override
44+
Map<String, dynamic> toJson() {
45+
return {
46+
'userInfoId': userInfoId,
47+
'deviceId': deviceId,
48+
};
49+
}
50+
51+
@override
52+
String toString() {
53+
return _i1.SerializationManager.encode(this);
54+
}
55+
}
56+
57+
class _ForceLogoutEventImpl extends ForceLogoutEvent {
58+
_ForceLogoutEventImpl({
59+
required int userInfoId,
60+
required String deviceId,
61+
}) : super._(
62+
userInfoId: userInfoId,
63+
deviceId: deviceId,
64+
);
65+
66+
/// Returns a shallow copy of this [ForceLogoutEvent]
67+
/// with some or all fields replaced by the given arguments.
68+
@_i1.useResult
69+
@override
70+
ForceLogoutEvent copyWith({
71+
int? userInfoId,
72+
String? deviceId,
73+
}) {
74+
return ForceLogoutEvent(
75+
userInfoId: userInfoId ?? this.userInfoId,
76+
deviceId: deviceId ?? this.deviceId,
77+
);
78+
}
79+
}

school_data_hub_client/lib/src/protocol/protocol.dart

Lines changed: 713 additions & 699 deletions
Large diffs are not rendered by default.

school_data_hub_flutter/assets/school_data_hub_server.svg

Lines changed: 1 addition & 1 deletion
Loading

school_data_hub_flutter/lib/common/audio/presentation/audio_button.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class _AudioButtonState extends State<AudioButton> {
7272
if (!AuthClearanceHelper.isCreatorOrAdmin(widget.file.createdBy)) {
7373
di<NotificationService>().showSnackBar(
7474
NotificationType.error,
75-
'Nur Admins können Dokumente löschen',
75+
'Nur Dokumenteninhaber können Dokumente löschen',
7676
);
7777
return;
7878
}

school_data_hub_flutter/lib/common/services/hub_stream_service.dart

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import 'package:flutter_it/flutter_it.dart';
77
import 'package:logging/logging.dart';
88
import 'package:school_data_hub_client/school_data_hub_client.dart';
99
import 'package:school_data_hub_flutter/core/env/env_manager.dart';
10-
import 'package:school_data_hub_flutter/core/session/hub_session_manager.dart';
10+
import 'package:school_data_hub_flutter/core/env/utils/env_utils.dart';
11+
import 'package:school_data_hub_flutter/core/session/hub_session_helper.dart';
1112
import 'package:school_data_hub_flutter/core/session/serverpod_connectivity_monitor.dart';
1213

1314
final _log = Logger('HubStreamService');
@@ -46,6 +47,7 @@ class HubStreamService with WidgetsBindingObserver {
4647
bool _disposed = false;
4748
final _random = Random();
4849
VoidCallback? _connectivityListener;
50+
String? _currentDeviceId;
4951

5052
final _events = StreamController<Object>.broadcast();
5153

@@ -61,6 +63,7 @@ class HubStreamService with WidgetsBindingObserver {
6163
bool get isConnected => _state.value == HubConnectionState.connected;
6264

6365
Future<HubStreamService> init() async {
66+
_currentDeviceId = (await EnvUtils.getDeviceNameAndId()).deviceId;
6467
_attemptConnect(isReconnect: false);
6568
final monitor = di<ServerpodConnectivityMonitor>();
6669
_connectivityListener = () {
@@ -210,9 +213,20 @@ class HubStreamService with WidgetsBindingObserver {
210213
_hasReceivedFirstEvent = true;
211214
_reconnectDelayMs = _initialReconnectDelayMs;
212215
}
213-
if (!_disposed) {
214-
_events.add(message as Object);
216+
if (_disposed) return;
217+
218+
// Check for force-logout targeting this device.
219+
if (message is ForceLogoutEvent &&
220+
message.deviceId == _currentDeviceId) {
221+
_log.warning(
222+
'[HUB] ForceLogoutEvent received for this device — wiping data',
223+
);
224+
_cleanupSubscription();
225+
SessionHelper.logoutAndDeleteAllInstanceData();
226+
return;
215227
}
228+
229+
_events.add(message as Object);
216230
},
217231
onError: (Object error) {
218232
_handleStreamError(error);
@@ -240,7 +254,8 @@ class HubStreamService with WidgetsBindingObserver {
240254

241255
if (error is ServerpodClientUnauthorized ||
242256
(error is ServerpodClientException && error.statusCode == 401)) {
243-
di<HubSessionManager>().signOutDevice();
257+
_log.warning('[HUB] Unauthorized — wiping data and signing out');
258+
SessionHelper.logoutAndDeleteAllInstanceData();
244259
return;
245260
}
246261

school_data_hub_flutter/lib/core/session/hub_session_manager.dart

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,32 +152,33 @@ class HubSessionManager with ChangeNotifier {
152152
Future<bool> _signOut({required bool allDevices}) async {
153153
if (!isSignedIn) return true;
154154

155+
// Attempt to notify the server; ignore failures (e.g. key already deleted).
155156
try {
156157
if (allDevices) {
157158
await caller.status.signOutAllDevices();
158159
} else {
159160
await caller.status.signOutDevice();
160161
}
161-
await caller.client.updateStreamingConnectionAuthenticationKey(null);
162+
} catch (e) {
163+
_log.warning('Server sign-out call failed (key may already be deleted): $e');
164+
}
162165

163-
_signedInUser = null;
166+
// Always clean up locally regardless of whether the server call succeeded.
167+
try {
168+
await caller.client.updateStreamingConnectionAuthenticationKey(null);
169+
} catch (_) {}
164170

165-
// await _handleAuthCallResultInStorage();
171+
_signedInUser = null;
166172

167-
await keyManager.remove();
173+
await keyManager.remove();
168174

169-
if (!_isDisposed) notifyListeners();
175+
if (!_isDisposed) notifyListeners();
170176

171-
/// Don't forget to set the flag in [EnvManager] to false
172-
/// to get to the login screen.
173-
_log.info('User signed out ');
177+
_log.info('User signed out');
174178

175-
_envManager.setUserAuthenticatedFlagOnlyByHubSessionManager(false);
179+
_envManager.setUserAuthenticatedFlagOnlyByHubSessionManager(false);
176180

177-
return true;
178-
} catch (e) {
179-
return false;
180-
}
181+
return true;
181182
}
182183

183184
Future<void> attemptLogin({

school_data_hub_flutter/lib/features/_pupil/domain/filters/pupil_filter_manager.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ class PupilFilterManager implements Resettable {
4545
void resetFilters() {
4646
_pupilFilterState.value = {...initialPupilFilterValues};
4747

48-
//TODO: fix this
49-
// di<SchooldayEventFilterManager>().resetFilters();
50-
51-
// _searchText.value = '';
52-
5348
_sortMode.value = {...initialSortModeValues};
5449

5550
di<FiltersStateManager>().setFilterState(

school_data_hub_flutter/lib/features/_pupil/presentation/pupil_profile_page/widgets/pupil_profile_page_content/learning_support_content/pupil_profile_learning_support_content_list.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class PupilProfileLearningSupportContentList extends WatchingWidget {
129129
if (!isAdmin) {
130130
di<NotificationService>().showSnackBar(
131131
NotificationType.error,
132-
'Nur Admins können Dokumente ansehen',
132+
'Nur Dokumenteninhaber können Dokumente löschen',
133133
);
134134
return;
135135
}

0 commit comments

Comments
 (0)