Skip to content

Commit

Permalink
Merge pull request #1309 from ucdavis/JCS/SearchIamPerson
Browse files Browse the repository at this point in the history
Jcs/search iam person
  • Loading branch information
jSylvestre authored Sep 21, 2023
2 parents ff14e04 + fde2c9a commit ecd5a33
Show file tree
Hide file tree
Showing 15 changed files with 382 additions and 20 deletions.
3 changes: 2 additions & 1 deletion Keas.Core/Keas.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="ietws" Version="0.2.17" />
<PackageReference Include="libphonenumber-csharp" Version="8.12.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.DataAnnotations" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.15" />
Expand Down
7 changes: 7 additions & 0 deletions Keas.Core/Models/IamAuthSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Keas.Core.Models
{
public class IamAuthSettings
{
public string IamKey { get; set; }
}
}
181 changes: 181 additions & 0 deletions Keas.Core/Services/IUpdateFromIamService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using Keas.Core.Data;
using Keas.Core.Models;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ietws;
using Microsoft.EntityFrameworkCore;
using Serilog;

namespace Keas.Core.Services
{
public interface IUpdateFromIamService
{
Task<int> UpdateUsersFromLastModifiedDateInIam(DateTime modifiedAfterDate);
Task<int> UpdateAllUsersFromIam();
}

public class UpdateFromIamService : IUpdateFromIamService
{
private readonly IamAuthSettings _authSettings;
private readonly ApplicationDbContext _context;

public UpdateFromIamService(IOptions<IamAuthSettings> authSettings, ApplicationDbContext context)
{
_authSettings = authSettings.Value;
_context = context;
}

/// <summary>
/// Note, this may or will contain IAM ids that do not exist in peaks.
/// </summary>
/// <param name="modifiedAfterDate"></param>
/// <returns></returns>
public async Task<int> UpdateUsersFromLastModifiedDateInIam(DateTime modifiedAfterDate)
{
var count = 0;
try
{
Log.Information($"Update IAM by Modified Date - Starting for date {modifiedAfterDate}");
var clientws = new IetClient(_authSettings.IamKey);
var result = await clientws.People.Search(PeopleSearchField.modifyDateAfter, modifiedAfterDate.ToString("yyyy-MM-dd"));
Log.Information($"Update IAM by Modified Date - Number Changed: {result.ResponseData.Results.Length}");
if (result.ResponseData.Results.Length > 0)
{
var iamIds = result.ResponseData.Results.Select(a => a.IamId).ToList();

var batches = Batch(iamIds, 100);
foreach (var batch in batches)
{
var batchCount = 0;
var users = await _context.Users.Where(a => batch.Contains(a.Iam)).Include(a => a.People).ToListAsync();
foreach (var user in users)
{
var ietData = result.ResponseData.Results.Where(a => a.IamId == user.Iam).FirstOrDefault();
if (ietData != null)
{
if (user.FirstName != ietData.DFirstName || user.LastName != ietData.DLastName)
{
count++;
batchCount++;
user.FirstName = ietData.DFirstName;
user.LastName = ietData.DLastName;
//user.pronouns = ietData.DPronouns; //if we add pronouns
foreach (var person in user.People)
{
person.FirstName = ietData.DFirstName;
person.LastName = ietData.DLastName;
}
Log.Information($"Update IAM by Modified Date - Updating {user.Iam} from Iam.");
}
}
}
if (batchCount > 0)
{
await _context.SaveChangesAsync();
}
}


Log.Information($"Update IAM by Modified Date - Updating {count} users from Iam.");

}
}
catch (Exception ex)
{
Log.Error("Update IAM by Modified Date - Getting List of Users to Update.", ex);
}
return count;
}

/// <summary>
/// Don't run this on prod during working hours.
/// </summary>
/// <returns></returns>
public async Task<int> UpdateAllUsersFromIam()
{
Log.Information("UpdateAllUsersFromIam - Starting");
var clientws = new IetClient(_authSettings.IamKey);
//Take 100 users at a time and check them against IAM
var count = 0;
var currentBatch = 0;
var userIamIds = await _context.Users.Where(a => a.Iam != null).Select(a => a.Iam).ToListAsync();
var batches = Batch(userIamIds, 100);
foreach (var batch in batches)
{
currentBatch++;
Log.Information($"UpdateAllUsersFromIam - Starting batch number {currentBatch} .");
var batchCount = 0;
//Pause for 5 seconds to not overload IAM
await Task.Delay(5000);

var users = await _context.Users.Where(a => batch.Contains(a.Iam)).Include(a => a.People).ToListAsync();
foreach (var user in users)
{
var result = await clientws.People.Search(PeopleSearchField.iamId, user.Iam);
if (result != null && result.ResponseData.Results.Length > 0)
{
var ietData = result.ResponseData.Results.Where(a => a.IamId == user.Iam).FirstOrDefault();
if (ietData == null)
{
continue;
}

if (user.FirstName != ietData.DFirstName || user.LastName != ietData.DLastName)
{
count++;
batchCount++;
user.FirstName = ietData.DFirstName;
user.LastName = ietData.DLastName;
//user.pronouns = ietData.DPronouns; //if we add pronouns
foreach (var person in user.People)
{
person.FirstName = ietData.DFirstName;
person.LastName = ietData.DLastName;
}
Log.Information($"Updating {user.Iam} from Iam.");
}
}
}
if (batchCount > 0)
{
Log.Information($"UpdateAllUsersFromIam - Updated {batchCount} users .");
await _context.SaveChangesAsync();
}
}


Log.Information($"UpdateAllUsersFromIam - Updated total of {count} users .");


return count;
}

private static IEnumerable<IEnumerable<TSource>> Batch<TSource>(IEnumerable<TSource> source, int size)
{
TSource[] bucket = null;
var count = 0;

foreach (var item in source)
{
if (bucket == null)
bucket = new TSource[size];

bucket[count++] = item;
if (count != size)
continue;

yield return bucket;

bucket = null;
count = 0;
}

if (bucket != null && count > 0)
yield return bucket.Take(count);
}
}
}
43 changes: 43 additions & 0 deletions Keas.Jobs.LivedName/Keas.Jobs.LivedName.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<UserSecretsId>93abda06-2870-4006-81e8-1eecba3d977c</UserSecretsId>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.15" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.15" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.15" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Keas.Core\Keas.Core.csproj" />
<ProjectReference Include="..\Keas.Jobs.Core\Keas.Jobs.Core.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="run.cmd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="settings.job">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
65 changes: 65 additions & 0 deletions Keas.Jobs.LivedName/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.IO;
using System.Linq;
using Keas.Core.Data;
using Keas.Core.Helper;
using Keas.Core.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Keas.Core.Services;
using Keas.Jobs.Core;
using Serilog;
using Keas.Core.Extensions;

