using System; using System.Collections.Generic; using System.Linq; using API.DTOs; using API.Entities; using API.Entities.Enums; using API.Extensions; using API.Helpers.Builders; namespace API.Helpers; public static class PersonHelper { /// /// Given a list of all existing people, this will check the new names and roles and if it doesn't exist in allPeople, will create and /// add an entry. For each person in name, the callback will be executed. /// /// This does not remove people if an empty list is passed into names /// This is used to add new people to a list without worrying about duplicating rows in the DB /// /// /// /// public static void UpdatePeople(ICollection allPeople, IEnumerable names, PersonRole role, Action action) { // TODO: Validate if we need this, not used var allPeopleTypeRole = allPeople.Where(p => p.Role == role).ToList(); foreach (var name in names) { var normalizedName = name.ToNormalized(); var person = allPeopleTypeRole.FirstOrDefault(p => p.NormalizedName != null && p.NormalizedName.Equals(normalizedName)); if (person == null) { person = new PersonBuilder(name, role).Build(); allPeople.Add(person); } action(person); } } /// /// Remove people on a list for a given role /// /// Used to remove before we update/add new people /// Existing people on Entity /// People from metadata /// Role to filter on /// Callback which will be executed for each person removed public static void RemovePeople(ICollection existingPeople, IEnumerable people, PersonRole role, Action? action = null) { var normalizedPeople = people.Select(Services.Tasks.Scanner.Parser.Parser.Normalize).ToList(); if (normalizedPeople.Count == 0) { var peopleToRemove = existingPeople.Where(p => p.Role == role).ToList(); foreach (var existingRoleToRemove in peopleToRemove) { existingPeople.Remove(existingRoleToRemove); action?.Invoke(existingRoleToRemove); } return; } foreach (var person in normalizedPeople) { var existingPerson = existingPeople.FirstOrDefault(p => p.Role == role && person.Equals(p.NormalizedName)); if (existingPerson == null) continue; existingPeople.Remove(existingPerson); action?.Invoke(existingPerson); } } /// /// Removes all people that are not present in the removeAllExcept list. /// /// /// /// Callback for all entities that should be removed public static void KeepOnlySamePeopleBetweenLists(IEnumerable existingPeople, ICollection removeAllExcept, Action? action = null) { foreach (var person in existingPeople) { var existingPerson = removeAllExcept .FirstOrDefault(p => p.Role == person.Role && person.NormalizedName.Equals(p.NormalizedName)); if (existingPerson == null) { action?.Invoke(person); } } } /// /// Adds the person to the list if it's not already in there /// /// /// public static void AddPersonIfNotExists(ICollection metadataPeople, Person person) { if (string.IsNullOrEmpty(person.Name)) return; var existingPerson = metadataPeople.FirstOrDefault(p => p.NormalizedName == person.Name.ToNormalized() && p.Role == person.Role); if (existingPerson == null) { metadataPeople.Add(person); } } /// /// For a given role and people dtos, update a series /// /// /// /// /// /// This will call with an existing or new tag, but the method does not update the series Metadata /// public static void UpdatePeopleList(PersonRole role, ICollection? tags, Series series, IReadOnlyCollection allTags, Action handleAdd, Action onModified) { if (tags == null) return; var isModified = false; // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different var existingTags = series.Metadata.People.Where(p => p.Role == role).ToList(); foreach (var existing in existingTags) { if (tags.SingleOrDefault(t => t.Id == existing.Id) == null) // This needs to check against role { // Remove tag series.Metadata.People.Remove(existing); isModified = true; } } // At this point, all tags that aren't in dto have been removed. foreach (var tag in tags) { var existingTag = allTags.SingleOrDefault(t => t.Name == tag.Name && t.Role == tag.Role); if (existingTag != null) { if (series.Metadata.People.Where(t => t.Role == tag.Role).All(t => t.Name != null && !t.Name.Equals(tag.Name))) { handleAdd(existingTag); isModified = true; } } else { // Add new tag handleAdd(new PersonBuilder(tag.Name, role).Build()); isModified = true; } } if (isModified) { onModified(); } } }