Files
SfeduSchedule/SfeduSchedule/Services/ModeusService.cs
Sergey Karmanov d726e28876
All checks were successful
Create and publish a Docker image / Publish image (push) Successful in 4m58s
Улучшил логгирование
2025-10-24 12:58:15 +03:00

278 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text.Json;
using Ical.Net.CalendarComponents;
using Ical.Net.DataTypes;
using Ical.Net.Serialization;
using Microsoft.Net.Http.Headers;
using SfeduSchedule.Abstractions;
namespace SfeduSchedule.Services
{
public class ModeusService
{
private readonly HttpClient _httpClient;
private readonly ILogger<ModeusService> _logger;
private readonly IConfiguration _configuration;
public ModeusService(HttpClient httpClient, ILogger<ModeusService> logger, IConfiguration configuration)
{
_httpClient = httpClient;
_logger = logger;
_configuration = configuration;
_httpClient.BaseAddress = new Uri("https://sfedu.modeus.org/");
var token = _configuration["TOKEN"];
_httpClient.DefaultRequestHeaders.Add(HeaderNames.Authorization, $"Bearer {token}");
}
public async Task<string?> GetScheduleAsync(ModeusScheduleRequest msr)
{
var request = new HttpRequestMessage(HttpMethod.Post,
$"schedule-calendar-v2/api/calendar/events/search?tz={_configuration["TZ"]!}");
request.Content = new StringContent(JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions),
System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
_logger.LogInformation("GetScheduleAsync: Ответ получен: {StatusCode}", response.StatusCode);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
public async Task<List<Attendees>> GetAttendeesAsync(Guid eventId)
{
var request = new HttpRequestMessage(HttpMethod.Get,
$"schedule-calendar-v2/api/calendar/events/{eventId}/attendees");
var response = await _httpClient.SendAsync(request);
_logger.LogInformation("GetAttendeesAsync: Ответ получен: {StatusCode}", response.StatusCode);
response.EnsureSuccessStatusCode();
List<Attendees>? attendees;
try
{
attendees = Attendees.FromJson(await response.Content.ReadAsStringAsync());
return attendees;
}
catch (Exception ex)
{
_logger.LogError(ex, "GetAttendeesAsync: Deserialization failed.");
}
return new List<Attendees>();
}
public async Task<string?> SearchRoomsAsync(RoomSearchRequest requestDto)
{
var request = new HttpRequestMessage(HttpMethod.Post, $"schedule-calendar-v2/api/campus/rooms/search");
request.Content =
new StringContent(JsonSerializer.Serialize(requestDto, GlobalVariables.JsonSerializerOptions),
System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
_logger.LogInformation("SearchRoomsAsync: Ответ получен: {StatusCode}", response.StatusCode);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
public async Task<string?> GetGuidAsync(string fullName)
{
var request = new HttpRequestMessage(HttpMethod.Post, $"schedule-calendar-v2/api/people/persons/search");
request.Content = new StringContent(JsonSerializer.Serialize(new
{
fullName = fullName,
sort = "+fullName",
size = 10,
page = 0
}), System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
_logger.LogInformation("GetGuidAsync: Ответ получен: {StatusCode}", response.StatusCode);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
string? personId;
try
{
personId = JsonDocument.Parse(json).RootElement
.GetProperty("_embedded")
.GetProperty("persons")[0]
.GetProperty("id")
.GetString();
}
catch
{
_logger.LogWarning(
"GetGuidAsync: Не удалось получить идентификатор пользователя, {FullName}, json: {Json}", fullName,
json);
return null;
}
return personId;
}
public async Task<Schedule?> GetScheduleJsonAsync(ModeusScheduleRequest msr)
{
var schedule = await GetScheduleAsync(msr);
if (schedule == null)
{
_logger.LogError("GetScheduleJsonAsync: Schedule is null. Request: {@msr}", msr);
throw new Exception("Schedule is null");
}
Schedule? scheduleJson;
try
{
scheduleJson = Schedule.FromJson(schedule);
switch (scheduleJson)
{
case null:
_logger.LogError(
"GetScheduleJsonAsync: scheduleJson is null. Schedule: {Schedule}\n Request: {msr}",
schedule, JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
break;
case { Embedded: null }:
_logger.LogError(
"GetScheduleJsonAsync: scheduleJson.Embedded is null. Response: {@response}\nscheduleJson: {@scheduleJson}\n Request: {msr}",
schedule, scheduleJson, JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
break;
case { Embedded.Events: null }:
_logger.LogError(
"GetScheduleJsonAsync: scheduleJson.Embedded.Events is null. Response: {@response}\nEmbedded: {@Embedded}\n Request: {msr}",
schedule, scheduleJson.Embedded, JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
break;
case { Embedded.Events.Length: 0 }:
_logger.LogWarning(
"GetScheduleJsonAsync: scheduleJson.Embedded.Events is empty. Embedded: {@Embedded}\n Request: {msr}",
scheduleJson.Embedded, JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
break;
default:
return scheduleJson;
}
}
catch (Exception ex)
{
_logger.LogError(ex,
"GetScheduleJsonAsync: Deserialization failed. Schedule: {Schedule}\n Request: {msr}", schedule,
JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
}
return null;
}
public async Task<string?> GetIcsAsync(ModeusScheduleRequest msr)
{
Schedule? scheduleJson = await GetScheduleJsonAsync(msr);
if (scheduleJson == null)
{
_logger.LogError("GetIcsAsync: scheduleJson is null after deserialization. Request: " + JsonSerializer.Serialize(msr, GlobalVariables.JsonSerializerOptions));
return null;
}
var calendar = new Ical.Net.Calendar();
calendar.AddTimeZone(new VTimeZone(_configuration["TZ"]!));
foreach (var e in scheduleJson.Embedded.Events)
{
// Получение названия аудитории для события
string? roomName = null;
if (scheduleJson.Embedded.EventLocations != null && scheduleJson.Embedded.Rooms != null &&
scheduleJson.Embedded.EventRooms != null)
{
var eventLocation = scheduleJson.Embedded.EventLocations.FirstOrDefault(el => el.EventId == e.Id);
if (eventLocation != null
&& eventLocation.Links != null
&& eventLocation.Links.EventRooms != null
&& eventLocation.Links.EventRooms.Href != null)
{
var eventRoomId = eventLocation.Links.EventRooms.Href.Split('/').Last();
var EventRoom =
scheduleJson.Embedded.EventRooms.FirstOrDefault(er =>
er.Id.ToString().ToLower() == eventRoomId);
if (EventRoom != null)
{
var roomId = EventRoom.Links.Room.Href.Split('/').Last();
var room = scheduleJson.Embedded.Rooms.FirstOrDefault(r =>
r.Id.ToString().ToLower() == roomId);
if (room != null)
roomName = room.Name;
}
}
}
// Получение преподавателей для события
string teachersNames = "";
if (scheduleJson.Embedded.EventOrganizers != null && scheduleJson.Embedded.EventAttendees != null &&
scheduleJson.Embedded.Persons != null)
{
// Получаем eventOrganizer
var eventOrganizers =
scheduleJson.Embedded.EventOrganizers.FirstOrDefault(eo => eo.EventId == e.Id);
if (eventOrganizers != null &&
eventOrganizers.Links.EventAttendees != null)
{
// Получаем eventAttendee id
// Тут может прийти массив или 1 объект
Self[] eventAttendeeIds = Array.Empty<Self>();
if (eventOrganizers.Links.EventAttendees.Value.Self != null)
eventAttendeeIds = new[] { eventOrganizers.Links.EventAttendees.Value.Self };
else if (eventOrganizers.Links.EventAttendees.Value.SelfArray != null)
eventAttendeeIds = eventOrganizers.Links.EventAttendees.Value.SelfArray;
if (eventAttendeeIds.Length > 0)
{
foreach (var eventAttendeeId in eventAttendeeIds)
{
var attendeeId = eventAttendeeId.Href.Split('/').Last();
// Получаем eventAttendee
var eventAttendee =
scheduleJson.Embedded.EventAttendees.FirstOrDefault(ea =>
ea.Id.ToString().ToLower() == attendeeId);
if (eventAttendee != null)
{
var personId = eventAttendee.Links.Person.Href.Split('/').Last();
// Получаем person
var teacher = scheduleJson.Embedded.Persons.FirstOrDefault(p =>
p.Id.ToString().ToLower() == personId);
if (teacher != null)
teachersNames += (string.IsNullOrEmpty(teachersNames) ? "" : ", ") +
teacher.FullName;
}
}
}
}
}
// Получение короткого названия для события
string shortNameCourse = "";
if (scheduleJson.Embedded.CourseUnitRealizations != null)
{
try
{
var courseUnitRealizationsLinks = e.Links["course-unit-realization"];
var courseUnitRealizationId = courseUnitRealizationsLinks.Href.Split('/').Last();
if (!string.IsNullOrEmpty(courseUnitRealizationId))
{
var courseUnitRealization = scheduleJson.Embedded.CourseUnitRealizations
.FirstOrDefault(cu => cu.Id.ToString().ToLower() == courseUnitRealizationId);
if (courseUnitRealization != null)
shortNameCourse = courseUnitRealization.NameShort ?? "";
}
}
catch (Exception)
{
// Ignored
}
}
calendar.Events.Add(new CalendarEvent
{
Summary = (string.IsNullOrEmpty(shortNameCourse) ? "" : shortNameCourse + " / ") + e.Name,
Description = e.NameShort + (string.IsNullOrEmpty(roomName) ? "" : $"\nАудитория: {roomName}") +
(string.IsNullOrEmpty(teachersNames) ? "" : $"\nПреподаватели: {teachersNames}"),
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;
}
}
}