Skip to content

Commit ba2170c

Browse files
authored
fix: user id migration (#960)
1 parent f3c53a1 commit ba2170c

13 files changed

Lines changed: 108 additions & 34 deletions

File tree

lib/app/router/main_shell.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,23 +472,23 @@ class _MainShellState extends State<MainShell> with WidgetsBindingObserver {
472472
final session = context.read<AppBloc>().state.session;
473473

474474
return MessagingBloc(
475-
session.userId,
476475
createMessagingSocket(session.coreUrl!, session.token!, session.tenantId),
477476
featureAccess.messagingConfig,
478477
context.read<ChatsRepository>(),
479478
context.read<ChatsOutboxRepository>(),
480479
context.read<SmsRepository>(),
481480
context.read<SmsOutboxRepository>(),
481+
context.read<SessionRepository>(),
482482
(n) => context.read<NotificationsBloc>().add(NotificationsSubmitted(n)),
483483
);
484484
},
485485
),
486486
BlocProvider<UnreadCountCubit>(
487487
create: (context) {
488488
return UnreadCountCubit(
489-
userId: context.read<AppBloc>().state.session.userId,
490489
chatsRepository: context.read<ChatsRepository>(),
491490
smsRepository: context.read<SmsRepository>(),
491+
sessionRepository: context.read<SessionRepository>(),
492492
)..init();
493493
},
494494
),

