Event compose implementation.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user