packages feed

wikimusic-model-hs-1.2.0.0: src/WikiMusic/Model/Artist.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoFieldSelectors #-}

module WikiMusic.Model.Artist
  ( Artist (..),
    ArtistArtwork (..),
    ArtistComment (..),
    ArtistOpinion (..),
    validateArtist,
    validateArtistArtwork,
    validateArtistComment,
    validateArtistOpinion,
    ArtistSortOrder (..),
    ArtistExternalSources (..),
    validateArtistExternalSources,
    ArtistArtworkOrderUpdate (..),
    validateArtistArtworkOrderUpdate,
    validateArtistDelta,
    ArtistDelta (..),
    Prelude.show,
    Prelude.read,
    ArtistIncludes (..),
    EnrichArtistParams (..),
    fullEnrichment,
    noEnrichment,
    parseInclude,
  )
where

import Data.Aeson hiding (Success)
import Data.Map qualified as Map
import Data.OpenApi
import Data.Text qualified as T
import Data.Time
import Data.UUID
import Keuringsdienst
import Keuringsdienst.Helpers
import Relude
import Text.Read
import WikiMusic.Model.Artwork
import WikiMusic.Model.Comment
import WikiMusic.Model.Opinion
import WikiMusic.Model.Thread
import Prelude qualified
import Optics

data ArtistIncludes = IncludeComments | IncludeOpinions | IncludeArtworks deriving (Eq, Generic, FromJSON, ToJSON, ToSchema)

instance Show ArtistIncludes where
  show IncludeComments = "comments"
  show IncludeOpinions = "opinions"
  show IncludeArtworks = "artworks"

instance Read ArtistIncludes where
  readsPrec _ "comments" = [(IncludeComments, "")]
  readsPrec _ "opinions" = [(IncludeOpinions, "")]
  readsPrec _ "artworks" = [(IncludeArtworks, "")]
  readsPrec _ _ = []

data ArtistSortOrder
  = DescCreatedAt
  | AscCreatedAt
  | DescLastEditedAt
  | AscLastEditedAt
  | DescDisplayName
  | AscDisplayName

instance Show ArtistSortOrder where
  show DescCreatedAt = "artists.created_at DESC"
  show AscCreatedAt = "artists.created_at ASC"
  show DescLastEditedAt = "artists.last_edited_at DESC"
  show AscLastEditedAt = "artists.last_edited_at ASC"
  show DescDisplayName = "artists.display_name DESC"
  show AscDisplayName = "artists.display_name ASC"

instance Read ArtistSortOrder where
  readsPrec _ "created-at-desc" = [(DescCreatedAt, "")]
  readsPrec _ "created-at-asc" = [(AscCreatedAt, "")]
  readsPrec _ "last-edited-at-desc" = [(DescLastEditedAt, "")]
  readsPrec _ "last-edited-at-asc" = [(AscLastEditedAt, "")]
  readsPrec _ "display-name-desc" = [(DescDisplayName, "")]
  readsPrec _ "display-name-asc" = [(AscDisplayName, "")]
  readsPrec _ _ = []

