Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic faculty selection #815

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion uni/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableJetifier=true
org.gradle.java.home=C:\\Program Files\\Java\\jdk-16.0.2
2 changes: 1 addition & 1 deletion uni/app_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7.15+205
1.7.17+207
14 changes: 0 additions & 14 deletions uni/lib/controller/local_storage/app_exams_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@ import 'package:uni/model/entities/exam.dart';
class AppExamsDatabase extends AppDatabase {
AppExamsDatabase()
: super('exams.db', [_createScript], onUpgrade: migrate, version: 5);
Map<String, String> months = {
'Janeiro': '01',
'Fevereiro': '02',
'Março': '03',
'Abril': '04',
'Maio': '05',
'Junho': '06',
'Julho': '07',
'Agosto': '08',
'Setembro': '09',
'Outubro': '10',
'Novembro': '11',
'Dezembro': '12'
};

static const _createScript = '''
CREATE TABLE exams(id TEXT, subject TEXT, begin TEXT, end TEXT,
Expand Down
33 changes: 31 additions & 2 deletions uni/lib/controller/networking/network_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,35 @@ class NetworkRouter {
/// This is useful for testing.
static http.Client? httpClient;

/*
/// Creates an authenticated [Session] on the given [faculty] with the
/// given username [user] and password [pass].
static Future<Session> login(String user, String pass, List<String> faculties,
bool persistentSession) async {
final String url =
'${NetworkRouter.getBaseUrl('feup')}mob_val_geral.autentica';

final http.Response response = await http.post(url.toUri(), body: {
'pv_login': user,
'pv_password': pass
}).timeout(const Duration(seconds: loginRequestTimeout));

if (response.statusCode == 200) {
final Session session = await Session.fromLogin(response, faculties);
session.persistentSession = persistentSession;
Logger().i('Login successful');
return session;
} else {
Logger().e('Login failed: ${response.body}');
return Session(
authenticated: false,
faculties: faculties,
studentNumber: '',
cookies: '',
type: '',
persistentSession: false);
}
*/
/// The timeout for Sigarra login requests.
static const Duration _requestTimeout = Duration(seconds: 30);

Expand Down Expand Up @@ -55,7 +84,7 @@ class NetworkRouter {
}

final url =
'${NetworkRouter.getBaseUrls(faculties)[0]}mob_val_geral.autentica';
'${NetworkRouter.getBaseUrl('feup')}mob_val_geral.autentica';
final response = await http.post(
url.toUri(),
body: {'pv_login': username, 'pv_password': password},
Expand All @@ -66,7 +95,7 @@ class NetworkRouter {
return null;
}

final session = Session.fromLogin(
final session = await Session.fromLogin(
response,
faculties,
persistentSession: persistentSession,
Expand Down
18 changes: 18 additions & 0 deletions uni/lib/controller/networking/url_launcher.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:uni/generated/l10n.dart';
import 'package:uni/view/common_widgets/toast_message.dart';
import 'package:url_launcher/url_launcher.dart';

Future<void> launchUrlWithToast(BuildContext context, String url) async {
final validUrl = Uri.parse(url);
if (url != '' && canLaunchUrl(validUrl) as bool) {
await launchUrl(Uri.parse(url));
} else {
await ToastMessage.error(
context,
S.of(context).no_link,
);
}
}
40 changes: 40 additions & 0 deletions uni/lib/controller/parsers/parser_faculties.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:html/parser.dart';
import 'package:uni/controller/networking/network_router.dart';
import 'package:uni/model/entities/session.dart';

Future<List<String>> getStudentFaculties(Session session) async {
final registerFaculties = <String>[];

final pctIdRequest = await NetworkRouter.getWithCookies(
'https://sigarra.up.pt/up/pt/web_page.inicial',
{},
session,
);
final pctDocument = parse(pctIdRequest.body);
final pctId = pctDocument
.querySelector('a.autenticacao-nome')
?.attributes['href']
?.toUri()
.queryParameters['pct_id'];

final response = await NetworkRouter.getWithCookies(
'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina',
{'pct_id': '$pctId'},
session,
);

final document = parse(response.body);
final list = document.querySelectorAll('#conteudoinner>ul a');

// user is only present in one faculty
if (list.isEmpty) {
list.add(document.querySelector('a')!); // the redirection link
}

for (final el in list) {
final uri = el.attributes['href']!.toUri();
registerFaculties.add(uri.pathSegments[0]);
}

return registerFaculties;
}
2 changes: 2 additions & 0 deletions uni/lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("No favorite restaurants"),
"no_info": MessageLookupByLibrary.simpleMessage(
"There is no information to display"),
"no_link":
MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"),
"no_menu_info": MessageLookupByLibrary.simpleMessage(
"There is no information available about meals"),
"no_menus": MessageLookupByLibrary.simpleMessage(
Expand Down
2 changes: 2 additions & 0 deletions uni/lib/generated/intl/messages_pt_PT.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Sem restaurantes favoritos"),
"no_info": MessageLookupByLibrary.simpleMessage(
"Não existem informações para apresentar"),
"no_link": MessageLookupByLibrary.simpleMessage(
"Não conseguimos abrir o link"),
"no_menu_info": MessageLookupByLibrary.simpleMessage(
"Não há informação disponível sobre refeições"),
"no_menus": MessageLookupByLibrary.simpleMessage(
Expand Down
10 changes: 10 additions & 0 deletions uni/lib/generated/l10n.dart

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

2 changes: 2 additions & 0 deletions uni/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@
"@no_selected_exams": {},
"occurrence_type": "Type of occurrence",
"@occurrence_type": {},
"no_link": "We couldn't open the link",
"@no_link": {},
"other_links": "Other links",
"@other_links": {},
"pass_change_request": "For security reasons, passwords must be changed periodically.",
Expand Down
2 changes: 2 additions & 0 deletions uni/lib/l10n/intl_pt_PT.arb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@
"@no_selected_exams": {},
"occurrence_type": "Tipo de ocorrência",
"@occurrence_type": {},
"no_link": "Não conseguimos abrir o link",
"@no_link": {},
"other_links": "Outros links",
"@other_links": {},
"pass_change_request": "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.",
Expand Down
11 changes: 8 additions & 3 deletions uni/lib/model/entities/session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:uni/controller/networking/network_router.dart';
import 'package:uni/controller/parsers/parser_faculties.dart';

/// Stores information about a user session.
class Session {
Expand All @@ -19,21 +20,25 @@ class Session {

/// Creates a new Session instance from an HTTP response.
/// Returns null if the authentication failed.
static Session? fromLogin(
static Future<Session?> fromLogin(
http.Response response,
List<String> faculties, {
required bool persistentSession,
}) {
}) async {
final responseBody = json.decode(response.body) as Map<String, dynamic>;

if (!(responseBody['authenticated'] as bool)) {
return null;
}

return Session(
final session = Session(
faculties: faculties,
username: responseBody['codigo'] as String,
cookies: NetworkRouter.extractCookies(response.headers),
);

session.faculties = await getStudentFaculties(session);

return session;
}
}
12 changes: 5 additions & 7 deletions uni/lib/view/about/widgets/terms_and_conditions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,30 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:uni/controller/load_static/terms_and_conditions.dart';
import 'package:uni/controller/networking/url_launcher.dart';
import 'package:uni/generated/l10n.dart';
import 'package:url_launcher/url_launcher.dart';

class TermsAndConditions extends StatelessWidget {
const TermsAndConditions({super.key});

@override
Widget build(BuildContext context) {
var termsAndConditionsSaved = S.of(context).loading_terms;
String? termsAndConditionsSaved = S.of(context).loading_terms;
final termsAndConditionsFuture = fetchTermsAndConditions();
return FutureBuilder(
future: termsAndConditionsFuture,
builder:
(BuildContext context, AsyncSnapshot<String> termsAndConditions) {
if (termsAndConditions.connectionState == ConnectionState.done &&
termsAndConditions.hasData) {
termsAndConditionsSaved = termsAndConditions.data!;
termsAndConditionsSaved = termsAndConditions.data;
}
return MarkdownBody(
styleSheet: MarkdownStyleSheet(),
shrinkWrap: false,
data: termsAndConditionsSaved,
data: termsAndConditionsSaved!,
onTapLink: (text, url, title) async {
if (await canLaunchUrl(Uri.parse(url!))) {
await launchUrl(Uri.parse(url));
}
await launchUrlWithToast(context, url!);
},
);
},
Expand Down
2 changes: 1 addition & 1 deletion uni/lib/view/login/login.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class LoginPageViewState extends State<LoginPageView> {
child: SingleChildScrollView(
child: Column(
children: [
createFacultyInput(context, faculties, setFaculties),
// createFacultyInput(context, faculties, setFaculties),
Padding(
padding: EdgeInsets.only(bottom: queryData.size.height / 35),
),
Expand Down
8 changes: 4 additions & 4 deletions uni/lib/view/schedule/widgets/schedule_slot.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:uni/controller/networking/network_router.dart';
import 'package:uni/controller/networking/url_launcher.dart';
import 'package:uni/view/common_widgets/row_container.dart';
import 'package:url_launcher/url_launcher.dart';

class ScheduleSlot extends StatelessWidget {
const ScheduleSlot({
Expand Down Expand Up @@ -113,9 +113,9 @@ class SubjectButtonWidget extends StatelessWidget {
'UCURR_GERAL.FICHA_UC_VIEW?pv_ocorrencia_id=$occurrId';
}

Future<void> _launchURL() async {
Future<void> _launchURL(BuildContext context) async {
final url = toUcLink(occurrId);
await launchUrl(Uri.parse(url));
await launchUrlWithToast(context, url);
}

@override
Expand All @@ -133,7 +133,7 @@ class SubjectButtonWidget extends StatelessWidget {
color: Colors.grey,
alignment: Alignment.centerRight,
tooltip: 'Abrir página da UC no browser',
onPressed: _launchURL,
onPressed: () => _launchURL(context),
),
],
);
Expand Down
2 changes: 1 addition & 1 deletion uni/lib/view/terms_and_condition_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class TermsAndConditionDialog {
),
),
],
)
),
],
),
);
Expand Down
4 changes: 2 additions & 2 deletions uni/lib/view/useful_info/widgets/link_button.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uni/controller/networking/url_launcher.dart';

class LinkButton extends StatelessWidget {
const LinkButton({
Expand Down Expand Up @@ -27,7 +27,7 @@ class LinkButton extends StatelessWidget {
.headlineSmall!
.copyWith(decoration: TextDecoration.underline),
),
onTap: () => launchUrl(Uri.parse(link)),
onTap: () => launchUrlWithToast(context, link),
),
)
],
Expand Down
4 changes: 2 additions & 2 deletions uni/lib/view/useful_info/widgets/text_components.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uni/controller/networking/url_launcher.dart';

Container h1(String text, BuildContext context, {bool initial = false}) {
final marginTop = initial ? 15.0 : 30.0;
Expand Down Expand Up @@ -44,7 +44,7 @@ Container infoText(
.bodyLarge!
.apply(color: Theme.of(context).colorScheme.tertiary),
),
onTap: () => link != '' ? launchUrl(Uri.parse(link)) : null,
onTap: () => launchUrlWithToast(context, link),
),
),
);
Expand Down
2 changes: 1 addition & 1 deletion uni/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev
# To change it manually, override the value in app_version.txt.
# The app version code is automatically also bumped by CI.
# Do not change it manually.
version: 1.7.15+205
version: 1.7.17+207

environment:
sdk: '>=3.0.0 <4.0.0'
Expand Down