Skip to content

Commit

Permalink
FR-163 - started adding support for external calendar feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
reven committed Apr 22, 2023
1 parent d4d93c2 commit a5bc7d7
Show file tree
Hide file tree
Showing 22 changed files with 762 additions and 113 deletions.
39 changes: 39 additions & 0 deletions Components/Pages/PageCalendar/PageCalendar.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@namespace Fenrus.Components

@inherits Fenrus.Pages.CommonPage<Fenrus.Models.CalendarFeed>

<FenrusPage Title="@lblTitle" Icon="fa-solid fa-puzzle-piece" PageDescription="@lblDescription">
<Body>

<FenrusTable TItem="Models.CalendarFeed" Data=@Items @ref="Table">
<ToolBar>
<FenrusTableButton Label="@lblAdd" Icon="fa-solid fa-plus" Clicked="() => Add()" />
</ToolBar>
<Columns>
<FenrusTableColumn TItem="Models.CalendarFeed" ColumnName="Name">
<Header>@lblName</Header>
<Cell Context="item">
<i class="fa-solid fa-puzzle-piece"></i>
<a href="#" @onclick="() => Edit(item)" @onclick:preventDefault="true">@item.Name</a>
</Cell>
</FenrusTableColumn>
<FenrusTableColumn TItem="Models.CalendarFeed" ColumnName="Enabled" Width="10rem">
<Header>@lblEnabled</Header>
<Cell Context="item">
<FenrusSwitch Value="@item.Enabled" ValueChanged="@((value) => ItemEnabled(item, value))"></FenrusSwitch>
</Cell>
</FenrusTableColumn>
<FenrusTableColumn TItem="Models.CalendarFeed" ColumnName="Actions" Width="10rem">
<Header></Header>
<Cell Context="item">
<div class="actions">
<a title="@lblEdit" class="fa-solid fa-pen-to-square" @onclick="() => Edit(item)"></a>
<span title="@lblDelete" class="fa-solid fa-trash" @onclick="() => Remove(item)"></span>
</div>
</Cell>
</FenrusTableColumn>
</Columns>
</FenrusTable>

</Body>
</FenrusPage>
82 changes: 82 additions & 0 deletions Components/Pages/PageCalendar/PageCalendar.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Fenrus.Components.SideEditors;
using Fenrus.Models;
using Fenrus.Pages;

namespace Fenrus.Components;

