Version 11 (modified by 5 days ago) ( diff ) | ,
---|
Implementation of user scenarios in the prototype
In the technical prototype of the application implemented so far, the following scenarios have been implemented:
ID | UseCase | |
---|---|---|
1 | Search Routes | |
2 | Organize Trip | |
3 | Manage Trip | |
4 | View My Trips | |
5 | Login | |
6 | Register |
ID 1 - Search Routes
The /search-routes
endpoint provides users with the ability to search for available transport routes from different organizers.
It supports both viewing all routes by default and filtering routes based on user input (departure and arrival locations).
The request is handled by UserRouteController
, which interacts with RouteService
to retrieve the relevant data.
Here is an example of a search query:
-/search-routes?from=sk&to=ohrid
@RequestMapping("/search-routes") public class UserRouteController { private final RouteService routeService; public UserRouteController(RouteService routeService) { this.routeService = routeService; } @GetMapping public String findRoutesByFromAndTo(@RequestParam(required = false) String from, @RequestParam(required = false) String to, Model model) { List<Route> filteredRoutes = ((from == null || from.isBlank()) && (to == null || to.isBlank())) ? routeService.findAll() : routeService.findRouteByFromAndToDest(from, to); model.addAttribute(filteredRoutes.isEmpty() ? "noRoutesMessage" : "routes", filteredRoutes.isEmpty() ? "No routes found for your search." : filteredRoutes); model.addAttribute("display", "user/search-routes"); return "master"; } }
Controller Details:
- URL Mapping:
/search-routes
- Method:
GET
- Functionality:
- Displays all routes when the page is accessed without search criteria.
- Filters results based on the user's input (
from
andto
).
- View: Uses the
master
template and dynamically embedsuser/search-routes
.
Breakdown:
- When users first visit
/search-routes
, the controller callsrouteService.findAll()
to display all available routes. - When users provide search criteria (
from
and/orto
), it filters results usingrouteService.findRouteByFromAndToDest(from, to)
. - If no matching routes are found, a "No routes found for your search." message is displayed instead of an empty table.
- The retrieved data is added to the
Model
, ensuring the front-end can render the appropriate content.
Result of /search-routes
Result of /search-routes?from=sk&to=ohrid
ID 2 - Organize Trip
The /routes
endpoint provides transport organizers with the ability to manage their routes and organize trips.
It supports viewing authorized routes, viewing trips for a specific route, and adding new trips.
The request is handled by CompanyRouteController
and CompanyTripController
, which interact with CompanyRouteService
and CompanyTripService
to manage routes and trips.
Here is an example of the flow to organize a trip:
- View routes:
/routes/company
- View trips for a specific route:
/routes/company/view-trips/{routeId}
- Add a new trip:
/routes/company/view-trips/{routeId}/add-trip
@RequestMapping("/routes") public class CompanyRouteController { private final CompanyRouteService companyRouteService; public CompanyRouteController(CompanyRouteService companyRouteService) { this.companyRouteService = companyRouteService; } @GetMapping("/company") public String routes(Model model) { model.addAttribute("companyRoutes", companyRouteService.getAuthorizedRoutes()); model.addAttribute("display", "/company/company-route"); return "master"; } }
@RequestMapping("/routes/company/view-trips/{routeId}") public class CompanyTripController { private final CompanyTripService companyTripService; private final RouteService routeService; private final LocationService locationService; public CompanyTripController(CompanyTripService companyTripService, RouteService routeService, LocationService locationService) { this.companyTripService = companyTripService; this.routeService = routeService; this.locationService = locationService; } @GetMapping public String routeTrips(@PathVariable Integer routeId, Model model) { Route route = routeService.findById(routeId); model.addAttribute("trips", companyTripService.getAuthorizedTripsByRoute(routeId)); model.addAttribute("routeId", routeId); model.addAttribute("locations", locationService.findAll()); model.addAttribute("routeSource", route.getSource()); model.addAttribute("routeDestination", route.getDestination()); model.addAttribute("display", "/company/company-view-trip"); return "master"; } @PostMapping("/add-trip") public String addNewTrip(@PathVariable Integer routeId, @RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestParam("freeSeats") int freeSeats, @RequestParam("locations") List<Integer> locationIds, @RequestParam("etas") @DateTimeFormat(pattern = "HH:mm") List<LocalTime> etas, RedirectAttributes redirectAttributes) { try { Route route = routeService.findById(routeId); companyTripService.createTrip(route, date, freeSeats, locationIds, etas); redirectAttributes.addFlashAttribute("message", "Trip created successfully!"); } catch (IllegalArgumentException | SecurityException e) { redirectAttributes.addFlashAttribute("error", e.getMessage()); } return "redirect:/routes/company/view-trips/" + routeId; } }
Controller Details:
- URL Mapping:
/routes
- Method:
GET
,POST
- Functionality:
- GET
/routes/company
: Displays authorized routes for the transport organizer. - GET
/routes/company/view-trips/{routeId}
: Displays all authorized trips for the selected route. - POST
/routes/company/view-trips/{routeId}/add-trip
: Allows the transport organizer to add a new trip to an existing route.
- GET
- View: Uses the
master
template and dynamically embeds/company/company-route
and/company/company-view-trip
.
Breakdown:
- When the transport organizer accesses
/routes/company
, the controller retrieves all authorized routes usingcompanyRouteService.getAuthorizedRoutes()
and displays them. - When the transport organizer accesses
/routes/company/view-trips/{routeId}
, the controller retrieves all authorized trips for the specified route usingcompanyTripService.getAuthorizedTripsByRoute(routeId)
and displays them along with the locations./** * Returns every trip for specific route if user is authorized. * * @param routeId the routeId for getting authorized trips * @return all trips for the route || SecurityException("Unauthorized to access these trips.") */ public List<Trip> getAuthorizedTripsByRoute(Integer routeId) { Integer transportOrganizerId = authorizationService.getAuthenticatedTransportOrganizerId(); List<Trip> trips = tripService.findAllByPredicate(TripSpecification.tripsByRoute(routeId)); if (!trips.isEmpty() && !trips.get(0).getTranOrg().getTranOrgId().equals(transportOrganizerId)) { throw new SecurityException("Unauthorized to access these trips."); } return trips; }
- The transport organizer can add a new trip by submitting the form with details like date, free seats, locations, and estimated times of arrival (ETAs).
Result of /routes/company
Result of /routes/company/view-trips/{routeId}
Result of /routes/company/view-trips/{routeId}/add-trip
ID 3 - Manage Trip
The /routes
endpoint allows transport organizers to manage their trips. It includes the ability to view, add, edit, and delete trips for their authorized routes.
Here is an example of the flow to manage trips:
- View routes:
/routes/company
- View trips for a specific route:
/routes/company/view-trips/{routeId}
- Add a new trip:
/routes/company/view-trips/{routeId}/add-trip
- Edit an existing trip:
/routes/company/view-trips/{routeId}/edit-trip/{tripId}
- Delete a trip:
/routes/company/view-trips/{routeId}/delete-trip/{tripId}
@RequestMapping("/routes") public class CompanyRouteController { private final CompanyRouteService companyRouteService; public CompanyRouteController(CompanyRouteService companyRouteService) { this.companyRouteService = companyRouteService; } @GetMapping("/company") public String routes(Model model) { model.addAttribute("companyRoutes", companyRouteService.getAuthorizedRoutes()); model.addAttribute("display", "/company/company-route"); return "master"; } }
@RequestMapping("/routes/company/view-trips/{routeId}") public class CompanyTripController { private final CompanyTripService companyTripService; private final RouteService routeService; private final LocationService locationService; public CompanyTripController(CompanyTripService companyTripService, RouteService routeService, LocationService locationService) { this.companyTripService = companyTripService; this.routeService = routeService; this.locationService = locationService; } @GetMapping public String routeTrips(@PathVariable Integer routeId, Model model) { Route route = routeService.findById(routeId); model.addAttribute("trips", companyTripService.getAuthorizedTripsByRoute(routeId)); model.addAttribute("routeId", routeId); model.addAttribute("locations", locationService.findAll()); model.addAttribute("routeSource", route.getSource()); model.addAttribute("routeDestination", route.getDestination()); model.addAttribute("display", "/company/company-view-trip"); return "master"; } @PostMapping("/add-trip") public String addNewTrip(@PathVariable Integer routeId, @RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestParam("freeSeats") int freeSeats, @RequestParam("locations") List<Integer> locationIds, @RequestParam("etas") @DateTimeFormat(pattern = "HH:mm") List<LocalTime> etas, RedirectAttributes redirectAttributes) { try { Route route = routeService.findById(routeId); companyTripService.createTrip(route, date, freeSeats, locationIds, etas); redirectAttributes.addFlashAttribute("message", "Trip created successfully!"); } catch (IllegalArgumentException | SecurityException e) { redirectAttributes.addFlashAttribute("error", e.getMessage()); } return "redirect:/routes/company/view-trips/" + routeId; } @PostMapping("/edit-trip/{tripId}") public String editTrip(@PathVariable Integer routeId, @PathVariable Integer tripId, @RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestParam("freeSeats") int freeSeats, @RequestParam("locations") List<Integer> locationIds, @RequestParam("etas") @DateTimeFormat(pattern = "HH:mm") List<LocalTime> etas, RedirectAttributes redirectAttributes) { try { Route route = routeService.findById(routeId); companyTripService.updateTrip(route, tripId, date, freeSeats, locationIds, etas); redirectAttributes.addFlashAttribute("message", "Trip updated successfully!"); } catch (IllegalArgumentException | SecurityException e) { redirectAttributes.addFlashAttribute("error", e.getMessage()); } return "redirect:/routes/company/view-trips/" + routeId; } @PostMapping("/delete-trip/{tripId}") public String deleteTrip(@PathVariable Integer routeId, @PathVariable Integer tripId) { return companyTripService.deleteTripIfAuthorized(tripId) ? "redirect:/routes/company/view-trips/" + routeId : "redirect:/"; } }
Controller Details for Routes:
- URL Mapping:
/routes/company
- Method:
GET
- Functionality: Displays all authorized routes for the transport organizer.
- View: Uses the
master
template and dynamically embeds/company/company-route
.
Breakdown:
- Displays a list of all routes that the transport organizer is authorized to manage.
- Retrieves authorized routes from the
CompanyRouteService
and populates them into theModel
. - The view is displayed using
/company/company-route
.
Controller Details for Trips:
- URL Mapping:
/routes/company/view-trips/{routeId}
- Method:
GET
,POST
- Functionality:
- GET
/routes/company/view-trips/{routeId}
: Displays all trips for the selected route. - POST
/routes/company/view-trips/{routeId}/add-trip
: Allows the transport organizer to add a new trip. - POST
/routes/company/view-trips/{routeId}/edit-trip/{tripId}
: Allows the transport organizer to edit an existing trip. - POST
/routes/company/view-trips/{routeId}/delete-trip/{tripId}
: Allows the transport organizer to delete a trip.
- GET
- View: Uses the
master
template and dynamically embeds/company/company-view-trip
.
Breakdown:
- Viewing trips: When the transport organizer accesses
/routes/company/view-trips/{routeId}
, the controller retrieves all trips for the specified route usingcompanyTripService.getAuthorizedTripsByRoute(routeId)
. - Adding a new trip: A form allows the transport organizer to specify the date, free seats, locations, and ETAs for the trip. The controller calls
companyTripService.createTrip()
to create a new trip. - Editing a trip: The transport organizer can modify trip details. The controller calls
companyTripService.updateTrip()
to update the trip. - Deleting a trip: The transport organizer can delete a trip. The controller calls
companyTripService.deleteTripIfAuthorized()
to remove the trip if the organizer is authorized. - Viewing trip stops trip The transport organizer can view and modify trip stops. The controller calls companyTripService.updateTrip() to update whatever the authorized transport organizer wants.
Edit Trip:
Free seats modified:
Delete Trip:
Trip Stops:
Attachments (15)
- search-routes.png (116.5 KB ) - added by 5 days ago.
- search-routes-filter.png (89.8 KB ) - added by 5 days ago.
- add-trip-success.png (82.9 KB ) - added by 5 days ago.
- company-routes-view.png (98.4 KB ) - added by 5 days ago.
- company-trips-view.png (121.0 KB ) - added by 5 days ago.
- trip-stops.png (130.4 KB ) - added by 5 days ago.
- edited-trip.png (93.4 KB ) - added by 5 days ago.
- delete-trip.png (88.0 KB ) - added by 5 days ago.
- edit-trip.png (145.9 KB ) - added by 5 days ago.
- add-modalv1.png (146.1 KB ) - added by 5 days ago.
- my-trips.png (106.1 KB ) - added by 2 days ago.
- login.png (77.0 KB ) - added by 2 days ago.
- register.png (106.8 KB ) - added by 2 days ago.
- login-error.png (83.8 KB ) - added by 2 days ago.
- register-error.png (122.6 KB ) - added by 2 days ago.
Download all attachments as: .zip