Skip to content

Commit

Permalink
Merge pull request #296 from mirea-ninja/release/v1.3.1
Browse files Browse the repository at this point in the history
* feature: Create Sentry integration

* docs: Add Env Variables to readme

* feature: Create custom BlocObserver for Sentry (#289)

Добавил логирование ошибок Bloc в Sentry

* fix: Select only active LKS profile (#288)

Теперь при наличии двух профилей (например, бакалавриат и магистратура), выбран будет только активный.

* ui: Update `ScoresChartModal` view (#290)

* ui: Add map magnifier (#291)

* feature: Add feedback modals (#292)

* ui: Update about app page (#293)

* Удалены патроны и ссылки на Patreon
* Актуализированы ссылки на соц. сети
* Изменён текст. Добавлена благодарность Анне за помощь с картами

* fix: Nullable edu program type with many profiles (#294)

* ui: Update scores chart modal (#295)

* Добавил закругление углов для модального окна
* Исправлены отступы слева у первого столбца
* Добавлены линии тренда и переключения между ними
* Изменён внешний вид элементов легенды графика
  • Loading branch information
0niel authored Feb 25, 2023
2 parents 96f7e7e + aa72c6e commit 4f2c1e0
Show file tree
Hide file tree
Showing 25 changed files with 1,117 additions and 377 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,28 @@ flutter packages pub run build_runner watch --delete-conflicting-outputs
flutter packages pub run build_runner build --delete-conflicting-outputs
```

## Конфигурация Firebase Analytics и Crashlytics
## Конфигурация Firebase Analytics
1. Зарегистрируйте приложение в [Firebase](https://console.firebase.google.com/).
1. Выполните шаги для генерации `firebase_options.dart` файла с помощью [FlutterFire CLI](https://firebase.flutter.dev/docs/cli).
2. Firebase Analytics для Android не поддерживает Dart-only конфигурацию. Как только ваше приложение для Android будет зарегистрировано в Firebase, загрузите файл конфигурации с консоли Firebase (файл называется `google-services.json`). Добавьте этот файл в каталог `android/app`.
3. Проект готов для использования с Firebase Analytics и Crashlytics.

## Переменные окружения
Приложение использует переменные среды времени компиляции для хранения конфиденциальных данных, таких как ключи API и токены.

Эти переменные должны передаваться при запуске или сборке приложения с помощью аргумента `--dart-define` или установленной переменной окружения. Если вам нужно передать несколько пар ключ-значение, просто определите --dart-define несколько раз.

### Переменные приложения:
- `SENTRY_DSN` - DSN для отправки отчетов об ошибках в Sentry.
- `LK_CLIENT_ID` - ID клиента для авторизации в Личном кабинете с помощью OAuth2.
- `LK_CLIENT_SECRET` - Секретный ключ клиента для авторизации в Личном кабинете с помощью OAuth2.

**Пример:**
```bash
flutter run --dart-define=SENTRY_DSN=YOUR_DSN --dart-define=LK_CLIENT_ID=YOUR_CLIENT_ID --dart-define=LK_CLIENT_SECRET=YOUR_CLIENT_SECRET
```


## При ошибках
**Исключения платформы**
1. flutter clean
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.8'
classpath 'com.google.gms:google-services:4.3.15'
}
}

Expand Down
21 changes: 21 additions & 0 deletions assets/icons/social-sharing.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 16 additions & 8 deletions lib/data/datasources/user_remote.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:rtu_mirea_app/data/models/employee_model.dart';
import 'package:rtu_mirea_app/data/models/nfc_pass_model.dart';
import 'package:rtu_mirea_app/data/models/score_model.dart';
import 'package:rtu_mirea_app/data/models/user_model.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

abstract class UserRemoteData {
Future<String> auth();
Expand Down Expand Up @@ -56,18 +57,25 @@ class UserRemoteDataImpl implements UserRemoteData {
final response = await lksOauth2.oauth2Helper.get(
'$_apiUrl/?action=getData&url=https://lk.mirea.ru/profile/',
);
var jsonResponse = json.decode(response.body);

log('Status code: ${response.statusCode}, Response: ${response.body}',
name: 'getProfileData');

if (jsonResponse.containsKey('errors')) {
throw ServerException(jsonResponse['errors'][0]);
}
if (response.statusCode == 200) {
return UserModel.fromRawJson(response.body);
} else {
throw ServerException('Response status code is ${response.statusCode}');
try {
var jsonResponse = json.decode(response.body);

if (jsonResponse.containsKey('errors')) {
throw ServerException(jsonResponse['errors'][0]);
}
if (response.statusCode == 200) {
return UserModel.fromJson(jsonResponse);
} else {
throw ServerException('Response status code is ${response.statusCode}');
}
} catch (e) {
Sentry.captureException(e, stackTrace: StackTrace.current);

throw ServerException(e.toString());
}
}

Expand Down
32 changes: 32 additions & 0 deletions lib/data/models/edu_program_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'dart:convert';

import 'package:rtu_mirea_app/domain/entities/edu_program.dart';

class EduProgramModel extends EduProgram {
const EduProgramModel({
required eduProgram,
required eduProgramCode,
required department,
required prodDepartment,
required type,
}) : super(
eduProgram: eduProgram,
eduProgramCode: eduProgramCode,
department: department,
prodDepartment: prodDepartment,
type: type,
);

factory EduProgramModel.fromRawJson(String str) =>
EduProgramModel.fromJson(json.decode(str));

factory EduProgramModel.fromJson(Map<String, dynamic> json) {
return EduProgramModel(
eduProgramCode: json["PROPERTIES"]["OKSO_CODE"]["VALUE"],
eduProgram: json["NAME"],
department: json["PROPERTIES"]["DEPARTMENT"]["VALUE_TEXT"],
prodDepartment: json["PROPERTIES"]["PROD_DEPARTMENT"]["VALUE_TEXT"],
type: json["TYPE"],
);
}
}
56 changes: 56 additions & 0 deletions lib/data/models/student_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'dart:convert';

import 'package:rtu_mirea_app/domain/entities/student.dart';

import 'edu_program_model.dart';

class StudentModel extends Student {
const StudentModel({
required id,
required isActive,
required course,
required personalNumber,
required educationStartDate,
required educationEndDate,
required academicGroup,
required code,
required eduProgram,
required status,
}) : super(
id: id,
isActive: isActive,
eduProgram: eduProgram,
course: course,
personalNumber: personalNumber,
educationStartDate: educationStartDate,
educationEndDate: educationEndDate,
academicGroup: academicGroup,
code: code,
status: status,
);

static List<StudentModel> fromRawJson(String str) =>
StudentModel.fromJson(json.decode(str));

static List<StudentModel> fromJson(Map<String, dynamic> json) {
final studentsRaw = json["STUDENTS"].values.where((element) =>
!element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Д") &&
!element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Ж"));

return List<StudentModel>.from(studentsRaw.map(
(e) => StudentModel(
id: e["ID"],
isActive: e["ACTIVE"] == "Y",
course: int.parse(e["PROPERTIES"]["COURSE"]["VALUE"]),
personalNumber: e["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"],
educationEndDate: e["PROPERTIES"]["END_DATE"]["VALUE"],
academicGroup: e["PROPERTIES"]["ACADEMIC_GROUP"]["VALUE_TEXT"],
educationStartDate: e["PROPERTIES"]["START_DATE"]["VALUE"],
code: e["CODE"],
eduProgram: EduProgramModel.fromJson(
json["EDU_PROGRAM"][e["PROPERTIES"]["EDU_PROGRAM"]["VALUE"]]),
status: e["PROPERTIES"]["STATUS"]["VALUE_TEXT"],
),
));
}
}
54 changes: 4 additions & 50 deletions lib/data/models/user_model.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:convert';

import 'package:rtu_mirea_app/data/models/student_model.dart';
import 'package:rtu_mirea_app/domain/entities/user.dart';

class UserModel extends User {
Expand All @@ -10,88 +11,41 @@ class UserModel extends User {
required name,
required lastName,
required secondName,
required isActive,
required birthday,
required eduProgram,
required eduProgramCode,
required photoUrl,
required authShortlink,
required registerDate,
required lastLoginDate,
required course,
required personalNumber,
required educationStartDate,
required educationEndDate,
required academicGroup,
required department,
required prodDepartment,
required type,
required code,
required studentId,
required students,
}) : super(
id: id,
login: login,
email: email,
name: name,
lastName: lastName,
secondName: secondName,
isActive: isActive,
birthday: birthday,
eduProgram: eduProgram,
eduProgramCode: eduProgramCode,
photoUrl: photoUrl,
authShortlink: authShortlink,
registerDate: registerDate,
lastLoginDate: lastLoginDate,
course: course,
personalNumber: personalNumber,
educationStartDate: educationStartDate,
educationEndDate: educationEndDate,
academicGroup: academicGroup,
department: department,
prodDepartment: prodDepartment,
type: type,
code: code,
studentId: studentId,
students: students,
);

factory UserModel.fromRawJson(String str) =>
UserModel.fromJson(json.decode(str));

factory UserModel.fromJson(Map<String, dynamic> json) {
final student = json["STUDENTS"].values.firstWhere((element) =>
!element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Д") &&
!element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Ж"));

final eduProgram = json["EDU_PROGRAM"]
.values
.firstWhere((element) => element["ACTIVE"] == "Y");

return UserModel(
id: json["ID"],
login: json["arUser"]["LOGIN"],
email: json["arUser"]["EMAIL"],
name: json["arUser"]["NAME"],
lastName: json["arUser"]["LAST_NAME"],
secondName: json["arUser"]["SECOND_NAME"],
isActive: student["ACTIVE"] == "Y",
photoUrl: json["arUser"]["PHOTO"],
authShortlink: json["arUser"]["UF_AUTH_SHORTLINK"],
lastLoginDate: json["arUser"]["LAST_LOGIN"],
registerDate: json["arUser"]["DATE_REGISTER"],
course: int.parse(student["PROPERTIES"]["COURSE"]["VALUE"]),
personalNumber: student["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"],
birthday: json["arUser"]["PERSONAL_BIRTHDAY"],
educationStartDate: student["PROPERTIES"]["START_DATE"]["VALUE"],
educationEndDate: student["PROPERTIES"]["END_DATE"]["VALUE"],
academicGroup: student["PROPERTIES"]["ACADEMIC_GROUP"]["VALUE_TEXT"],
eduProgramCode: eduProgram["PROPERTIES"]["OKSO_CODE"]["VALUE"],
eduProgram: eduProgram["NAME"],
department: eduProgram["PROPERTIES"]["DEPARTMENT"]["VALUE_TEXT"],
prodDepartment: eduProgram["PROPERTIES"]["PROD_DEPARTMENT"]["VALUE_TEXT"],
type: eduProgram["TYPE"],
code: student["CODE"],
studentId: student["ID"],
students: StudentModel.fromJson(json),
);
}
}
26 changes: 26 additions & 0 deletions lib/domain/entities/edu_program.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:equatable/equatable.dart';

class EduProgram extends Equatable {
final String eduProgram;
final String eduProgramCode;
final String department;
final String prodDepartment;
final String? type;

const EduProgram({
required this.eduProgram,
required this.eduProgramCode,
required this.department,
required this.prodDepartment,
required this.type,
});

@override
List<Object?> get props => [
eduProgram,
eduProgramCode,
department,
prodDepartment,
type,
];
}
43 changes: 43 additions & 0 deletions lib/domain/entities/student.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:equatable/equatable.dart';

import 'edu_program.dart';

class Student extends Equatable {
final String id;
final bool isActive;
final int course;
final String personalNumber;
final String educationStartDate;
final String educationEndDate;
final String academicGroup;
final String code;
final EduProgram eduProgram;
final String status; // must be 'активный'

const Student({
required this.id,
required this.isActive,
required this.course,
required this.personalNumber,
required this.educationStartDate,
required this.educationEndDate,
required this.academicGroup,
required this.code,
required this.eduProgram,
required this.status,
});

@override
List<Object?> get props => [
id,
isActive,
course,
personalNumber,
educationStartDate,
educationEndDate,
academicGroup,
code,
eduProgram,
status,
];
}
Loading

0 comments on commit 4f2c1e0

Please sign in to comment.