From 5e0db40829f3213f52133aa7f6017b062fb252b1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 2 Aug 2026 17:56:21 +0000 Subject: [PATCH 1/7] Add mauniver.ru portal guides and student services parity Bring key university website sections into MAUverse: student and applicant guides, library/events shortcuts, international news, branch campuses, support forms, and privacy links in settings. Co-authored-by: D3C0Y --- .../UniversityPortalTests.cs | 73 ++++++++ .../mauverse_mobile.Tests.csproj | 4 + mauverse_mobile/AppShell.xaml.cs | 2 + mauverse_mobile/MauiProgram.cs | 2 + mauverse_mobile/Models/CampusBuilding.cs | 4 +- mauverse_mobile/Models/UniversityGuideLink.cs | 7 + .../Models/UniversityGuideSection.cs | 5 + mauverse_mobile/Pages/ApplicantGuidePage.xaml | 91 ++++++++++ .../Pages/ApplicantGuidePage.xaml.cs | 14 ++ .../Pages/CampusNavigatorPage.xaml | 45 ++++- mauverse_mobile/Pages/OnlineFormsPage.xaml | 7 + mauverse_mobile/Pages/SettingsPage.xaml | 135 +++++++++++++++ mauverse_mobile/Pages/SettingsPage.xaml.cs | 10 +- mauverse_mobile/Pages/StudentGuidePage.xaml | 91 ++++++++++ .../Pages/StudentGuidePage.xaml.cs | 14 ++ .../Services/BrowserDestinationRegistry.cs | 29 +++- .../Utils/Services/UniversityGuideCatalog.cs | 162 ++++++++++++++++++ .../Utils/Services/UniversityPortalUrls.cs | 64 +++++++ .../ViewModel/News/NewsViewModel.cs | 4 + .../Services/CampusNavigatorViewModel.cs | 42 ++++- .../Services/OnlineFormsViewModel.cs | 39 +++++ .../ViewModel/Services/ServicesViewModel.cs | 25 ++- .../Services/UniversityGuideViewModel.cs | 69 ++++++++ .../ViewModel/SettingsViewModel.cs | 28 ++- mauverse_mobile/mau.csproj | 4 +- 25 files changed, 959 insertions(+), 11 deletions(-) create mode 100644 mauverse_mobile.Tests/UniversityPortalTests.cs create mode 100644 mauverse_mobile/Models/UniversityGuideLink.cs create mode 100644 mauverse_mobile/Models/UniversityGuideSection.cs create mode 100644 mauverse_mobile/Pages/ApplicantGuidePage.xaml create mode 100644 mauverse_mobile/Pages/ApplicantGuidePage.xaml.cs create mode 100644 mauverse_mobile/Pages/StudentGuidePage.xaml create mode 100644 mauverse_mobile/Pages/StudentGuidePage.xaml.cs create mode 100644 mauverse_mobile/Utils/Services/UniversityGuideCatalog.cs create mode 100644 mauverse_mobile/Utils/Services/UniversityPortalUrls.cs create mode 100644 mauverse_mobile/ViewModel/Services/UniversityGuideViewModel.cs diff --git a/mauverse_mobile.Tests/UniversityPortalTests.cs b/mauverse_mobile.Tests/UniversityPortalTests.cs new file mode 100644 index 0000000..23f2953 --- /dev/null +++ b/mauverse_mobile.Tests/UniversityPortalTests.cs @@ -0,0 +1,73 @@ +using mau.Models; +using mau.Utils.Services; +using Xunit; + +namespace Mauverse.Mobile.Tests; + +public sealed class UniversityPortalTests +{ + [Fact] + public void StudentPortalUrlsStayOnUniversityHosts() + { + Assert.Contains( + UniversityPortalUrls.StudentUrls, + url => url.Contains("/structure/divs/studof/", StringComparison.Ordinal)); + Assert.Contains( + UniversityPortalUrls.StudentUrls, + url => url.Contains("/student/faq/", StringComparison.Ordinal)); + Assert.Contains( + UniversityPortalUrls.StudentUrls, + url => url.Contains("lib.mauniver.ru", StringComparison.Ordinal)); + + Assert.All(UniversityPortalUrls.StudentUrls, AssertUniversityHttps); + } + + [Fact] + public void ApplicantPortalUrlsIncludeAdmissionPortal() + { + Assert.Contains( + UniversityPortalUrls.ApplicantUrls, + url => url.StartsWith("https://priem.mauniver.ru", StringComparison.OrdinalIgnoreCase)); + Assert.Contains( + UniversityPortalUrls.ApplicantUrls, + url => url.Contains("/structure/branches/", StringComparison.Ordinal)); + + Assert.All(UniversityPortalUrls.ApplicantUrls, AssertUniversityHttps); + } + + [Theory] + [InlineData(BrowserDestinationRegistry.LibraryKey, "lib.mauniver.ru")] + [InlineData(BrowserDestinationRegistry.EventsCalendarKey, "mauniver.ru")] + [InlineData(BrowserDestinationRegistry.PrivacyPolicyKey, "mauniver.ru")] + [InlineData(BrowserDestinationRegistry.SvedenKey, "mauniver.ru")] + [InlineData(BrowserDestinationRegistry.CampusNavigatorSiteKey, "mauniver.ru")] + [InlineData(BrowserDestinationRegistry.OfficialSiteKey, "mauniver.ru")] + public void KnownPortalDestinationsResolveToUniversityHosts(string key, string hostFragment) + { + var request = BrowserDestinationRegistry.GetRequired(key); + + Assert.Contains(hostFragment, request.Uri.IdnHost, StringComparison.OrdinalIgnoreCase); + Assert.True(request.IsInternalUri(request.Uri)); + } + + [Fact] + public void CampusBuildingSupportsBranchMapCities() + { + var branch = new CampusBuilding( + "Филиал в г. Апатиты", + "ул. Лесная, 29", + "МАУ Филиал в г. Апатиты, ул. Лесная, 29, Апатиты", + "apatity"); + + Assert.Equal("apatity", branch.MapCity); + Assert.Contains("Апатиты", branch.SearchQuery, StringComparison.Ordinal); + } + + static void AssertUniversityHttps(string url) + { + Assert.True(Uri.TryCreate(url, UriKind.Absolute, out var uri)); + Assert.Equal(Uri.UriSchemeHttps, uri.Scheme); + Assert.True(BrowserRequest.IsUniversityHost(uri.IdnHost)); + Assert.True(BrowserDestinationRegistry.IsUniversityUri(uri)); + } +} diff --git a/mauverse_mobile.Tests/mauverse_mobile.Tests.csproj b/mauverse_mobile.Tests/mauverse_mobile.Tests.csproj index a16ddfd..7fb2f9a 100644 --- a/mauverse_mobile.Tests/mauverse_mobile.Tests.csproj +++ b/mauverse_mobile.Tests/mauverse_mobile.Tests.csproj @@ -21,8 +21,12 @@ + + diff --git a/mauverse_mobile/AppShell.xaml.cs b/mauverse_mobile/AppShell.xaml.cs index d63b885..2b10449 100644 --- a/mauverse_mobile/AppShell.xaml.cs +++ b/mauverse_mobile/AppShell.xaml.cs @@ -24,6 +24,8 @@ public AppShell() Routing.RegisterRoute("services/study_info/details", typeof(DetailStudentDebtPage)); Routing.RegisterRoute("services/forms", typeof(OnlineFormsPage)); Routing.RegisterRoute("services/forms/certificate", typeof(CertificateRequestPage)); + Routing.RegisterRoute("services/student_guide", typeof(StudentGuidePage)); + Routing.RegisterRoute("services/applicant", typeof(ApplicantGuidePage)); Routing.RegisterRoute("profile/settings", typeof(SettingsPage)); Routing.RegisterRoute(BrowserDestinationRegistry.InternalBrowserRoute, typeof(InternalBrowserPage)); Navigated += OnNavigated; diff --git a/mauverse_mobile/MauiProgram.cs b/mauverse_mobile/MauiProgram.cs index 73309f9..2f945ad 100644 --- a/mauverse_mobile/MauiProgram.cs +++ b/mauverse_mobile/MauiProgram.cs @@ -95,6 +95,8 @@ public static MauiApp CreateMauiApp() builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/mauverse_mobile/Models/CampusBuilding.cs b/mauverse_mobile/Models/CampusBuilding.cs index d59f245..82504ec 100644 --- a/mauverse_mobile/Models/CampusBuilding.cs +++ b/mauverse_mobile/Models/CampusBuilding.cs @@ -3,4 +3,6 @@ namespace mau.Models; public sealed record CampusBuilding( string Title, string Address, - string SearchQuery); + string SearchQuery, + string MapCity = "murmansk"); + diff --git a/mauverse_mobile/Models/UniversityGuideLink.cs b/mauverse_mobile/Models/UniversityGuideLink.cs new file mode 100644 index 0000000..3304bd4 --- /dev/null +++ b/mauverse_mobile/Models/UniversityGuideLink.cs @@ -0,0 +1,7 @@ +namespace mau.Models; + +public sealed record UniversityGuideLink( + string Title, + string Description, + string Url, + string Glyph); diff --git a/mauverse_mobile/Models/UniversityGuideSection.cs b/mauverse_mobile/Models/UniversityGuideSection.cs new file mode 100644 index 0000000..b3a0143 --- /dev/null +++ b/mauverse_mobile/Models/UniversityGuideSection.cs @@ -0,0 +1,5 @@ +namespace mau.Models; + +public sealed record UniversityGuideSection( + string Title, + IReadOnlyList Links); diff --git a/mauverse_mobile/Pages/ApplicantGuidePage.xaml b/mauverse_mobile/Pages/ApplicantGuidePage.xaml new file mode 100644 index 0000000..913bc16 --- /dev/null +++ b/mauverse_mobile/Pages/ApplicantGuidePage.xaml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/mauverse_mobile/Pages/ApplicantGuidePage.xaml.cs b/mauverse_mobile/Pages/ApplicantGuidePage.xaml.cs new file mode 100644 index 0000000..fb7eedb --- /dev/null +++ b/mauverse_mobile/Pages/ApplicantGuidePage.xaml.cs @@ -0,0 +1,14 @@ +using mau.Utils.Services.Interface; +using mau.ViewModel.Services; + +namespace mau; + +public partial class ApplicantGuidePage : ContentPage +{ + public ApplicantGuidePage(IAppNavigationService navigation) + { + InitializeComponent(); + BindingContext = UniversityGuideViewModel.CreateApplicant(navigation); + Shell.SetTabBarIsVisible(this, false); + } +} diff --git a/mauverse_mobile/Pages/CampusNavigatorPage.xaml b/mauverse_mobile/Pages/CampusNavigatorPage.xaml index 952fb2c..26898ce 100644 --- a/mauverse_mobile/Pages/CampusNavigatorPage.xaml +++ b/mauverse_mobile/Pages/CampusNavigatorPage.xaml @@ -75,10 +75,51 @@ RowSpacing="16" MaximumWidthRequest="720"> - diff --git a/mauverse_mobile/Pages/OnlineFormsPage.xaml b/mauverse_mobile/Pages/OnlineFormsPage.xaml index be8b83b..7f5764e 100644 --- a/mauverse_mobile/Pages/OnlineFormsPage.xaml +++ b/mauverse_mobile/Pages/OnlineFormsPage.xaml @@ -89,6 +89,13 @@ + + + diff --git a/mauverse_mobile/Pages/SettingsPage.xaml b/mauverse_mobile/Pages/SettingsPage.xaml index 9f98c6a..dc44d82 100644 --- a/mauverse_mobile/Pages/SettingsPage.xaml +++ b/mauverse_mobile/Pages/SettingsPage.xaml @@ -303,6 +303,141 @@ + + +