Добавил ICS
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Create and publish a Docker image / Publish image (push) Failing after 10s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Create and publish a Docker image / Publish image (push) Failing after 10s
				
			This commit is contained in:
		
							
								
								
									
										709
									
								
								SfeduSchedule.Abstractions/ScheduleDTO.CS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										709
									
								
								SfeduSchedule.Abstractions/ScheduleDTO.CS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,709 @@ | |||||||
|  | // <auto-generated />  | ||||||
|  | // Вот этим сайтом https://app.quicktype.io/?l=csharp | ||||||
|  | // Не является точной копией ответа, могут быть отличия | ||||||
|  |  | ||||||
|  | #nullable enable | ||||||
|  | #pragma warning disable CS8618 | ||||||
|  | #pragma warning disable CS8601 | ||||||
|  | #pragma warning disable CS8603 | ||||||
|  |  | ||||||
|  | namespace SfeduSchedule | ||||||
|  | { | ||||||
|  |     using System; | ||||||
|  |     using System.Collections.Generic; | ||||||
|  |  | ||||||
|  |     using System.Text.Json; | ||||||
|  |     using System.Text.Json.Serialization; | ||||||
|  |     using System.Globalization; | ||||||
|  |  | ||||||
|  |     public partial class Schedule | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("_embedded")] | ||||||
|  |         public Embedded Embedded { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("page")] | ||||||
|  |         public Page Page { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Embedded | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("events")] | ||||||
|  |         public Event[] Events { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("course-unit-realizations")] | ||||||
|  |         public CourseUnitRealization[] CourseUnitRealizations { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("cycle-realizations")] | ||||||
|  |         public CycleRealization[] CycleRealizations { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("lesson-realization-teams")] | ||||||
|  |         public LessonRealizationTeam[] LessonRealizationTeams { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("lesson-realizations")] | ||||||
|  |         public LessonRealization[] LessonRealizations { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event-locations")] | ||||||
|  |         public EventLocation[] EventLocations { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("durations")] | ||||||
|  |         public Duration[] Durations { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event-rooms")] | ||||||
|  |         public EventRoom[] EventRooms { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("rooms")] | ||||||
|  |         public Room[] Rooms { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("buildings")] | ||||||
|  |         public BuildingElement[] Buildings { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event-teams")] | ||||||
|  |         public EventTeam[] EventTeams { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event-organizers")] | ||||||
|  |         public EventOrganizer[] EventOrganizers { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event-attendees")] | ||||||
|  |         public EventAttendee[] EventAttendees { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("persons")] | ||||||
|  |         public Person[] Persons { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class BuildingElement | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("address")] | ||||||
|  |         public string Address { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("searchableAddress")] | ||||||
|  |         public string SearchableAddress { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("displayOrder")] | ||||||
|  |         public long DisplayOrder { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public BuildingLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class BuildingLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Self | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("href")] | ||||||
|  |         public string Href { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class CourseUnitRealization | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("prototypeId")] | ||||||
|  |         public Guid PrototypeId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public CourseUnitRealizationLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class CourseUnitRealizationLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("planning-period")] | ||||||
|  |         public Self PlanningPeriod { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class CycleRealization | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("code")] | ||||||
|  |         public string Code { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("courseUnitRealizationNameShort")] | ||||||
|  |         public string CourseUnitRealizationNameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public CycleRealizationLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class CycleRealizationLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("course-unit-realization")] | ||||||
|  |         public Self CourseUnitRealization { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Duration | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("eventId")] | ||||||
|  |         public Guid EventId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("value")] | ||||||
|  |         public long Value { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("timeUnitId")] | ||||||
|  |         public string TimeUnitId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("minutes")] | ||||||
|  |         public long Minutes { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public DurationLinks Links { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class DurationLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self[] Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("time-unit")] | ||||||
|  |         public Self TimeUnit { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventAttendee | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("roleId")] | ||||||
|  |         public string RoleId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("roleName")] | ||||||
|  |         public string RoleName { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("roleNamePlural")] | ||||||
|  |         public string RoleNamePlural { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("roleDisplayOrder")] | ||||||
|  |         public long RoleDisplayOrder { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public EventAttendeeLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventAttendeeLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event")] | ||||||
|  |         public Self Event { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("person")] | ||||||
|  |         public Self Person { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventLocation | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("eventId")] | ||||||
|  |         public Guid EventId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("customLocation")] | ||||||
|  |         public string CustomLocation { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public EventLocationLinks Links { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventLocationLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self[] Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | ||||||
|  |         [JsonPropertyName("event-rooms")] | ||||||
|  |         public Self EventRooms { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventOrganizer | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("eventId")] | ||||||
|  |         public Guid EventId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public EventOrganizerLinks Links { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventOrganizerLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event")] | ||||||
|  |         public Self Event { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | ||||||
|  |         [JsonPropertyName("event-attendees")] | ||||||
|  |         public EventAttendees? EventAttendees { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventRoom | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public EventRoomLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventRoomLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event")] | ||||||
|  |         public Self Event { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("room")] | ||||||
|  |         public Self Room { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventTeam | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("eventId")] | ||||||
|  |         public Guid EventId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("size")] | ||||||
|  |         public long Size { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public EventTeamLinks Links { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class EventTeamLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("event")] | ||||||
|  |         public Self Event { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Event | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("description")] | ||||||
|  |         public object Description { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("typeId")] | ||||||
|  |         public string TypeId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("formatId")] | ||||||
|  |         public string FormatId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("start")] | ||||||
|  |         public DateTime Start { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("end")] | ||||||
|  |         public DateTime End { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("startsAtLocal")] | ||||||
|  |         public DateTime StartsAtLocal { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("endsAtLocal")] | ||||||
|  |         public DateTime EndsAtLocal { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("startsAt")] | ||||||
|  |         public DateTime StartsAt { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("endsAt")] | ||||||
|  |         public DateTime EndsAt { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("holdingStatus")] | ||||||
|  |         public HoldingStatus HoldingStatus { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("repeatedLessonRealization")] | ||||||
|  |         public RepeatedLessonRealization RepeatedLessonRealization { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("userRoleIds")] | ||||||
|  |         public string[] UserRoleIds { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("lessonTemplateId")] | ||||||
|  |         public Guid LessonTemplateId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("__version")] | ||||||
|  |         public long Version { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public Dictionary<string, Self> Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class HoldingStatus | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public string Id { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("audModifiedAt")] | ||||||
|  |         public DateTimeOffset? AudModifiedAt { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("audModifiedBy")] | ||||||
|  |         public Guid? AudModifiedBy { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("audModifiedBySystem")] | ||||||
|  |         public bool? AudModifiedBySystem { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class RepeatedLessonRealization | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("lessonTeamName")] | ||||||
|  |         public string LessonTeamName { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class LessonRealizationTeam | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("cycleRealizationId")] | ||||||
|  |         public Guid CycleRealizationId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public BuildingLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class LessonRealization | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("prototypeId")] | ||||||
|  |         public Guid PrototypeId { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("ordinal")] | ||||||
|  |         public long Ordinal { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public BuildingLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Person | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("lastName")] | ||||||
|  |         public string LastName { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("firstName")] | ||||||
|  |         public string FirstName { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("middleName")] | ||||||
|  |         public string MiddleName { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("fullName")] | ||||||
|  |         public string FullName { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public BuildingLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Room | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("building")] | ||||||
|  |         public RoomBuilding Building { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("projectorAvailable")] | ||||||
|  |         public bool ProjectorAvailable { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("totalCapacity")] | ||||||
|  |         public long TotalCapacity { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("workingCapacity")] | ||||||
|  |         public long WorkingCapacity { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("deletedAtUtc")] | ||||||
|  |         public object DeletedAtUtc { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("_links")] | ||||||
|  |         public RoomLinks Links { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class RoomBuilding | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("id")] | ||||||
|  |         public Guid Id { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("name")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("nameShort")] | ||||||
|  |         public string NameShort { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("address")] | ||||||
|  |         public string Address { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("displayOrder")] | ||||||
|  |         public long DisplayOrder { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class RoomLinks | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("self")] | ||||||
|  |         public Self Self { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("type")] | ||||||
|  |         public Self Type { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("building")] | ||||||
|  |         public Self Building { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Page | ||||||
|  |     { | ||||||
|  |         [JsonPropertyName("size")] | ||||||
|  |         public long Size { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("totalElements")] | ||||||
|  |         public long TotalElements { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("totalPages")] | ||||||
|  |         public long TotalPages { get; set; } | ||||||
|  |  | ||||||
|  |         [JsonPropertyName("number")] | ||||||
|  |         public long Number { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial struct EventAttendees | ||||||
|  |     { | ||||||
|  |         public Self Self; | ||||||
|  |         public Self[] SelfArray; | ||||||
|  |  | ||||||
|  |         public static implicit operator EventAttendees(Self Self) => new EventAttendees { Self = Self }; | ||||||
|  |         public static implicit operator EventAttendees(Self[] SelfArray) => new EventAttendees { SelfArray = SelfArray }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public partial class Schedule | ||||||
|  |     { | ||||||
|  |         public static Schedule FromJson(string json) => JsonSerializer.Deserialize<Schedule>(json, SfeduSchedule.Converter.Settings); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static class Serialize | ||||||
|  |     { | ||||||
|  |         public static string ToJson(this Schedule self) => JsonSerializer.Serialize(self, SfeduSchedule.Converter.Settings); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     internal static class Converter | ||||||
|  |     { | ||||||
|  |         public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General) | ||||||
|  |         { | ||||||
|  |             Converters = | ||||||
|  |             { | ||||||
|  |                 EventAttendeesConverter.Singleton, | ||||||
|  |                 new DateOnlyConverter(), | ||||||
|  |                 new TimeOnlyConverter(), | ||||||
|  |                 IsoDateTimeOffsetConverter.Singleton | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     internal class EventAttendeesConverter : JsonConverter<EventAttendees> | ||||||
|  |     { | ||||||
|  |         public override bool CanConvert(Type t) => t == typeof(EventAttendees); | ||||||
|  |  | ||||||
|  |         public override EventAttendees Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |             switch (reader.TokenType) | ||||||
|  |             { | ||||||
|  |                 case JsonTokenType.StartObject: | ||||||
|  |                     var objectValue = JsonSerializer.Deserialize<Self>(ref reader, options); | ||||||
|  |                     return new EventAttendees { Self = objectValue }; | ||||||
|  |                 case JsonTokenType.StartArray: | ||||||
|  |                     var arrayValue = JsonSerializer.Deserialize<Self[]>(ref reader, options); | ||||||
|  |                     return new EventAttendees { SelfArray = arrayValue }; | ||||||
|  |             } | ||||||
|  |             throw new Exception("Cannot unmarshal type EventAttendees"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override void Write(Utf8JsonWriter writer, EventAttendees value, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |             if (value.SelfArray != null) | ||||||
|  |             { | ||||||
|  |                 JsonSerializer.Serialize(writer, value.SelfArray, options); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (value.Self != null) | ||||||
|  |             { | ||||||
|  |                 JsonSerializer.Serialize(writer, value.Self, options); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             throw new Exception("Cannot marshal type EventAttendees"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static readonly EventAttendeesConverter Singleton = new EventAttendeesConverter(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public class DateOnlyConverter : JsonConverter<DateOnly> | ||||||
|  |     { | ||||||
|  |         private readonly string serializationFormat; | ||||||
|  |         public DateOnlyConverter() : this(null) { } | ||||||
|  |  | ||||||
|  |         public DateOnlyConverter(string? serializationFormat) | ||||||
|  |         { | ||||||
|  |                 this.serializationFormat = serializationFormat ?? "yyyy-MM-dd"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |                 var value = reader.GetString(); | ||||||
|  |                 return DateOnly.Parse(value!); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) | ||||||
|  |                 => writer.WriteStringValue(value.ToString(serializationFormat)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class TimeOnlyConverter : JsonConverter<TimeOnly> | ||||||
|  |     { | ||||||
|  |         private readonly string serializationFormat; | ||||||
|  |  | ||||||
|  |         public TimeOnlyConverter() : this(null) { } | ||||||
|  |  | ||||||
|  |         public TimeOnlyConverter(string? serializationFormat) | ||||||
|  |         { | ||||||
|  |                 this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |                 var value = reader.GetString(); | ||||||
|  |                 return TimeOnly.Parse(value!); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) | ||||||
|  |                 => writer.WriteStringValue(value.ToString(serializationFormat)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     internal class IsoDateTimeOffsetConverter : JsonConverter<DateTimeOffset> | ||||||
|  |     { | ||||||
|  |         public override bool CanConvert(Type t) => t == typeof(DateTimeOffset); | ||||||
|  |  | ||||||
|  |         private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; | ||||||
|  |  | ||||||
|  |         private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; | ||||||
|  |         private string? _dateTimeFormat; | ||||||
|  |         private CultureInfo? _culture; | ||||||
|  |  | ||||||
|  |         public DateTimeStyles DateTimeStyles | ||||||
|  |         { | ||||||
|  |                 get => _dateTimeStyles; | ||||||
|  |                 set => _dateTimeStyles = value; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public string? DateTimeFormat | ||||||
|  |         { | ||||||
|  |                 get => _dateTimeFormat ?? string.Empty; | ||||||
|  |                 set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public CultureInfo Culture | ||||||
|  |         { | ||||||
|  |                 get => _culture ?? CultureInfo.CurrentCulture; | ||||||
|  |                 set => _culture = value; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |                 string text; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                 if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal | ||||||
|  |                         || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) | ||||||
|  |                 { | ||||||
|  |                         value = value.ToUniversalTime(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); | ||||||
|  |  | ||||||
|  |                 writer.WriteStringValue(text); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||||||
|  |         { | ||||||
|  |                 string? dateText = reader.GetString(); | ||||||
|  |  | ||||||
|  |                 if (string.IsNullOrEmpty(dateText) == false) | ||||||
|  |                 { | ||||||
|  |                         if (!string.IsNullOrEmpty(_dateTimeFormat)) | ||||||
|  |                         { | ||||||
|  |                                 return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                                 return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                         return default(DateTimeOffset); | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #pragma warning restore CS8618 | ||||||
|  | #pragma warning restore CS8601 | ||||||
|  | #pragma warning restore CS8603 | ||||||
| @@ -6,80 +6,124 @@ using Microsoft.AspNetCore.RateLimiting; | |||||||
| using SfeduSchedule.Abstractions; | using SfeduSchedule.Abstractions; | ||||||
| using SfeduSchedule.Services; | using SfeduSchedule.Services; | ||||||
|  |  | ||||||
| namespace SfeduSchedule.Controllers | namespace SfeduSchedule.Controllers; | ||||||
|  |  | ||||||
|  | [ApiController] | ||||||
|  | [Route("api/[controller]")] | ||||||
|  | [EnableRateLimiting("throttle")] | ||||||
|  | public class ScheduleController(ModeusService modeusService, ILogger<ScheduleController> logger) : ControllerBase | ||||||
| { | { | ||||||
|     [ApiController] |     /// <summary> | ||||||
|     [Route("api/[controller]")] |     /// Получить расписание по пользовательскому запросу. | ||||||
|     [EnableRateLimiting("throttle")] |     /// </summary> | ||||||
|     public class ScheduleController(ModeusService modeusService, ILogger<ScheduleController> logger) : ControllerBase |     /// <param name="request">Объект запроса, содержащий параметры фильтрации расписания.</param> | ||||||
|  |     /// <returns>Список событий расписания.</returns> | ||||||
|  |     /// <response code="200">Возвращает расписание</response> | ||||||
|  |     /// <response code="429">Слишком много запросов</response> | ||||||
|  |     [HttpPost] | ||||||
|  |     public async Task<IActionResult> Post([FromBody] ModeusScheduleRequest request) | ||||||
|     { |     { | ||||||
|  |         string? schedule; | ||||||
|         /// <summary> |         try | ||||||
|         /// Получить расписание по пользовательскому запросу. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="request">Объект запроса, содержащий параметры фильтрации расписания.</param> |  | ||||||
|         /// <returns>Список событий расписания.</returns> |  | ||||||
|         /// <response code="200">Возвращает расписание</response> |  | ||||||
|         /// <response code="429">Слишком много запросов</response> |  | ||||||
|         [HttpPost] |  | ||||||
|         public async Task<IActionResult> Post([FromBody] ModeusScheduleRequest request) |  | ||||||
|         { |         { | ||||||
|             string? schedule; |             schedule = await modeusService.GetScheduleAsync(request); | ||||||
|             try |         } | ||||||
|             { |         catch (HttpRequestException e) | ||||||
|                 schedule = await modeusService.GetScheduleAsync(request); |         { | ||||||
|             } |             logger.LogError("Ошибка при получении расписания\n\n" + e.Message + "\n\n" + e.StackTrace + | ||||||
|             catch (HttpRequestException e) |                             "\n\n JSON: " + | ||||||
|             { |                             JsonSerializer.Serialize(request, GlobalVariables.jsonSerializerOptions)); | ||||||
|                 logger.LogError("Ошибка при получении расписания\n\n" + e.Message + "\n\n" + e.StackTrace + "\n\n JSON: " + JsonSerializer.Serialize(request, GlobalVariables.jsonSerializerOptions)); |             return StatusCode((int)(e.StatusCode ?? HttpStatusCode.InternalServerError), | ||||||
|                 return StatusCode((int)(e.StatusCode ?? HttpStatusCode.InternalServerError), "Proxied Modeus: " + e.Message); |                 "Proxied Modeus: " + e.Message); | ||||||
|             } |  | ||||||
|             return Ok(schedule); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         return Ok(schedule); | ||||||
|         /// Поиск аудиторий по пользовательскому запросу. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="request">Объект запроса, содержащий параметры фильтрации аудиторий.</param> |  | ||||||
|         /// <returns>Список аудиторий.</returns> |  | ||||||
|         /// <response code="200">Возвращает список аудиторий</response> |  | ||||||
|         /// <response code="429">Слишком много запросов</response> |  | ||||||
|         [HttpPost] |  | ||||||
|         [Route("rooms/search")] |  | ||||||
|         public async Task<IActionResult> SearchRooms([FromBody] RoomSearchRequest request) |  | ||||||
|         { |  | ||||||
|             string? rooms; |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 rooms = await modeusService.SearchRoomsAsync(request); |  | ||||||
|             } |  | ||||||
|             catch (HttpRequestException e) |  | ||||||
|             { |  | ||||||
|                 logger.LogError("Ошибка при поиске аудиторий\n\n" + e.Message + "\n\n" + e.StackTrace + "\n\n JSON: " + JsonSerializer.Serialize(request, GlobalVariables.jsonSerializerOptions)); |  | ||||||
|                 return StatusCode((int)(e.StatusCode ?? HttpStatusCode.InternalServerError), "Proxied Modeus: " + e.Message); |  | ||||||
|             } |  | ||||||
|             return Ok(rooms); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Получить GUID пользователя по полному имени. (требуется авторизация) |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="fullname">Полное имя пользователя.</param> |  | ||||||
|         /// <returns>GUID пользователя.</returns> |  | ||||||
|         /// <response code="200">Возвращает GUID пользователя</response> |  | ||||||
|         /// <response code="404">Пользователь не найден</response> |  | ||||||
|         /// <response code="401">Неавторизованный</response> |  | ||||||
|         [HttpGet] |  | ||||||
|         [Authorize(AuthenticationSchemes = "ApiKey")] |  | ||||||
|         [DisableRateLimiting] |  | ||||||
|         [Route("getguid")] |  | ||||||
|         public async Task<IActionResult> GetGuid(string fullname) |  | ||||||
|         { |  | ||||||
|             var guid = await modeusService.GetGuidAsync(fullname); |  | ||||||
|             if (string.IsNullOrEmpty(guid)) |  | ||||||
|                 return NotFound(); |  | ||||||
|  |  | ||||||
|             return Ok(guid); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Поиск аудиторий по пользовательскому запросу. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="request">Объект запроса, содержащий параметры фильтрации аудиторий.</param> | ||||||
|  |     /// <returns>Список аудиторий.</returns> | ||||||
|  |     /// <response code="200">Возвращает список аудиторий</response> | ||||||
|  |     /// <response code="429">Слишком много запросов</response> | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("rooms/search")] | ||||||
|  |     public async Task<IActionResult> SearchRooms([FromBody] RoomSearchRequest request) | ||||||
|  |     { | ||||||
|  |         string? rooms; | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             rooms = await modeusService.SearchRoomsAsync(request); | ||||||
|  |         } | ||||||
|  |         catch (HttpRequestException e) | ||||||
|  |         { | ||||||
|  |             logger.LogError("Ошибка при поиске аудиторий\n\n" + e.Message + "\n\n" + e.StackTrace + "\n\n JSON: " + | ||||||
|  |                             JsonSerializer.Serialize(request, GlobalVariables.jsonSerializerOptions)); | ||||||
|  |             return StatusCode((int)(e.StatusCode ?? HttpStatusCode.InternalServerError), | ||||||
|  |                 "Proxied Modeus: " + e.Message); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return Ok(rooms); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Получить GUID пользователя по полному имени. (требуется авторизация) | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="fullname">Полное имя пользователя.</param> | ||||||
|  |     /// <returns>GUID пользователя.</returns> | ||||||
|  |     /// <response code="200">Возвращает GUID пользователя</response> | ||||||
|  |     /// <response code="404">Пользователь не найден</response> | ||||||
|  |     /// <response code="401">Неавторизованный</response> | ||||||
|  |     [HttpGet] | ||||||
|  |     [Authorize(AuthenticationSchemes = "ApiKey")] | ||||||
|  |     [DisableRateLimiting] | ||||||
|  |     [Route("getguid")] | ||||||
|  |     public async Task<IActionResult> GetGuid(string fullname) | ||||||
|  |     { | ||||||
|  |         var guid = await modeusService.GetGuidAsync(fullname); | ||||||
|  |         if (string.IsNullOrEmpty(guid)) | ||||||
|  |             return NotFound(); | ||||||
|  |  | ||||||
|  |         return Ok(guid); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Получить расписание в формате ICS по пользовательскому запросу. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="request">Объект запроса, содержащий параметры фильтрации расписания.</param> | ||||||
|  |     /// <returns>Файл ICS с расписанием за -1 неделя + 1 месяц</returns> | ||||||
|  |     /// <response code="200">Возвращает файл ICS с расписанием</response> | ||||||
|  |     /// <response code="404">Расписание не найдено</response> | ||||||
|  |     /// <response code="429">Слишком много запросов</response> | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("ics")] | ||||||
|  |     public async Task<IActionResult> PostIcs([FromBody] ModeusScheduleRequest request) | ||||||
|  |     { | ||||||
|  |         var ics = await modeusService.GetIcsAsync(request); | ||||||
|  |         if (string.IsNullOrEmpty(ics)) | ||||||
|  |             return NotFound(); | ||||||
|  |  | ||||||
|  |         return new FileContentResult(System.Text.Encoding.UTF8.GetBytes(ics), "text/calendar") | ||||||
|  |         { | ||||||
|  |             FileDownloadName = "schedule.ics" | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /// <summary> | ||||||
|  |     /// Получить расписание в формате ICS для указанного пользователя за -1 неделя + 1 месяц. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="attendeePersonId"></param> | ||||||
|  |     /// <returns>Файл ICS с расписанием</returns> | ||||||
|  |     /// <response code="200">Возвращает файл ICS с расписанием</response> | ||||||
|  |     /// <response code="404">Расписание не найдено</response> | ||||||
|  |     /// <response code="429">Слишком много запросов</response> | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("ics")] | ||||||
|  |     public async Task<IActionResult> GetIcs([FromQuery] Guid attendeePersonId) | ||||||
|  |     { | ||||||
|  |         return await PostIcs(new ModeusScheduleRequest(1000, DateTime.UtcNow.AddDays(-7), | ||||||
|  |             DateTime.UtcNow.AddMonths(1), null, new List<Guid> { attendeePersonId }, null, null, null, null, null, | ||||||
|  |             null, null)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,4 +1,7 @@ | |||||||
| using System.Text.Json; | using System.Text.Json; | ||||||
|  | using Ical.Net.CalendarComponents; | ||||||
|  | using Ical.Net.DataTypes; | ||||||
|  | using Ical.Net.Serialization; | ||||||
| using Microsoft.Net.Http.Headers; | using Microsoft.Net.Http.Headers; | ||||||
| using SfeduSchedule.Abstractions; | using SfeduSchedule.Abstractions; | ||||||
|  |  | ||||||
| @@ -75,5 +78,58 @@ namespace SfeduSchedule.Services | |||||||
|             return personId; |             return personId; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         public async Task<string?> GetIcsAsync(ModeusScheduleRequest msr) | ||||||
|  |         { | ||||||
|  |             var schedule = await GetScheduleAsync(msr); | ||||||
|  |             if (schedule == null) | ||||||
|  |             { | ||||||
|  |                 _logger.LogError("GetIcsAsync: Schedule is null. Request: {@msr}", msr); | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Schedule? scheduleJson; | ||||||
|  |             try | ||||||
|  |             { | ||||||
|  |                 scheduleJson = Schedule.FromJson(schedule); | ||||||
|  |             } | ||||||
|  |             catch (Exception ex) | ||||||
|  |             { | ||||||
|  |                 _logger.LogError(ex, "GetIcsAsync: Deserialization failed. Schedule: {Schedule}", schedule); | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (scheduleJson?.Embedded?.Events is not { Length: > 0 } events) | ||||||
|  |             { | ||||||
|  |                 if (scheduleJson == null) | ||||||
|  |                     _logger.LogError("GetIcsAsync: scheduleJson is null. Schedule: {Schedule}", schedule); | ||||||
|  |                 else if (scheduleJson.Embedded == null) | ||||||
|  |                     _logger.LogError("GetIcsAsync: scheduleJson.Embedded is null. scheduleJson: {@scheduleJson}", scheduleJson); | ||||||
|  |                 else if (scheduleJson.Embedded.Events == null) | ||||||
|  |                     _logger.LogError("GetIcsAsync: scheduleJson.Embedded.Events is null. Embedded: {@Embedded}", scheduleJson.Embedded); | ||||||
|  |                 else | ||||||
|  |                     _logger.LogWarning("GetIcsAsync: scheduleJson.Embedded.Events is empty. Embedded: {@Embedded}", scheduleJson.Embedded); | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var calendar = new Ical.Net.Calendar(); | ||||||
|  |             calendar.AddTimeZone(new VTimeZone(_configuration["TZ"]!)); | ||||||
|  |  | ||||||
|  |             foreach (var e in scheduleJson.Embedded.Events) | ||||||
|  |             { | ||||||
|  |                 calendar.Events.Add(new CalendarEvent | ||||||
|  |                 { | ||||||
|  |                     Summary = e.Name, | ||||||
|  |                     Description = e.NameShort, | ||||||
|  |                     Start = new CalDateTime(e.StartsAtLocal, _configuration["TZ"]!), | ||||||
|  |                     End = new CalDateTime(e.EndsAtLocal, _configuration["TZ"]!), | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             var serializer = new CalendarSerializer(); | ||||||
|  |             var serializedCalendar = serializer.SerializeToString(calendar); | ||||||
|  |             _logger.LogInformation("GetIcsAsync: Serialized calendar created. Length: {Length}", serializedCalendar?.Length ?? 0); | ||||||
|  |             return serializedCalendar; | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |          | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
|     </PropertyGroup> |     </PropertyGroup> | ||||||
|  |  | ||||||
|     <ItemGroup> |     <ItemGroup> | ||||||
|  |         <PackageReference Include="Ical.Net" Version="5.1.0" /> | ||||||
|         <PackageReference Include="Microsoft.Identity.Web" Version="3.14.0" /> |         <PackageReference Include="Microsoft.Identity.Web" Version="3.14.0" /> | ||||||
|         <PackageReference Include="Microsoft.Playwright" Version="1.55.0" /> |         <PackageReference Include="Microsoft.Playwright" Version="1.55.0" /> | ||||||
|         <PackageReference Include="Quartz.AspNetCore" Version="3.15.0" /> |         <PackageReference Include="Quartz.AspNetCore" Version="3.15.0" /> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user