namespace Keas.Jobs.LivedName
{
public class Program : JobBase
{
private static ILogger _log;

static void Main(string[] args)
{
Configure();

var assembyName = typeof(Program).Assembly.GetName();
_log = Log.Logger
.ForContext("jobname", assembyName.Name)
.ForContext("jobid", Guid.NewGuid());

_log.Information("Running {job} build {build}", assembyName.Name, assembyName.Version);

// setup di
var provider = ConfigureServices();


UpdateLivedNames(provider);


}

private static void UpdateLivedNames(ServiceProvider provider)
{
Log.Information("Staring UpdateLivedNames");
var updateService = provider.GetService<IUpdateFromIamService>();
var count = updateService.UpdateUsersFromLastModifiedDateInIam(DateTime.UtcNow.AddDays(-1).ToPacificTime().Date).GetAwaiter().GetResult();
Log.Information("Updated {count} users", count);
Log.Information("Finished UpdateLivedNames");

}

private static ServiceProvider ConfigureServices()
{
IServiceCollection services = new ServiceCollection();
services.AddOptions();
services.AddDbContextPool<ApplicationDbContext>(o => o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.Configure<IamAuthSettings>(Configuration.GetSection("Authentication"));

services.AddTransient<IUpdateFromIamService, UpdateFromIamService>();

return services.BuildServiceProvider();
}
}
}
10 changes: 10 additions & 0 deletions Keas.Jobs.LivedName/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"profiles": {
"Keas.Jobs.LivedName": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
8 changes: 8 additions & 0 deletions Keas.Jobs.LivedName/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\sqlexpress;Database=keas;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Authentication": {
"IamKey": "[External]"
}
}
3 changes: 3 additions & 0 deletions Keas.Jobs.LivedName/run.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off

dotnet Keas.Jobs.LivedName.dll
3 changes: 3 additions & 0 deletions Keas.Jobs.LivedName/settings.job
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schedule": "0 0 10 * * *"
}
32 changes: 27 additions & 5 deletions Keas.Mvc/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
using Keas.Core.Models;
using Microsoft.AspNetCore.Authorization;
using Keas.Mvc.Services;

using Keas.Core.Extensions;
using Keas.Core.Services;

namespace Keas.Mvc.Controllers
{
[Authorize(Policy = AccessCodes.Codes.SystemAdminAccess)]
Expand All @@ -17,13 +19,33 @@ public class AdminController : SuperController
private readonly ApplicationDbContext _context;
private readonly IIdentityService _identityService;

private readonly IUserService _userService;

public AdminController(ApplicationDbContext context, IIdentityService identityService, IUserService userService)
private readonly IUserService _userService;
private readonly IUpdateFromIamService _updateFromIamService;

public AdminController(ApplicationDbContext context, IIdentityService identityService, IUserService userService, IUpdateFromIamService updateFromIamService)
{
_context = context;
_identityService = identityService;
_userService = userService;
_userService = userService;
_updateFromIamService = updateFromIamService;
}

public async Task<IActionResult> UpdateFromIam()
{
var xxx = await _updateFromIamService.UpdateUsersFromLastModifiedDateInIam(System.DateTime.UtcNow.ToPacificTime().Date.AddDays(-1));

return Content(xxx.ToString());
}

/// <summary>
/// Don't run this against prod during work hours. It will take a long time.
/// </summary>
/// <returns></returns>
public async Task<IActionResult> UpdateAllFromIam()
{
var xxx = await _updateFromIamService.UpdateAllUsersFromIam();

return Content(xxx.ToString());
}

public async Task<IActionResult> Index()
Expand Down
Loading

0 comments on commit ecd5a33

Please sign in to comment.