diff --git a/ResourceInformationV2.Data/DataHelpers/SecurityHelper.cs b/ResourceInformationV2.Data/DataHelpers/SecurityHelper.cs index d9265cd..89c3dce 100644 --- a/ResourceInformationV2.Data/DataHelpers/SecurityHelper.cs +++ b/ResourceInformationV2.Data/DataHelpers/SecurityHelper.cs @@ -29,6 +29,20 @@ public async Task GetDepartmentName(string sourceName, string netId) { return entry?.DepartmentTag ?? ""; } + public async Task ChangeOwner(string sourceName, int newId) { + var oldOwner = await resourceRepository.ReadAsync(c => c.SecurityEntries.Include(c => c.Source).FirstOrDefault(se => se.Source != null && se.Source.Code == sourceName.Replace("!", "") && se.IsOwner)); + if (oldOwner == null) { + return false; + } + oldOwner.IsOwner = false; + var newOwner = await resourceRepository.ReadAsync(c => c.SecurityEntries.FirstOrDefault(se => se.Id == newId)); + if (newOwner == null) { + return false; + } + newOwner.IsOwner = true; + return await resourceRepository.UpdateAsync(oldOwner) > 0 && await resourceRepository.UpdateAsync(newOwner) > 0; + } + public async Task ConfirmNetIdCanAccessSource(string sourceName, string netId) { return await resourceRepository.ReadAsync(c => c.SecurityEntries.Include(c => c.Source).Any(se => se.Source != null && se.Source.Code == sourceName.Replace("!", "") && se.Email == netId)); } diff --git a/ResourceInformationV2.Data/PageList/PageGroup.cs b/ResourceInformationV2.Data/PageList/PageGroup.cs index bd2f11e..55a331e 100644 --- a/ResourceInformationV2.Data/PageList/PageGroup.cs +++ b/ResourceInformationV2.Data/PageList/PageGroup.cs @@ -17,23 +17,17 @@ public static class PageGroup { { SidebarEnum.AddEditInformation, new() { new ("Home", "/"), new ("Add/Edit Information", "/add") } }, { SidebarEnum.PeopleItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("People", "/person/general") } }, + new ("Edit People", "/person/edit") } }, { SidebarEnum.PublicationItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("Publications", "/publication/general") } }, + new ("Edit Publications", "/publication/edit") } }, { SidebarEnum.ResourceItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("Resources", "/resource/general") } }, + new ("Edit Resources", "/resource/edit") } }, { SidebarEnum.FaqItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("FAQs", "/faq/general") } }, + new ("Edit FAQs", "/faq/edit") } }, { SidebarEnum.NotesItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("Notes", "/note/general") } }, + new ("Edit Notes", "/note/edit") } }, { SidebarEnum.EventItem, new() { new ("Home", "/"), - new ("Edit", "/edit"), - new ("Notes", "/event/general") } } + new ("Edit Events", "/event/edit") } } }; private static readonly Dictionary> _sidebars = new() { diff --git a/ResourceInformationV2/Components/Pages/Configuration/Security.razor b/ResourceInformationV2/Components/Pages/Configuration/Security.razor index 3619ca5..feef344 100644 --- a/ResourceInformationV2/Components/Pages/Configuration/Security.razor +++ b/ResourceInformationV2/Components/Pages/Configuration/Security.razor @@ -9,7 +9,7 @@ {

@netid.Display

- +
} @@ -19,16 +19,17 @@

Add a Net ID to add to the list. The @@illinois.edu is optional.

-
- - -
+ @if (Departments.Count > 0) { +
+ + +
+ }

API Updates

This generates an API key that will allow you to programatically add, update, and delete items within your source.

@@ -54,4 +55,18 @@

If you had a valid API key before creating this new API key, it will be usable as well. If you wish to deactivate the old API key (because it has been compromised), then you should invalidate the API key and then create a new key.

API Key: @ApiGuid

} + +

Change Owner

+

Each Resource Source must have an owner. You can change the owner below:

+
+ + +
+

