packages feed

gerrit-0.1.6.1: src/Gerrit/Data/Event.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- | Gerrit stream event data type
module Gerrit.Data.Event (
    -- * Main event data types
    EventType (..),
    Event (..),

    -- * Common data types
    User (..),
    PatchSet (..),
    Change (..),
    Ref (..),

    -- * Individual event data types
    AssigneeChanged (..),
    ChangeAbandoned (..),
    ChangeDeleted (..),
    ChangeMerged (..),
    ChangeRestored (..),
    CommentAdded (..),
    HashtagsChanged (..),
    ProjectCreated (..),
    PatchsetCreated (..),
    RefUpdated (..),
    ReviewerAdded (..),
    ReviewerDeleted (..),
    TopicChanged (..),
    WorkInProgressStateChanged (..),
    PrivateStateChanged (..),
    VoteDeleted (..),

    -- * Convenient functions
    getChange,
    getPatchSet,
    getUser,
    getCreatedOn,
    getEventType,
    eventName,
)
where

import Control.Monad (mzero)
import Data.Aeson (
    FromJSON (..),
    Options (fieldLabelModifier),
    Value (Object, String),
    defaultOptions,
    genericParseJSON,
    (.:),
 )
import Data.Char (toLower)
import Data.Text (Text)
import qualified Data.Text as Text
import GHC.Generics (Generic)
import GHC.Int (Int64)

aesonOption :: Text -> Options
aesonOption prefix = defaultOptions{fieldLabelModifier = recordToJson}
  where
    recordToJson = updateCase . drop (Text.length prefix)
    updateCase [] = []
    updateCase (x : xs) = toLower x : xs

-------------------------------------------------------------------------------
-- Shared types
-------------------------------------------------------------------------------
data User = User
    { userName :: Maybe Text
    , userEmail :: Maybe Text
    , userUsername :: Maybe Text
    }
    deriving (Show, Eq, Generic)

instance FromJSON User where
    parseJSON = genericParseJSON $ aesonOption "user"

data PatchSet = PatchSet
    { patchSetNumber :: Int
    , patchSetRef :: Text
    , patchSetUploader :: User
    , patchsetAuthor :: User
    }
    deriving (Show, Eq, Generic)

instance FromJSON PatchSet where
    parseJSON = genericParseJSON $ aesonOption "patchSet"