lib/blocs/app/app_bloc.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class AppBloc extends Bloc<AppEvent, AppState> {
3939
required AppThemes appThemes,
4040
}) : super(
4141
AppState(
42-
session: sessionRepository.getCurrent() ?? const Session(),
43-
status: (sessionRepository.getCurrent()?.isLoggedIn ?? false)
42+
session: sessionRepository.getCurrent(),
43+
status: (sessionRepository.getCurrent().isLoggedIn)
4444
? AppLifecycleStatus.authenticated
4545
: AppLifecycleStatus.unauthenticated,
4646
themeSettings: appThemes.values.first.settings,
@@ -135,7 +135,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
135135
// guarantees the session is already terminated.
136136
final shouldRevokeRemote = reason == AppLogoutReason.userRequest || reason == AppLogoutReason.serverRejection;
137137

138-
if (shouldRevokeRemote && currentSession != null && currentSession.isLoggedIn) {
138+
if (shouldRevokeRemote && currentSession.isLoggedIn) {
139139
_logger.info('Revoking remote session. Reason: $reason');
140140
unawaited(sessionRepository.revokeSession(currentSession));
141141
} else {

lib/features/messaging/bloc/messaging_bloc.dart

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ final _logger = Logger('MessagingBloc');
2828

2929
class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
3030
MessagingBloc(
31-
this._userId,
3231
this._client,
3332
this._messagingConfig,
3433
this._chatsRepository,
3534
this._chatsOutboxRepository,
3635
this._smsRepository,
3736
this._smsOutboxRepository,
37+
this._sessionRepository,
3838
this._submitNotification,
39-
) : super(MessagingState.initial(_client, _messagingConfig)) {
39+
) : super(MessagingState.initial(_sessionRepository.getCurrent().userId, _client, _messagingConfig)) {
4040
on<Connect>(_connect);
4141
on<Refresh>(_refresh);
4242
on<Disconnect>(_onDisconnect);
@@ -49,13 +49,13 @@ class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
4949
_subs.add(_client.errorStream.listen((e) => add(_ClientError(e))));
5050
}
5151

52-
final String _userId;
5352
final PhoenixSocket _client;
5453
final MessagingConfig _messagingConfig;
5554
final ChatsRepository _chatsRepository;
5655
final ChatsOutboxRepository _chatsOutboxRepository;
5756
final SmsRepository _smsRepository;
5857
final SmsOutboxRepository _smsOutboxRepository;
58+
final SessionRepository _sessionRepository;
5959
final Function(Notification) _submitNotification;
6060
final List<StreamSubscription> _subs = [];
6161

@@ -70,10 +70,7 @@ class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
7070
// -
7171
// Uncomment section below to wipe messaging related data
7272
// -
73-
// _chatsRepository.wipeChatsData();
74-
// _chatsOutboxRepository.wipeOutboxData();
75-
// _smsRepository.wipeData();
76-
// _smsOutboxRepository.wipeOutboxData();
73+
// wipeData()
7774

7875
emit(state.copyWith(status: ConnectionStatus.connecting));
7976
_client.connect();
@@ -89,8 +86,26 @@ class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
8986
try {
9087
// Join channel for user specific events
9188
if (_client.userChannel == null) {
92-
final userChannel = _client.createUserChannel(_userId);
93-
await userChannel.join().future;
89+
final userId = _sessionRepository.getCurrent().userId;
90+
final userChannel = _client.createUserChannel(userId);
91+
final joinReq = await userChannel.join().future;
92+
final response = joinReq.response;
93+
94+
/// Handle the workaround for core userId upgrade
95+
/// When the server detects that the client is using an old userId format, it responds with a "forbidden" message containing the new userId.
96+
/// The client then updates its session with the new userId, wipes local messaging data to prevent inconsistencies
97+
/// and rejoins the channel with the new userId.
98+
if (response is List && response[0] == 'forbidden' && response[1] is String) {
99+
final newUserId = response[1] as String;
100+
_logger.warning('UserId upgrade required, new userId: $newUserId');
101+
102+
await _sessionRepository.patchSession(userId: newUserId);
103+
await wipeData();
104+
105+
emit(state.copyWith(userId: newUserId));
106+
final userChannel = _client.createUserChannel(newUserId);
107+
await userChannel.join().future;
108+
}
94109
}
95110

96111
// Init workers
@@ -137,6 +152,13 @@ class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
137152
}
138153
}
139154

155+
Future<void> wipeData() async {
156+
await _chatsRepository.wipeChatsData();
157+
await _chatsOutboxRepository.wipeOutboxData();
158+
await _smsRepository.wipeData();
159+
await _smsOutboxRepository.wipeOutboxData();
160+
}
161+
140162
void _disposeWorkers() {
141163
_chatsSyncWorker?.dispose();
142164
_chatsSyncWorker = null;

lib/features/messaging/bloc/messaging_state.dart

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,37 @@ part of 'messaging_bloc.dart';
33
enum ConnectionStatus { initial, error, connecting, connected }
44

55
class MessagingState with EquatableMixin {
6-
const MessagingState._(this.client, this.status, this.messagingConfig, this.error);
6+
const MessagingState._(this.userId, this.client, this.status, this.messagingConfig, this.error);
77

8+
final String userId;
89
final PhoenixSocket client;
910
final ConnectionStatus status;
1011
final MessagingConfig messagingConfig;
1112
final Exception? error;
1213

13-
factory MessagingState.initial(PhoenixSocket client, MessagingConfig messagingConfig) {
14-
return MessagingState._(client, ConnectionStatus.initial, messagingConfig, null);
14+
factory MessagingState.initial(String userId, PhoenixSocket client, MessagingConfig messagingConfig) {
15+
return MessagingState._(userId, client, ConnectionStatus.initial, messagingConfig, null);
1516
}
1617

17-
MessagingState copyWith({ConnectionStatus? status, MessagingConfig? messagingConfig, Exception? error}) {
18-
return MessagingState._(client, status ?? this.status, messagingConfig ?? this.messagingConfig, error);
18+
MessagingState copyWith({
19+
String? userId,
20+
PhoenixSocket? client,
21+
ConnectionStatus? status,
22+
MessagingConfig? messagingConfig,
23+
Exception? error,
24+
}) {
25+
return MessagingState._(
26+
userId ?? this.userId,
27+
client ?? this.client,
28+
status ?? this.status,
29+
messagingConfig ?? this.messagingConfig,
30+
error,
31+
);
1932
}
2033

2134
@override
2235
bool? get stringify => true;
2336

2437
@override
25-
List<Object?> get props => [client, status];
38+
List<Object?> get props => [userId, client, status, messagingConfig, error];
2639
}

lib/features/messaging/cubits/unread_count/unread_count_cubit.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ final _logger = Logger('UnreadCountCubit');
1111

1212
class UnreadCountCubit extends Cubit<UnreadCountState> {
1313
UnreadCountCubit({
14-
required this.userId,
1514
required this.chatsRepository,
1615
required this.smsRepository,
16+
required this.sessionRepository,
1717
this.updateDebounce = const Duration(seconds: 1),
1818
}) : super(UnreadCountState.initial());
1919

20-
final String userId;
2120
final ChatsRepository chatsRepository;
2221
final SmsRepository smsRepository;
22+
final SessionRepository sessionRepository;
2323
final Duration updateDebounce;
2424
StreamSubscription? _chatsUpdatesSub;
2525
StreamSubscription? _smsUpdatesSub;
@@ -32,6 +32,7 @@ class UnreadCountCubit extends Cubit<UnreadCountState> {
3232
}
3333

3434
void _updateUnreadCount() async {
35+
final userId = sessionRepository.getCurrent().userId;
3536
final chatCounts = await chatsRepository.unreadedCountPerChat(userId);
3637
final smsCounts = await smsRepository.unreadedCountPerConversation(userId);
3738

lib/features/messaging/extensions/phoenix_socket.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ PhoenixSocket createMessagingSocket(String coreUrl, String token, String tenantI
2626
}
2727

2828
extension PhoenixSocketExt on PhoenixSocket {
29-
/// Create user channel by [userId] and connect, if already exists returns it
30-
PhoenixChannel createUserChannel(String userId) => addChannel(topic: 'chat:user:$userId');
29+
/// Create user channel by [userId] and connect, if already exists replaces it
30+
PhoenixChannel createUserChannel(String userId) {
31+
final oldChannel = userChannel;
32+
if (oldChannel != null) removeChannel(oldChannel);
33+
34+
return addChannel(topic: 'chat:user:$userId');
35+
}
3136

3237
/// Get user channel if exists
3338
PhoenixChannel? get userChannel => channels.values.firstWhereOrNull((c) => c.topic.startsWith('chat:user:'));

lib/features/messaging/features/chat_conversation/view/conversation_screen.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'package:auto_route/auto_route.dart';
66
import 'package:flutter_bloc/flutter_bloc.dart';
77

88
import 'package:webtrit_phone/app/router/app_router.dart';
9-
import 'package:webtrit_phone/blocs/app/app_bloc.dart';
109
import 'package:webtrit_phone/features/features.dart';
1110
import 'package:webtrit_phone/models/models.dart';
1211
import 'package:webtrit_phone/l10n/l10n.dart';
@@ -22,9 +21,9 @@ class ChatConversationScreen extends StatefulWidget {
2221
}
2322

2423
class _ChatConversationScreenState extends State<ChatConversationScreen> {
25-
late final userId = context.read<AppBloc>().state.session.userId;
2624
late final messagingBloc = context.read<MessagingBloc>();
2725
late final conversationCubit = context.read<ConversationCubit>();
26+
late final userId = messagingBloc.state.userId;
2827

2928
void onMenuTap() {
3029
final state = conversationCubit.state;

lib/features/messaging/features/conversations/view/conversations_screen.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class _ConversationsScreenState extends State<ConversationsScreen> with SingleTi
264264
body: MessagingStateWrapper(
265265
child: TabBarView(
266266
controller: _tabController,
267-
children: [for (final tab in _tabs) ConversationsList(selectedTab: tab)],
267+
children: [for (final tab in _tabs) ConversationsList(selectedTab: tab)], // TODO: wtf
268268
),
269269
),
270270
floatingActionButton: Builder(

lib/features/messaging/features/conversations/widgets/conversations_list.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
33

4-
import 'package:webtrit_phone/blocs/app/app_bloc.dart';
54
import 'package:webtrit_phone/features/features.dart';
65
import 'package:webtrit_phone/l10n/l10n.dart';
76
import 'package:webtrit_phone/widgets/widgets.dart';
@@ -16,7 +15,7 @@ class ConversationsList extends StatefulWidget {
1615
}
1716

1817
class _ConversationsListState extends State<ConversationsList> {
19-
late final userId = context.read<AppBloc>().state.session.userId;
18+
late final messagingBloc = context.read<MessagingBloc>();
2019

2120
@override
2221
Widget build(BuildContext context) {
@@ -29,6 +28,8 @@ class _ConversationsListState extends State<ConversationsList> {
2928

3029
return ListView(
3130
children: conversationsToShow.map((e) {
31+
final userId = messagingBloc.state.userId;
32+
3233
final (:chat, :message, contacts: _) = e;
3334
return FadeIn(
3435
child: ChatConversationsTile(conversation: chat, lastMessage: message, userId: userId, key: ValueKey(e)),
@@ -47,6 +48,8 @@ class _ConversationsListState extends State<ConversationsList> {
4748

4849
return ListView(
4950
children: conversationsToShow.map((e) {
51+
final userId = messagingBloc.state.userId;
52+
5053
final conversation = e.$1;
5154
final lastMessage = e.$2;
5255
return FadeIn(

lib/features/messaging/features/sms_conversation/view/sms_conversation_screen.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'package:auto_route/auto_route.dart';
77
import 'package:flutter_bloc/flutter_bloc.dart';
88

99
import 'package:webtrit_phone/app/router/app_router.dart';
10-
import 'package:webtrit_phone/blocs/app/app_bloc.dart';
1110
import 'package:webtrit_phone/features/features.dart';
1211
import 'package:webtrit_phone/repositories/repositories.dart';
1312
import 'package:webtrit_phone/widgets/fade_id.dart';
@@ -22,10 +21,10 @@ class SmsConversationScreen extends StatefulWidget {
2221
}
2322

2423
class _SmsConversationScreenState extends State<SmsConversationScreen> {
25-
late final userId = context.read<AppBloc>().state.session.userId;
2624
late final messagingBloc = context.read<MessagingBloc>();
2725
late final conversationCubit = context.read<SmsConversationCubit>();
2826
late final contactsRepo = context.read<ContactsRepository>();
27+
late final userId = messagingBloc.state.userId;
2928

3029
Future<void> onDeleteDialog() async {
3130
final askResult = await showDialog<bool>(

0 commit comments

Comments
 (0)