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

feat: new restaurants api #1393

Merged
merged 26 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
63aa00c
feat: added up_menus dependency
HenriqueSFernandes Nov 16, 2024
9e8f5c0
feat: Updated day of the week parser to include datetime
HenriqueSFernandes Nov 16, 2024
ece6d19
partially implemented new restaurants api
HenriqueSFernandes Nov 16, 2024
bdc9497
refactor: removed GSheets fetching logic
HenriqueSFernandes Nov 18, 2024
2f4d9dd
refactor: removed debug prints
HenriqueSFernandes Nov 18, 2024
6a4731b
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Nov 18, 2024
5b2568d
refactor: disable past meals filtering temporarily
HenriqueSFernandes Nov 18, 2024
72c189f
fix: The new API uses "pescado" for fish and "hortícola" for salad, i…
HenriqueSFernandes Nov 19, 2024
87c7d26
Merge remote-tracking branch 'origin/develop' into feat/new-restauran…
HenriqueSFernandes Nov 29, 2024
9f1457e
feat: removed restautant filtering function
HenriqueSFernandes Dec 1, 2024
3f34f44
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Dec 1, 2024
3d021d8
feat: Added suffix to distinguish lunch and dinner
HenriqueSFernandes Dec 1, 2024
b08a26a
refactor: removed dead code
HenriqueSFernandes Dec 1, 2024
27fff36
feat: added restaurant period translation
HenriqueSFernandes Dec 3, 2024
0789126
feat: added period to restaurant model
HenriqueSFernandes Dec 3, 2024
748e3df
fix: fixed period on favourite restaurants
HenriqueSFernandes Dec 3, 2024
6dcdf53
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Dec 3, 2024
9d62d9e
refactor: simplified restaurant fetcher
HenriqueSFernandes Dec 3, 2024
af50845
feat: added english translation to meals
HenriqueSFernandes Dec 4, 2024
ac9aa9d
fix: resolved conflicts
HenriqueSFernandes Dec 9, 2024
5e360e2
feat: moved translations to frontend
HenriqueSFernandes Dec 30, 2024
8113c80
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Dec 30, 2024
e1ba23f
fix: linter issues
HenriqueSFernandes Dec 30, 2024
287e78f
feat: simplified weekday parser
HenriqueSFernandes Dec 31, 2024
2ecb3f8
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Dec 31, 2024
e17b8d1
Merge branch 'develop' into feat/new-restaurants-api
HenriqueSFernandes Jan 2, 2025
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
127 changes: 68 additions & 59 deletions packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart
Original file line number Diff line number Diff line change
@@ -1,47 +1,80 @@
import 'package:intl/intl.dart';
import 'package:uni/controller/networking/network_router.dart';
import 'package:uni/controller/parsers/parser_restaurants.dart';
import 'package:uni/model/entities/meal.dart';
import 'package:uni/model/entities/restaurant.dart';
import 'package:uni/model/utils/day_of_week.dart';
import 'package:uni/session/flows/base/session.dart';
import 'package:up_menus/up_menus.dart';

