diff --git a/WowsKarma.Api/Data/Models/Post.cs b/WowsKarma.Api/Data/Models/Post.cs index 1e80c987..f258b79d 100644 --- a/WowsKarma.Api/Data/Models/Post.cs +++ b/WowsKarma.Api/Data/Models/Post.cs @@ -92,6 +92,18 @@ public sealed record Post : ITimestamped, IDisposable /// public bool ModLocked { get; set; } + /// + /// The Customer Support ticket ID associated with this post. + /// + /// + /// This is used by WG staff to track and manage player reports. + /// + /// + /// Set as if no ticket is associated. + /// When present, takes form as a positive integer, up to 9 digits. + /// + [Range(1, 999_999_999)] + public int? CustomerSupportTicketId { get; set; } /// public void Dispose() diff --git a/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.Designer.cs b/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.Designer.cs new file mode 100644 index 00000000..597dfce6 --- /dev/null +++ b/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.Designer.cs @@ -0,0 +1,602 @@ +// +using System; +using System.Collections.Generic; +using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Nodsoft.Wargaming.Api.Common.Data.Responses.Wows; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using WowsKarma.Api.Data; +using WowsKarma.Api.Data.Models.Replays; +using WowsKarma.Common.Models; + +#nullable disable + +namespace WowsKarma.Api.Migrations +{ + [DbContext(typeof(ApiDbContext))] + [Migration("20240901093435_AddCSTicketId")] + partial class AddCSTicketId + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "clan_role", new[] { "unknown", "commander", "executive_officer", "recruitment_officer", "commissioned_officer", "officer", "private" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "mod_action_type", new[] { "deletion", "update" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "notification_type", new[] { "unknown", "other", "post_added", "post_edited", "post_deleted", "post_mod_edited", "post_mod_deleted", "platform_ban" }); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Clan", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("NOW()"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsDisbanded") + .HasColumnType("boolean"); + + b.Property("LeagueColor") + .HasColumnType("bigint"); + + b.Property("MembersUpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Clans"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.ClanMember", b => + { + b.Property("PlayerId") + .HasColumnType("bigint"); + + b.Property("ClanId") + .HasColumnType("bigint"); + + b.Property("JoinedAt") + .HasColumnType("date"); + + b.Property("LeftAt") + .HasColumnType("date"); + + b.Property("Role") + .HasColumnType("clan_role"); + + b.HasKey("PlayerId"); + + b.HasIndex("ClanId"); + + b.ToTable("ClanMembers"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.NotificationBase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("AcknowledgedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EmittedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("notification_type"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Notifications"); + + b.HasDiscriminator("Type").IsComplete(false).HasValue(NotificationType.Unknown); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.PlatformBan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BannedUntil") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("NOW()"); + + b.Property("ModId") + .HasColumnType("bigint"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("text"); + + b.Property("Reverted") + .HasColumnType("boolean"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ModId"); + + b.HasIndex("UserId"); + + b.ToTable("PlatformBans"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Player", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CourtesyRating") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("NOW()"); + + b.Property("GameKarma") + .HasColumnType("integer"); + + b.Property("LastBattleTime") + .HasColumnType("timestamp with time zone"); + + b.Property("OptOutChanged") + .HasColumnType("timestamp with time zone"); + + b.Property("OptedOut") + .HasColumnType("boolean"); + + b.Property("PerformanceRating") + .HasColumnType("integer"); + + b.Property("PostsBanned") + .HasColumnType("boolean"); + + b.Property("SiteKarma") + .HasColumnType("integer"); + + b.Property("TeamplayRating") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.Property("WgAccountCreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WgHidden") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("NOW()"); + + b.Property("CustomerSupportTicketId") + .HasColumnType("integer"); + + b.Property("Flairs") + .HasColumnType("integer"); + + b.Property("ModLocked") + .HasColumnType("boolean"); + + b.Property("NegativeKarmaAble") + .HasColumnType("boolean"); + + b.Property("PlayerId") + .HasColumnType("bigint"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("ReplayId") + .HasColumnType("uuid"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.PostModAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActionType") + .HasColumnType("mod_action_type"); + + b.Property("ModId") + .HasColumnType("bigint"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ModId"); + + b.HasIndex("PostId"); + + b.ToTable("PostModActions"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Replays.Replay", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ArenaInfo") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("BlobName") + .IsRequired() + .HasColumnType("text"); + + b.Property>("ChatMessages") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("MinimapRendered") + .HasColumnType("boolean"); + + b.Property>("Players") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PlatformBanNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("BanId") + .HasColumnType("uuid"); + + b.HasIndex("BanId"); + + b.HasDiscriminator().HasValue(NotificationType.PlatformBan); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostAddedNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("PostId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid"); + + b.HasIndex("PostId"); + + b.HasDiscriminator().HasValue(NotificationType.PostAdded); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostDeletedNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("PostId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid"); + + b.HasIndex("PostId"); + + b.HasDiscriminator().HasValue(NotificationType.PostDeleted); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostEditedNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("PostId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid"); + + b.HasIndex("PostId"); + + b.HasDiscriminator().HasValue(NotificationType.PostEdited); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostModDeletedNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("ModActionId") + .HasColumnType("uuid"); + + b.HasIndex("ModActionId"); + + b.HasDiscriminator().HasValue(NotificationType.PostModDeleted); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostModEditedNotification", b => + { + b.HasBaseType("WowsKarma.Api.Data.Models.Notifications.NotificationBase"); + + b.Property("ModActionId") + .HasColumnType("uuid"); + + b.HasIndex("ModActionId"); + + b.ToTable("Notifications", t => + { + t.Property("ModActionId") + .HasColumnName("PostModEditedNotification_ModActionId"); + }); + + b.HasDiscriminator().HasValue(NotificationType.PostModEdited); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.ClanMember", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Clan", "Clan") + .WithMany("Members") + .HasForeignKey("ClanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WowsKarma.Api.Data.Models.Player", "Player") + .WithOne("ClanMember") + .HasForeignKey("WowsKarma.Api.Data.Models.ClanMember", "PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clan"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.NotificationBase", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Player", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.PlatformBan", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Player", "Mod") + .WithMany() + .HasForeignKey("ModId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WowsKarma.Api.Data.Models.Player", "User") + .WithMany("PlatformBans") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Mod"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Post", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Player", "Author") + .WithMany("PostsSent") + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("WowsKarma.Api.Data.Models.Player", "Player") + .WithMany("PostsReceived") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("WowsKarma.Api.Data.Models.Replays.Replay", "Replay") + .WithOne("Post") + .HasForeignKey("WowsKarma.Api.Data.Models.Post", "ReplayId"); + + b.Navigation("Author"); + + b.Navigation("Player"); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.PostModAction", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Player", "Mod") + .WithMany() + .HasForeignKey("ModId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WowsKarma.Api.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Mod"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PlatformBanNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.PlatformBan", "Ban") + .WithMany() + .HasForeignKey("BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostAddedNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostDeletedNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostEditedNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostModDeletedNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.PostModAction", "ModAction") + .WithMany() + .HasForeignKey("ModActionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ModAction"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Notifications.PostModEditedNotification", b => + { + b.HasOne("WowsKarma.Api.Data.Models.PostModAction", "ModAction") + .WithMany() + .HasForeignKey("ModActionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ModAction"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Clan", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Player", b => + { + b.Navigation("ClanMember"); + + b.Navigation("PlatformBans"); + + b.Navigation("PostsReceived"); + + b.Navigation("PostsSent"); + }); + + modelBuilder.Entity("WowsKarma.Api.Data.Models.Replays.Replay", b => + { + b.Navigation("Post") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.cs b/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.cs new file mode 100644 index 00000000..1fe46b15 --- /dev/null +++ b/WowsKarma.Api/Migrations/20240901093435_AddCSTicketId.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WowsKarma.Api.Migrations +{ + /// + public partial class AddCSTicketId : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CustomerSupportTicketId", + table: "Posts", + type: "integer", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CustomerSupportTicketId", + table: "Posts"); + } + } +} diff --git a/WowsKarma.Api/Migrations/ApiDb/ApiDbContextModelSnapshot.cs b/WowsKarma.Api/Migrations/ApiDb/ApiDbContextModelSnapshot.cs index 87968ea9..cc557dff 100644 --- a/WowsKarma.Api/Migrations/ApiDb/ApiDbContextModelSnapshot.cs +++ b/WowsKarma.Api/Migrations/ApiDb/ApiDbContextModelSnapshot.cs @@ -1,11 +1,11 @@ // using System; using System.Collections.Generic; +using System.Text.Json; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Nodsoft.Wargaming.Api.Common.Data.Responses.Wows; -using Nodsoft.WowsReplaysUnpack.Core.Models; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using WowsKarma.Api.Data; using WowsKarma.Api.Data.Models.Replays; @@ -22,7 +22,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.1") + .HasAnnotation("ProductVersion", "8.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "clan_role", new[] { "unknown", "commander", "executive_officer", "recruitment_officer", "commissioned_officer", "officer", "private" }); @@ -234,6 +234,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("timestamp with time zone") .HasDefaultValueSql("NOW()"); + b.Property("CustomerSupportTicketId") + .HasColumnType("integer"); + b.Property("Flairs") .HasColumnType("integer"); @@ -305,7 +308,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("ArenaInfo") + b.Property("ArenaInfo") .IsRequired() .HasColumnType("jsonb"); diff --git a/WowsKarma.Api/Services/Discord/PostWebhookService.cs b/WowsKarma.Api/Services/Discord/PostWebhookService.cs index 2c2388d5..03d2c22b 100644 --- a/WowsKarma.Api/Services/Discord/PostWebhookService.cs +++ b/WowsKarma.Api/Services/Discord/PostWebhookService.cs @@ -86,6 +86,11 @@ private static DiscordEmbedBuilder AddPostContent(DiscordEmbedBuilder embed, Pla embed.AddField("Teamplay", GetFlairValueString(parsedFlairs?.Teamplay), true); embed.AddField("Courtesy", GetFlairValueString(parsedFlairs?.Courtesy), true); + if (post.SupportTicketStatus.HasTicket) + { + embed.AddField("CS Ticket ID", $"`{post.SupportTicketStatus.TicketId:D}`"); + } + return embed; } } \ No newline at end of file diff --git a/WowsKarma.Api/Services/Posts/PostService.cs b/WowsKarma.Api/Services/Posts/PostService.cs index b35e6b4c..f6ae235c 100644 --- a/WowsKarma.Api/Services/Posts/PostService.cs +++ b/WowsKarma.Api/Services/Posts/PostService.cs @@ -177,6 +177,7 @@ public async Task EditPostAsync(Guid id, PlayerPostDTO edited, bool modEditLock current.Flairs = edited.Flairs; current.UpdatedAt = DateTimeOffset.UtcNow; // Forcing UpdatedAt refresh current.ReadOnly = current.ReadOnly || modEditLock; + current.CustomerSupportTicketId = edited.SupportTicketStatus.TicketId; KarmaService.UpdatePlayerKarma(player, current.ParsedFlairs, previousFlairs, current.NegativeKarmaAble); KarmaService.UpdatePlayerRatings(player, current.ParsedFlairs, previousFlairs); diff --git a/WowsKarma.Api/Utilities/Conversions.cs b/WowsKarma.Api/Utilities/Conversions.cs index edf1928e..c69d72db 100644 --- a/WowsKarma.Api/Utilities/Conversions.cs +++ b/WowsKarma.Api/Utilities/Conversions.cs @@ -15,12 +15,17 @@ public static class Conversions public static void ConfigureMapping() { TypeAdapterConfig.GlobalSettings.Compiler = exp => exp.CompileWithDebugInfo(); - + TypeAdapterConfig .NewConfig() .IgnoreNullValues(true) .Ignore(dest => dest.Author) - .Ignore(dest => dest.Player); + .Ignore(dest => dest.Player) + .Map( + dest => dest.CustomerSupportTicketId, + src => src.SupportTicketStatus.TicketId, + srcCond => srcCond.SupportTicketStatus.TicketId != null + ); TypeAdapterConfig .NewConfig() @@ -34,7 +39,12 @@ public static void ConfigureMapping() : ReplayState.Processing ) .Map(dest => dest.Author.Clan, src => src.Author.ClanMember.Clan) - .Map(dest => dest.Player.Clan, src => src.Player.ClanMember.Clan); + .Map(dest => dest.Player.Clan, src => src.Player.ClanMember.Clan) + .Map(dest => dest.SupportTicketStatus, src => new PlayerPostDTO.CustomerSupportStatus + { + HasTicket = src.CustomerSupportTicketId != null, + TicketId = src.CustomerSupportTicketId + }); TypeAdapterConfig .NewConfig() diff --git a/WowsKarma.Common/Models/DTOs/PlayerPostDTO.cs b/WowsKarma.Common/Models/DTOs/PlayerPostDTO.cs index 87693cdf..5c337f81 100644 --- a/WowsKarma.Common/Models/DTOs/PlayerPostDTO.cs +++ b/WowsKarma.Common/Models/DTOs/PlayerPostDTO.cs @@ -26,4 +26,29 @@ public record PlayerPostDTO // Computed by DB Engine (hopefully) public DateTimeOffset? CreatedAt { get; init; } public DateTimeOffset? UpdatedAt { get; init; } + + /// + /// The status of the Customer Support ticket associated with the post when applicable. + /// + public CustomerSupportStatus SupportTicketStatus { get; init; } + + /// + /// Defines the status of the Customer Support ticket associated with the post when applicable. + /// + public readonly struct CustomerSupportStatus + { + /// + /// Whether the post has an associated Customer Support ticket. + /// + public bool HasTicket { get; init; } + + /// + /// The Customer Support ticket ID associated with this post. + /// + /// + /// This is only available when is , + /// and only visible to the post's author, platform staff, and Wargaming staff. + /// + public int? TicketId { get; init; } + } } diff --git a/wowskarma.app/src/app/services/api/models/player-post-dto.ts b/wowskarma.app/src/app/services/api/models/player-post-dto.ts index f623c8ed..10615fcb 100644 --- a/wowskarma.app/src/app/services/api/models/player-post-dto.ts +++ b/wowskarma.app/src/app/services/api/models/player-post-dto.ts @@ -20,6 +20,10 @@ export interface PlayerPostDto { replayState?: ReplayState title?: null | string; updatedAt?: null | string; + supportTicketStatus?: { + hasTicket: boolean; + ticketId: number | null; + } } enum ReplayState { diff --git a/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.html b/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.html new file mode 100644 index 00000000..5264d4e3 --- /dev/null +++ b/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.html @@ -0,0 +1,63 @@ + + + diff --git a/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.ts b/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.ts new file mode 100644 index 00000000..79cb23ef --- /dev/null +++ b/wowskarma.app/src/app/shared/modals/cs-ticket-id-help/cs-ticket-id-help.component.ts @@ -0,0 +1,56 @@ +import { ChangeDetectionStrategy, Component, computed, inject, Input } from '@angular/core'; +import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap"; +import { AuthService } from "../../../services/api/services/auth.service"; +import { AppConfigService } from "../../../services/app-config.service"; + +@Component({ + selector: 'app-cs-ticket-id', + standalone: true, + imports: [], + templateUrl: './cs-ticket-id-help.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CsTicketIdHelpComponent { + @Input() modal!: NgbModalRef; + + appConfig = inject(AppConfigService); + + region = computed(() => this.appConfig.currentRegion); + + csLinks = computed<[string, string]>(() => { + /* + * In order: + * - Gameplay / Collusions + * - Chat Issues + * + * See: https://github.com/SakuraIsayeki/WOWS-Karma/issues/165 + */ + + if (this.region() === 'EU') { + return [ + 'https://eu.wargaming.net/support/en/products/wows/help/29948/29949/29955/29957/', + 'https://eu.wargaming.net/support/en/products/wows/help/29948/29949/29951/29952/' + ]; + } else if (this.region() === 'NA') { + return [ + 'https://na.wargaming.net/support/en/products/wows/help/31336/31337/31338/31339/', + 'https://na.wargaming.net/support/en/products/wows/help/31336/31337/31345/' + ]; + } else if (this.region() === 'SEA') { + return [ + "https://asia.wargaming.net/support/en/products/wows/help/28687/28688/28689/", + "https://asia.wargaming.net/support/en/products/wows/help/28687/28688/28694/" + ]; + } + + return ['', '']; + }) + + constructor() { + } + + static OpenModal(modalService: NgbModal) { + const modalRef = modalService.open(CsTicketIdHelpComponent, { size: "lg" }); + modalRef.componentInstance.modal = modalRef; + } +} diff --git a/wowskarma.app/src/app/shared/modals/post-editor/post-editor.component.html b/wowskarma.app/src/app/shared/modals/post-editor/post-editor.component.html index dc658a7b..54bcc245 100644 --- a/wowskarma.app/src/app/shared/modals/post-editor/post-editor.component.html +++ b/wowskarma.app/src/app/shared/modals/post-editor/post-editor.component.html @@ -69,20 +69,41 @@
{{group.label}}
-
-

Replay File

+
+
+

Replay File

- + -
- +
+ +
+ + + @if (flairGroups.length > 1 && (flairGroups[1].control.value === false || flairGroups[2].control.value === false)) { +
+
+ + + (optional) + + + + +
+ + +
+ }
- -