Merge pull request #58 from refilc/dev

Dev
This commit is contained in:
Márton Kiss
2023-09-26 20:32:21 +02:00
committed by GitHub
22 changed files with 469 additions and 126 deletions

View File

@@ -53,9 +53,14 @@ class FilcAPI {
.map((json) => School.fromJson(json))
.toList();
schools.add(School(
city: "Tiszabura",
instituteCode: "supporttest-reni-tiszabura-teszt01",
name: "FILC Éles Reni tiszabura-teszt",
city: "Stockholm",
instituteCode: "refilc-test-sweden",
name: "reFilc Test SE - Leo Ekström High School",
));
schools.add(School(
city: "Madrid",
instituteCode: "refilc-test-spain",
name: "reFilc Test ES - Emilio Obrero University",
));
return schools;
} else {

View File

@@ -1,6 +1,7 @@
// ignore_for_file: avoid_print, use_build_context_synchronously
import 'package:filcnaplo/utils/jwt.dart';
import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
@@ -20,6 +21,7 @@ import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/api/nonce.dart';
import 'package:uuid/uuid.dart';
enum LoginState {
missingFields,
@@ -47,87 +49,141 @@ Future loginAPI({
void Function(User)? onLogin,
void Function()? onSuccess,
}) async {
Provider.of<KretaClient>(context, listen: false).userAgent =
Provider.of<SettingsProvider>(context, listen: false).config.userAgent;
Future testLogin(School school) async {
var user = User(
username: username,
password: password,
instituteCode: instituteCode,
name: 'Teszt Lajos',
student: Student(
birth: DateTime.now(),
id: const Uuid().v4(),
name: 'Teszt Lajos',
school: school,
yearId: '1',
parents: ['Teszt András', 'Teszt Linda'],
json: {"a": "b"},
address: '1117 Budapest, Gábor Dénes utca 4.',
),
role: Role.parent,
);
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
};
if (onLogin != null) onLogin(user);
String nonceStr = await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.nonce, json: false);
// store test user in db
await Provider.of<DatabaseProvider>(context, listen: false)
.store
.storeUser(user);
Provider.of<UserProvider>(context, listen: false).addUser(user);
Provider.of<UserProvider>(context, listen: false).setUser(user.id);
Nonce nonce = getNonce(nonceStr, username, instituteCode);
headers.addAll(nonce.header());
if (onSuccess != null) onSuccess();
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login,
headers: headers,
body: User.loginBody(
username: username,
password: password,
instituteCode: instituteCode,
));
if (res != null) {
if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") {
return LoginState.invalidGrant;
}
} else {
if (res.containsKey("access_token")) {
try {
Provider.of<KretaClient>(context, listen: false).accessToken =
res["access_token"];
Map? studentJson =
await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.student(instituteCode));
Student student = Student.fromJson(studentJson!);
var user = User(
username: username,
password: password,
instituteCode: instituteCode,
name: student.name,
student: student,
role: JwtUtils.getRoleFromJWT(res["access_token"])!,
);
return LoginState.success;
}
if (onLogin != null) onLogin(user);
// if institute matches one of test things do test login
if (instituteCode == 'refilc-test-sweden') {
School school = School(
city: "Stockholm",
instituteCode: "refilc-test-sweden",
name: "reFilc Test SE - Leo Ekström High School",
);
// Store User in the database
await Provider.of<DatabaseProvider>(context, listen: false)
.store
.storeUser(user);
Provider.of<UserProvider>(context, listen: false).addUser(user);
Provider.of<UserProvider>(context, listen: false).setUser(user.id);
await testLogin(school);
} else if (instituteCode == 'refilc-test-spain') {
School school = School(
city: "Madrid",
instituteCode: "refilc-test-spain",
name: "reFilc Test ES - Emilio Obrero University",
);
// Get user data
await testLogin(school);
} else {
// normal login from here
Provider.of<KretaClient>(context, listen: false).userAgent =
Provider.of<SettingsProvider>(context, listen: false).config.userAgent;
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
};
String nonceStr = await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.nonce, json: false);
Nonce nonce = getNonce(nonceStr, username, instituteCode);
headers.addAll(nonce.header());
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login,
headers: headers,
body: User.loginBody(
username: username,
password: password,
instituteCode: instituteCode,
));
if (res != null) {
if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") {
return LoginState.invalidGrant;
}
} else {
if (res.containsKey("access_token")) {
try {
await Future.wait([
Provider.of<GradeProvider>(context, listen: false).fetch(),
Provider.of<TimetableProvider>(context, listen: false)
.fetch(week: Week.current()),
Provider.of<ExamProvider>(context, listen: false).fetch(),
Provider.of<HomeworkProvider>(context, listen: false).fetch(),
Provider.of<MessageProvider>(context, listen: false).fetchAll(),
Provider.of<NoteProvider>(context, listen: false).fetch(),
Provider.of<EventProvider>(context, listen: false).fetch(),
Provider.of<AbsenceProvider>(context, listen: false).fetch(),
]);
Provider.of<KretaClient>(context, listen: false).accessToken =
res["access_token"];
Map? studentJson =
await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.student(instituteCode));
Student student = Student.fromJson(studentJson!);
var user = User(
username: username,
password: password,
instituteCode: instituteCode,
name: student.name,
student: student,
role: JwtUtils.getRoleFromJWT(res["access_token"])!,
);
if (onLogin != null) onLogin(user);
// Store User in the database
await Provider.of<DatabaseProvider>(context, listen: false)
.store
.storeUser(user);
Provider.of<UserProvider>(context, listen: false).addUser(user);
Provider.of<UserProvider>(context, listen: false).setUser(user.id);
// Get user data
try {
await Future.wait([
Provider.of<GradeProvider>(context, listen: false).fetch(),
Provider.of<TimetableProvider>(context, listen: false)
.fetch(week: Week.current()),
Provider.of<ExamProvider>(context, listen: false).fetch(),
Provider.of<HomeworkProvider>(context, listen: false).fetch(),
Provider.of<MessageProvider>(context, listen: false).fetchAll(),
Provider.of<NoteProvider>(context, listen: false).fetch(),
Provider.of<EventProvider>(context, listen: false).fetch(),
Provider.of<AbsenceProvider>(context, listen: false).fetch(),
]);
} catch (error) {
print("WARNING: failed to fetch user data: $error");
}
if (onSuccess != null) onSuccess();
return LoginState.success;
} catch (error) {
print("WARNING: failed to fetch user data: $error");
print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;
}
if (onSuccess != null) onSuccess();
return LoginState.success;
} catch (error) {
print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;
}
}
}
}
return LoginState.failed;
}

