264 lines
10 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
}
|