Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public void SetUserAuthToken(string token)
return
new EventDataResponseDTO
{
Version = 1,
Id = 1,
Version = 0, //Set to 0 so if we ever connect this to a real API then it will update!
TimeSlots = new[]
{
new TimeSlotDTO
Expand Down
12 changes: 0 additions & 12 deletions PocketDDD.Server/PocketDDD.Server.DB/Migrations/2025_SeedData.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@ delete TimeSlots
delete Tracks
delete EventDetail


GO

-- Reset the identity columns
DBCC CHECKIDENT ('[Tracks]', RESEED, 0);
DBCC CHECKIDENT ('[TimeSlots]', RESEED, 0);
DBCC CHECKIDENT ('[Sessions]', RESEED, 0);

-- There is hardcoding to EventDetail ID 1 so we reset to 1 not 0
DBCC CHECKIDENT ('[EventDetail]', RESEED, 1); -- Use if this is a brand new table that has never been used before
--DBCC CHECKIDENT ('[EventDetail]', RESEED, 0); -- Use if this is an empty table that used to have rows

GO

-- Add 2025 Sessionize ID
Expand Down
110 changes: 63 additions & 47 deletions PocketDDD.Server/PocketDDD.Server.Services/EventDataService.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,79 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using PocketDDD.Server.DB;
using PocketDDD.Server.Model.DTOs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PocketDDD.Shared.API.RequestDTOs;
using PocketDDD.Shared.API.ResponseDTOs;

namespace PocketDDD.Server.Services;
public class EventDataService

public class EventDataService(PocketDDDContext dbContext, IMemoryCache memoryCache, ILogger<EventDataService> logger)
{
private readonly PocketDDDContext dbContext;
private const string FetchLatestEventDataCacheKey = nameof(FetchLatestEventData);
private const string FetchCurrentEventDetailIdCacheKey = nameof(FetchCurrentEventDetailId);

public EventDataService(PocketDDDContext dbContext)
public async Task<int> FetchCurrentEventDetailId()
{
this.dbContext = dbContext;
if (memoryCache.TryGetValue<int?>(FetchCurrentEventDetailIdCacheKey, out var cachedEventDetailId))
return cachedEventDetailId!.Value;

cachedEventDetailId = await dbContext.EventDetail.MaxAsync(e => e.Id);
memoryCache.Set(FetchCurrentEventDetailIdCacheKey, cachedEventDetailId, TimeSpan.FromMinutes(5));

return cachedEventDetailId.Value;
}

public async Task<EventDataResponseDTO?> FetchLatestEventData(EventDataUpdateRequestDTO requestDTO)
public async Task<EventDataResponseDTO?> FetchLatestEventData(EventDataUpdateRequestDTO requestDto)
{
var eventDetails = await dbContext.EventDetail
.Include(x => x.TimeSlots)
.Include(x => x.Tracks)
.Include(x => x.Sessions)
.SingleAsync(x => x.Id == 1);

if (requestDTO.Version == eventDetails!.Version)
var currentEventDetailId = await FetchCurrentEventDetailId();

if (memoryCache.TryGetValue<EventDataResponseDTO?>(FetchLatestEventDataCacheKey, out var latestEventData))
{
logger.LogDebug("Retrieved latest event data from the cache {eventData}", latestEventData);
}
else
{
logger.LogDebug("No event data in the cache, retrieving from the db");
latestEventData = await dbContext.EventDetail
.AsNoTracking()
.AsSingleQuery()
.Select(eventDetails => new EventDataResponseDTO
{
Id = eventDetails.Id,
Version = eventDetails.Version,
TimeSlots = eventDetails.TimeSlots.Select(ts => new TimeSlotDTO
{
Id = ts.Id,
Info = ts.Info,
From = ts.From,
To = ts.To
}).ToList(),
Tracks = eventDetails.Tracks.Select(t => new TrackDTO
{
Id = t.Id,
Name = t.Name,
RoomName = t.RoomName
}).ToList(),
Sessions = eventDetails.Sessions.Select(s => new SessionDTO
{
Id = s.Id,
Title = s.Title,
ShortDescription = s.ShortDescription,
FullDescription = s.FullDescription,
Speaker = s.Speaker,
TimeSlotId = s.TimeSlot.Id,
TrackId = s.Track.Id
}).ToList()
})
.SingleAsync(e => e.Id == currentEventDetailId);

memoryCache.Set(FetchLatestEventDataCacheKey, latestEventData, TimeSpan.FromMinutes(5));
logger.LogDebug("Updated the latest event data in the cache {eventData}", latestEventData);
}

if (requestDto.Version >= latestEventData!.Version)
return null;

var dtoResponse = new EventDataResponseDTO
{
Version = eventDetails.Version,
TimeSlots = eventDetails.TimeSlots.Select(ts => new TimeSlotDTO
{
Id = ts.Id,
Info = ts.Info,
From = ts.From,
To = ts.To
}).ToList(),
Tracks = eventDetails.Tracks.Select(t => new TrackDTO
{
Id = t.Id,
Name = t.Name,
RoomName = t.RoomName
}).ToList(),
Sessions = eventDetails.Sessions.Select(s => new SessionDTO
{
Id = s.Id,
Title = s.Title,
ShortDescription = s.ShortDescription,
FullDescription = s.FullDescription,
Speaker = s.Speaker,
TimeSlotId = s.TimeSlot.Id,
TrackId = s.Track.Id
}).ToList()
};

return dtoResponse;
return latestEventData;
}
}
24 changes: 7 additions & 17 deletions PocketDDD.Server/PocketDDD.Server.Services/RegistrationService.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
using PocketDDD.Server.DB;
using System.Security.Cryptography;
using PocketDDD.Server.DB;
using PocketDDD.Server.Model.DBModel;
using PocketDDD.Server.Model.DTOs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using PocketDDD.Shared.API.RequestDTOs;
using PocketDDD.Shared.API.ResponseDTOs;

namespace PocketDDD.Server.Services;
public class RegistrationService
{
private readonly PocketDDDContext dbContext;

public RegistrationService(PocketDDDContext dbContext)
{
this.dbContext = dbContext;
}

public class RegistrationService(PocketDDDContext dbContext, EventDataService eventDataService)
{
public async Task<LoginResultDTO> Register(RegisterDTO dto)
{
var currentEventDetailId = await eventDataService.FetchCurrentEventDetailId();

var user = new User
{
EventDetailId = 1,
EventDetailId = currentEventDetailId,
Name = dto.Name,
Token = GenerateBearerToken(),
EventScore = 1
Expand Down
71 changes: 57 additions & 14 deletions PocketDDD.Server/PocketDDD.Server.Services/SessionizeService.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
using Microsoft.EntityFrameworkCore;
using System.Net.Http.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PocketDDD.Server.DB;
using PocketDDD.Server.Model.DBModel;
using PocketDDD.Server.Model.Sessionize;
using System.Net.Http.Json;
using Session = PocketDDD.Server.Model.DBModel.Session;

namespace PocketDDD.Server.Services;

public class SessionizeService
{
private readonly HttpClient httpClient;
private readonly PocketDDDContext dbContext;
private readonly HttpClient httpClient;

public SessionizeService(HttpClient httpClient, PocketDDDContext dbContext)
public SessionizeService(HttpClient httpClient, PocketDDDContext dbContext, ILogger<SessionizeService> logger)
{
Logger = logger;
this.httpClient = httpClient;
this.dbContext = dbContext;
httpClient.BaseAddress = new Uri("https://sessionize.com/api/v2/");
}

private ILogger<SessionizeService> Logger { get; }

public async Task UpdateFromSessionize()
{
var dbEvent = await dbContext.EventDetail.SingleAsync(x => x.Id == 1);
Logger.LogInformation("Looking for event detail in database");

var dbEvent = await dbContext.EventDetail.OrderBy(x => x.Id).LastAsync();
var sessionizeEventId = dbEvent.SessionizeId;

Logger.LogInformation("About to get data from Sessionize API");

var sessionizeEvent = await httpClient.GetFromJsonAsync<SessionizeEvent>($"{sessionizeEventId}/view/All");

if (sessionizeEvent is null)
throw new ArgumentNullException(nameof(sessionizeEvent));

var dbTracks = await dbContext.Tracks.ToListAsync();
Logger.LogInformation("Information retrieved from Sessionize API");
Logger.LogInformation("Looking for changes to rooms");

var dbTracks = await dbContext.Tracks.Where(track => track.EventDetail.Id == dbEvent.Id).ToListAsync();
foreach (var item in sessionizeEvent.rooms)
{
var dbTrack = dbTracks.SingleOrDefault(x => x.SessionizeId == item.id);
Expand All @@ -46,10 +58,21 @@ public async Task UpdateFromSessionize()
dbTrack.Name = $"Track {item.sort}";
}

await dbContext.SaveChangesAsync();
if (dbContext.ChangeTracker.HasChanges())
{
dbEvent.Version++;
Logger.LogInformation("Updating db with changes to rooms");
await dbContext.SaveChangesAsync();
}
else
{
Logger.LogInformation("No changes to rooms were detected");
}

Logger.LogInformation("Looking for changes to time slots and breaks");

var dbTimeSlots = await dbContext.TimeSlots.ToListAsync();
var dbTimeSlots = await dbContext.TimeSlots.Where(timeSlot => timeSlot.EventDetail.Id == dbEvent.Id)
.ToListAsync();
var sessionizeTimeSlots = sessionizeEvent.sessions
.Select(x => (x.startsAt, x.endsAt, x.isServiceSession,
serviceSessionDetails: x.isServiceSession ? x.title : null))
Expand All @@ -65,17 +88,28 @@ public async Task UpdateFromSessionize()
{
EventDetail = dbEvent,
From = item.startsAt,
To = item.endsAt,
Info = item.isServiceSession ? item.serviceSessionDetails : null
To = item.endsAt
};
dbContext.TimeSlots.Add(dbTimeSlot);
}

dbTimeSlot.Info = item.isServiceSession ? item.serviceSessionDetails : null;
}

await dbContext.SaveChangesAsync();
if (dbContext.ChangeTracker.HasChanges())
{
dbEvent.Version++;
Logger.LogInformation("Updating db with changes to time slots and breaks");
await dbContext.SaveChangesAsync();
}
else
{
Logger.LogInformation("No changes to time slots or breaks were detected");
}

Logger.LogInformation("Looking for changes to sessions");

var dbSessions = await dbContext.Sessions.ToListAsync();
var dbSessions = await dbContext.Sessions.Where(session => session.EventDetail.Id == dbEvent.Id).ToListAsync();
var speakers = sessionizeEvent.speakers;
dbTracks = await dbContext.Tracks.ToListAsync();
dbTimeSlots = await dbContext.TimeSlots.ToListAsync();
Expand All @@ -89,7 +123,7 @@ public async Task UpdateFromSessionize()
var dbSession = dbSessions.SingleOrDefault(x => x.SessionizeId == sessionizeId);
if (dbSession == null)
{
dbSession = new Model.DBModel.Session
dbSession = new Session
{
SessionizeId = sessionizeId,
EventDetail = dbEvent,
Expand All @@ -106,7 +140,16 @@ public async Task UpdateFromSessionize()
dbSession.TimeSlot = GetTimeSlot(dbTimeSlots, item.startsAt, item.endsAt);
}

await dbContext.SaveChangesAsync();
if (dbContext.ChangeTracker.HasChanges())
{
dbEvent.Version++;
Logger.LogInformation("Updating db with changes to sessions");
await dbContext.SaveChangesAsync();
}
else
{
Logger.LogInformation("No changes to sessions were detected");
}
}

private string GetSpeakers(List<Speaker> speakers, List<string> speakerIds)
Expand Down
5 changes: 5 additions & 0 deletions PocketDDD.Server/PocketDDD.Server.WebAPI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PocketDDD.Server.DB;
using PocketDDD.Server.Services;
using PocketDDD.Server.WebAPI;
using PocketDDD.Server.WebAPI.Authentication;

var corsPolicy = "corsPolicy";
Expand Down Expand Up @@ -28,6 +29,8 @@
options => options.UseSqlServer("name=ConnectionStrings:PocketDDDContext")
);

builder.Services.AddMemoryCache();

builder.Services.AddScoped<RegistrationService>();
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped<FeedbackService>();
Expand All @@ -37,6 +40,8 @@

builder.Services.AddHttpClient<SessionizeService>();

builder.Services.AddHostedService<UpdateFromSessionizeBackgroundService>();

builder.Services.AddAuthentication()
.AddScheme<UserIsRegisteredOptions, UserIsRegisteredAuthHandler>(UserIsRegisteredAuthHandler.SchemeName, null);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using PocketDDD.Server.Services;

namespace PocketDDD.Server.WebAPI;

public class UpdateFromSessionizeBackgroundService(
IServiceProvider services,
ILogger<UpdateFromSessionizeBackgroundService> logger)
: BackgroundService
{
private ILogger<UpdateFromSessionizeBackgroundService> Logger { get; } = logger;
private IServiceProvider Services { get; } = services;

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Logger.LogInformation("Update from Sessionize background task started.");

while (!stoppingToken.IsCancellationRequested)
{
Logger.LogInformation("About to update from Sessionize.");
try
{
using var scope = Services.CreateScope();

var sessionizeService = scope.ServiceProvider.GetRequiredService<SessionizeService>();
await sessionizeService.UpdateFromSessionize();

Logger.LogInformation("Update from Sessionize complete.");
}
catch (Exception e)
{
Logger.LogError(e, "Update from Sessionize failed.");
}

await Task.Delay(TimeSpan.FromMinutes(30), stoppingToken);
}
}
}
Loading
Loading