View File

@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
@@ -12,6 +14,7 @@ class StatusProvider extends ChangeNotifier {
StatusProvider() {
_handleNetworkChanges();
_handleDNSFailure();
Connectivity().checkConnectivity().then((value) => _networkType = value);
}
@@ -24,6 +27,7 @@ class StatusProvider extends ChangeNotifier {
_networkType = event;
if (event == ConnectivityResult.none) {
if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network);
notifyListeners();
}
@@ -36,6 +40,31 @@ class StatusProvider extends ChangeNotifier {
});
}
void _handleDNSFailure() {
try {
InternetAddress.lookup('api.refilc.hu').then((status) {
if (status.isEmpty) {
if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network);
notifyListeners();
}
} else {
if (_stack.contains(Status.network)) {
_stack.remove(Status.network);
notifyListeners();
}
}
});
} on SocketException catch (_) {
if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network);
notifyListeners();
}
}
}
void triggerRequest(http.Response res) {
if (res.headers.containsKey("x-maintenance-mode") ||
res.statusCode == 503) {
@@ -50,6 +79,7 @@ class StatusProvider extends ChangeNotifier {
}
}
if (_stack.contains(Status.network)) return;
if (res.body == "invalid_grant" ||
res.body.replaceAll(' ', '') == '' ||
res.statusCode == 400) {

View File

@@ -33,6 +33,7 @@ const settingsDB = DatabaseStruct("settings", {
"renamed_subjects_italics": int, "renamed_teachers_enabled": int,
"renamed_teachers_italics": int,
"live_activity_color": String,
"welcome_message": String,
});
// DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING
// YOU'VE BEEN WARNED!!!

View File

@@ -20,7 +20,6 @@ class Ad {
});
factory Ad.fromJson(Map json) {
print(json);
return Ad(
title: json['title'] ?? 'Ad',
description: json['description'] ?? '',

View File

@@ -76,6 +76,7 @@ class SettingsProvider extends ChangeNotifier {
bool _renamedTeachersEnabled;
bool _renamedTeachersItalics;
Color _liveActivityColor;
String _welcomeMessage;
SettingsProvider({
DatabaseProvider? database,
@@ -120,6 +121,7 @@ class SettingsProvider extends ChangeNotifier {
required bool renameTeachersEnabled,
required bool renameTeachersItalics,
required Color liveActivityColor,
required String welcomeMessage,
}) : _database = database,
_language = language,
_startPage = startPage,
@@ -161,7 +163,8 @@ class SettingsProvider extends ChangeNotifier {
_renamedSubjectsItalics = renameSubjectsItalics,
_renamedTeachersEnabled = renameTeachersEnabled,
_renamedTeachersItalics = renameTeachersItalics,
_liveActivityColor = liveActivityColor;
_liveActivityColor = liveActivityColor,
_welcomeMessage = welcomeMessage;
factory SettingsProvider.fromMap(Map map,
{required DatabaseProvider database}) {
@@ -223,6 +226,7 @@ class SettingsProvider extends ChangeNotifier {
renameTeachersEnabled: map["renamed_teachers_enabled"] == 1,
renameTeachersItalics: map["renamed_teachers_italics"] == 1,
liveActivityColor: Color(map["live_activity_color"]),
welcomeMessage: map["welcome_message"],
);
}
@@ -272,6 +276,7 @@ class SettingsProvider extends ChangeNotifier {
"renamed_teachers_enabled": _renamedTeachersEnabled ? 1 : 0,
"renamed_teachers_italics": _renamedTeachersItalics ? 1 : 0,
"live_activity_color": _liveActivityColor.value,
"welcome_message": _welcomeMessage,
};
}
@@ -325,6 +330,7 @@ class SettingsProvider extends ChangeNotifier {
renameTeachersEnabled: false,
renameTeachersItalics: false,
liveActivityColor: const Color(0xFF676767),
welcomeMessage: '',
);
}
@@ -373,6 +379,7 @@ class SettingsProvider extends ChangeNotifier {
bool get renamedTeachersEnabled => _renamedTeachersEnabled;
bool get renamedTeachersItalics => _renamedTeachersItalics;
Color get liveActivityColor => _liveActivityColor;
String get welcomeMessage => _welcomeMessage;
Future<void> update({
bool store = true,
@@ -417,6 +424,7 @@ class SettingsProvider extends ChangeNotifier {
bool? renamedTeachersEnabled,
bool? renamedTeachersItalics,
Color? liveActivityColor,
String? welcomeMessage,
}) async {
if (language != null && language != _language) _language = language;
if (startPage != null && startPage != _startPage) _startPage = startPage;
@@ -535,6 +543,9 @@ class SettingsProvider extends ChangeNotifier {
if (liveActivityColor != null && liveActivityColor != _liveActivityColor) {
_liveActivityColor = liveActivityColor;
}
if (welcomeMessage != null && welcomeMessage != _welcomeMessage) {
_welcomeMessage = welcomeMessage;
}
if (store) await _database?.store.storeSettings(this);
notifyListeners();
}

View File

@@ -93,4 +93,13 @@ class User {
"refresh_user_data": "false",
};
}
static Map<String, Object?> logoutBody({
required String refreshToken,
}) {
return {
"refresh_token": refreshToken,
"client_id": KretaAPI.clientId,
};
}
}

View File

@@ -3,7 +3,7 @@ description: "Nem hivatalos e-napló alkalmazás az e-Kréta rendszerhez"
homepage: https://refilc.hu
publish_to: "none"
version: 4.2.3+223
version: 4.2.4+224
environment:
sdk: ">=2.17.0 <3.0.0"