using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Iceshrimp.Backend.Core.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Iceshrimp.Backend.Core.Database.Tables; [Table("emoji")] [Index(nameof(Host))] [Index(nameof(Name))] public class Emoji { [Key] [Column("id")] [StringLength(32)] public string Id { get; set; } = null!; [Column("updatedAt")] public DateTime? UpdatedAt { get; set; } [Column("name")] [StringLength(128)] public string Name { get; set; } = null!; [Column("host")] [StringLength(512)] public string? Host { get; set; } [Column("originalUrl")] [StringLength(512)] public string OriginalUrl { get; set; } = null!; [Column("uri")] [StringLength(512)] public string? Uri { get; set; } [Column("type")] [StringLength(64)] public string? Type { get; set; } [Column("tags", TypeName = "character varying(128)[]")] public List Tags { get; set; } = []; [Column("category")] [StringLength(128)] public string? Category { get; set; } [Column("publicUrl")] [StringLength(512)] public string RawPublicUrl { get; set; } = null!; [Column("license")] [StringLength(1024)] public string? License { get; set; } /// /// Image width /// [Column("width")] public int? Width { get; set; } /// /// Image height /// [Column("height")] public int? Height { get; set; } [Column("sensitive")] public bool Sensitive { get; set; } public string GetPublicUri(Config.InstanceSection config) => Host == null ? $"https://{config.WebDomain}/emoji/{Name}" : throw new Exception("Cannot access PublicUri for remote emoji"); public string? GetPublicUriOrNull(Config.InstanceSection config) => Host == null ? $"https://{config.WebDomain}/emoji/{Name}" : null; public string GetAccessUrl(Config.InstanceSection config) => $"https://{config.WebDomain}/media/emoji/{Id}"; private class EntityTypeConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder entity) { entity.Property(e => e.Tags).HasDefaultValueSql("'{}'::character varying[]"); entity.Property(e => e.Height).HasComment("Image height"); entity.Property(e => e.RawPublicUrl).HasDefaultValueSql("''::character varying"); entity.Property(e => e.Width).HasComment("Image width"); entity.HasIndex(e => e.Name, "GIN_TRGM_emoji_name") .HasMethod("gin") .HasOperators("gin_trgm_ops"); entity.HasIndex(e => e.Host, "GIN_TRGM_emoji_host") .HasMethod("gin") .HasOperators("gin_trgm_ops"); // This index must be NULLS NOT DISTINCT to make having multiple local emoji with the same name cause a constraint failure entity.HasIndex(nameof(Name), nameof(Host)).IsUnique().AreNullsDistinct(false); } } }