From 6ede8af20486f0c5bf1954ae80c79299bb09caa4 Mon Sep 17 00:00:00 2001 From: AlanMoonbase Date: Mon, 3 Mar 2025 13:29:34 -0800 Subject: [PATCH] implement ``BuddyService`` add ``CreatedAt`` to ``Buddy`` model add missing schemas --- ...50303212804_Buddies_CreateDate.Designer.cs | 1310 +++++++++++++++++ .../20250303212804_Buddies_CreateDate.cs | 114 ++ src/Migrations/DBContextModelSnapshot.cs | 5 +- src/Model/Buddy.cs | 2 + src/Schema/BuddyActionResult.cs | 22 + src/Schema/BuddyActionResultType.cs | 30 + src/Services/BuddyService.cs | 117 ++ 7 files changed, 1599 insertions(+), 1 deletion(-) create mode 100644 src/Migrations/20250303212804_Buddies_CreateDate.Designer.cs create mode 100644 src/Migrations/20250303212804_Buddies_CreateDate.cs create mode 100644 src/Schema/BuddyActionResult.cs create mode 100644 src/Schema/BuddyActionResultType.cs create mode 100644 src/Services/BuddyService.cs diff --git a/src/Migrations/20250303212804_Buddies_CreateDate.Designer.cs b/src/Migrations/20250303212804_Buddies_CreateDate.Designer.cs new file mode 100644 index 0000000..8e1eb7d --- /dev/null +++ b/src/Migrations/20250303212804_Buddies_CreateDate.Designer.cs @@ -0,0 +1,1310 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using sodoff.Model; + +#nullable disable + +namespace sodoff.Migrations +{ + [DbContext(typeof(DBContext))] + [Migration("20250303212804_Buddies_CreateDate")] + partial class Buddies_CreateDate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.20") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("GroupViking", b => + { + b.Property("GroupsId") + .HasColumnType("INTEGER"); + + b.Property("VikingsId") + .HasColumnType("INTEGER"); + + b.HasKey("GroupsId", "VikingsId"); + + b.HasIndex("VikingsId"); + + b.ToTable("GroupViking"); + }); + + modelBuilder.Entity("sodoff.Model.AchievementPoints", b => + { + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("VikingId", "Type"); + + b.ToTable("AchievementPoints"); + }); + + modelBuilder.Entity("sodoff.Model.AchievementTaskState", b => + { + b.Property("TaskId") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("Points") + .HasColumnType("INTEGER"); + + b.HasKey("TaskId", "VikingId"); + + b.HasIndex("VikingId"); + + b.ToTable("AchievementTaskState"); + }); + + modelBuilder.Entity("sodoff.Model.Buddy", b => + { + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("BuddyStatus1") + .HasColumnType("INTEGER"); + + b.Property("BuddyStatus2") + .HasColumnType("INTEGER"); + + b.Property("BuddyVikingId") + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("IsBestFriend1") + .HasColumnType("INTEGER"); + + b.Property("IsBestFriend2") + .HasColumnType("INTEGER"); + + b.HasKey("VikingId"); + + b.HasIndex("BuddyVikingId"); + + b.ToTable("Buddies"); + }); + + modelBuilder.Entity("sodoff.Model.Dragon", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EntityId") + .HasColumnType("TEXT"); + + b.Property("PetXP") + .HasColumnType("INTEGER"); + + b.Property("RaisedPetData") + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("Dragons"); + }); + + modelBuilder.Entity("sodoff.Model.GameData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DatePlayed") + .HasColumnType("TEXT"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("GameLevel") + .HasColumnType("INTEGER"); + + b.Property("IsMultiplayer") + .HasColumnType("INTEGER"); + + b.Property("Loss") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("Win") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("GameData"); + }); + + modelBuilder.Entity("sodoff.Model.GameDataPair", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("GameDataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GameDataId"); + + b.ToTable("GameDataPairs"); + }); + + modelBuilder.Entity("sodoff.Model.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Color") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GroupID") + .HasColumnType("TEXT"); + + b.Property("Logo") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("sodoff.Model.Image", b => + { + b.Property("ImageType") + .HasColumnType("TEXT"); + + b.Property("ImageSlot") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("ImageData") + .HasColumnType("TEXT"); + + b.Property("TemplateName") + .HasColumnType("TEXT"); + + b.HasKey("ImageType", "ImageSlot", "VikingId"); + + b.HasIndex("VikingId"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("sodoff.Model.InventoryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AttributesSerialized") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("INTEGER"); + + b.Property("StatsSerialized") + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("InventoryItems"); + }); + + modelBuilder.Entity("sodoff.Model.MMORole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("MMORoles"); + }); + + modelBuilder.Entity("sodoff.Model.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConversationID") + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("IsDeleted") + .HasColumnType("INTEGER"); + + b.Property("IsNew") + .HasColumnType("INTEGER"); + + b.Property("LastUpdatedAt") + .HasColumnType("TEXT"); + + b.Property("MemberMessage") + .HasColumnType("TEXT"); + + b.Property("MessageLevel") + .HasColumnType("INTEGER"); + + b.Property("MessageType") + .HasColumnType("INTEGER"); + + b.Property("MessageTypeID") + .HasColumnType("INTEGER"); + + b.Property("NonMemberMessage") + .HasColumnType("TEXT"); + + b.Property("ParentMessageId") + .HasColumnType("INTEGER"); + + b.Property("QueueID") + .HasColumnType("INTEGER"); + + b.Property("ToVikingId") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentMessageId"); + + b.HasIndex("ToVikingId"); + + b.HasIndex("VikingId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("sodoff.Model.MissionState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MissionId") + .HasColumnType("INTEGER"); + + b.Property("MissionStatus") + .HasColumnType("INTEGER"); + + b.Property("UserAccepted") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("MissionStates"); + }); + + modelBuilder.Entity("sodoff.Model.Neighborhood", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Slot0") + .HasColumnType("TEXT"); + + b.Property("Slot1") + .HasColumnType("TEXT"); + + b.Property("Slot2") + .HasColumnType("TEXT"); + + b.Property("Slot3") + .HasColumnType("TEXT"); + + b.Property("Slot4") + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId") + .IsUnique(); + + b.ToTable("Neighborhoods"); + }); + + modelBuilder.Entity("sodoff.Model.Pair", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MasterId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MasterId"); + + b.ToTable("Pairs"); + }); + + modelBuilder.Entity("sodoff.Model.PairData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DragonId") + .HasColumnType("INTEGER"); + + b.Property("PairId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DragonId"); + + b.HasIndex("UserId"); + + b.HasIndex("VikingId"); + + b.ToTable("PairData"); + }); + + modelBuilder.Entity("sodoff.Model.Party", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AssetBundle") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("Location") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LocationIconAsset") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PrivateParty") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("Parties"); + }); + + modelBuilder.Entity("sodoff.Model.ProfileAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AnswerID") + .HasColumnType("INTEGER"); + + b.Property("QuestionID") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("ProfileAnswers"); + }); + + modelBuilder.Entity("sodoff.Model.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("RankId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RankId"); + + b.HasIndex("VikingId"); + + b.ToTable("Ratings"); + }); + + modelBuilder.Entity("sodoff.Model.RatingRank", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CategoryID") + .HasColumnType("INTEGER"); + + b.Property("Rank") + .HasColumnType("INTEGER"); + + b.Property("RatedEntityID") + .HasColumnType("INTEGER"); + + b.Property("RatedUserID") + .HasColumnType("TEXT"); + + b.Property("RatingAverage") + .HasColumnType("REAL"); + + b.Property("UpdateDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RatingRanks"); + }); + + modelBuilder.Entity("sodoff.Model.Room", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RoomId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("Rooms"); + }); + + modelBuilder.Entity("sodoff.Model.RoomItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RoomId") + .HasColumnType("INTEGER"); + + b.Property("RoomItemData") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoomId"); + + b.ToTable("RoomItems"); + }); + + modelBuilder.Entity("sodoff.Model.SavedData", b => + { + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("SaveId") + .HasColumnType("INTEGER"); + + b.Property("SerializedData") + .HasColumnType("TEXT"); + + b.HasKey("VikingId", "SaveId"); + + b.ToTable("SavedData"); + }); + + modelBuilder.Entity("sodoff.Model.SceneData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("SceneName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("XmlData") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("SceneData"); + }); + + modelBuilder.Entity("sodoff.Model.Session", b => + { + b.Property("ApiToken") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("ApiToken"); + + b.HasIndex("UserId"); + + b.HasIndex("VikingId"); + + b.ToTable("Sessions"); + }); + + modelBuilder.Entity("sodoff.Model.TaskStatus", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("MissionId") + .HasColumnType("INTEGER"); + + b.Property("Completed") + .HasColumnType("INTEGER"); + + b.Property("Payload") + .HasColumnType("TEXT"); + + b.HasKey("Id", "VikingId", "MissionId"); + + b.HasIndex("VikingId"); + + b.ToTable("TaskStatuses"); + }); + + modelBuilder.Entity("sodoff.Model.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("sodoff.Model.UserBadgeCompleteData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BadgeId") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("UserBadgesCompleted"); + }); + + modelBuilder.Entity("sodoff.Model.UserBan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("ExpiresOn") + .HasColumnType("TEXT"); + + b.Property("UserBanType") + .HasColumnType("INTEGER"); + + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VikingId"); + + b.ToTable("Bans"); + }); + + modelBuilder.Entity("sodoff.Model.UserMissionData", b => + { + b.Property("VikingId") + .HasColumnType("INTEGER"); + + b.Property("WorldId") + .HasColumnType("INTEGER"); + + b.Property("MissionId") + .HasColumnType("INTEGER"); + + b.Property("IsCompleted") + .HasColumnType("INTEGER"); + + b.Property("StepId") + .HasColumnType("INTEGER"); + + b.Property("TaskId") + .HasColumnType("INTEGER"); + + b.HasKey("VikingId", "WorldId", "MissionId"); + + b.ToTable("UserMissionData"); + }); + + modelBuilder.Entity("sodoff.Model.Viking", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvatarSerialized") + .HasColumnType("TEXT"); + + b.Property("BirthDate") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("GameVersion") + .HasColumnType("INTEGER"); + + b.Property("Gender") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SelectedDragonId") + .HasColumnType("INTEGER"); + + b.Property("Uid") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SelectedDragonId") + .IsUnique(); + + b.HasIndex("Uid"); + + b.HasIndex("UserId"); + + b.ToTable("Vikings"); + }); + + modelBuilder.Entity("GroupViking", b => + { + b.HasOne("sodoff.Model.Group", null) + .WithMany() + .HasForeignKey("GroupsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("sodoff.Model.Viking", null) + .WithMany() + .HasForeignKey("VikingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("sodoff.Model.AchievementPoints", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("AchievementPoints") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.AchievementTaskState", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("AchievementTaskStates") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Buddy", b => + { + b.HasOne("sodoff.Model.Viking", "BuddyViking") + .WithMany("BuddyList") + .HasForeignKey("BuddyVikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("BuddiesMade") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BuddyViking"); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Dragon", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Dragons") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.GameData", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("GameData") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.GameDataPair", b => + { + b.HasOne("sodoff.Model.GameData", "GameData") + .WithMany("GameDataPairs") + .HasForeignKey("GameDataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameData"); + }); + + modelBuilder.Entity("sodoff.Model.Image", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Images") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.InventoryItem", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("InventoryItems") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.MMORole", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("MMORoles") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Message", b => + { + b.HasOne("sodoff.Model.Message", "ParentMessage") + .WithMany("Replies") + .HasForeignKey("ParentMessageId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("sodoff.Model.Viking", "ToViking") + .WithMany("MessageBoard") + .HasForeignKey("ToVikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("MessagesMade") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParentMessage"); + + b.Navigation("ToViking"); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.MissionState", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("MissionStates") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Neighborhood", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithOne("Neighborhood") + .HasForeignKey("sodoff.Model.Neighborhood", "VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Pair", b => + { + b.HasOne("sodoff.Model.PairData", "PairData") + .WithMany("Pairs") + .HasForeignKey("MasterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PairData"); + }); + + modelBuilder.Entity("sodoff.Model.PairData", b => + { + b.HasOne("sodoff.Model.Dragon", "Dragon") + .WithMany("PairData") + .HasForeignKey("DragonId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("sodoff.Model.User", "User") + .WithMany("PairData") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("PairData") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Dragon"); + + b.Navigation("User"); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Party", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Parties") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.ProfileAnswer", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("ProfileAnswers") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Rating", b => + { + b.HasOne("sodoff.Model.RatingRank", "Rank") + .WithMany("Ratings") + .HasForeignKey("RankId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Ratings") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Rank"); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Room", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Rooms") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.RoomItem", b => + { + b.HasOne("sodoff.Model.Room", "Room") + .WithMany("Items") + .HasForeignKey("RoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Room"); + }); + + modelBuilder.Entity("sodoff.Model.SavedData", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("SavedData") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.SceneData", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("SceneData") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Session", b => + { + b.HasOne("sodoff.Model.User", "User") + .WithMany("Sessions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("Sessions") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.TaskStatus", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("TaskStatuses") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.UserBadgeCompleteData", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("UserBadgesCompleted") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.UserBan", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("UserBans") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.UserMissionData", b => + { + b.HasOne("sodoff.Model.Viking", "Viking") + .WithMany("UserMissions") + .HasForeignKey("VikingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Viking"); + }); + + modelBuilder.Entity("sodoff.Model.Viking", b => + { + b.HasOne("sodoff.Model.Dragon", "SelectedDragon") + .WithOne() + .HasForeignKey("sodoff.Model.Viking", "SelectedDragonId"); + + b.HasOne("sodoff.Model.User", "User") + .WithMany("Vikings") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SelectedDragon"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("sodoff.Model.Dragon", b => + { + b.Navigation("PairData"); + }); + + modelBuilder.Entity("sodoff.Model.GameData", b => + { + b.Navigation("GameDataPairs"); + }); + + modelBuilder.Entity("sodoff.Model.Message", b => + { + b.Navigation("Replies"); + }); + + modelBuilder.Entity("sodoff.Model.PairData", b => + { + b.Navigation("Pairs"); + }); + + modelBuilder.Entity("sodoff.Model.RatingRank", b => + { + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("sodoff.Model.Room", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("sodoff.Model.User", b => + { + b.Navigation("PairData"); + + b.Navigation("Sessions"); + + b.Navigation("Vikings"); + }); + + modelBuilder.Entity("sodoff.Model.Viking", b => + { + b.Navigation("AchievementPoints"); + + b.Navigation("AchievementTaskStates"); + + b.Navigation("BuddiesMade"); + + b.Navigation("BuddyList"); + + b.Navigation("Dragons"); + + b.Navigation("GameData"); + + b.Navigation("Images"); + + b.Navigation("InventoryItems"); + + b.Navigation("MMORoles"); + + b.Navigation("MessageBoard"); + + b.Navigation("MessagesMade"); + + b.Navigation("MissionStates"); + + b.Navigation("Neighborhood"); + + b.Navigation("PairData"); + + b.Navigation("Parties"); + + b.Navigation("ProfileAnswers"); + + b.Navigation("Ratings"); + + b.Navigation("Rooms"); + + b.Navigation("SavedData"); + + b.Navigation("SceneData"); + + b.Navigation("Sessions"); + + b.Navigation("TaskStatuses"); + + b.Navigation("UserBadgesCompleted"); + + b.Navigation("UserBans"); + + b.Navigation("UserMissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Migrations/20250303212804_Buddies_CreateDate.cs b/src/Migrations/20250303212804_Buddies_CreateDate.cs new file mode 100644 index 0000000..d4efbc9 --- /dev/null +++ b/src/Migrations/20250303212804_Buddies_CreateDate.cs @@ -0,0 +1,114 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace sodoff.Migrations +{ + /// + public partial class Buddies_CreateDate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Buddy_Vikings_BuddyVikingId", + table: "Buddy"); + + migrationBuilder.DropForeignKey( + name: "FK_Buddy_Vikings_VikingId", + table: "Buddy"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Buddy", + table: "Buddy"); + + migrationBuilder.RenameTable( + name: "Buddy", + newName: "Buddies"); + + migrationBuilder.RenameIndex( + name: "IX_Buddy_BuddyVikingId", + table: "Buddies", + newName: "IX_Buddies_BuddyVikingId"); + + migrationBuilder.AddColumn( + name: "CreatedAt", + table: "Buddies", + type: "TEXT", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddPrimaryKey( + name: "PK_Buddies", + table: "Buddies", + column: "VikingId"); + + migrationBuilder.AddForeignKey( + name: "FK_Buddies_Vikings_BuddyVikingId", + table: "Buddies", + column: "BuddyVikingId", + principalTable: "Vikings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Buddies_Vikings_VikingId", + table: "Buddies", + column: "VikingId", + principalTable: "Vikings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Buddies_Vikings_BuddyVikingId", + table: "Buddies"); + + migrationBuilder.DropForeignKey( + name: "FK_Buddies_Vikings_VikingId", + table: "Buddies"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Buddies", + table: "Buddies"); + + migrationBuilder.DropColumn( + name: "CreatedAt", + table: "Buddies"); + + migrationBuilder.RenameTable( + name: "Buddies", + newName: "Buddy"); + + migrationBuilder.RenameIndex( + name: "IX_Buddies_BuddyVikingId", + table: "Buddy", + newName: "IX_Buddy_BuddyVikingId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Buddy", + table: "Buddy", + column: "VikingId"); + + migrationBuilder.AddForeignKey( + name: "FK_Buddy_Vikings_BuddyVikingId", + table: "Buddy", + column: "BuddyVikingId", + principalTable: "Vikings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Buddy_Vikings_VikingId", + table: "Buddy", + column: "VikingId", + principalTable: "Vikings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Migrations/DBContextModelSnapshot.cs b/src/Migrations/DBContextModelSnapshot.cs index a450226..74b3ae2 100644 --- a/src/Migrations/DBContextModelSnapshot.cs +++ b/src/Migrations/DBContextModelSnapshot.cs @@ -84,6 +84,9 @@ namespace sodoff.Migrations b.Property("BuddyVikingId") .HasColumnType("INTEGER"); + b.Property("CreatedAt") + .HasColumnType("TEXT"); + b.Property("IsBestFriend1") .HasColumnType("INTEGER"); @@ -94,7 +97,7 @@ namespace sodoff.Migrations b.HasIndex("BuddyVikingId"); - b.ToTable("Buddy"); + b.ToTable("Buddies"); }); modelBuilder.Entity("sodoff.Model.Dragon", b => diff --git a/src/Model/Buddy.cs b/src/Model/Buddy.cs index 273e3de..37db04a 100644 --- a/src/Model/Buddy.cs +++ b/src/Model/Buddy.cs @@ -17,6 +17,8 @@ public class Buddy public bool IsBestFriend1 { get; set; } public bool IsBestFriend2 { get; set; } + public DateTime CreatedAt { get; set; } + public virtual Viking? Viking { get; set; } public virtual Viking? BuddyViking { get; set; } } diff --git a/src/Schema/BuddyActionResult.cs b/src/Schema/BuddyActionResult.cs new file mode 100644 index 0000000..deb41ca --- /dev/null +++ b/src/Schema/BuddyActionResult.cs @@ -0,0 +1,22 @@ +using sodoff.Schema; +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "BuddyActionResult", Namespace = "")] + [Serializable] + public class BuddyActionResult + { + // Token: 0x04000203 RID: 515 + [XmlElement(ElementName = "Result")] + public BuddyActionResultType Result; + + // Token: 0x04000204 RID: 516 + [XmlElement(ElementName = "Status")] + public BuddyStatus Status; + + // Token: 0x04000205 RID: 517 + [XmlElement(ElementName = "BuddyUserID")] + public string BuddyUserID; + } +} \ No newline at end of file diff --git a/src/Schema/BuddyActionResultType.cs b/src/Schema/BuddyActionResultType.cs new file mode 100644 index 0000000..d29ba40 --- /dev/null +++ b/src/Schema/BuddyActionResultType.cs @@ -0,0 +1,30 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [Flags] + public enum BuddyActionResultType + { + // Token: 0x04000217 RID: 535 + [XmlEnum("0")] + Unknown = 0, + // Token: 0x04000218 RID: 536 + [XmlEnum("1")] + Success = 1, + // Token: 0x04000219 RID: 537 + [XmlEnum("2")] + BuddyListFull = 2, + // Token: 0x0400021A RID: 538 + [XmlEnum("3")] + FriendBuddyListFull = 3, + // Token: 0x0400021B RID: 539 + [XmlEnum("4")] + AlreadyInList = 4, + // Token: 0x0400021C RID: 540 + [XmlEnum("5")] + InvalidFriendCode = 5, + // Token: 0x0400021D RID: 541 + [XmlEnum("6")] + CannotAddSelf = 6 + } +} \ No newline at end of file diff --git a/src/Services/BuddyService.cs b/src/Services/BuddyService.cs new file mode 100644 index 0000000..f750be5 --- /dev/null +++ b/src/Services/BuddyService.cs @@ -0,0 +1,117 @@ +using System; +using System.Data; +using sodoff.Model; +using sodoff.Schema; +using sodoff.Util; + +namespace sodoff.Services; + +public class BuddyService +{ + private readonly DBContext ctx; + private readonly MessagingService messagingService; + public BuddyService(DBContext ctx, MessagingService messagingService) + { + this.ctx = ctx; + this.messagingService = messagingService; + } + + public BuddyActionResult CreateBuddyRelation(Viking viking1, Viking viking2, BuddyStatus buddyStatus1 = BuddyStatus.PendingApprovalFromOther, BuddyStatus buddyStatus2 = BuddyStatus.PendingApprovalFromSelf) + { + // get execution UTC timestamp + DateTime now = DateTime.UtcNow; + + // construct buddy + Model.Buddy buddy = new Model.Buddy + { + Viking = viking1, + VikingId = viking1.Id, + BuddyViking = viking2, + BuddyVikingId = viking2.Id, + BuddyStatus1 = buddyStatus1, + BuddyStatus2 = buddyStatus2, + IsBestFriend1 = false, + IsBestFriend2 = false, + CreatedAt = now + }; + + // do not add if viking1 is on a different game version than viking2 + if (viking1.GameVersion < viking2.GameVersion) return new BuddyActionResult { Result = BuddyActionResultType.InvalidFriendCode }; + + // do not add if relationship already exists + Model.Buddy? existingBuddy = ctx.Buddies.FirstOrDefault(e => e.VikingId == buddy.VikingId && e.BuddyVikingId == buddy.BuddyVikingId); + if (existingBuddy != null) return new BuddyActionResult { Result = BuddyActionResultType.AlreadyInList }; + + // add relationship to database + ctx.Buddies.Add(buddy); + ctx.SaveChanges(); + + // if this is a buddy relationship, use MessagingService to send buddy request message to viking2 + if (buddyStatus1 == BuddyStatus.PendingApprovalFromOther && buddyStatus2 == BuddyStatus.PendingApprovalFromSelf) + messagingService.AddMessageToViking(viking1, viking2, MessageType.Data, MessageTypeID.BuddyList, MessageLevel.WhiteList, "[[Line1]]=[[{{BuddyUserName}} Wants To Add You As A Buddy!]]", "[[Line1]]=[[{{BuddyUserName}} Wants To Add You As A Buddy!]]", "[[Line1]]=[[{{BuddyUserName}} Wants To Add You As A Buddy!]]"); + + // return result + return new BuddyActionResult + { + Result = BuddyActionResultType.Success, + Status = buddy.BuddyStatus1, + BuddyUserID = viking2.Uid.ToString() + }; + } + + public void RemoveBuddy(Viking viking, Guid buddyUid) + { + // find buddy viking + Viking? buddyViking = ctx.Vikings.FirstOrDefault(e => e.Uid == buddyUid); + + if (buddyViking != null) + { + // find buddy relationship + Model.Buddy? buddy = ctx.Buddies.Where(e => e.VikingId == viking.Id) + .FirstOrDefault(e => e.BuddyVikingId == buddyViking.Id); + + if (buddy != null) + // remove it + ctx.Buddies.Remove(buddy); + else throw new InvalidOperationException("Cannot Remove A Buddy That Doesn't Exist"); + + ctx.SaveChanges(); + } + } + + public BuddyList ConstructBuddyList(Viking viking) + { + // get all relationships viking has made + List buddies = ctx.Buddies.Where(e => e.BuddyVikingId == viking.Id).ToList(); + List schemaBuddies = new(); + foreach (var buddy in buddies) + { + // show differently depending on requester + if (buddy.VikingId == viking.Id) + schemaBuddies.Add(new Schema.Buddy + { + UserID = buddy.BuddyViking.Uid.ToString(), + DisplayName = XmlUtil.DeserializeXml(buddy.BuddyViking.AvatarSerialized).DisplayName, + Status = buddy.BuddyStatus2, + CreateDate = buddy.CreatedAt, + Online = true, // hardcoded until mmo reports precense + OnMobile = false, + BestBuddy = buddy.IsBestFriend2 + }); + else + schemaBuddies.Add(new Schema.Buddy + { + UserID = buddy.Viking.Uid.ToString(), + DisplayName = XmlUtil.DeserializeXml(buddy.Viking.AvatarSerialized).DisplayName, + Status = buddy.BuddyStatus1, + CreateDate = buddy.CreatedAt, + Online = true, // hardcoded until mmo reports precense + OnMobile = false, + BestBuddy = buddy.IsBestFriend1 + }); + } + + // return buddy list + return new BuddyList { Buddy = schemaBuddies.ToArray() }; + } +}