Skip to content

Commit

Permalink
refactor: update AuthenticatedUser model to require id and remove pas…
Browse files Browse the repository at this point in the history
…sword, enhance server URI handling in AddNewServer widget
  • Loading branch information
Dr-Blank committed Oct 4, 2024
1 parent eda45ef commit fa815ae
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 72 deletions.
68 changes: 61 additions & 7 deletions lib/api/api_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:vaani/db/cache_manager.dart';
import 'package:vaani/models/error_response.dart';
import 'package:vaani/settings/api_settings_provider.dart';
import 'package:vaani/settings/models/authenticated_user.dart';
import 'package:vaani/shared/extensions/obfuscation.dart';

part 'api_provider.g.dart';
Expand Down Expand Up @@ -49,6 +51,7 @@ AudiobookshelfApi authenticatedApi(AuthenticatedApiRef ref) {
final apiSettings = ref.watch(apiSettingsProvider);
final user = apiSettings.activeUser;
if (user == null) {
_logger.severe('No active user can not provide authenticated api');
throw StateError('No active user');
}
return AudiobookshelfApi(
Expand Down Expand Up @@ -97,17 +100,26 @@ class PersonalizedView extends _$PersonalizedView {
final api = ref.watch(authenticatedApiProvider);
final apiSettings = ref.watch(apiSettingsProvider);
final user = apiSettings.activeUser;
if (user == null) {
_logger.warning('no active user');
yield [];
return;
}
if (apiSettings.activeLibraryId == null) {
// set it to default user library by logging in and getting the library id
final login =
await api.login(username: user!.username!, password: user.password!);
final login = await ref.read(loginProvider().future);
if (login == null) {
_logger.shout('failed to login, not building personalized view');
yield [];
return;
}
ref.read(apiSettingsProvider.notifier).updateState(
apiSettings.copyWith(activeLibraryId: login!.userDefaultLibraryId),
apiSettings.copyWith(activeLibraryId: login.userDefaultLibraryId),
);
}
// try to find in cache
// final cacheKey = 'personalizedView:${apiSettings.activeLibraryId}';
var key = 'personalizedView:${apiSettings.activeLibraryId! + user!.id!}';
final key = 'personalizedView:${apiSettings.activeLibraryId! + user.id}';
final cachedRes = await apiResponseCacheManager.getFileFromMemory(
key,
) ??
Expand All @@ -127,7 +139,7 @@ class PersonalizedView extends _$PersonalizedView {
}
}

// ! exagerated delay
// ! exaggerated delay
// await Future.delayed(const Duration(seconds: 2));
final res = await api.libraries
.getPersonalized(libraryId: apiSettings.activeLibraryId!);
Expand All @@ -151,6 +163,7 @@ class PersonalizedView extends _$PersonalizedView {
// method to force refresh the view and ignore the cache
Future<void> forceRefresh() async {
// clear the cache
// TODO: find a better way to clear the cache for only personalized view key
return apiResponseCacheManager.emptyCache();
}
}
Expand All @@ -173,6 +186,47 @@ FutureOr<User> me(
MeRef ref,
) async {
final api = ref.watch(authenticatedApiProvider);
final res = await api.me.getUser();
return res!;
final errorResponseHandler = ErrorResponseHandler();
final res = await api.me.getUser(
responseErrorHandler: errorResponseHandler.storeError,
);
if (res == null) {
_logger.severe(
'me failed, got response: ${errorResponseHandler.response.obfuscate()}',
);
throw StateError('me failed');
}
return res;
}

@riverpod
FutureOr<LoginResponse?> login(
LoginRef ref, {
AuthenticatedUser? user,
}) async {
if (user == null) {
// try to get the user from settings
final apiSettings = ref.watch(apiSettingsProvider);
user = apiSettings.activeUser;
if (user == null) {
_logger.severe('no active user to login');
return null;
}
_logger.fine('no user provided, using active user: ${user.obfuscate()}');
}
final api = ref.watch(audiobookshelfApiProvider(user.server.serverUrl));
api.token = user.authToken;
var errorResponseHandler = ErrorResponseHandler();
_logger.fine('logging in with authenticated api');
final res = await api.misc.authorize(
responseErrorHandler: errorResponseHandler.storeError,
);
if (res == null) {
_logger.severe(
'login failed, got response: ${errorResponseHandler.response.obfuscate()}',
);
return null;
}
_logger.fine('login response: ${res.obfuscate()}');
return res;
}
133 changes: 130 additions & 3 deletions lib/api/api_provider.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/features/onboarding/view/onboarding_single_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class OnboardingSinglePage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final apiSettings = ref.watch(apiSettingsProvider);
final serverUriController = useTextEditingController(
text: apiSettings.activeServer?.serverUrl.toString() ?? '',
text: apiSettings.activeServer?.serverUrl.toString() ?? 'https://',
);
var audiobookshelfUri = makeBaseUrl(serverUriController.text);

Expand Down
1 change: 0 additions & 1 deletion lib/features/onboarding/view/user_login_with_password.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ class UserLoginWithPassword extends HookConsumerWidget {
final authenticatedUser = model.AuthenticatedUser(
server: addServer(),
id: success.user.id,
password: password,
username: username,
authToken: api.token!,
);
Expand Down
6 changes: 5 additions & 1 deletion lib/models/error_response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ final _logger = Logger('ErrorResponse');
class ErrorResponseHandler {
String? name;
http.Response _response;
bool logRawResponse;

ErrorResponseHandler({
this.name,
http.Response? response,
this.logRawResponse = false,
}) : _response = response ?? http.Response('', 418);

void storeError(http.Response response, [Object? error]) {
_logger.fine('for $name got response: ${response.obfuscate()}');
if (logRawResponse) {
_logger.fine('for $name got response: ${response.obfuscate()}');
}
_response = response;
}

Expand Down
3 changes: 1 addition & 2 deletions lib/settings/models/authenticated_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ class AuthenticatedUser with _$AuthenticatedUser {
const factory AuthenticatedUser({
required AudiobookShelfServer server,
required String authToken,
String? id,
required String id,
String? username,
String? password,
}) = _AuthenticatedUser;

factory AuthenticatedUser.fromJson(Map<String, dynamic> json) =>
Expand Down
Loading

0 comments on commit fa815ae

Please sign in to comment.