639 lines
26 KiB
C#
639 lines
26 KiB
C#
using LiteDB;
|
|
using Vanadium.Classes;
|
|
using Vanadium.Classes.DBs.DBClasses;
|
|
using static Vanadium.Classes.DBs.DBClasses.InventionDBClasses;
|
|
|
|
namespace Vanadium.Classes.DBs
|
|
{
|
|
public class InventionDB
|
|
{
|
|
public static LiteDatabase InventionDBFile = new LiteDatabase("Filename=" + Path.Join(Program.dataDir, "DBs", "Inventions.db") + ";Connection=shared");
|
|
public static readonly ILiteCollection<Invention> Inventions = InventionDBFile.GetCollection<Invention>("Inventions");
|
|
public static readonly ILiteCollection<InventionVersion> Versions = InventionDBFile.GetCollection<InventionVersion>("Versions");
|
|
|
|
public static void Setup()
|
|
{
|
|
Inventions.EnsureIndex(x => x.InventionId);
|
|
Inventions.EnsureIndex(x => x.CreatorPlayerId);
|
|
Versions.EnsureIndex(x => x.InventionId);
|
|
}
|
|
|
|
public static object MapVersion(InventionVersion v) => new
|
|
{
|
|
v.InventionId,
|
|
v.ReplicationId,
|
|
v.VersionNumber,
|
|
v.BlobName,
|
|
v.BlobHash,
|
|
v.InstantiationCost,
|
|
v.LightsCost,
|
|
v.ChipsCost,
|
|
v.CloudVariablesCost,
|
|
v.AICost,
|
|
v.inkCost,
|
|
CreatedAt = v.CreatedAt.ToString("O")
|
|
};
|
|
|
|
public static object MapInventionFull(Invention inv)
|
|
{
|
|
var resolvedCurrentVersion = inv.CurrentVersion
|
|
?? (inv.Versions ?? new List<InventionVersion>())
|
|
.OrderByDescending(v => v.VersionNumber)
|
|
.FirstOrDefault();
|
|
|
|
return new
|
|
{
|
|
inv.InventionId,
|
|
inv.ReplicationId,
|
|
inv.CreatorPlayerId,
|
|
inv.Name,
|
|
inv.Description,
|
|
inv.LongDescription,
|
|
inv.ImageName,
|
|
inv.CurrentVersionNumber,
|
|
inv.LatestVersionNumber,
|
|
inv.UgcVersion,
|
|
inv.ForceCannotPublish,
|
|
CurrentVersion = resolvedCurrentVersion != null ? MapVersion(resolvedCurrentVersion) : (object?)null,
|
|
Versions = (inv.Versions ?? new List<InventionVersion>()).Select(v => MapVersion(v)).ToList(),
|
|
Accessibility = (int)inv.Accessibility,
|
|
inv.IsPublished,
|
|
inv.IsFeatured,
|
|
inv.IsRecRoomApproved,
|
|
inv.IsAGInvention,
|
|
inv.IsCertifiedInvention,
|
|
ModifiedAt = inv.ModifiedAt.ToString("O"),
|
|
CreatedAt = inv.CreatedAt.ToString("O"),
|
|
FirstPublishedAt = inv.FirstPublishedAt.HasValue && inv.FirstPublishedAt.Value != DateTime.MinValue
|
|
? inv.FirstPublishedAt.Value.ToString("O")
|
|
: (string?)null,
|
|
inv.CreationRoomId,
|
|
inv.NumPlayersHaveUsedInRoom,
|
|
inv.NumDownloads,
|
|
inv.CheerCount,
|
|
inv.CreatorPermission,
|
|
inv.GeneralPermission,
|
|
inv.Price,
|
|
inv.AllowTrial,
|
|
inv.HideFromPlayer,
|
|
inv.DisplayMetadataJson,
|
|
ReferencedInventions = inv.ReferencedInventions ?? new List<long>(),
|
|
Tags = inv.Tags ?? new List<InventionTag>()
|
|
};
|
|
}
|
|
|
|
public static InventionData MapInventionToData(Invention inv) => new InventionData
|
|
{
|
|
AllowTrial = inv.AllowTrial,
|
|
CheerCount = inv.CheerCount,
|
|
CreatedAt = inv.CreatedAt.ToString("O"),
|
|
CreatorPermission = inv.CreatorPermission,
|
|
CreatorPlayerId = inv.CreatorPlayerId,
|
|
CurrentVersionNumber = inv.CurrentVersionNumber,
|
|
Description = inv.Description,
|
|
GeneralPermission = inv.GeneralPermission,
|
|
HideFromPlayer = inv.HideFromPlayer,
|
|
ImageName = inv.ImageName,
|
|
InventionId = inv.InventionId,
|
|
IsAGInvention = inv.IsAGInvention,
|
|
IsCertifiedInvention = inv.IsCertifiedInvention,
|
|
IsPublished = inv.IsPublished,
|
|
IsFeatured = inv.IsFeatured,
|
|
IsRecRoomApproved = inv.IsRecRoomApproved,
|
|
ModifiedAt = inv.ModifiedAt.ToString("O"),
|
|
Name = inv.Name,
|
|
NumDownloads = inv.NumDownloads,
|
|
NumPlayersHaveUsedInRoom = inv.NumPlayersHaveUsedInRoom,
|
|
Price = inv.Price,
|
|
ReplicationId = inv.ReplicationId,
|
|
LongDescription = inv.LongDescription,
|
|
UgcVersion = inv.UgcVersion,
|
|
ForceCannotPublish = inv.ForceCannotPublish,
|
|
LatestVersionNumber = inv.LatestVersionNumber,
|
|
Versions = inv.Versions,
|
|
CurrentVersion = inv.CurrentVersion,
|
|
Accessibility = (int)inv.Accessibility,
|
|
FirstPublishedAt = inv.FirstPublishedAt,
|
|
CreationRoomId = inv.CreationRoomId,
|
|
DisplayMetadataJson = inv.DisplayMetadataJson,
|
|
ReferencedInventions = inv.ReferencedInventions ?? new List<long>(),
|
|
Tags = inv.Tags ?? new List<InventionTag>()
|
|
};
|
|
|
|
public static Invention? GetInvention(long inventionId)
|
|
{
|
|
var invention = Inventions.FindById(inventionId);
|
|
if (invention == null) return null;
|
|
|
|
if (invention.CurrentVersion == null)
|
|
{
|
|
var fallback = Versions
|
|
.Find(v => v.InventionId == inventionId)
|
|
.OrderByDescending(v => v.VersionNumber)
|
|
.FirstOrDefault();
|
|
|
|
if (fallback != null)
|
|
{
|
|
invention.CurrentVersion = fallback;
|
|
invention.CurrentVersionNumber = fallback.VersionNumber;
|
|
invention.LatestVersionNumber = fallback.VersionNumber;
|
|
Inventions.Update(invention);
|
|
}
|
|
}
|
|
|
|
return invention;
|
|
}
|
|
|
|
public static List<Invention> GetInventionsBatch(List<long> inventionIds)
|
|
{
|
|
var inventions = Inventions.Find(x => inventionIds.Contains(x.InventionId)).ToList();
|
|
|
|
foreach (var invention in inventions.Where(inv => inv.CurrentVersion == null))
|
|
{
|
|
var fallback = Versions
|
|
.Find(v => v.InventionId == invention.InventionId)
|
|
.OrderByDescending(v => v.VersionNumber)
|
|
.FirstOrDefault();
|
|
|
|
if (fallback != null)
|
|
{
|
|
invention.CurrentVersion = fallback;
|
|
invention.CurrentVersionNumber = fallback.VersionNumber;
|
|
invention.LatestVersionNumber = fallback.VersionNumber;
|
|
Inventions.Update(invention);
|
|
}
|
|
}
|
|
|
|
return inventions;
|
|
}
|
|
|
|
public static List<InventionData> GetInventionsByPlayer(long playerId)
|
|
=> Inventions.Find(x => x.DownloadIds.Contains(playerId)).ToList()
|
|
.Select(inv => MapInventionToData(inv)).ToList();
|
|
|
|
public static List<object> GetInventionsByCreator(long creatorId)
|
|
=> Inventions.Find(x => x.CreatorPlayerId == creatorId).ToList()
|
|
.Select(inv => MapInventionFull(inv)).ToList();
|
|
|
|
public static List<object> GetInventionsByRoom(long roomId)
|
|
=> Inventions.Find(x => x.CreationRoomId == roomId).ToList()
|
|
.Select(inv => MapInventionFull(inv)).ToList();
|
|
|
|
public static List<object> GetVersionsForInvention(long inventionId)
|
|
=> Versions.Find(v => v.InventionId == inventionId)
|
|
.Select(v => MapVersion(v)).ToList();
|
|
|
|
public static InventionVersion? GetVersion(long inventionId, int versionNumber)
|
|
=> Versions.FindOne(x => x.InventionId == inventionId && x.VersionNumber == versionNumber);
|
|
|
|
public static InventionVersion? GetLatestVersion(long inventionId)
|
|
=> Versions.Find(v => v.InventionId == inventionId)
|
|
.OrderByDescending(v => v.VersionNumber)
|
|
.FirstOrDefault();
|
|
|
|
public static long GetNextInventionId()
|
|
{
|
|
if (Inventions.Count() == 0)
|
|
return 5012352472715840656;
|
|
return Convert.ToInt64(Inventions.Max(x => x.InventionId)) + 1;
|
|
}
|
|
|
|
public static (Invention invention, InventionVersion version)? SaveInvention(long creatorPlayerId, SaveInventionRequest request)
|
|
{
|
|
try
|
|
{
|
|
long inventionId = GetNextInventionId();
|
|
|
|
var version = new InventionVersion
|
|
{
|
|
InventionId = inventionId,
|
|
VersionNumber = 1,
|
|
ReplicationId = Guid.NewGuid().ToString(),
|
|
BlobName = request.inventionDataFilename ?? string.Empty,
|
|
BlobHash = string.Empty,
|
|
ChipsCost = request.chipsCost,
|
|
CloudVariablesCost = request.cloudVariablesCost,
|
|
InstantiationCost = request.instantiationCost,
|
|
LightsCost = request.lightsCost,
|
|
AICost = request.aiCost,
|
|
inkCost = request.inkCost,
|
|
CreatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
var invention = new Invention
|
|
{
|
|
InventionId = inventionId,
|
|
ReplicationId = Guid.NewGuid().ToString(),
|
|
CreatorPlayerId = creatorPlayerId,
|
|
CreationRoomId = request.creationRoomId,
|
|
Name = request.name ?? string.Empty,
|
|
Description = request.description ?? string.Empty,
|
|
ImageName = request.imageName ?? string.Empty,
|
|
CurrentVersionNumber = 1,
|
|
LatestVersionNumber = 1,
|
|
CurrentVersion = version,
|
|
Versions = new List<InventionVersion> { version },
|
|
Accessibility = RoomDBClasses.RoomAccessibility.Private,
|
|
AllowTrial = true,
|
|
HideFromPlayer = false,
|
|
CreatorPermission = (int)InventionPermissions.Unlimited,
|
|
GeneralPermission = (int)InventionPermissions.Unassigned,
|
|
inkCost = 1,
|
|
CreatedAt = DateTime.UtcNow,
|
|
ModifiedAt = DateTime.UtcNow,
|
|
DownloadIds = new List<long> { creatorPlayerId },
|
|
ReferencedInventions = request.referencedInventions ?? new List<long>()
|
|
};
|
|
|
|
Inventions.Insert(invention);
|
|
Versions.Insert(version);
|
|
|
|
return (invention, version);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[InventionDB] Error saving invention: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static (Invention invention, InventionVersion version)? AddVersion(Invention invention, AddVersionRequest request)
|
|
{
|
|
int nextVersion = invention.CurrentVersionNumber + 1;
|
|
|
|
var version = new InventionVersion
|
|
{
|
|
InventionId = invention.InventionId,
|
|
VersionNumber = nextVersion,
|
|
BlobName = request.inventionDataFilename ?? string.Empty,
|
|
ChipsCost = request.chipsCost,
|
|
CloudVariablesCost = request.cloudVariablesCost,
|
|
InstantiationCost = request.instantiationCost,
|
|
LightsCost = request.lightsCost,
|
|
AICost = request.aiCost,
|
|
inkCost = request.inkCost,
|
|
ReplicationId = Guid.NewGuid().ToString(),
|
|
CreatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
invention.CurrentVersionNumber = nextVersion;
|
|
invention.LatestVersionNumber = nextVersion;
|
|
invention.CurrentVersion = version;
|
|
invention.Versions.Add(version);
|
|
invention.ModifiedAt = DateTime.UtcNow;
|
|
|
|
Versions.Insert(version);
|
|
Inventions.Update(invention);
|
|
|
|
return (invention, version);
|
|
}
|
|
|
|
public static Invention? UpdateInvention(long inventionId, long playerId,
|
|
string? name, string? description, string? imageName,
|
|
int? price, bool? isPublished, bool? allowTrial,
|
|
bool? hideFromPlayer, int? generalPermission, int? creatorPermission)
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null || invention.CreatorPlayerId != playerId) return null;
|
|
|
|
if (name != null) invention.Name = name;
|
|
if (description != null) invention.Description = description;
|
|
if (imageName != null) invention.ImageName = imageName;
|
|
if (price.HasValue) invention.Price = price.Value;
|
|
if (isPublished.HasValue) invention.IsPublished = isPublished.Value;
|
|
if (allowTrial.HasValue) invention.AllowTrial = allowTrial.Value;
|
|
if (hideFromPlayer.HasValue) invention.HideFromPlayer = hideFromPlayer.Value;
|
|
if (generalPermission.HasValue) invention.GeneralPermission = generalPermission.Value;
|
|
if (creatorPermission.HasValue) invention.CreatorPermission = creatorPermission.Value;
|
|
|
|
invention.ModifiedAt = DateTime.UtcNow;
|
|
Inventions.Update(invention);
|
|
|
|
return invention;
|
|
}
|
|
|
|
public static Invention? PublishInvention(long inventionId, long playerId, int permissionLevel, int accessibility, int price)
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null || invention.CreatorPlayerId != playerId) return null;
|
|
|
|
invention.CreatorPermission = 255;
|
|
invention.GeneralPermission = permissionLevel;
|
|
invention.Accessibility = (RoomDBClasses.RoomAccessibility)accessibility;
|
|
invention.Price = price;
|
|
invention.IsPublished = true;
|
|
|
|
invention.ModifiedAt = DateTime.UtcNow;
|
|
Inventions.Update(invention);
|
|
|
|
return invention;
|
|
}
|
|
|
|
public static Invention? UnpublishInvention(long inventionId, long playerId)
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null || invention.CreatorPlayerId != playerId) return null;
|
|
|
|
invention.IsPublished = false;
|
|
|
|
invention.ModifiedAt = DateTime.UtcNow;
|
|
Inventions.Update(invention);
|
|
|
|
return invention;
|
|
}
|
|
|
|
public static List<Invention> GetTopTodayInventions(bool featuredOnly, bool includeUnpublished = false)
|
|
{
|
|
var query = Inventions.FindAll().AsEnumerable();
|
|
if (featuredOnly)
|
|
{
|
|
query = query.Where(r => r.Tags.Any(t => string.Equals(t.Tag, "featured", StringComparison.OrdinalIgnoreCase) || r.IsFeatured));
|
|
}
|
|
if (!includeUnpublished)
|
|
query = query.Where(r => r.IsPublished);
|
|
|
|
return query.OrderByDescending(r => r.CheerCount).ToList();
|
|
}
|
|
|
|
public static (List<Invention> Results, int Total) Search(string query, int skip = 0, int take = 30)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(query))
|
|
return (new List<Invention>(), 0);
|
|
|
|
var segments = query.Split('|', StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(s => s.Trim())
|
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
|
.ToList();
|
|
|
|
var candidatePool = Inventions.FindAll()
|
|
.Where(i => i.IsPublished)
|
|
.Where(i => !i.HideFromPlayer)
|
|
.Where(i => i.Accessibility == RoomDBClasses.RoomAccessibility.Public)
|
|
.ToList();
|
|
|
|
var allPlayers = PlayerDB.Players.FindAll().ToList();
|
|
|
|
var matched = new Dictionary<long, Invention>();
|
|
|
|
foreach (var segment in segments)
|
|
{
|
|
var terms = segment.Split(new char[] { ' ', '+' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
var nameParts = new List<string>();
|
|
var tagParts = new List<string>();
|
|
var authorParts = new List<string>();
|
|
|
|
foreach (var term in terms)
|
|
{
|
|
if (term.StartsWith("#"))
|
|
tagParts.Add(term.Substring(1).ToLowerInvariant().Trim());
|
|
else if (term.StartsWith("@"))
|
|
authorParts.Add(term.Substring(1).ToLowerInvariant().Trim());
|
|
else
|
|
nameParts.Add(term.ToLowerInvariant().Trim());
|
|
}
|
|
|
|
long? resolvedAuthorId = null;
|
|
|
|
if (authorParts.Count > 0)
|
|
{
|
|
var authorQuery = string.Join(" ", authorParts);
|
|
|
|
var exactMatch = allPlayers.FirstOrDefault(p =>
|
|
string.Equals(p.Player?.Username, authorQuery, StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(p.Player?.DisplayName, authorQuery, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (exactMatch != null)
|
|
{
|
|
resolvedAuthorId = exactMatch.PlayerId;
|
|
}
|
|
else
|
|
{
|
|
var fuzzyMatch = allPlayers
|
|
.Where(p => p.Player != null)
|
|
.Select(p => new
|
|
{
|
|
Player = p,
|
|
Score = Math.Max(
|
|
ScoreShit((p.Player!.Username ?? "").ToLowerInvariant(), authorQuery),
|
|
ScoreShit((p.Player!.DisplayName ?? "").ToLowerInvariant(), authorQuery))
|
|
})
|
|
.Where(x => x.Score > 0)
|
|
.OrderByDescending(x => x.Score)
|
|
.FirstOrDefault();
|
|
|
|
if (fuzzyMatch != null)
|
|
resolvedAuthorId = fuzzyMatch.Player.PlayerId;
|
|
else
|
|
continue;
|
|
}
|
|
}
|
|
|
|
foreach (var invention in candidatePool)
|
|
{
|
|
if (resolvedAuthorId.HasValue && invention.CreatorPlayerId != resolvedAuthorId.Value)
|
|
continue;
|
|
|
|
if (tagParts.Count > 0)
|
|
{
|
|
var inventionTags = (invention.Tags ?? new List<InventionTag>())
|
|
.Select(t => t.Tag.ToLowerInvariant().Trim())
|
|
.ToList();
|
|
|
|
bool allTagsMatch = tagParts.All(tp =>
|
|
{
|
|
if (inventionTags.Contains(tp))
|
|
return true;
|
|
|
|
foreach (var it in inventionTags)
|
|
{
|
|
if (it.Contains(tp) || tp.Contains(it))
|
|
return true;
|
|
|
|
int dist = EditDistance(it, tp);
|
|
int maxLen = Math.Max(it.Length, tp.Length);
|
|
if (maxLen > 0 && (double)dist / maxLen <= 0.34)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
if (!allTagsMatch)
|
|
continue;
|
|
}
|
|
|
|
if (nameParts.Count > 0)
|
|
{
|
|
string inventionNameLower = (invention.Name ?? "").ToLowerInvariant();
|
|
|
|
bool nameMatch = nameParts.All(np =>
|
|
{
|
|
if (inventionNameLower.Contains(np))
|
|
return true;
|
|
|
|
int dist = EditDistance(inventionNameLower, np);
|
|
int maxLen = Math.Max(inventionNameLower.Length, np.Length);
|
|
if (maxLen > 0 && (double)dist / maxLen <= 0.34)
|
|
return true;
|
|
|
|
return false;
|
|
});
|
|
|
|
if (!nameMatch)
|
|
continue;
|
|
}
|
|
|
|
matched[invention.InventionId] = invention;
|
|
}
|
|
}
|
|
|
|
var all = matched.Values
|
|
.OrderByDescending(i => i.CheerCount)
|
|
.ThenByDescending(i => i.NumDownloads)
|
|
.ToList();
|
|
|
|
return (all.Skip(skip).Take(take).ToList(), all.Count);
|
|
}
|
|
|
|
public static (bool success, bool isCheering, int cheerCount)? CheerInvention(long inventionId, long playerId, bool cheer)
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null) return null;
|
|
|
|
var player = PlayerDB.Players.FindById(playerId);
|
|
if (player?.Player?.PlayerExtra == null) return null;
|
|
|
|
player.Player.PlayerExtra.PersonalDetails ??= new PlayerDBClasses.PersonalDetails();
|
|
player.Player.PlayerExtra.PersonalDetails.inventionsCheered ??= new List<long>();
|
|
|
|
bool alreadyCheering = player.Player.PlayerExtra.PersonalDetails.inventionsCheered.Contains(inventionId);
|
|
|
|
if (cheer && !alreadyCheering)
|
|
{
|
|
invention.CheerCount++;
|
|
player.Player.PlayerExtra.PersonalDetails.inventionsCheered.Add(inventionId);
|
|
player.Player.PlayerExtra.PersonalDetails.IsCheering = true;
|
|
}
|
|
else if (!cheer && alreadyCheering)
|
|
{
|
|
invention.CheerCount = Math.Max(0, invention.CheerCount - 1);
|
|
player.Player.PlayerExtra.PersonalDetails.inventionsCheered.Remove(inventionId);
|
|
player.Player.PlayerExtra.PersonalDetails.IsCheering = false;
|
|
}
|
|
|
|
Inventions.Update(invention);
|
|
PlayerDB.Players.Update(player);
|
|
|
|
return (true, player.Player.PlayerExtra.PersonalDetails.inventionsCheered.Contains(inventionId), invention.CheerCount);
|
|
}
|
|
|
|
public static bool DeleteInvention(long inventionId, long playerId)
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null || invention.CreatorPlayerId != playerId) return false;
|
|
|
|
try
|
|
{
|
|
var cdnPath = Path.Join(Program.dataDir, "cdn", "inv");
|
|
|
|
if (Directory.Exists(cdnPath))
|
|
{
|
|
foreach (var v in Versions.Find(v => v.InventionId == inventionId).ToList())
|
|
if (!string.IsNullOrWhiteSpace(v.ReplicationId))
|
|
foreach (var file in Directory.GetFiles(cdnPath, v.ReplicationId + "*"))
|
|
try { File.Delete(file); } catch { }
|
|
|
|
if (!string.IsNullOrWhiteSpace(invention.ReplicationId))
|
|
foreach (var file in Directory.GetFiles(cdnPath, invention.ReplicationId + "*"))
|
|
try { File.Delete(file); } catch { }
|
|
}
|
|
|
|
Versions.DeleteMany(v => v.InventionId == inventionId);
|
|
Inventions.Delete(inventionId);
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[InventionDB] Error deleting invention: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static SetTagsResponse SetTags(long inventionId, SetTagsRequest request)
|
|
{
|
|
try
|
|
{
|
|
var invention = GetInvention(inventionId);
|
|
if (invention == null)
|
|
return new SetTagsResponse { Result = -1 };
|
|
|
|
invention.Tags.Clear();
|
|
|
|
var allTags = new List<string>();
|
|
|
|
foreach (var autoTag in request.AutoTags ?? new List<string>())
|
|
{
|
|
invention.Tags.Add(new InventionTag { Tag = autoTag, Type = 0 });
|
|
allTags.Add(autoTag);
|
|
}
|
|
|
|
foreach (var customTag in request.CustomTags ?? new List<string>())
|
|
{
|
|
invention.Tags.Add(new InventionTag { Tag = customTag, Type = 1 });
|
|
allTags.Add(customTag);
|
|
}
|
|
|
|
Inventions.Update(invention);
|
|
|
|
return new SetTagsResponse { Result = 0, Tags = allTags };
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[InventionDB] Error setting tags: {ex.Message}");
|
|
return new SetTagsResponse { Result = -1 };
|
|
}
|
|
}
|
|
|
|
private static int ScoreShit(string source, string target)
|
|
{
|
|
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target)) return 0;
|
|
if (source == target) return 1000;
|
|
if (source.Contains(target) || target.Contains(source)) return 500;
|
|
|
|
int dist = EditDistance(source, target);
|
|
int maxLen = Math.Max(source.Length, target.Length);
|
|
if (maxLen == 0) return 0;
|
|
|
|
double similarity = 1.0 - (double)dist / maxLen;
|
|
if (similarity >= 0.66) return (int)(similarity * 100);
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static int EditDistance(string a, string b)
|
|
{
|
|
if (string.IsNullOrEmpty(a)) return b?.Length ?? 0;
|
|
if (string.IsNullOrEmpty(b)) return a.Length;
|
|
|
|
int m = a.Length, n = b.Length;
|
|
var dp = new int[m + 1, n + 1];
|
|
|
|
for (int i = 0; i <= m; i++) dp[i, 0] = i;
|
|
for (int j = 0; j <= n; j++) dp[0, j] = j;
|
|
|
|
for (int i = 1; i <= m; i++)
|
|
{
|
|
for (int j = 1; j <= n; j++)
|
|
{
|
|
dp[i, j] = a[i - 1] == b[j - 1]
|
|
? dp[i - 1, j - 1]
|
|
: 1 + Math.Min(dp[i - 1, j - 1], Math.Min(dp[i - 1, j], dp[i, j - 1]));
|
|
}
|
|
}
|
|
|
|
return dp[m, n];
|
|
}
|
|
}
|
|
} |