Skip to content

Commit

Permalink
- Adding duplicate user detection and merging
Browse files Browse the repository at this point in the history
  • Loading branch information
SaviorXTanren committed Nov 14, 2023
1 parent f300b3a commit 0e1a212
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 75 deletions.
72 changes: 72 additions & 0 deletions MixItUp.Base/Model/User/UserV2Model.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using MixItUp.Base.Model.User.Platform;
using MixItUp.Base.Services;
using MixItUp.Base.ViewModel.User;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;

namespace MixItUp.Base.Model.User
{
Expand Down Expand Up @@ -118,6 +121,75 @@ public string GetPlatformDisplayName(StreamingPlatformTypeEnum platform)

public IEnumerable<string> GetAllPlatformDisplayNames() { return (this.PlatformData.Count > 0) ? this.PlatformData.Select(p => p.Value.DisplayName ?? p.Value.Username) : new List<string>(); }

public void MergeUserData(UserV2Model other)
{
this.OnlineViewingMinutes += other.OnlineViewingMinutes;

foreach (var kvp in other.CurrencyAmounts)
{
if (!this.CurrencyAmounts.ContainsKey(kvp.Key))
{
this.CurrencyAmounts[kvp.Key] = 0;
}
this.CurrencyAmounts[kvp.Key] += kvp.Value;
}

foreach (var kvp in other.InventoryAmounts)
{
if (!this.InventoryAmounts.ContainsKey(kvp.Key))
{
this.InventoryAmounts[kvp.Key] = new Dictionary<Guid, int>();
}

foreach (var itemKVP in kvp.Value)
{
if (!this.InventoryAmounts[kvp.Key].ContainsKey(itemKVP.Key))
{
this.InventoryAmounts[kvp.Key][itemKVP.Key] = 0;
}
this.InventoryAmounts[kvp.Key][itemKVP.Key] += itemKVP.Value;
}
}

foreach (var kvp in other.StreamPassAmounts)
{
if (!this.StreamPassAmounts.ContainsKey(kvp.Key))
{
this.StreamPassAmounts[kvp.Key] = 0;
}
this.StreamPassAmounts[kvp.Key] += kvp.Value;
}

if (string.IsNullOrEmpty(this.CustomTitle)) { this.CustomTitle = other.CustomTitle; }
if (!this.IsSpecialtyExcluded) { this.IsSpecialtyExcluded = other.IsSpecialtyExcluded; }
if (this.EntranceCommandID == Guid.Empty) { this.EntranceCommandID = other.EntranceCommandID; }

foreach (Guid id in other.CustomCommandIDs)
{
this.CustomCommandIDs.Add(id);
}

if (string.IsNullOrEmpty(this.PatreonUserID)) { this.PatreonUserID = other.PatreonUserID; }

if (string.IsNullOrEmpty(this.Notes))
{
this.Notes = other.Notes;
}
else if (!string.IsNullOrEmpty(other.Notes))
{
this.Notes += Environment.NewLine + Environment.NewLine + other.Notes;
}

this.TotalStreamsWatched += other.TotalStreamsWatched;
this.TotalAmountDonated += other.TotalAmountDonated;
this.TotalSubsGifted += other.TotalSubsGifted;
this.TotalSubsReceived += other.TotalSubsReceived;
this.TotalChatMessageSent += other.TotalChatMessageSent;
this.TotalTimesTagged += other.TotalTimesTagged;
this.TotalCommandsRun += other.TotalCommandsRun;
this.TotalMonthsSubbed += other.TotalMonthsSubbed;
}

public override bool Equals(object obj)
{
if (obj is UserV2Model)
Expand Down
77 changes: 67 additions & 10 deletions MixItUp.Base/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using MixItUp.Base.Util;
using MixItUp.Base.ViewModel.Chat;
using MixItUp.Base.ViewModel.User;
using StreamingClient.Base.Util;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -71,8 +72,8 @@ public async Task<UserV2ViewModel> GetUserByID(Guid id)
IEnumerable<UserV2Model> results = await ChannelSession.Settings.LoadUserV2Data("SELECT * FROM Users WHERE ID = $ID", new Dictionary<string, object>() { { "$ID", id.ToString() } });
if (results.Count() > 0)
{
this.SetUserData(results.First());
return new UserV2ViewModel(ChannelSession.Settings.DefaultStreamingPlatform, results.First());
UserV2Model userData = this.SetUserData(results.First());
return new UserV2ViewModel(ChannelSession.Settings.DefaultStreamingPlatform, userData);
}

return null;
Expand Down Expand Up @@ -104,8 +105,15 @@ public async Task<UserV2ViewModel> GetUserByPlatformID(StreamingPlatformTypeEnum
IEnumerable<UserV2Model> results = await ChannelSession.Settings.LoadUserV2Data($"SELECT * FROM Users WHERE {platform.ToString()}ID = $PlatformID", new Dictionary<string, object>() { { "$PlatformID", platformID } });
if (results.Count() > 0)
{
this.SetUserData(results.First());
return new UserV2ViewModel(platform, results.First());
// Check if there is more than 1 user record and if so, merge them together
UserV2Model userData = results.First();
if (results.Count() > 1)
{
userData = this.MergeData(results);
}

userData = this.SetUserData(userData);
return new UserV2ViewModel(platform, userData);
}

if (performPlatformSearch)
Expand Down Expand Up @@ -185,8 +193,15 @@ await StreamingPlatforms.ForEachPlatform(async (p) =>
IEnumerable<UserV2Model> results = await ChannelSession.Settings.LoadUserV2Data($"SELECT * FROM Users WHERE {platform}Username = $PlatformUsername", new Dictionary<string, object>() { { "$PlatformUsername", platformUsername } });
if (results.Count() > 0)
{
this.SetUserData(results.First());
return new UserV2ViewModel(platform, results.First());
// Check if there is more than 1 user record and if so, merge them together
UserV2Model userData = results.First();
if (results.Count() > 1)
{
userData = this.MergeData(results);
}

userData = this.SetUserData(userData);
return new UserV2ViewModel(platform, userData);
}

if (performPlatformSearch)
Expand Down Expand Up @@ -316,6 +331,7 @@ public void DeleteUserData(Guid id)

ChannelSession.Settings.Users.Remove(user.ID);
}
ChannelSession.Settings.Users.ManualValueDeleted(id);
}

public async Task ClearUserDataRange(int days)
Expand Down Expand Up @@ -356,10 +372,11 @@ public async Task ClearAllUserData()
await ServiceManager.Get<IDatabaseService>().Write(ChannelSession.Settings.DatabaseFilePath, "DELETE FROM ImportedUsers");
}

public void SetUserData(UserV2Model userData)
public UserV2Model SetUserData(UserV2Model userData)
{
if (userData != null && userData.ID != Guid.Empty && userData.GetPlatforms().Count() > 0 && !userData.HasPlatformData(StreamingPlatformTypeEnum.None))
{
UserV2Model userDataToDelete = null;
lock (ChannelSession.Settings.Users)
{
if (!ChannelSession.Settings.Users.ContainsKey(userData.ID))
Expand All @@ -378,6 +395,23 @@ public void SetUserData(UserV2Model userData)
UserPlatformV2ModelBase platformModel = userData.GetPlatformData<UserPlatformV2ModelBase>(platform);
if (platformModel != null)
{
// Check if there is more than 1 user record and if so, merge them together
try
{
if (this.platformUserIDLookups[platform].TryGetValue(platformModel.ID, out Guid existingUserID) &&
existingUserID != userData.ID &&
ChannelSession.Settings.Users.TryGetValue(existingUserID, out UserV2Model existingUserData))
{
existingUserData.MergeUserData(userData);
userDataToDelete = userData;
userData = existingUserData;
}
}
catch (Exception ex)
{
Logger.Log(ex);
}

this.platformUserIDLookups[platform][platformModel.ID] = userData.ID;
if (!string.IsNullOrEmpty(platformModel.Username))
{
Expand All @@ -390,19 +424,37 @@ public void SetUserData(UserV2Model userData)
}
}
}

if (userDataToDelete != null)
{
this.DeleteUserData(userDataToDelete.ID);
}
}
return userData;
}

private UserV2Model MergeData(IEnumerable<UserV2Model> users)
{
UserV2Model primaryUserData = users.First();
foreach (UserV2Model duplicateUserData in users.Skip(1))
{
primaryUserData.MergeUserData(duplicateUserData);
this.DeleteUserData(duplicateUserData.ID);
}
ChannelSession.Settings.Users.ManualValueChanged(primaryUserData.ID);
return primaryUserData;
}

private async Task<UserV2ViewModel> CreateUserInternal(UserPlatformV2ModelBase platformModel)
{
if (platformModel != null && !string.IsNullOrEmpty(platformModel.ID))
{
UserV2Model userModel = new UserV2Model(platformModel);
UserV2ViewModel user = new UserV2ViewModel(platformModel.Platform, userModel);

UserV2ViewModel user = null;
if (platformModel.Platform != StreamingPlatformTypeEnum.None)
{
this.SetUserData(userModel);
userModel = this.SetUserData(userModel);
user = new UserV2ViewModel(platformModel.Platform, userModel);

UserImportModel import = await ChannelSession.Settings.LoadUserImportData(platformModel.Platform, platformModel.ID, platformModel.Username);
if (import != null)
Expand All @@ -411,6 +463,11 @@ private async Task<UserV2ViewModel> CreateUserInternal(UserPlatformV2ModelBase p
ChannelSession.Settings.ImportedUsers.Remove(import.ID);
}
}
else
{
user = new UserV2ViewModel(platformModel.Platform, userModel);
}

return user;
}
return null;
Expand Down
8 changes: 8 additions & 0 deletions MixItUp.Base/Util/DatabaseDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ public void ManualValueChanged(K key)
}
}