+ + diff --git a/ResourceInformationV2/Components/Pages/Configuration/Security.razor.cs b/ResourceInformationV2/Components/Pages/Configuration/Security.razor.cs index 41e33f6..1fac4e0 100644 --- a/ResourceInformationV2/Components/Pages/Configuration/Security.razor.cs +++ b/ResourceInformationV2/Components/Pages/Configuration/Security.razor.cs @@ -14,6 +14,7 @@ public partial class Security { public string ApiGuid { get; set; } = ""; + public int CurrentOwnerId { get; set; } public List Departments { get; set; } = []; public DateTime LastDateApiChanged { get; set; } @@ -76,10 +77,21 @@ public async Task InvalidateApi() { UseApi = false; } + public async Task ChangeOwner() { + var source = await Layout.CheckSource(); + if (await SecurityHelper.ChangeOwner(source, CurrentOwnerId)) { + if (NetIds.Any(a => a.IsOwner) && NetIds.Any(a => a.Id == CurrentOwnerId)) { + NetIds.First(a => a.IsOwner).IsOwner = false; + NetIds.First(a => a.Id == CurrentOwnerId).IsOwner = true; + } + await Layout.AddMessage("The Owner has been changed"); + } + } + public async Task Remove(string netId) { var source = await Layout.CheckSource(); if (await SecurityHelper.RemoveName(source, netId)) { - NetIds.Remove(NetIds.FirstOrDefault(n => n.Email == netId)); + NetIds.Remove(NetIds.FirstOrDefault(n => n.Email == netId) ?? new SecurityEntry()); } var email = await UserHelper.GetUser(AuthenticationStateProvider); if (netId == email) { @@ -96,6 +108,7 @@ protected override async Task OnInitializedAsync() { NetIds = await SecurityHelper.GetNames(source); (UseApi, LastDateApiChanged, ApiDraft) = await ApiHelper.GetApi(source); Layout.SetSidebar(SidebarEnum.Configuration, "Configuration"); + CurrentOwnerId = NetIds.FirstOrDefault(n => n.IsOwner)?.Id ?? 0; Departments = [.. (await FilterHelper.GetFilters(source, TagType.Department)).TagSources.Select(ts => ts.Title)]; } } diff --git a/ResourceInformationV2/Components/Pages/ContactUs/About.razor b/ResourceInformationV2/Components/Pages/ContactUs/About.razor index 1045e27..feaa0d9 100644 --- a/ResourceInformationV2/Components/Pages/ContactUs/About.razor +++ b/ResourceInformationV2/Components/Pages/ContactUs/About.razor @@ -7,12 +7,14 @@

Resources

To get help with the resource repository, contact Bryan Jonker at jonker@illinois.edu.

-

To report a bug or request an enhancement, go to our GitHub repository and create an issue. This will log the issue so we can review it. Note that this application is meant for campus, which means we cannot customize it to a specific unit unless others will benefit from the change.

+

The Resource API allows you to pull this information into your webpage. If you want to see the details of the API, see our API Documentation.

-

This application is meant to be used with the Illinois Toolkit, although there's no reason why you cannot use this application alone. The Toolkit Builder will have examples of how this can be integrated with the toolkit.

+

To report a bug or request an enhancement, go to our GitHub repository and create an issue. This will log the issue so we can review it. Note that this application is meant for campus, which means we cannot customize it to a specific unit unless others will benefit from the change.

We are also working on enhancements and documentation for this. To see the project status of individual items, you can look at our GitHub project status board.

+

This application is meant to be used with the Illinois Toolkit, although there's no reason why you cannot use this application alone. The Toolkit Builder will have examples of how this can be integrated with the toolkit.

+

About This Project

diff --git a/ResourceInformationV2/Components/Pages/Transfer/DownloadFile.razor.cs b/ResourceInformationV2/Components/Pages/Transfer/DownloadFile.razor.cs index 4513e05..c74ec80 100644 --- a/ResourceInformationV2/Components/Pages/Transfer/DownloadFile.razor.cs +++ b/ResourceInformationV2/Components/Pages/Transfer/DownloadFile.razor.cs @@ -1,11 +1,11 @@ -using System.Text; -using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using ResourceInformationV2.Components.Layout; using ResourceInformationV2.Data.DataHelpers; using ResourceInformationV2.Data.PageList; using ResourceInformationV2.Search.Getters; using ResourceInformationV2.Search.Models; +using System.Text; namespace ResourceInformationV2.Components.Pages.Transfer { @@ -88,7 +88,7 @@ private async Task Download() { default: break; } - var fileStream = new MemoryStream(Encoding.ASCII.GetBytes(text)); + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(text)); using var streamRef = new DotNetStreamReference(fileStream); await JsRuntime.InvokeVoidAsync("downloadFileFromStream", $"{source}_{DateTime.Now.ToString("yyyy_MM_dd")}_{SelectedOption.ToLowerInvariant()}.txt", streamRef); await Layout.AddMessage("Text file downloaded successfully."); diff --git a/ResourceInformationV2/Components/Pages/Transfer/DownloadJson.razor.cs b/ResourceInformationV2/Components/Pages/Transfer/DownloadJson.razor.cs index d542a5b..7ea8371 100644 --- a/ResourceInformationV2/Components/Pages/Transfer/DownloadJson.razor.cs +++ b/ResourceInformationV2/Components/Pages/Transfer/DownloadJson.razor.cs @@ -1,11 +1,11 @@ -using System.Text; -using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using ResourceInformationV2.Components.Layout; using ResourceInformationV2.Data.DataHelpers; using ResourceInformationV2.Data.PageList; using ResourceInformationV2.Search.Helpers; using ResourceInformationV2.Search.Models; +using System.Text; namespace ResourceInformationV2.Components.Pages.Transfer { @@ -40,9 +40,9 @@ private async Task Download() { await Layout.AddMessage("JSON file being prepared -- this may take a while."); var source = await Layout.CheckSource(); - Enum.TryParse(SelectedOption, out UrlTypes urlType); + _ = Enum.TryParse(SelectedOption, out UrlTypes urlType); var text = await JsonHelper.GetJsonFull(source, urlType); - var fileStream = new MemoryStream(Encoding.ASCII.GetBytes(text)); + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(text)); using var streamRef = new DotNetStreamReference(fileStream); await JsRuntime.InvokeVoidAsync("downloadFileFromStream", $"{source}_{DateTime.Now.ToString("yyyy_MM_dd")}_{SelectedOption.ToLowerInvariant()}.json", streamRef); await Layout.AddMessage("JSON file downloaded successfully."); diff --git a/ResourceInformationV2/Components/Pages/Transfer/UploadFile.razor.cs b/ResourceInformationV2/Components/Pages/Transfer/UploadFile.razor.cs index 23bebef..0ba3fe3 100644 --- a/ResourceInformationV2/Components/Pages/Transfer/UploadFile.razor.cs +++ b/ResourceInformationV2/Components/Pages/Transfer/UploadFile.razor.cs @@ -7,6 +7,7 @@ using ResourceInformationV2.Search.Helpers; using ResourceInformationV2.Search.Models; using ResourceInformationV2.Search.Setters; +using System.Text; namespace ResourceInformationV2.Components.Pages.Transfer { @@ -62,7 +63,8 @@ protected override async Task OnInitializedAsync() { } private async Task LoadFile(InputFileChangeEventArgs e) { - _reader = await new StreamReader(e.File.OpenReadStream(_maxFileSize)).ReadToEndAsync(); + using var streamReader = new StreamReader(e.File.OpenReadStream(_maxFileSize), Encoding.UTF8, detectEncodingFromByteOrderMarks: true); + _reader = await streamReader.ReadToEndAsync(); await Layout.AddMessage("File loaded for " + SelectedOption + " and ready to be uploaded"); } diff --git a/ResourceInformationV2/Components/Pages/Transfer/UploadJson.razor.cs b/ResourceInformationV2/Components/Pages/Transfer/UploadJson.razor.cs index a47eb93..2975d20 100644 --- a/ResourceInformationV2/Components/Pages/Transfer/UploadJson.razor.cs +++ b/ResourceInformationV2/Components/Pages/Transfer/UploadJson.razor.cs @@ -6,6 +6,7 @@ using ResourceInformationV2.Data.PageList; using ResourceInformationV2.Search.Helpers; using ResourceInformationV2.Search.Models; +using System.Text; namespace ResourceInformationV2.Components.Pages.Transfer { @@ -39,7 +40,8 @@ protected override async Task OnInitializedAsync() { } private async Task LoadFile(InputFileChangeEventArgs e) { - _reader = await new StreamReader(e.File.OpenReadStream(_maxFileSize)).ReadToEndAsync(); + using var streamReader = new StreamReader(e.File.OpenReadStream(_maxFileSize), Encoding.UTF8, detectEncodingFromByteOrderMarks: true); + _reader = await streamReader.ReadToEndAsync(); await Layout.AddMessage("File loaded for " + SelectedOption + " and ready to be uploaded"); }