validateArtistOpinion :: ArtistOpinion -> ValidationResult
validateArtistOpinion x =
  (x ^. #opinion % #isLike)
    |?| isNotEqualTo (x ^. #opinion % #isDislike)
    <> (x ^. #opinion % #isDislike)
      |?| isNotEqualTo (x ^. #opinion % #isLike)

data ArtistOpinion = ArtistOpinion
  { artistIdentifier :: UUID,
    opinion :: Opinion
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

validateArtistArtwork :: ArtistArtwork -> ValidationResult
validateArtistArtwork x =
  (x ^. #artwork % #contentUrl)
    |?| isNonEmptyText
    <> (x ^. #artwork % #contentCaption)
      |??| isNonEmptyText
    <> (x ^. #artwork % #visibilityStatus)
      |?| isPositiveOrZero
    <> (x ^. #artwork % #orderValue)
      |?| isPositiveOrZero

data ArtistArtwork = ArtistArtwork
  { artistIdentifier :: UUID,
    artwork :: Artwork
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

validateArtistComment :: ArtistComment -> ValidationResult
validateArtistComment x =
  (x ^. #comment % #visibilityStatus)
    |?| isPositiveOrZero
    <> (x ^. #comment % #contents)
      |?| (isNonEmptyText <> isTextSmallerThanOrEqual 8200)

data ArtistComment = ArtistComment
  { artistIdentifier :: UUID,
    comment :: Comment
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

validateArtist :: Artist -> ValidationResult
validateArtist x =
  (x ^. #displayName)
    |?| (isNonEmptyText <> isTextSmallerThanOrEqual 340)
    <> (x ^. #visibilityStatus)
      |?| isPositiveOrZero
    <> (x ^. #spotifyUrl)
      |??| isNonEmptyText
    <> (x ^. #youtubeUrl)
      |??| isNonEmptyText
    <> (x ^. #soundcloudUrl)
      |??| isNonEmptyText
    <> (x ^. #wikipediaUrl)
      |??| isNonEmptyText

data Artist = Artist
  { identifier :: UUID,
    displayName :: Text,
    createdBy :: UUID,
    visibilityStatus :: Int,
    approvedBy :: Maybe UUID,
    createdAt :: UTCTime,
    lastEditedAt :: Maybe UTCTime,
    artworks :: Map UUID ArtistArtwork,
    comments :: [ThreadRender ArtistComment],
    opinions :: Map UUID ArtistOpinion,
    spotifyUrl :: Maybe Text,
    youtubeUrl :: Maybe Text,
    soundcloudUrl :: Maybe Text,
    wikipediaUrl :: Maybe Text,
    viewCount :: Int,
    description :: Maybe Text
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

makeFieldLabelsNoPrefix ''Artist
makeFieldLabelsNoPrefix ''ArtistComment
makeFieldLabelsNoPrefix ''ArtistArtwork
makeFieldLabelsNoPrefix ''ArtistOpinion

validateArtistExternalSources :: ArtistExternalSources -> ValidationResult
validateArtistExternalSources x =
  (x ^. #spotifyUrl)
    |??| isNonEmptyText
    <> (x ^. #youtubeUrl)
      |??| isNonEmptyText
    <> (x ^. #soundcloudUrl)
      |??| isNonEmptyText
    <> (x ^. #wikipediaUrl)
      |??| isNonEmptyText

data ArtistExternalSources = ArtistExternalSources
  { identifier :: UUID,
    artistIdentifier :: UUID,
    createdBy :: UUID,
    spotifyUrl :: Maybe Text,
    youtubeUrl :: Maybe Text,
    soundcloudUrl :: Maybe Text,
    wikipediaUrl :: Maybe Text,
    createdAt :: UTCTime,
    lastEditedAt :: Maybe UTCTime
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

makeFieldLabelsNoPrefix ''ArtistExternalSources

validateArtistArtworkOrderUpdate :: ArtistArtworkOrderUpdate -> ValidationResult
validateArtistArtworkOrderUpdate x =
  (x ^. #orderValue) |?| isPositiveOrZero

data ArtistArtworkOrderUpdate = ArtistArtworkOrderUpdate
  { identifier :: UUID,
    orderValue :: Int
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

data ArtistDelta = ArtistDelta
  { identifier :: UUID,
    displayName :: Maybe Text,
    spotifyUrl :: Maybe Text,
    youtubeUrl :: Maybe Text,
    soundcloudUrl :: Maybe Text,
    wikipediaUrl :: Maybe Text,
    description :: Maybe Text
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

makeFieldLabelsNoPrefix ''ArtistDelta

validateArtistDelta :: ArtistDelta -> ValidationResult
validateArtistDelta x =
  (x ^. #displayName)
    |??| (isNonEmptyText <> isTextSmallerThanOrEqual 340)
    <> (x ^. #spotifyUrl)
      |??| isNonEmptyText
    <> (x ^. #youtubeUrl)
      |??| isNonEmptyText
    <> (x ^. #soundcloudUrl)
      |??| isNonEmptyText
    <> (x ^. #wikipediaUrl)
      |??| isNonEmptyText

data EnrichArtistParams = EnrichArtistParams
  { includeComments :: Bool,
    includeOpinions :: Bool,
    includeArtworks :: Bool
  }
  deriving (Eq, Show, Generic, FromJSON, ToJSON, ToSchema)

makeFieldLabelsNoPrefix ''EnrichArtistParams

fullEnrichment :: EnrichArtistParams
fullEnrichment =
  EnrichArtistParams
    { includeComments = True,
      includeArtworks = True,
      includeOpinions = True
    }

noEnrichment :: EnrichArtistParams
noEnrichment =
  EnrichArtistParams
    { includeComments = False,
      includeArtworks = False,
      includeOpinions = False
    }

parseInclude :: Text -> EnrichArtistParams
parseInclude includeString = do
  EnrichArtistParams
    { includeComments = fromIncludeMap IncludeComments,
      includeOpinions = fromIncludeMap IncludeOpinions,
      includeArtworks = fromIncludeMap IncludeArtworks
    }
  where
    includes = Map.fromList $ map (,True) (T.split (== ',') includeString)
    fromIncludeMap k = fromMaybe False (includes Map.!? (T.pack . show $ k))