/// Class for fetching the menu
class RestaurantFetcher {
final String spreadSheetUrl = 'https://docs.google.com/spreadsheets/d/'
'1TJauM0HwIf2RauQU2GmhdZZ1ZicFLMHuBkxWwVOw3Q4';
final String jsonEndpoint = '/gviz/tq?tqx=out:json';

// Format: Date(dd/mm/yyyy), Meal("Almoço", "Jantar), Dish("Sopa", "Carne",
// "Peixe", "Dieta", "Vegetariano", "Salada"), Description(String)
final String sheetsColumnRange = 'A:D';

// List the Restaurant sheet names in the Google Sheets Document
final List<String> restaurantSheets = ['Cantina'];

// Generate the Gsheets endpoints list based on a list of sheets
String buildGSheetsEndpoint(String sheet) {
return Uri.encodeFull(
'$spreadSheetUrl$jsonEndpoint&sheet=$sheet&range=$sheetsColumnRange',
Restaurant convertToRestaurant(
Establishment establishment,
Iterable<DayMenu> dayMenus,
String period,
) {
final currentLocale = Intl.getCurrentLocale();

final meals = <Meal>[];
for (final dayMenu in dayMenus) {
for (final dish in dayMenu.dishes) {
// Extract the information about the meal.
meals.add(
Meal(
dish.dishType.namePt,
currentLocale.startsWith('pt')
? dish.dish.namePt
: dish.dish.nameEn ??
dish.dish
.namePt, // if there isn't an english name, use the portuguese one.
parseDateTime(dayMenu.day),
dayMenu.day,
),
);
}
}
return Restaurant(
establishment.id,
currentLocale.startsWith('pt')
? establishment.namePt
: establishment.nameEn,
period,
'',
meals: meals,
);
}

String getRestaurantGSheetName(Restaurant restaurant) {
return restaurantSheets.firstWhere(
(sheetName) =>
restaurant.name.toLowerCase().contains(sheetName.toLowerCase()),
orElse: () => '',
);
}
Future<List<Restaurant>> fetchSASUPRestaurants() async {
// TODO: change the implementation to accomodate changes for the new UI.
final upMenus = UPMenusApi();
final establishments = await upMenus.establishments.list();
final restaurants = <Restaurant>[];

Future<Restaurant> fetchGSheetsRestaurant(
String url,
String restaurantName,
Session session, {
bool isDinner = false,
}) async {
return getRestaurantFromGSheets(
await NetworkRouter.getWithCookies(url, {}, session),
restaurantName,
isDinner: isDinner,
);
const periods = [
{'period': Period.lunch, 'meal': 'lunch'},
{'period': Period.dinner, 'meal': 'dinner'},
{'period': Period.snackBar, 'meal': 'snackbar'},
{'period': Period.breakfast, 'meal': 'breakfast'},
];

for (final establishment in establishments) {
if (establishment.dayMenu == false) {
continue;
}

for (final period in periods) {
restaurants.add(
convertToRestaurant(
establishment,
await upMenus.dayMenus
.get(establishment.id, period['period']! as Period),
period['meal']! as String,
),
);
}
}
return restaurants;
}

final List<String> sigarraMenuEndpoints = [
Expand All @@ -64,32 +97,8 @@ class RestaurantFetcher {
}

Future<List<Restaurant>> getRestaurants(Session session) async {
final restaurants = await fetchSigarraRestaurants(session);

// Check for restaurants without associated meals and attempt to parse them
// from GSheets
final restaurantsWithoutMeals =
restaurants.where((restaurant) => restaurant.meals.isEmpty).toList();

for (final restaurant in restaurantsWithoutMeals) {
final sheetName = getRestaurantGSheetName(restaurant);
if (sheetName.isEmpty) {
continue;
}

final gSheetsRestaurant = await fetchGSheetsRestaurant(
buildGSheetsEndpoint(sheetName),
restaurant.name,
session,
isDinner: restaurant.name.toLowerCase().contains('jantar'),
);

restaurants
..removeWhere(
(restaurant) => restaurant.name == gSheetsRestaurant.name,
)
..insert(0, gSheetsRestaurant);
}
final restaurants =
await fetchSASUPRestaurants() + await fetchSigarraRestaurants(session);

return restaurants;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class RestaurantDatabase extends AppDatabase<List<Restaurant>> {
return Restaurant(
restaurantId,
map['name'] as String,
map['period'] as String,
DGoiana marked this conversation as resolved.
Show resolved Hide resolved
map['ref'] as String,
meals: meals,
);
Expand All @@ -70,7 +71,7 @@ class RestaurantDatabase extends AppDatabase<List<Restaurant>> {
}
});

return filterPastMeals(restaurants);
return restaurants;
}

Future<List<Meal>> getRestaurantMeals(
Expand Down Expand Up @@ -129,22 +130,3 @@ class RestaurantDatabase extends AppDatabase<List<Restaurant>> {
});
}
}

List<Restaurant> filterPastMeals(List<Restaurant> restaurants) {
final restaurantsCopy = List<Restaurant>.from(restaurants);
// Hide past and next weeks' meals
// (To replicate sigarra's behaviour for the GSheets meals)
final now = DateTime.now().toUtc();
final today = DateTime.utc(now.year, now.month, now.day);
final nextSunday = today.add(Duration(days: DateTime.sunday - now.weekday));

for (final restaurant in restaurantsCopy) {
for (final meals in restaurant.meals.values) {
meals.removeWhere(
(meal) => meal.date.isBefore(today) || meal.date.isAfter(nextSunday),
);
}
}

return restaurantsCopy;
}
47 changes: 1 addition & 46 deletions packages/uni_app/lib/controller/parsers/parser_restaurants.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:convert';

import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
Expand Down Expand Up @@ -72,52 +70,9 @@ List<Restaurant> getRestaurantsFromHtml(Response response) {
null,
restaurantTuple.item2,
restaurantTuple.item1,
'',
meals: meals,
);
}).toList();
return restaurants;
}