public void ManualValueDeleted(K key)
{
if (key != null)
{
this.ValueRemoved(key);
}
}

public void ClearTracking()
{
this.addedValues.Clear();
Expand Down
66 changes: 1 addition & 65 deletions MixItUp.Base/ViewModel/User/UserV2ViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -641,71 +641,7 @@ public void RefreshPatreonProperties()
public async Task MergeUserData(UserV2ViewModel other)
{
this.model.AddPlatformData(other.platformModel);
this.model.OnlineViewingMinutes += other.model.OnlineViewingMinutes;

foreach (var kvp in other.model.CurrencyAmounts)
{
if (!this.model.CurrencyAmounts.ContainsKey(kvp.Key))
{
this.model.CurrencyAmounts[kvp.Key] = 0;
}
this.model.CurrencyAmounts[kvp.Key] += kvp.Value;
}

foreach (var kvp in other.model.InventoryAmounts)
{
if (!this.model.InventoryAmounts.ContainsKey(kvp.Key))
{
this.model.InventoryAmounts[kvp.Key] = new Dictionary<Guid, int>();
}

foreach (var itemKVP in kvp.Value)
{
if (!this.model.InventoryAmounts[kvp.Key].ContainsKey(itemKVP.Key))
{
this.model.InventoryAmounts[kvp.Key][itemKVP.Key] = 0;
}
this.model.InventoryAmounts[kvp.Key][itemKVP.Key] += itemKVP.Value;
}
}

foreach (var kvp in other.model.StreamPassAmounts)
{
if (!this.model.StreamPassAmounts.ContainsKey(kvp.Key))
{
this.model.StreamPassAmounts[kvp.Key] = 0;
}
this.model.StreamPassAmounts[kvp.Key] += kvp.Value;
}

if (string.IsNullOrEmpty(this.model.CustomTitle)) { this.model.CustomTitle = other.model.CustomTitle; }
if (!this.model.IsSpecialtyExcluded) { this.model.IsSpecialtyExcluded = other.model.IsSpecialtyExcluded; }
if (this.model.EntranceCommandID == Guid.Empty) { this.model.EntranceCommandID = other.model.EntranceCommandID; }

foreach (Guid id in other.model.CustomCommandIDs)
{
this.model.CustomCommandIDs.Add(id);
}

if (string.IsNullOrEmpty(this.model.PatreonUserID)) { this.model.PatreonUserID = other.model.PatreonUserID; }

if (string.IsNullOrEmpty(this.model.Notes))
{
this.model.Notes = other.model.Notes;
}
else if (!string.IsNullOrEmpty(other.model.Notes))
{
this.model.Notes += Environment.NewLine + Environment.NewLine + other.model.Notes;
}

this.model.TotalStreamsWatched += other.Model.TotalStreamsWatched;
this.model.TotalAmountDonated += other.Model.TotalAmountDonated;
this.model.TotalSubsGifted += other.Model.TotalSubsGifted;
this.model.TotalSubsReceived += other.Model.TotalSubsReceived;
this.model.TotalChatMessageSent += other.Model.TotalChatMessageSent;
this.model.TotalTimesTagged += other.Model.TotalTimesTagged;
this.model.TotalCommandsRun += other.Model.TotalCommandsRun;
this.model.TotalMonthsSubbed += other.Model.TotalMonthsSubbed;
this.model.MergeUserData(other.Model);

await ServiceManager.Get<UserService>().RemoveActiveUser(other.ID);
await ServiceManager.Get<UserService>().RemoveActiveUser(this.ID);
Expand Down

0 comments on commit 0e1a212

Please sign in to comment.