/// <summary>
/// Page for Calendars
/// </summary>
public partial class PageCalendar : CommonPage<Models.CalendarFeed>
{
public List<Models.CalendarFeed> Items { get; set; } = new();

private FenrusTable<Models.CalendarFeed> Table { get; set; }

private string lblTitle, lblDescription;

protected override Task PostGotUser()
{
lblTitle = Translator.Instant("Pages.Calendar.Title" + (IsSystem ? "-System" : string.Empty));
lblDescription = Translator.Instant("Pages.Calendar.Labels.PageDescription" + (IsSystem ? "-System" : string.Empty));
var service = new CalendarFeedService();
Items = (IsSystem ? service.GetAllSystem() : service.GetAllForUser(UserUid)).OrderBy(x => x.Name).ToList();
return Task.CompletedTask;
}

/// <summary>
/// Enables an item
/// </summary>
/// <param name="item">the item being enabled</param>
/// <param name="enabled">the enabled state</param>
private void ItemEnabled(CalendarFeed item, bool enabled)
{
item.Enabled = enabled;
new CalendarFeedService().Enable(item.Uid, enabled);
}

protected override bool DoDelete(CalendarFeed item)
{
var service = new CalendarFeedService();
service.Delete(item.Uid);
Items = Items.Where(x => x.Uid != item.Uid).ToList();
Table.SetData(Items);
return true;
}
/// <summary>
/// Edits a calendar feed
/// </summary>
/// <param name="feed">the calendar feed being edited</param>
private async Task Edit(CalendarFeed feed)
{
var result = await Popup.OpenEditor<CalendarFeedEditor, CalendarFeed>(Translator, feed, new ()
{
{ nameof(CalendarFeedEditor.IsSystem), IsSystem },
{ nameof(CalendarFeedEditor.Settings), Settings }
});
if (result.Success == false)
return;
feed.Name = result.Data.Name;
feed.Url = result.Data.Url;
feed.Type = result.Data.Type;
Items = Items.OrderBy(x => x.Name).ToList();
Table.SetData(Items);
}

/// <summary>
/// Adds a new calendar feed
/// </summary>
protected override async Task Add()
{
var result = await Popup.OpenEditor<CalendarFeedEditor, CalendarFeed>(Translator, null, new ()
{
{ nameof(CalendarFeedEditor.IsSystem), IsSystem },
{ nameof(CalendarFeedEditor.Settings), Settings }
});
if (result.Success == false)
return;
Items.Add(result.Data);
Items = Items.OrderBy(x => x.Name).ToList();
Table.SetData(Items);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ protected override bool DoDelete(Models.SearchEngine item)
/// <summary>
/// Edits a search engine
/// </summary>
/// <param name="engine">the search engine being editted</param>
/// <param name="engine">the search engine being edited</param>
private async Task Edit(SearchEngine engine)
{
var result = await Popup.OpenEditor<SearchEngineEditor, SearchEngine>(Translator, engine, new ()
Expand Down
17 changes: 17 additions & 0 deletions Components/SideEditors/CalendarFeedEditor/CalendarFeedEditor.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@namespace Fenrus.Components.SideEditors
@using Fenrus.Models
@inherits SideEditorBase

<SideEditor Title=@Title @ref=Editor>
<Buttons>
<button class="btn" @onclick="() => Save()">@lblSave</button>
<button class="btn" @onclick="() => Cancel()">@lblCancel</button>
</Buttons>
<Body>
<InputText Page="Calendar" Label="Name" @bind-Value="@Model.Name" />
<InputText Page="Calendar" Label="Url" @bind-Value="@Model.Url" />
<InputSelect Page="Calendar" TItem="CalendarFeedType" Label="Type" @bind-Value="@Model.Type">
<InputSelectOption TItem="CalendarFeedType" StringValue="iCal" Label="iCal" />
</InputSelect>
</Body>
</SideEditor>
132 changes: 132 additions & 0 deletions Components/SideEditors/CalendarFeedEditor/CalendarFeedEditor.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using Fenrus.Models;
using Microsoft.AspNetCore.Components;

namespace Fenrus.Components.SideEditors;

/// <summary>
/// Calendar Feed Editor
/// </summary>
public partial class CalendarFeedEditor: SideEditorBase
{
/// <summary>
/// Gets or sets the item this is editing, leave null for a new item
/// </summary>
[Parameter] public CalendarFeed? Item { get; set; }

/// <summary>
/// Gets or sets the callback when this editor is saved
/// </summary>
[Parameter] public EventCallback<CalendarFeed> OnSaved { get; set; }

/// <summary>
/// Gets or sets the callback when this editor is canceled
/// </summary>
[Parameter] public EventCallback OnCanceled { get; set; }

/// <summary>
/// Gets or sets if this is a system calendar feed
/// </summary>
[Parameter] public bool IsSystem { get; set; }

/// <summary>
/// Gets or sets the user settings
/// </summary>
[Parameter] public UserSettings Settings { get; set; }

/// <summary>
/// Gets or sets the bound model the user is editing
/// </summary>
private CalendarFeed Model;

/// <summary>
/// Gets or sets the title of the editor
/// </summary>
private string Title;

/// <summary>
/// Gets or sets if this is an editor for a new item
/// </summary>
private bool IsNew;

/// <summary>
/// Gets or sets the side editor instance
/// </summary>
private SideEditor Editor { get; set; }

private string Icon { get; set; }

private string lblSave, lblCancel;

protected override void OnInitialized()
{
Model = new();
IsNew = false;
this.lblSave = Translator.Instant("Labels.Save");
this.lblCancel = Translator.Instant("Labels.Cancel");

if (Item != null)
{
Title = Translator.Instant("Pages.Calendar.Labels.EditCalendarFeed");
Model.Name = Item.Name;
Model.Uid = Item.Uid;
Model.Url = Item.Url;
Model.Type = Item.Type;
Model.Enabled = Item.Enabled;
}
else
{
Title = Translator.Instant("Pages.Calendar.Labels.NewCalendarFeed");
Model.Name = string.Empty;
Model.Uid = Guid.NewGuid();
Model.Url = string.Empty;
Model.Type = CalendarFeedType.iCal;
Model.Enabled = true;
IsNew = true;
}
}

/// <summary>
/// Save the editor
/// </summary>
async Task Save()
{
// validate
if (await Editor.Validate() == false)
return;

if (this.Model.Uid == Guid.Empty)
this.Model.Uid = Guid.NewGuid();

string saveImage = ImageHelper.SaveImageFromBase64(Icon);

var service = new CalendarFeedService();
if (IsNew)
{
Model.Uid = Guid.NewGuid();
Model.IsSystem = IsSystem;

Model.UserUid = IsSystem ? Guid.Empty : Settings.UserUid;
service.Add(Model);
}
else
{
var existing = service.GetByUid(this.Model.Uid);
existing.Enabled = Model.Enabled;
existing.IsSystem = IsSystem;

existing.Name = Model.Name;
existing.Url = Model.Url;
service.Update(existing);
}

await OnSaved.InvokeAsync(Model);
}


/// <summary>
/// Cancels the editor
/// </summary>
/// <returns>a task to await</returns>
Task Cancel()
=> OnCanceled.InvokeAsync();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Fenrus.Models;
using Fenrus.Services;
using Microsoft.AspNetCore.Components;

namespace Fenrus.Components.SideEditors;
Expand Down
54 changes: 16 additions & 38 deletions Controllers/CalendarController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public IEnumerable<CalendarEventModel> GetAll([FromQuery]DateTime start, [FromQu
var all = new CalendarService().GetAllForUser(uid);
var results = all.Where(x => x.StartUtc >= startUtc && x.StartUtc < endUtc)
.Select(x => CalendarEventModel.From(x)).ToList();
return results;
// get the feed events
var feeds = new CalendarFeedService().GetEvents(uid, start, end);
return results.Union(feeds);
}

/// <summary>
Expand All @@ -44,46 +46,22 @@ public CalendarEventModel Save([FromBody] CalendarEvent @event)
return CalendarEventModel.From(@event);
}


/// <summary>
/// Models for a calender event used by the UI control
/// Deletes a calendar event
/// </summary>
public class CalendarEventModel
/// <param name="uid">the UID of the event to delete</param>
[HttpDelete("{uid}")]
public IActionResult Delete([FromRoute] Guid uid)
{
/// <summary>
/// Gets the UID of the event
/// </summary>
[JsonPropertyName("id")]
public Guid Uid { get; init; }
/// <summary>
/// Gets the name of the event
/// </summary>
[JsonPropertyName("title")]
public string Title { get; init; }
/// <summary>
/// Gets the start date of the event
/// </summary>
[JsonPropertyName("start")]
public string Start { get; init; }
/// <summary>
/// Gets the end date of the event
/// </summary>
[JsonPropertyName("end")]
public string End { get; init; }

/// <summary>
/// Converts a CalendarEvent to a CalendarEventModel
/// </summary>
/// <param name="event">the CalendarEvent</param>
/// <returns>the CalendarEventModel</returns>
public static CalendarEventModel From(CalendarEvent @event)
=> new()
{
Uid = @event.Uid,
Title = @event.Name,
Start = @event.StartUtc.ToString("yyyy-MM-ddTHH:mm:ssZ"),
End = @event.EndUtc.ToString("yyyy-MM-ddTHH:mm:ssZ")
};
var userUid = User.GetUserUid().Value;
var service = new CalendarService();
var @event = service.GetByUid(uid);
if (@event == null)
return Ok(); // already deleted
if (@event.UserUid != userUid)
return Unauthorized();
service.Delete(uid);
return Ok();
}
}

4 changes: 1 addition & 3 deletions Controllers/ProxyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ namespace Fenrus.Controllers;
[Route("proxy")]
public class ProxyController: BaseController
{
private static HttpClient Client = new ();

/// <summary>
/// Proxies a resource
/// </summary>
Expand Down Expand Up @@ -48,7 +46,7 @@ public async Task Get([FromRoute] string url)

try
{
var result = await Client.SendAsync(new HttpRequestMessage()
var result = await Globals.Client.SendAsync(new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
Expand Down
2 changes: 2 additions & 0 deletions Fenrus.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<PackageReference Include="Blazored.Toast" Version="3.2.2" />
<PackageReference Include="Docker.DotNet" Version="3.125.13" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Ical.Net.NetCore" Version="4.1.11" />
<PackageReference Include="Jint" Version="3.0.0-beta-2047" />
<PackageReference Include="LigerShark.WebOptimizer.Core" Version="3.0.380" />
<PackageReference Include="LigerShark.WebOptimizer.Sass" Version="3.0.91" />
Expand All @@ -27,6 +28,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.12" />
<PackageReference Include="NLog" Version="5.1.2" />
<PackageReference Include="SSH.NET" Version="2020.0.2" />
<PackageReference Include="System.Runtime.Caching" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit a5bc7d7

Please sign in to comment.