Files
messengerapi/code/MessengerApi/Handlers/UserConfigHandler.cs

264 lines
10 KiB
C#

using MessengerApi.Configuration.Model;
using MessengerApi.Contracts.Factories;
using MessengerApi.Db.Entities;
using MessengerApi.Models;
using Microsoft.EntityFrameworkCore;
using System.Text;
namespace MessengerApi.Handlers
{
public class UserConfigHandler
{
private readonly MessengerConfiguration configuration;
private readonly ILogger logger;
private readonly IDbContextFactory dbContextFactory;
public UserConfigHandler(
MessengerConfiguration configuration,
ILogger logger,
IDbContextFactory dbContextFactory)
{
this.configuration = configuration;
this.logger = logger;
this.dbContextFactory = dbContextFactory;
}
public async Task<UserIngestionItem[]> GetItemsFromFile(FileInfo file)
{
if (file == null)
{
throw new InvalidOperationException("No file provided.");
}
else if (File.Exists(file.FullName) == false)
{
throw new FileNotFoundException($"Userfile doesn't exist: {this.configuration.UsersConfig.FullName}.");
}
var lines = await File.ReadAllLinesAsync(file.FullName, Encoding.UTF8);
var collection = new List<Tuple<UserIngestionItem, string>>();
foreach (var line in lines)
{
var columns = line.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var item = new UserIngestionItem();
item.UserName = columns[0];
item.IsEnabled = bool.Parse(columns[1]);
item.Id = Guid.Parse(columns[2]);
item.ApiKey = Guid.Parse(columns[3]);
var recipients = columns.Length == 5
? columns[4]
: null;
collection.Add(new Tuple<UserIngestionItem, string>(item, recipients));
this.logger.Trace($"Reading user {item.UserName} with ID {item.Id}");
}
foreach (var item in collection)
{
if(item.Item2 == null)
{
item.Item1.CanSendTo = [];
continue;
}
var names = item.Item2.Split(
',',
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
item.Item1.CanSendTo = names
.Select(x => collection.Single(c => c.Item1.UserName == x).Item1)
.ToArray();
this.logger.Trace($"User {item.Item1.UserName} has buddies {item.Item2}.");
}
return collection.Select(x => x.Item1).ToArray();
}
public Task<UserIngestionOperation[]> GetOperationsFromItems(UserIngestionItem[] fileItems)
{
if(fileItems == null)
{
throw new ArgumentNullException(nameof(fileItems));
}
using var context = this.dbContextFactory.CreateDbContext();
var existingUsers = context.Users.ToList();
var existingRoutes = context.UserRoutes.Include(x => x.From).Include(x => x.To).ToList();
var collection = new List<UserIngestionOperation>();
foreach (var item in fileItems)
{
var dbItem = context.Users.SingleOrDefault(x => x.Id == item.Id);
if (dbItem == null)
{
collection.Add(new UserIngestionOperation
{
Type = UserIngestionOperationTypes.Create,
Subtype = UserIngestionOperationSubtypes.AddUser,
Username = item.UserName,
Operation = (c) =>
{
c.Users.Local.Add(new User
{
Id = item.Id,
ApiKey = item.ApiKey,
IsEnabled = item.IsEnabled,
Name = item.UserName,
});
}
});
}
else
{
if(dbItem.ApiKey != item.ApiKey)
{
collection.Add(new UserIngestionOperation
{
Type = UserIngestionOperationTypes.Update,
Subtype = UserIngestionOperationSubtypes.ChangeUserApiKey,
Username = item.UserName,
Operation = (c) =>
{
c.Users.Single(x => x.Id == item.ApiKey).ApiKey = item.ApiKey;
}
});
}
if(dbItem.IsEnabled != item.IsEnabled)
{
collection.Add(new UserIngestionOperation
{
Type = UserIngestionOperationTypes.Update,
Subtype = UserIngestionOperationSubtypes.ChangeUserIsEnabled,
Username = item.UserName,
Operation = (c) =>
{
c.Users.Single(x => x.Id == item.ApiKey).IsEnabled = item.IsEnabled;
}
});
}
if (dbItem.Name != item.UserName)
{
collection.Add(new UserIngestionOperation
{
Type = UserIngestionOperationTypes.Update,
Subtype = UserIngestionOperationSubtypes.ChangeUserName,
Username = item.UserName,
Operation = (c) =>
{
c.Users.Single(x => x.Id == item.ApiKey).Name = item.UserName;
}
});
}
}
this.logger.Trace($"Processed line with {item.UserName}.");
}
this.logger.Debug("Finished evaluating add/update users, doing routes.");
foreach(var item in fileItems)
{
foreach(var com in item.CanSendTo)
{
this.logger.Trace($"Validating if {item.UserName} can send to {com.UserName}.");
var dbRoute = context.UserRoutes
.Include(x => x.From)
.Include(x => x.To)
.SingleOrDefault(x => x.From.Id == item.Id && x.To.Id == com.Id);
if(dbRoute == null)
{
collection.Add(new UserIngestionOperation
{
Type = UserIngestionOperationTypes.Create,
Subtype = UserIngestionOperationSubtypes.AddUserRoute,
Username = item.UserName,
Operation = (c) =>
{
var from = c.Users
.SingleOrDefault(x => x.Id == item.Id) ??
c.Users.Local.Single(x => x.Id == item.Id);
var to = c.Users
.SingleOrDefault(x => x.Id == com.Id) ??
c.Users.Local.Single(x => x.Id == com.Id);
c.Add(new UserRoute
{
From = from,
To = to
});
}
});
}
}
}
this.logger.Debug("Finished evaluating add userroutes, doing user deletes.");
foreach(var existingDbUser in existingUsers)
{
if(fileItems.Any(x=>x.Id == existingDbUser.Id) == false)
{
collection.Add(new UserIngestionOperation
{
Username = existingDbUser.Name,
Type = UserIngestionOperationTypes.Delete,
Subtype = UserIngestionOperationSubtypes.RemoveUser,
Operation = (c) =>
{
c.Remove(c.Users.Single(x => x.Id == existingDbUser.Id));
}
});
}
}
foreach (var existingRoute in existingRoutes)
{
if (fileItems.Any(fi => fi.CanSendTo.Any(fic => fi.Id == existingRoute.From.Id && fic.Id == existingRoute.To.Id)) == false)
{
collection.Add(new UserIngestionOperation
{
Username = existingRoute.From.Name,
Type = UserIngestionOperationTypes.Delete,
Subtype = UserIngestionOperationSubtypes.RemoveUserRoute,
Operation = (c) =>
{
c.Remove(c.UserRoutes.Single(x => x.Id == existingRoute.Id));
}
});
}
}
return Task.FromResult(collection.ToArray());
}
public async Task UpdateFromFile(FileInfo file)
{
var fileItems = await this.GetItemsFromFile(file);
var operations = await this.GetOperationsFromItems(fileItems);
using var context = this.dbContextFactory.CreateDbContext();
foreach(var operation in operations)
{
this.logger.Info(operation.ToString());
operation.Operation(context);
}
if(operations.Any())
{
await context.SaveChangesAsync();
}
}
}
}