diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml
deleted file mode 100644
index 7008872..0000000
--- a/.forgejo/workflows/deploy.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-on:
- release:
- types: [published]
-jobs:
- test:
- runs-on: docker
- steps:
- - run: apt update && apt install -y sshpass jq
- - uses: actions/checkout@v4
- - name: Set up Flutter
- uses: https://github.com/subosito/flutter-action@v2
- with:
- channel: stable
- flutter-version: 3.35.1
- cache: true
- - run: git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.35.1-x64
- - run: flutter build web --release --wasm --base-href /app/
- - run: sshpass -p "${{ secrets.DEPLOY_PASSWORD }}" scp -o StrictHostKeyChecking=accept-new -rp build/web/* ${{ secrets.DEPLOY_USERNAME }}@${{ secrets.DEPLOY_ADDRESS }}:${{ secrets.DEPLOY_PATH }}
diff --git a/README.md b/README.md
index a5a46b7..304117b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,3 @@
-> [!WARNING]
-> This repo has been moved to [illes](https://git.illes.fr/UEAuvergne/Seshat).
-
# seshat
Client android/iOS/web, écrit en dart x flutter, pour Alexandria.
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 80cd4ad..d2ea4a2 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -24,7 +24,7 @@ android {
applicationId = "fr.ueauvergne.seshat"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
- minSdkVersion(24)
+ minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html
index d098403..f7fc0b1 100644
--- a/android/build/reports/problems/problems-report.html
+++ b/android/build/reports/problems/problems-report.html
@@ -650,7 +650,7 @@ code + .copy-button {
diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart
index c55d564..2b56ddb 100644
--- a/lib/data/repositories/auth_repository.dart
+++ b/lib/data/repositories/auth_repository.dart
@@ -2,7 +2,6 @@ import 'package:flutter/foundation.dart';
import 'package:seshat/data/services/auth_client.dart';
import 'package:seshat/utils/result.dart';
-/// Repository to manage authentification
class AuthRepository extends ChangeNotifier {
AuthRepository({required AuthClient authClient}) : _authClient = authClient;
@@ -10,7 +9,6 @@ class AuthRepository extends ChangeNotifier {
bool? _isAuthenticated;
- /// Checks the validity of the token if not already checked
Future get isLoggedIn async {
if (_isAuthenticated != null) {
return _isAuthenticated!;
@@ -27,7 +25,6 @@ class AuthRepository extends ChangeNotifier {
}
}
- /// Logs in the user
Future> login(String username, String password) async {
try {
final result = await _authClient.login(username, password);
@@ -36,14 +33,13 @@ class AuthRepository extends ChangeNotifier {
_isAuthenticated = true;
return Result.ok(());
case Error():
- return result;
+ return Result.error(result.error);
}
} catch (e) {
return Result.error(Exception(e));
}
}
- /// Gets the API's remote version
Future> getRemoteApiVersion() async {
return await _authClient.getRemoteApiVersion();
}
diff --git a/lib/data/repositories/bal_repository.dart b/lib/data/repositories/bal_repository.dart
index 97bc023..ccce2e4 100644
--- a/lib/data/repositories/bal_repository.dart
+++ b/lib/data/repositories/bal_repository.dart
@@ -5,19 +5,13 @@ import 'package:seshat/domain/models/bal_stats.dart';
import 'package:seshat/domain/models/enums.dart';
import 'package:seshat/utils/result.dart';
-/// Repository to manage [Bal]
class BalRepository {
BalRepository({required ApiClient apiClient}) : _apiClient = apiClient;
final ApiClient _apiClient;
-
- /// [List] of all the user's [Bal]
List? _bals;
+ Accounting? accounting;
- /// [Accounting] of [Bal], mapped by [Bal] id
- final Map _accountingMap = {};
-
- /// Gets a list of all [Bal] from cache or remote
Future>> getBals() async {
if (_bals != null) {
return Result.ok(_bals!);
@@ -32,7 +26,6 @@ class BalRepository {
}
}
- /// Gets a list of all [Bal] from remote only
Future>> _getBalsNoCache() async {
final result = await _apiClient.getBals();
switch (result) {
@@ -44,16 +37,15 @@ class BalRepository {
}
}
- /// Gets a [Bal] by [balId], either from cache or remote
- Future> balById(int balId) async {
+ Future> balById(int id) async {
if (_bals == null) {
await getBals();
}
- Bal? bal = _bals!.where((bal) => bal.id == balId).firstOrNull;
+ Bal? bal = _bals!.where((bal) => bal.id == id).firstOrNull;
if (bal != null) {
return Result.ok(bal);
}
- final result = await _apiClient.getBalById(balId);
+ final result = await _apiClient.getBalById(id);
switch (result) {
case Ok():
return Result.ok(result.value);
@@ -62,13 +54,11 @@ class BalRepository {
}
}
- /// Return wether or not a [Bal] is currently [BalState.ongoing]
bool isABalOngoing() {
return _bals?.where((bal) => bal.state == BalState.ongoing).isNotEmpty ??
false;
}
- /// Gets the [Bal] that is [BalState.ongoing]
Future ongoingBal() async {
if (_bals == null) {
await _getBalsNoCache();
@@ -76,14 +66,12 @@ class BalRepository {
return _bals!.where((bal) => bal.state == BalState.ongoing).firstOrNull;
}
- /// Stops a [Bal] and refresh cache
Future> stopBal(int id) async {
final result = await _apiClient.stopBal(id);
_getBalsNoCache();
return result;
}
- /// Starts a [Bal] and refresh cache
Future> startBal(int id) async {
if (isABalOngoing()) {
return Result.error(
@@ -95,62 +83,52 @@ class BalRepository {
return result;
}
- /// Changes a [Bal]'s [name], [startTime] or [endTime]
Future> editBal(
int id,
String name,
- DateTime startTime,
- DateTime endTime,
+ DateTime start,
+ DateTime end,
) async {
- final result = await _apiClient.editBal(id, name, startTime, endTime);
+ final result = await _apiClient.editBal(id, name, start, end);
await _getBalsNoCache();
return result;
}
- /// Creates a [Bal] from its [name], [startTime] and [endTime]
- Future> addBal(
- String name,
- DateTime startTime,
- DateTime endTime,
- ) async {
- final result = await _apiClient.addBal(name, startTime, endTime);
+ Future> addBal(String name, DateTime start, DateTime end) async {
+ final result = await _apiClient.addBal(name, start, end);
await _getBalsNoCache();
return result;
}
- /// Gets a [BalStats] from its [balId]
- Future> getBalStats(int balId) async {
- return _apiClient.getBalStats(balId);
+ Future> getBalStats(int id) async {
+ return _apiClient.getBalStats(id);
}
- /// Get [Accounting] of a [Bal] from remote only
Future> getAccountingNoCache(int balId) async {
final result = await _apiClient.getAccounting(balId);
switch (result) {
case Ok():
- _accountingMap[balId] = result.value;
+ accounting = result.value;
break;
default:
}
return result;
}
- /// Get [Accounting] of a [Bal] from cache or remote
Future> getAccounting(int balId) async {
- if (_accountingMap[balId] != null) {
- return Result.ok(_accountingMap[balId]!);
+ if (accounting != null) {
+ return Result.ok(accounting!);
}
final result = await _apiClient.getAccounting(balId);
switch (result) {
case Ok():
- _accountingMap[balId] = result.value;
+ accounting = result.value;
break;
default:
}
return result;
}
- /// Manages what returning (of type [ReturnType]) does to cache and notifies remote
Future> returnToId(
int balId,
int ownerId,
@@ -161,32 +139,26 @@ class BalRepository {
case Ok():
switch (type) {
case ReturnType.books:
- final owner = _accountingMap[balId]?.owners
+ final owner = accounting?.owners
.where((el) => el.ownerId == ownerId)
.firstOrNull;
if (owner?.owedMoney == 0) {
- _accountingMap[balId]?.owners.removeWhere(
- (el) => el.ownerId == ownerId,
- );
+ accounting?.owners.removeWhere((el) => el.ownerId == ownerId);
}
owner?.owed = [];
owner?.owedInstances = [];
break;
case ReturnType.money:
- final owner = _accountingMap[balId]?.owners
+ final owner = accounting?.owners
.where((el) => el.ownerId == ownerId)
.firstOrNull;
if (owner?.owed == null || owner!.owed.isEmpty) {
- _accountingMap[balId]?.owners.removeWhere(
- (el) => el.ownerId == ownerId,
- );
+ accounting?.owners.removeWhere((el) => el.ownerId == ownerId);
}
owner?.owedMoney = 0;
break;
case ReturnType.all:
- _accountingMap[balId]?.owners.removeWhere(
- (el) => el.ownerId == ownerId,
- );
+ accounting?.owners.removeWhere((el) => el.ownerId == ownerId);
break;
}
break;
diff --git a/lib/data/repositories/book_instance_repository.dart b/lib/data/repositories/book_instance_repository.dart
index 7a60d19..4a07167 100644
--- a/lib/data/repositories/book_instance_repository.dart
+++ b/lib/data/repositories/book_instance_repository.dart
@@ -6,19 +6,16 @@ import 'package:seshat/domain/models/owner.dart';
import 'package:seshat/domain/models/search_result.dart';
import 'package:seshat/utils/result.dart';
-/// Repository to manage [BookInstance]
class BookInstanceRepository {
BookInstanceRepository({required ApiClient apiClient})
: _apiClient = apiClient;
final ApiClient _apiClient;
- /// Gets a [List] from an [ean]
Future>> getByEan(int balId, int ean) async {
return await _apiClient.getBookInstanceByEAN(balId, ean);
}
- /// Gets a [List] from a [title] and [author]
Future>> getBySearch(
int balId,
String title,
@@ -27,17 +24,15 @@ class BookInstanceRepository {
return await _apiClient.getBookInstanceBySearch(balId, title, author);
}
- /// Sends a new [BookInstance]'s [book], [owner], [bal] and [price]
- Future> sendNewBookInstance(
+ Future> sendBook(
Book book,
Owner owner,
Bal bal,
double price,
) async {
- return await _apiClient.sendNewBookInstance(book, owner, bal, price);
+ return await _apiClient.sendBook(book, owner, bal, price);
}
- /// Sells a [List]
Future> sellBooks(List books) async {
Map res = {};
for (BookInstance instance in books) {
diff --git a/lib/data/repositories/book_repository.dart b/lib/data/repositories/book_repository.dart
index 5d38be1..984d85b 100644
--- a/lib/data/repositories/book_repository.dart
+++ b/lib/data/repositories/book_repository.dart
@@ -2,19 +2,16 @@ import 'package:seshat/data/services/api_client.dart';
import 'package:seshat/domain/models/book.dart';
import 'package:seshat/utils/result.dart';
-/// Repository to manage [Book]
class BookRepository {
BookRepository({required ApiClient apiClient}) : _apiClient = apiClient;
final ApiClient _apiClient;
- /// Gets a [Book] by its [ean]
Future> getBookByEAN(String ean) async {
return await _apiClient.getBookByEAN(ean);
}
- /// Gets a [Book] by its [bookId]
- Future> getBookById(int bookId) async {
- return await _apiClient.getBookById(bookId);
+ Future> getBookById(int id) async {
+ return await _apiClient.getBookById(id);
}
}
diff --git a/lib/data/repositories/owner_repository.dart b/lib/data/repositories/owner_repository.dart
index 817bea0..5020123 100644
--- a/lib/data/repositories/owner_repository.dart
+++ b/lib/data/repositories/owner_repository.dart
@@ -5,7 +5,6 @@ import 'package:seshat/data/services/websocket_client.dart';
import 'package:seshat/domain/models/owner.dart';
import 'package:seshat/utils/result.dart';
-/// Repository to manage [Owner]
class OwnerRepository {
OwnerRepository({
required ApiClient apiClient,
@@ -15,25 +14,18 @@ class OwnerRepository {
final ApiClient _apiClient;
final WebsocketClient _wsClient;
-
- /// [StreamSubscription] to the [Stream] for [_wsClient]
late final StreamSubscription sub;
-
- /// [List] of owners, updated by [_wsClient]
List? _cachedOwners;
+ Owner? _sectionOwner;
- /// [Owner] of the current user
- Owner? _ownerOfUser;
-
- /// [Owner] of the current user
- Future> get ownerOfUser async {
- if (_ownerOfUser != null) {
- return Result.ok(_ownerOfUser!);
+ Future> get sectionOwner async {
+ if (_sectionOwner != null) {
+ return Result.ok(_sectionOwner!);
}
- final result = await _apiClient.getOwnerOfUser();
+ final result = await _apiClient.getSectionOwner();
switch (result) {
case Ok():
- _ownerOfUser = result.value;
+ _sectionOwner = result.value;
break;
default:
break;
@@ -41,17 +33,16 @@ class OwnerRepository {
return result;
}
- /// Gets an [Owner] from its [ownerId]
- Future> getOwnerById(int ownerId) async {
+ Future> getOwnerById(int id) async {
if (_cachedOwners != null) {
final result1 = _cachedOwners!
- .where((owner) => owner.id == ownerId)
+ .where((owner) => owner.id == id)
.firstOrNull;
if (result1 != null) {
return Result.ok(result1);
}
}
- return await _apiClient.getOwnerById(ownerId);
+ return await _apiClient.getOwnerById(id);
}
/// Adds an [Owner] to the database, and gets the resulting [Owner].
diff --git a/lib/data/services/api_client.dart b/lib/data/services/api_client.dart
index c638d4c..383f269 100644
--- a/lib/data/services/api_client.dart
+++ b/lib/data/services/api_client.dart
@@ -1,17 +1,19 @@
import 'dart:convert';
+import 'dart:math';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/widgets.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart';
-import 'package:logger/logger.dart';
import 'package:seshat/config/constants.dart';
import 'package:seshat/domain/models/accounting.dart';
import 'package:seshat/domain/models/bal.dart';
import 'package:seshat/domain/models/bal_stats.dart';
import 'package:seshat/domain/models/book.dart';
import 'package:seshat/domain/models/book_instance.dart';
-import 'package:seshat/domain/models/enums.dart';
import 'package:seshat/domain/models/owner.dart';
import 'package:seshat/domain/models/search_result.dart';
+import 'package:seshat/utils/command.dart';
import 'package:seshat/utils/result.dart';
extension StringExtension on String {
@@ -20,33 +22,22 @@ extension StringExtension on String {
}
}
-/// API Client to manage all authenticated REST routes
+typedef AuthHeaderProvider = String? Function();
+
class ApiClient {
- ApiClient();
+ ApiClient({String? host, int? port});
- /// JWT for registration
+ late final Command0 load;
String? token;
-
- /// Readiness of the API Client
bool isReady = false;
-
- /// Storage to access JWT
FlutterSecureStorage? _secureStorage;
- Logger log = Logger(
- printer: PrettyPrinter(
- colors: true,
- lineLength: 100,
- methodCount: 0,
- dateTimeFormat: DateTimeFormat.dateAndTime,
- ),
- );
- /// Initializes connection to the [_secureStorage]
Future _initStore() async {
- _secureStorage ??= const FlutterSecureStorage();
+ _secureStorage ??= const FlutterSecureStorage(
+ aOptions: AndroidOptions(encryptedSharedPreferences: true),
+ );
}
- /// Generates authorization headers and option [additionalHeaders]
Future