Event compose implementation.

This commit is contained in:
Burak Kaan Köse
2026-03-07 01:46:07 +01:00
parent 6608baed69
commit e94cce451f
26 changed files with 1285 additions and 674 deletions
@@ -0,0 +1,7 @@
namespace Wino.Core.Domain.Enums;
public enum NewEventButtonBehavior
{
AskEachTime = 0,
AlwaysUseSpecificCalendar = 1
}
@@ -0,0 +1,10 @@
using System;
namespace Wino.Core.Domain.Exceptions;
public sealed class CalendarEventComposeValidationException : Exception
{
public CalendarEventComposeValidationException(string message) : base(message)
{
}
}
@@ -18,6 +18,7 @@ public interface ICalendarService
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar);
Task SetPrimaryCalendarAsync(Guid accountId, Guid accountCalendarId);
Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
/// <summary>
@@ -227,6 +227,16 @@ public interface IPreferencesService : INotifyPropertyChanged
/// </summary>
int DefaultSnoozeDurationInMinutes { get; set; }
/// <summary>
/// Setting: How the New Event button chooses a calendar.
/// </summary>
NewEventButtonBehavior NewEventButtonBehavior { get; set; }
/// <summary>
/// Setting: Default calendar used when New Event is configured to always use a specific calendar.
/// </summary>
Guid? DefaultNewEventCalendarId { get; set; }
CalendarSettings GetCurrentCalendarSettings();
#endregion
@@ -1049,6 +1049,10 @@
"CalendarAccountSettings_DefaultShowAsDescription": "Default availability status for new events created with this account",
"CalendarAccountSettings_PrimaryCalendar": "Primary Calendar",
"CalendarAccountSettings_PrimaryCalendarDescription": "Mark this calendar as the primary calendar for the account",
"CalendarSettings_NewEventBehavior_Header": "New Event button behavior",
"CalendarSettings_NewEventBehavior_Description": "Choose whether the New Event button should ask for a calendar each time or always open a specific calendar.",
"CalendarSettings_NewEventBehavior_AskEachTime": "Ask each time.",
"CalendarSettings_NewEventBehavior_AlwaysUseSpecificCalendar": "Always use specific calendar.",
"WhatIsNew_GetStartedButton": "Get Started",
"WhatIsNew_ContinueAnywayButton": "Continue anyway",
"WhatIsNew_PreparingForNewVersionButton": "Preparing for new version...",
@@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Mail;
using Wino.Core.Domain.Exceptions;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Core.Domain.Validation;
public sealed class CalendarEventComposeResultValidator
{
public void Validate(CalendarEventComposeResult result)
{
ArgumentNullException.ThrowIfNull(result);
if (result.CalendarId == Guid.Empty)
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationMissingCalendar);
if (result.AccountId == Guid.Empty)
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationMissingCalendar);
if (string.IsNullOrWhiteSpace(result.Title))
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationMissingTitle);
if (result.EndDate <= result.StartDate)
{
var message = result.IsAllDay
? Translator.CalendarEventCompose_ValidationInvalidAllDayRange
: Translator.CalendarEventCompose_ValidationInvalidTimeRange;
throw new CalendarEventComposeValidationException(message);
}
var missingAttachments = result.Attachments
.Where(attachment => string.IsNullOrWhiteSpace(attachment.FilePath) || !File.Exists(attachment.FilePath))
.Select(attachment => attachment.FileName)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (missingAttachments.Count > 0)
{
throw new CalendarEventComposeValidationException(
string.Format(Translator.CalendarEventCompose_ValidationMissingAttachment, string.Join(", ", missingAttachments)));
}
var invalidAttendee = result.Attendees
.FirstOrDefault(attendee => string.IsNullOrWhiteSpace(attendee.Email) || !IsValidEmailAddress(attendee.Email.Trim()));
if (invalidAttendee != null)
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationInvalidAttendee);
var duplicateAttendeeGroups = result.Attendees
.Where(attendee => !string.IsNullOrWhiteSpace(attendee.Email))
.GroupBy(attendee => attendee.Email.Trim(), StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(group => group.Count() > 1);
if (duplicateAttendeeGroups != null)
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationInvalidAttendee);
}
private static bool IsValidEmailAddress(string address)
{
try
{
var parsedAddress = new MailAddress(address);
return parsedAddress.Address.Equals(address, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
}