data Change = Change
    { changeProject :: Text
    , changeBranch :: Text
    , changeSubject :: Text
    , changeNumber :: Int
    , changeUrl :: Text
    , changeOwner :: User
    , changeWip :: Maybe Bool
    , changeTopic :: Maybe Text
    , changeCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

instance FromJSON Change where
    parseJSON = genericParseJSON $ aesonOption "change"

data Ref = Ref
    { refOldRev :: Text
    , refNewRev :: Text
    , refRefName :: Text
    , refProject :: Text
    }
    deriving (Show, Eq, Generic)

instance FromJSON Ref where
    parseJSON = genericParseJSON $ aesonOption "ref"

-------------------------------------------------------------------------------
-- Individual Event data types
-------------------------------------------------------------------------------
data AssigneeChanged = AssigneeChanged
    { assigneeChangedChange :: Change
    , assigneeChangedChanger :: User
    , assigneeChangedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ChangeAbandoned = ChangeAbandoned
    { changeAbandonedProject :: Text
    , changeAbandonedAbandoner :: User
    , changeAbandonedChange :: Change
    , changeAbandonedPatchSet :: PatchSet
    , changeAbandonedReason :: Maybe Text
    , changeAbandonedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ChangeDeleted = ChangeDeleted
    { changeDeletedChange :: Change
    , changeDeletedDeleter :: User
    }
    deriving (Show, Eq, Generic)

data ChangeMerged = ChangeMerged
    { changeMergedProject :: Text
    , changeMergedSubmitter :: User
    , changeMergedChange :: Change
    , changeMergedPatchSet :: PatchSet
    , changeMergedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ChangeRestored = ChangeRestored
    { changeRestoredChange :: Change
    , changeRestoredPatchSet :: PatchSet
    , changeRestoredRestorer :: User
    , changeRestoredReason :: Maybe Text
    , changeRestoredEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data CommentAdded = CommentAdded
    { commentAddedChange :: Change
    , commentAddedPatchSet :: PatchSet
    , commentAddedAuthor :: User
    , commentAddedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data HashtagsChanged = HashtagsChanged
    { hashtagsChangedChange :: Change
    , hashtagsChangedEditor :: User
    , hashtagsChangedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ProjectCreated = ProjectCreated
    { projectCreatedProjectName :: Text
    , projectCreatedHeadName :: Text
    , projectCreatedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data PatchsetCreated = PatchsetCreated
    { patchsetCreatedUploader :: User
    , patchsetCreatedChange :: Change
    , patchsetCreatedPatchSet :: PatchSet
    , patchsetCreatedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data RefUpdated = RefUpdated
    { refUpdatedSubmitter :: User
    , refUpdatedRefUpdate :: Ref
    , refUpdatedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ReviewerAdded = ReviewerAdded
    { reviewerAddedChange :: Change
    , reviewerAddedPatchSet :: PatchSet
    , reviewerAddedAdder :: User
    , reviewerAddedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data ReviewerDeleted = ReviewerDeleted
    { reviewerDeletedChange :: Change
    , reviewerDeletedPatchSet :: PatchSet
    , reviewerDeletedRemover :: User
    , reviewerDeletedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data TopicChanged = TopicChanged
    { topicChangedChange :: Change
    , topicChangedChanger :: User
    , topicChangedOldTopic :: Text
    , topicChangedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data WorkInProgressStateChanged = WorkInProgressStateChanged
    { workInProgressStateChangedChange :: Change
    , workInProgressStateChangedPatchSet :: PatchSet
    , workInProgressStateChangedChanger :: User
    , workInProgressStateChangedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data PrivateStateChanged = PrivateStateChanged
    { privateStateChangedChange :: Change
    , privateStateChangedPatchSet :: PatchSet
    , privateStateChangedChanger :: User
    , privateStateChangedChangedEventCreatedOn :: Int64
    }
    deriving (Show, Eq, Generic)

data VoteDeleted = VoteDeleted
    { voteDeletedChange :: Change
    , voteDeletedPatchSet :: PatchSet
    , voteDeletedRemover :: User
    }
    deriving (Show, Eq, Generic)

-------------------------------------------------------------------------------
-- Events FromJSON instances
-------------------------------------------------------------------------------
instance FromJSON AssigneeChanged where
    parseJSON = genericParseJSON $ aesonOption "assigneeChanged"

instance FromJSON ChangeAbandoned where
    parseJSON = genericParseJSON $ aesonOption "changeAbandoned"

instance FromJSON ChangeDeleted where
    parseJSON = genericParseJSON $ aesonOption "changeDeleted"

instance FromJSON ChangeMerged where
    parseJSON = genericParseJSON $ aesonOption "changeMerged"

instance FromJSON ChangeRestored where
    parseJSON = genericParseJSON $ aesonOption "changeRestored"

instance FromJSON CommentAdded where
    parseJSON = genericParseJSON $ aesonOption "commentAdded"

instance FromJSON HashtagsChanged where
    parseJSON = genericParseJSON $ aesonOption "hashtagsChanged"

instance FromJSON ProjectCreated where
    parseJSON = genericParseJSON $ aesonOption "projectCreated"

instance FromJSON PatchsetCreated where
    parseJSON = genericParseJSON $ aesonOption "patchsetCreated"

instance FromJSON RefUpdated where
    parseJSON = genericParseJSON $ aesonOption "refUpdated"

instance FromJSON ReviewerAdded where
    parseJSON = genericParseJSON $ aesonOption "reviewerAdded"

instance FromJSON ReviewerDeleted where
    parseJSON = genericParseJSON $ aesonOption "reviewerDeleted"

instance FromJSON TopicChanged where
    parseJSON = genericParseJSON $ aesonOption "topicChanged"

instance FromJSON WorkInProgressStateChanged where
    parseJSON = genericParseJSON $ aesonOption "workInProgressStateChanged"

instance FromJSON PrivateStateChanged where
    parseJSON = genericParseJSON $ aesonOption "privateStateChanged"

instance FromJSON VoteDeleted where
    parseJSON = genericParseJSON $ aesonOption "voteDeleted"

-- | The event "type" data type
data EventType
    = AssigneeChangedEvent
    | ChangeAbandonedEvent
    | ChangeDeletedEvent
    | ChangeMergedEvent
    | ChangeRestoredEvent
    | CommentAddedEvent
    | DroppedOutputEvent
    | HashtagsChangedEvent
    | ProjectCreatedEvent
    | PatchsetCreatedEvent
    | RefUpdatedEvent
    | ReviewerAddedEvent
    | ReviewerDeletedEvent
    | TopicChangedEvent
    | WorkInProgressStateChangedEvent
    | PrivateStateChangedEvent
    | VoteDeletedEvent
    deriving (Show, Eq)

instance FromJSON EventType where
    parseJSON (String v) = case v of
        "assignee-changed" -> pure AssigneeChangedEvent
        "change-abandoned" -> pure ChangeAbandonedEvent
        "change-deleted" -> pure ChangeDeletedEvent
        "change-merged" -> pure ChangeMergedEvent
        "change-restored" -> pure ChangeRestoredEvent
        "comment-added" -> pure CommentAddedEvent
        "dropped-output" -> pure DroppedOutputEvent
        "hashtags-changed" -> pure HashtagsChangedEvent
        "project-created" -> pure ProjectCreatedEvent
        "patchset-created" -> pure PatchsetCreatedEvent
        "ref-updated" -> pure RefUpdatedEvent
        "reviewer-added" -> pure ReviewerAddedEvent
        "reviewer-deleted" -> pure ReviewerDeletedEvent
        "topic-changed" -> pure TopicChangedEvent
        "wip-state-changed" -> pure WorkInProgressStateChangedEvent
        "private-state-changed" -> pure PrivateStateChangedEvent
        "vote-deleted" -> pure VoteDeletedEvent
        _ -> mzero
    parseJSON _ = mzero

-- | The main event union data type
data Event
    = EventAssigneeChanged AssigneeChanged
    | EventChangeAbandoned ChangeAbandoned
    | EventChangeDeleted ChangeDeleted
    | EventChangeMerged ChangeMerged
    | EventChangeRestored ChangeRestored
    | EventCommentAdded CommentAdded
    | EventDroppedOutput
    | EventHashtagsChanged HashtagsChanged
    | EventProjectCreated ProjectCreated
    | EventPatchsetCreated PatchsetCreated
    | EventRefUpdated RefUpdated
    | EventReviewerAdded ReviewerAdded
    | EventReviewerDeleted ReviewerDeleted
    | EventTopicChanged TopicChanged
    | EventWorkInProgressStateChanged WorkInProgressStateChanged
    | EventPrivateStateChanged PrivateStateChanged
    | EventVoteDeleted VoteDeleted
    deriving (Show, Eq)

instance FromJSON Event where
    parseJSON o@(Object v) = do
        eType <- v .: "type"
        case eType of
            AssigneeChangedEvent -> EventAssigneeChanged <$> parseJSON o
            ChangeAbandonedEvent -> EventChangeAbandoned <$> parseJSON o
            ChangeDeletedEvent -> EventChangeDeleted <$> parseJSON o
            ChangeMergedEvent -> EventChangeMerged <$> parseJSON o
            ChangeRestoredEvent -> EventChangeRestored <$> parseJSON o
            CommentAddedEvent -> EventCommentAdded <$> parseJSON o
            DroppedOutputEvent -> pure EventDroppedOutput
            HashtagsChangedEvent -> EventHashtagsChanged <$> parseJSON o
            ProjectCreatedEvent -> EventProjectCreated <$> parseJSON o
            PatchsetCreatedEvent -> EventPatchsetCreated <$> parseJSON o
            RefUpdatedEvent -> EventRefUpdated <$> parseJSON o
            ReviewerAddedEvent -> EventReviewerAdded <$> parseJSON o
            ReviewerDeletedEvent -> EventReviewerDeleted <$> parseJSON o
            TopicChangedEvent -> EventTopicChanged <$> parseJSON o
            WorkInProgressStateChangedEvent -> EventWorkInProgressStateChanged <$> parseJSON o
            PrivateStateChangedEvent -> EventPrivateStateChanged <$> parseJSON o
            VoteDeletedEvent -> EventVoteDeleted <$> parseJSON o
    parseJSON _ = mzero

-------------------------------------------------------------------------------
-- Utilities function
-------------------------------------------------------------------------------

-- | Get the associated change
getChange :: Event -> Maybe Change
getChange event = case event of
    EventAssigneeChanged AssigneeChanged{..} -> Just assigneeChangedChange
    EventChangeAbandoned ChangeAbandoned{..} -> Just changeAbandonedChange
    EventChangeDeleted ChangeDeleted{..} -> Just changeDeletedChange
    EventChangeMerged ChangeMerged{..} -> Just changeMergedChange
    EventChangeRestored ChangeRestored{..} -> Just changeRestoredChange
    EventCommentAdded CommentAdded{..} -> Just commentAddedChange
    EventDroppedOutput -> Nothing
    EventHashtagsChanged HashtagsChanged{..} -> Just hashtagsChangedChange
    EventProjectCreated _ -> Nothing
    EventPatchsetCreated PatchsetCreated{..} -> Just patchsetCreatedChange
    EventRefUpdated _ -> Nothing
    EventReviewerAdded ReviewerAdded{..} -> Just reviewerAddedChange
    EventReviewerDeleted ReviewerDeleted{..} -> Just reviewerDeletedChange
    EventTopicChanged TopicChanged{..} -> Just topicChangedChange
    EventWorkInProgressStateChanged WorkInProgressStateChanged{..} -> Just workInProgressStateChangedChange
    EventPrivateStateChanged PrivateStateChanged{..} -> Just privateStateChangedChange
    EventVoteDeleted VoteDeleted{..} -> Just voteDeletedChange

-- | Get the associated patchset
getPatchSet :: Event -> Maybe PatchSet
getPatchSet event = case event of
    EventAssigneeChanged _ -> Nothing
    EventChangeAbandoned ChangeAbandoned{..} -> Just changeAbandonedPatchSet
    EventChangeDeleted _ -> Nothing
    EventChangeMerged ChangeMerged{..} -> Just changeMergedPatchSet
    EventChangeRestored ChangeRestored{..} -> Just changeRestoredPatchSet
    EventCommentAdded CommentAdded{..} -> Just commentAddedPatchSet
    EventDroppedOutput -> Nothing
    EventHashtagsChanged _ -> Nothing
    EventProjectCreated _ -> Nothing
    EventPatchsetCreated PatchsetCreated{..} -> Just patchsetCreatedPatchSet
    EventRefUpdated _ -> Nothing
    EventReviewerAdded ReviewerAdded{..} -> Just reviewerAddedPatchSet
    EventReviewerDeleted ReviewerDeleted{..} -> Just reviewerDeletedPatchSet
    EventTopicChanged _ -> Nothing
    EventWorkInProgressStateChanged WorkInProgressStateChanged{..} -> Just workInProgressStateChangedPatchSet
    EventPrivateStateChanged PrivateStateChanged{..} -> Just privateStateChangedPatchSet
    EventVoteDeleted VoteDeleted{..} -> Just voteDeletedPatchSet

-- | Get the associated author
getUser :: Event -> Maybe User
getUser event = case event of
    EventAssigneeChanged AssigneeChanged{..} -> Just assigneeChangedChanger
    EventChangeAbandoned ChangeAbandoned{..} -> Just changeAbandonedAbandoner
    EventChangeDeleted ChangeDeleted{..} -> Just changeDeletedDeleter
    EventChangeMerged ChangeMerged{..} -> Just changeMergedSubmitter
    EventChangeRestored ChangeRestored{..} -> Just changeRestoredRestorer
    EventCommentAdded CommentAdded{..} -> Just commentAddedAuthor
    EventDroppedOutput -> Nothing
    EventHashtagsChanged HashtagsChanged{..} -> Just hashtagsChangedEditor
    EventProjectCreated _ -> Nothing
    EventPatchsetCreated PatchsetCreated{..} -> Just patchsetCreatedUploader
    EventRefUpdated _ -> Nothing
    EventReviewerAdded ReviewerAdded{..} -> Just reviewerAddedAdder
    EventReviewerDeleted ReviewerDeleted{..} -> Just reviewerDeletedRemover
    EventTopicChanged TopicChanged{..} -> Just topicChangedChanger
    EventWorkInProgressStateChanged WorkInProgressStateChanged{..} -> Just workInProgressStateChangedChanger
    EventPrivateStateChanged PrivateStateChanged{..} -> Just privateStateChangedChanger
    EventVoteDeleted VoteDeleted{..} -> Just voteDeletedRemover

-- | Get the creation timestamp
getCreatedOn :: Event -> Maybe Int64
getCreatedOn event = case event of
    EventAssigneeChanged AssigneeChanged{..} -> Just assigneeChangedEventCreatedOn
    EventChangeAbandoned ChangeAbandoned{..} -> Just changeAbandonedEventCreatedOn
    EventChangeDeleted _ -> Nothing
    EventChangeMerged ChangeMerged{..} -> Just changeMergedEventCreatedOn
    EventChangeRestored ChangeRestored{..} -> Just changeRestoredEventCreatedOn
    EventCommentAdded CommentAdded{..} -> Just commentAddedEventCreatedOn
    EventDroppedOutput -> Nothing
    EventHashtagsChanged HashtagsChanged{..} -> Just hashtagsChangedEventCreatedOn
    EventProjectCreated ProjectCreated{..} -> Just projectCreatedEventCreatedOn
    EventPatchsetCreated PatchsetCreated{..} -> Just patchsetCreatedEventCreatedOn
    EventRefUpdated RefUpdated{..} -> Just refUpdatedEventCreatedOn
    EventReviewerAdded ReviewerAdded{..} -> Just reviewerAddedEventCreatedOn
    EventReviewerDeleted ReviewerDeleted{..} -> Just reviewerDeletedEventCreatedOn
    EventTopicChanged TopicChanged{..} -> Just topicChangedEventCreatedOn
    EventWorkInProgressStateChanged WorkInProgressStateChanged{..} -> Just workInProgressStateChangedEventCreatedOn
    EventPrivateStateChanged PrivateStateChanged{..} -> Just privateStateChangedChangedEventCreatedOn
    EventVoteDeleted _ -> Nothing

-- | Get the 'EventType' back from an 'Event'
getEventType :: Event -> EventType
getEventType event = case event of
    EventAssigneeChanged _ -> AssigneeChangedEvent
    EventChangeAbandoned _ -> ChangeAbandonedEvent
    EventChangeDeleted _ -> ChangeDeletedEvent
    EventChangeMerged _ -> ChangeMergedEvent
    EventChangeRestored _ -> ChangeRestoredEvent
    EventCommentAdded _ -> CommentAddedEvent
    EventDroppedOutput -> DroppedOutputEvent
    EventHashtagsChanged _ -> HashtagsChangedEvent
    EventProjectCreated _ -> ProjectCreatedEvent
    EventPatchsetCreated _ -> PatchsetCreatedEvent
    EventRefUpdated _ -> RefUpdatedEvent
    EventReviewerAdded _ -> ReviewerAddedEvent
    EventReviewerDeleted _ -> ReviewerDeletedEvent
    EventTopicChanged _ -> TopicChangedEvent
    EventWorkInProgressStateChanged _ -> WorkInProgressStateChangedEvent
    EventPrivateStateChanged _ -> PrivateStateChangedEvent
    EventVoteDeleted _ -> VoteDeletedEvent

-- | Get the text representation suitable for event subscription.
eventName :: EventType -> Text
eventName eventType = case eventType of
    AssigneeChangedEvent -> "assignee-changed"
    ChangeAbandonedEvent -> "change-abandoned"
    ChangeDeletedEvent -> "change-deleted"
    ChangeMergedEvent -> "change-merged"
    ChangeRestoredEvent -> "change-restored"
    CommentAddedEvent -> "comment-added"
    DroppedOutputEvent -> "dropped-output"
    HashtagsChangedEvent -> "hashtags-changed"
    ProjectCreatedEvent -> "project-created"
    PatchsetCreatedEvent -> "patchset-created"
    RefUpdatedEvent -> "ref-updated"
    ReviewerAddedEvent -> "reviewer-added"
    ReviewerDeletedEvent -> "reviewer-deleted"
    TopicChangedEvent -> "topic-changed"
    WorkInProgressStateChangedEvent -> "wip-state-changed"
    PrivateStateChangedEvent -> "private-state-changed"
    VoteDeletedEvent -> "vote-deleted"