Restaurant getRestaurantFromGSheets(
Response response,
String restaurantName, {
bool isDinner = false,
}) {
// Ignore beginning of response: "/*O_o*/\ngoogle.visualization.Query.setResponse("
// Ignore the end of the response: ");"
// Check the structure by accessing the link:
// https://docs.google.com/spreadsheets/d/1TJauM0HwIf2RauQU2GmhdZZ1ZicFLMHuBkxWwVOw3Q4/gviz/tq?tqx=out:json&sheet=Cantina%20de%20Engenharia&range=A:D
final jsonString = response.body.substring(
response.body.indexOf('(') + 1,
response.body.lastIndexOf(')'),
);
final parsedJson = jsonDecode(jsonString) as Map<String, dynamic>;

final mealsList = <Meal>[];

final format = DateFormat('d/M/y');

final table = parsedJson['table'] as Map<String, dynamic>;
final rows = table['rows'] as List<dynamic>;

for (final row in rows) {
final cellList = (row as Map<String, dynamic>)['c'] as List<dynamic>;
if (((cellList[1] as Map<String, dynamic>)['v'] == 'Almoço' && isDinner) ||
((cellList[1] as Map<String, dynamic>)['v'] != 'Almoço' && !isDinner)) {
continue;
}

final meal = Meal(
(cellList[2] as Map<String, dynamic>)['v'] as String,
(cellList[3] as Map<String, dynamic>)['v'] as String,
DayOfWeek.values[format
.parseUtc((cellList[0] as Map<String, dynamic>)['f'] as String)
.weekday -
1],
format.parseUtc((cellList[0] as Map<String, dynamic>)['f'] as String),
);
mealsList.add(meal);
}

return Restaurant(null, restaurantName, '', meals: mealsList);
}
4 changes: 4 additions & 0 deletions packages/uni_app/lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class MessageLookup extends MessageLookupByLibrary {
"banner_info": MessageLookupByLibrary.simpleMessage(
"We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."),
"bibliography": MessageLookupByLibrary.simpleMessage("Bibliography"),
"breakfast": MessageLookupByLibrary.simpleMessage("Breakfast"),
"bs_description": MessageLookupByLibrary.simpleMessage(
"Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!"),
"bug_description": MessageLookupByLibrary.simpleMessage(
Expand Down Expand Up @@ -110,6 +111,7 @@ class MessageLookup extends MessageLookupByLibrary {
"description": MessageLookupByLibrary.simpleMessage("Description"),
"desired_email": MessageLookupByLibrary.simpleMessage(
"Email where you want to be contacted"),
"dinner": MessageLookupByLibrary.simpleMessage("Dinner"),
"dona_bia": MessageLookupByLibrary.simpleMessage(
"D. Beatriz\'s stationery store"),
"dona_bia_building": MessageLookupByLibrary.simpleMessage(
Expand Down Expand Up @@ -167,6 +169,7 @@ class MessageLookup extends MessageLookupByLibrary {
"login_with_credentials":
MessageLookupByLibrary.simpleMessage("Login with credentials"),
"logout": MessageLookupByLibrary.simpleMessage("Log out"),
"lunch": MessageLookupByLibrary.simpleMessage("Lunch"),
"menus": MessageLookupByLibrary.simpleMessage("Menus"),
"min_value_reference":
MessageLookupByLibrary.simpleMessage("Minimum value: 1,00 €"),
Expand Down Expand Up @@ -272,6 +275,7 @@ class MessageLookup extends MessageLookupByLibrary {
"sent_error": MessageLookupByLibrary.simpleMessage(
"An error occurred in sending"),
"settings": MessageLookupByLibrary.simpleMessage("Settings"),
"snackbar": MessageLookupByLibrary.simpleMessage("Snackbar"),
"some_error": MessageLookupByLibrary.simpleMessage("Some error!"),
"stcp_stops":
MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"),
Expand Down
4 changes: 4 additions & 0 deletions packages/uni_app/lib/generated/intl/messages_pt_PT.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class MessageLookup extends MessageLookupByLibrary {
"banner_info": MessageLookupByLibrary.simpleMessage(
"Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."),
"bibliography": MessageLookupByLibrary.simpleMessage("Bibliografia"),
"breakfast": MessageLookupByLibrary.simpleMessage("Pequeno Almoço"),
"bs_description": MessageLookupByLibrary.simpleMessage(
"Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!"),
"bug_description": MessageLookupByLibrary.simpleMessage(
Expand Down Expand Up @@ -109,6 +110,7 @@ class MessageLookup extends MessageLookupByLibrary {
"description": MessageLookupByLibrary.simpleMessage("Descrição"),
"desired_email": MessageLookupByLibrary.simpleMessage(
"Email em que desejas ser contactado"),
"dinner": MessageLookupByLibrary.simpleMessage("Jantar"),
"dona_bia":
MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"),
"dona_bia_building": MessageLookupByLibrary.simpleMessage(
Expand Down Expand Up @@ -166,6 +168,7 @@ class MessageLookup extends MessageLookupByLibrary {
"login_with_credentials": MessageLookupByLibrary.simpleMessage(
"Iniciar sessão com credenciais"),
"logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"),
"lunch": MessageLookupByLibrary.simpleMessage("Almoço"),
"menus": MessageLookupByLibrary.simpleMessage("Ementas"),
"min_value_reference":
MessageLookupByLibrary.simpleMessage("Valor mínimo: 1,00 €"),
Expand Down Expand Up @@ -273,6 +276,7 @@ class MessageLookup extends MessageLookupByLibrary {
"sent_error":
MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"),
"settings": MessageLookupByLibrary.simpleMessage("Definições"),
"snackbar": MessageLookupByLibrary.simpleMessage("Snackbar"),
"some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"),
"stcp_stops":
MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"),
Expand Down
40 changes: 40 additions & 0 deletions packages/uni_app/lib/generated/l10n.dart

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

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

Loading
Loading