################################################################################
## Custom Scalar Types
################################################################################

# Date represented as an ISO8601 string.
scalar Date

# Cursor represents a paginating cursor.
scalar Cursor

################################################################################
## Reliability
################################################################################

# Reliability defines how a given user should be considered reliable for their
# comment or flag activity.
type Reliability {

  # flagger will be `true` when the flagger is reliable, `false` if not, or
  # `null` if the reliability cannot be determined.
  flagger: Boolean

  # flaggerKarma will contains the number of agreed flags vs disagred flag
  # count.
  flaggerKarma: Int!

  # Commenter will be `true` when the commenter is reliable, `false` if not, or
  # `null` if the reliability cannot be determined.
  commenter: Boolean

  # commenterKarma the number of approved comments (not untouched) subtracted by
  # the number of rejected comments.
  commenterKarma: Int!
}

################################################################################
## Users
################################################################################

# Roles that a user can have, these can be combined.
enum USER_ROLES {

  # an administrator of the site
  ADMIN

  # a moderator of the site
  MODERATOR

  # a staff of the site
  STAFF

  # a user without administrative roles.
  COMMENTER
}

# Token is a personal access token associated with a given user.
type Token {

  # ID is the unique identifier for the token.
  id: ID!

  # Name is the description for the token.
  name: String!

  # Active determines if the token is available to hit the API.
  active: Boolean!

  # JWT is the actual token to use for authentication, this is only available
  # on token creation, otherwise it will be null.
  jwt: String
}

interface UserProfile {
  # The id is an identifier for the user profile (email, facebook id, etc)
  id: String!

  # name of the provider attached to the authentication mode
  provider: String!
}

# DefaultUserProfile is a fallback if the type of UserProfile can't be
# determined (like if it was from a plugin that was removed).
type DefaultUserProfile implements UserProfile {
  # The id is an identifier for the user profile (email, facebook id, etc)
  id: String!

  # name of the provider attached to the authentication mode
  provider: String!
}

# LocalUserProfile is for a User who has an authentication profile linked to
# their email address.
type LocalUserProfile implements UserProfile {
  # id is the User's email address.
  id: String!

  # name of the provider attached to the authentication mode, in this case,
  # 'local'.
  provider: String!

  # confirmedAt is the Date that the user had their email address confirmed,
  # which is null if it has not been verified.
  confirmedAt: Date
}

# USER_STATUS_USERNAME is the different states that a username can be in.
enum USER_STATUS_USERNAME {
  # UNSET is used when the username can be changed, and does not necessarily
  # require moderator action to become active. This can be used when the user
  # signs up with a social login and has the option of setting their own
  # username.
  UNSET

  # SET is used when the username has been set for the first time, but cannot
  # change without the username being rejected by a moderator and that moderator
  # agreeing that the username should be allowed to change.
  SET

  # APPROVED is used when the username was changed, and subsequently approved by
  # said moderator.
  APPROVED

  # REJECTED is used when the username was changed, and subsequently rejected by
  # said moderator.
  REJECTED

  # CHANGED is used after a user has changed their username after it was
  # rejected.
  CHANGED
}

# UserStatusInput describes the queryable components of the UserStatus.
input UserStatusInput {
  # username will restrict the returned users to only those with the given
  # username status's. If not provided, no filtering will be performed.
  username: [USER_STATUS_USERNAME!]

  # banned will restrict the returned users to only those that are, or are not
  # banned. If not provided, no filtering will be performed.
  banned: Boolean

  # suspended will restrict the returned users to only those that are, or are not
  # suspended. If not provided, no filtering will be performed.
  suspended: Boolean

  # alwaysPremod will restrict the returned users to only those that are, or are not
  # marked as always premoderate. If not provided, no filtering will be performed.
  alwaysPremod: Boolean
}

type UsernameStatusHistory {
  status: USER_STATUS_USERNAME!
  assigned_by: User
  created_at: Date!
}

type UsernameStatus {
  status: USER_STATUS_USERNAME!
  history: [UsernameStatusHistory!]
}

type BannedStatusHistory {
  status: Boolean!
  assigned_by: User
  created_at: Date!
}

type BannedStatus {
  status: Boolean!
  history: [BannedStatusHistory!]
}

type AlwaysPremodStatusHistory {
  status: Boolean!
  assigned_by: User
  created_at: Date!
}

type AlwaysPremodStatus {
  status: Boolean!
  history: [AlwaysPremodStatusHistory!]
}

type SuspensionStatusHistory {
  until: Date
  assigned_by: User
  created_at: Date!
}

type SuspensionStatus {
  until: Date
  history: [SuspensionStatusHistory!]
}

type UserStatus {
  # username is the status of the username.
  username: UsernameStatus!

  # banned is the bool that determines if the user is banned or not.
  banned: BannedStatus!

  # alwaysPremod is the bool that determines if the user comments are always pushed to the premod queue or not
  alwaysPremod: AlwaysPremodStatus!

  # suspension is the date that the user is suspended until.
  suspension: SuspensionStatus!
}

input UserStateInput {
  role: USER_ROLES
  status: UserStatusInput
}

# UserState describes the different permission based details for a user.
type UserState {
  # status describes the statuses of different aspects of the user's details.
  status: UserStatus
}

# Any person who can author comments, create actions, and view comments on a
# stream.
type User {

  # The ID of the User.
  id: ID!

  # Username of a user.
  username: String!

  # creation date of user
  created_at: Date!

  # Action summaries against the user.
  action_summaries: [ActionSummary!]!

  # Actions completed on the parent.
  actions: [Action!]

  # The current roles of the user.
  role: USER_ROLES

  # The current profiles of the user.
  profiles: [UserProfile]

  # The primary email address of the user. Only accessible to Administrators or
  # the current user.
  email: String

  # The tags on the user.
  tags: [TagLink!]

  # ignored users.
  ignoredUsers: [User!]

  # Tokens are the personal access tokens for a given user.
  tokens: [Token!]

  # returns all comments based on a query.
  comments(query: CommentsQuery): CommentConnection!

  # reliable is the reference to a given user's Reliability. If the requesting
  # user does not have permission to access the reliability, null will be
  # returned.
  reliable: Reliability

  # returns user status
  state: UserState
}

# UserConnection represents a paginable subset of a user list.
type UserConnection {

  # Indicates that there are more users after this subset.
  hasNextPage: Boolean!

  # Cursor of first user in subset.
  startCursor: Cursor

  # Cursor of last user in subset.
  endCursor: Cursor

  # Subset of users.
  nodes: [User!]!
}

# UsersQuery allows the ability to query users by a specific fields.
input UsersQuery {

  # Users returned will only be ones which have at least one action of this.
  action_type: ACTION_TYPE

  # state will filter the users to a specific set of users that meet.
  state: UserStateInput

  # value is the search string to use to search for a pa
  value: String = ""

  # Limit the number of results to be returned.
  limit: Int = 10

  # Skip results from the last created_at timestamp.
  cursor: Cursor

  # Sort the results by created_at.
  sortOrder: SORT_ORDER = DESC
}

# AssetsQuery allows teh ability to query assets by specific fields
input AssetsQuery {

  # a search string to match against titles, authors, urls, etc.
  value: String = ""

  # Limit the number of results to be returned
  limit: Int = 10

  # open filters assets that are open/closed/all. Not providing this parameter
  # will return all the assets, true will return assets that are open, and false
  # will return assets that are closed.
  open: Boolean

  # sortOrder specifies the order of the sort for the returned Assets.
  sortOrder: SORT_ORDER = DESC

  # Skip results from the last created_at timestamp.
  cursor: Cursor
}

################################################################################
## Tags
################################################################################

# Used to represent the item type for a tag.
enum TAGGABLE_ITEM_TYPE {

  # The action references a entity of type Asset.
  ASSETS

  # The action references a entity of type Comment.
  COMMENTS

  # The action references a entity of type User.
  USERS
}

# Tag represents the underlying Tag that can be either stored in a global list
# or added uniquely to the entity.
type Tag {

  # The actual name of the tag entry.
  name: String!

  # The time that this Tag was created.
  created_at: Date!
}

# TagLink is used to associate a given Tag with a Model via a TagLink.
type TagLink {

  # The underlying Tag that is either duplicated from the global list or created
  # uniquely for this specific model.
  tag: Tag!

  # The user that assigned the tag. This TagLink could have been created by the
  # system, in which case this will be null. It could also be null if the
  # current user is not an Admin/Moderator.
  assigned_by: User

  # The date that the TagLink was created.
  created_at: Date!
}

################################################################################
## Comments
################################################################################

# The statuses that a comment may have.
enum COMMENT_STATUS {

  # The comment is not PREMOD, but was not applied a moderation status by a
  # moderator.
  NONE

  # The comment has been accepted by a moderator.
  ACCEPTED

  # The comment has been rejected by a moderator.
  REJECTED

  # The comment was created while the asset's premoderation option was on, and
  # new comments that haven't been moderated yet are referred to as
  # "premoderated" or "premod" comments.
  PREMOD

  # SYSTEM_WITHHELD represents a comment that was withheld by the system because
  # it was flagged by an internal process for further review.
  SYSTEM_WITHHELD
}

# The types of action there are as enums.
enum ACTION_TYPE {

  # Represents a FlagAction.
  FLAG

  # Represents a don't agree action
  DONTAGREE
}

# CommentsQuery allows the ability to query comments by a specific methods.
input CommentsQuery {

  # Author of the comments.
  author_id: ID

  # Current status of a comment.
  # This field is restricted.
  statuses: [COMMENT_STATUS!] = [NONE, ACCEPTED]

  # Asset that a comment is on.
  asset_id: ID

  # The parent of the comment that we want to retrieve.
  parent_id: ID

  # Comments returned will only be ones which have at least one action of this
  # type. Requires the `ADMIN` role.
  action_type: ACTION_TYPE

  # Limit the number of results to be returned.
  limit: Int = 10

  # Skip results from the last created_at timestamp.
  cursor: Cursor

  # Sort the results by from largest first.
  sortOrder: SORT_ORDER = DESC

  # The order to sort the comments by, sorting by default the created at
  # timestamp.
  sortBy: SORT_COMMENTS_BY = CREATED_AT

  # Filter by a specific tag name.
  tags: [String!]

  # Exclude comments ignored by the requesting user
  excludeIgnored: Boolean

  # excludeDeleted when true will exclude deleted comments from the response.
  excludeDeleted: Boolean = false
}

input RepliesQuery {

  # Sort the results by from smallest first.
  sortOrder: SORT_ORDER = ASC

  # The order to sort the comments by, sorting by default the created at
  # timestamp.
  sortBy: SORT_COMMENTS_BY = CREATED_AT

  # Limit the number of results to be returned.
  limit: Int = 3

  # Exclude comments ignored by the requesting user
  excludeIgnored: Boolean

  # excludeDeleted when true will exclude deleted comments from the response.
  excludeDeleted: Boolean = false
}

# CommentCountQuery allows the ability to query comment counts by specific
# methods.
input CommentCountQuery {

  # Current status of a comment.
  # This field is restricted.
  statuses: [COMMENT_STATUS!] = [NONE, ACCEPTED]

  # Asset that a comment is on.
  asset_id: ID

  # The URL that the asset is located on.
  asset_url: String

  # The parent of the comment that we want to retrieve.
  parent_id: ID

  # comments returned will only be ones which have at least one action of this
  # type.
  action_type: ACTION_TYPE

  # author_id allows the querying of comment counts based on the author of the
  # comments.
  author_id: ID

  # Filter by a specific tag name.
  tags: [String!]

  # excludeDeleted when true will exclude deleted comments from the count.
  excludeDeleted: Boolean = false
}

# UserCountQuery allows the ability to query user counts by specific
# methods.
input UserCountQuery {

  # comments returned will only be ones which have at least one action of this
  # type.
  action_type: ACTION_TYPE

  # state queries for a specific subset of users with the given state query.
  state: UserStateInput
}

type EditInfo {
  edited: Boolean!
  editableUntil: Date
}

type CommentBodyHistory {
  body: String!
  created_at: Date!
}

type CommentStatusHistory {
  type: COMMENT_STATUS!
  created_at: Date!
  assigned_by: User
}

# Comment is the base representation of user interaction in Talk.
type Comment {

  # The parent of the comment (if there is one).
  parent: Comment

  # The ID of the comment.
  id: ID!

  # The actual comment data.
  body: String

  # The body history of the comment. Requires the `ADMIN` or `MODERATOR` role or
  # the author.
  body_history: [CommentBodyHistory!]

  # The tags on the comment
  tags: [TagLink!]

  # The user who authored the comment.
  user: User

  # The replies that were made to the comment.
  replies(query: RepliesQuery = {}): CommentConnection!

  # replyCount is the number of replies with a depth of 1. Only direct replies
  # to this comment are counted. Deleted comments are included in this count.
  replyCount: Int

  # Actions completed on the parent. Requires the `ADMIN` role.
  actions: [Action]

  # Action summaries against a comment.
  action_summaries: [ActionSummary]!

  # The asset that a comment was made on.
  asset: Asset

  # The current status of a comment.
  status: COMMENT_STATUS!

  # The status history of the comment. Requires the `ADMIN` or `MODERATOR` role.
  status_history: [CommentStatusHistory!]

  # The date that the comment was deleted at if it was.
  deleted_at: Date

  # The time when the comment was created
  created_at: Date!

  # The time when the comment was updated.
  updated_at: Date

  # describes how the comment can be edited
  editing: EditInfo

  # Indicates if it has a parent
  hasParent: Boolean

  # url is the permalink to this particular Comment on the Asset.
  url: String
}

# CommentConnection represents a paginable subset of a comment list.
type CommentConnection {

  # Indicates that there are more comments after this subset.
  hasNextPage: Boolean!

  # Cursor of first comment in subset.
  startCursor: Cursor

  # Cursor of last comment in subset.
  endCursor: Cursor

  # Subset of comments.
  nodes: [Comment!]!
}

################################################################################
## Actions
################################################################################

# An action rendered against a parent entity item.
interface Action {

  # The ID of the action.
  id: ID!

  # The author of the action.
  user: User

  # The time when the Action was updated.
  updated_at: Date

  # The time when the Action was created.
  created_at: Date
}

# DefaultAction is the Action provided for undefined types.
type DefaultAction implements Action {

  # The ID of the action.
  id: ID!

  # The author of the action.
  user: User

  # The time when the Action was updated.
  updated_at: Date

  # The time when the Action was created.
  created_at: Date
}

# A summary of actions based on the specific grouping of the group_id.
interface ActionSummary {

  # The count of actions with this group.
  count: Int

  # The current user's action.
  current_user: Action
}

# DefaultActionSummary is the ActionSummary provided for undefined types.
type DefaultActionSummary implements ActionSummary {

  # The count of actions with this group.
  count: Int

  # The current user's action.
  current_user: Action
}

# A summary of actions for a specific action type on an Asset.
interface AssetActionSummary {

  # Number of actions associated with actionable types on this this Asset.
  actionCount: Int

  # Number of unique actionable types that are referenced by the actions.
  actionableItemCount: Int
}

# DefaultAssetActionSummary is the AssetActionSummary provided for undefined types.
type DefaultAssetActionSummary implements AssetActionSummary {

  # Number of actions associated with actionable types on this this Asset.
  actionCount: Int

  # Number of unique actionable types that are referenced by the actions.
  actionableItemCount: Int
}

# A summary of counts related to all the Flags on an Asset.
type FlagAssetActionSummary implements AssetActionSummary {

  # Number of flags associated with actionable types on this this Asset.
  actionCount: Int

  # Number of unique actionable types that are referenced by the flags.
  actionableItemCount: Int
}

enum FLAG_REASON {

  # The current user thinks that the flagged username is offensive.
  USERNAME_OFFENSIVE

  # The current user does not like the flagged username.
  USERNAME_NOLIKE

  # The current user thinks that the flagged username is being used to
  # impersonate another user.
  USERNAME_IMPERSONATING

  # The current user thinks that the flagged username is spam.
  USERNAME_SPAM

  # The current user thinks that the flagged username is wrong for another
  # reason.
  USERNAME_OTHER

  # The current user thinks that the flagged comment is offensive.
  COMMENT_OFFENSIVE

  # The current user thinks that the flagged comment is spam.
  COMMENT_SPAM

  # The current user thinks that the flagged comment is wrong for another
  # reason.
  COMMENT_OTHER
}

# A FLAG action that contains flag metadata.
type FlagAction implements Action {

  # The ID of the Flag Action.
  id: ID!

  # The reason for which the Flag Action was created.
  reason: String

  # An optional message sent with the flagging action by the user.
  message: String

  # The user who created the action.
  user: User

  # The time when the Flag Action was updated.
  updated_at: Date

  # The time when the Flag Action was created.
  created_at: Date
}

# A DONTAGREE action that contains do not agree metadata.
type DontAgreeAction implements Action {

  # The ID of the DontAgree Action.
  id: ID!

  # An optional message sent with the flagging action by the user.
  message: String

  # The user who created the action.
  user: User

  # The time when the DontAgree Action was updated.
  updated_at: Date

  # The time when the DontAgree Action was created.
  created_at: Date
}

# Summary for Flag Action with a a unique reason.
type FlagActionSummary implements ActionSummary {

  # The total count of flags with this reason.
  count: Int!

  # The reason for which the Flag Action was created.
  reason: String

  # The flag by the current user against the parent entity with this reason.
  current_user: FlagAction
}

# Summary for Don't Agree Action with a a unique reason.
type DontAgreeActionSummary implements ActionSummary {

  # The total count of flags with this reason.
  count: Int!

  # The don't agree action by the current user against the parent entity with this reason.
  current_user: DontAgreeAction
}

################################################################################
## Settings
################################################################################

# The moderation mode of the site.
enum MODERATION_MODE {

  # Comments posted while in `PRE` mode will be labeled with a `PREMOD`
  # status and will require a moderator decision before being visible.
  PRE

  # Comments posted while in `POST` will be visible immediately.
  POST
}

# Wordlist describes all the available wordlists.
type Wordlist {

  # banned words will by default reject the comment if it is found.
  banned: [String!]!

  # suspect words will simply flag the comment.
  suspect: [String!]!
}

# Domains describes all the available lists of domains.
type Domains {

  # whitelist is the list of domains that the embed is allowed to render on.
  whitelist: [String!]!
}

# KarmaThreshold defines the bounds for which a User will become unreliable or
# reliable based on their karma score. If the score is equal or less than the
# unreliable value, they are unreliable. If the score is equal or more than the
# reliable value, they are reliable. If they are neither reliable or unreliable
# then they are neutral.
type KarmaThreshold {
  reliable: Int!
  unreliable: Int!
}

# KarmaThresholds contains the currently set thresholds for triggering Trust
# beheviour.
type KarmaThresholds {

  # flag represents karma settings in relation to how well a User's flagging
  # ability aligns with the moderation decicions made by moderators.
  flag: KarmaThreshold!

  # comment represents the karma setting in relation to how well a User's
  # comments are moderated.
  comment: KarmaThreshold!
}

# Settings stores the global settings for a given installation.
type Settings {

  # moderation is the moderation mode for all Asset's on the site.
  moderation: MODERATION_MODE!

  # Enables a requirement for email confirmation before a user can login.
  requireEmailConfirmation: Boolean

  # infoBoxEnable will enable the Info Box content visible above the question
  # box.
  infoBoxEnable: Boolean

  # infoBoxContent is the content of the Info Box.
  infoBoxContent: String

  # questionBoxEnable will enable the Question Box's content to be visible above
  # The comment box.
  questionBoxEnable: Boolean

  # questionBoxContent is the content of the Question Box.
  questionBoxContent: String

  # premodLinksEnable will put all comments that contain links into premod.
  premodLinksEnable: Boolean

  # questionBoxIcon is the icon for the Question Box.
  questionBoxIcon: String

  # autoCloseStream when true will auto close the stream when the `closeTimeout`
  # amount of seconds have been reached.
  autoCloseStream: Boolean

  # customCssUrl is the URL of the custom CSS used to display on the frontend.
  customCssUrl: String

  # customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
  customAdminCssUrl: String

  # closedTimeout is the amount of seconds from the created_at timestamp that a
  # given asset will be considered closed.
  closedTimeout: Int

  # closedMessage is the message shown to the user when the given Asset is
  # closed.
  closedMessage: String

  # disableCommenting will disable commenting site-wide.
  disableCommenting: Boolean

  # disableCommentingMessage will be shown above the comment stream while
  # commenting is disabled site-wide.
  disableCommentingMessage: String

  # editCommentWindowLength is the length of time (in milliseconds) after a
  # comment is posted that it can still be edited by the author.
  editCommentWindowLength: Int

  # charCountEnable is true when the character count restriction is enabled.
  charCountEnable: Boolean

  # charCount is the maximum number of characters a comment may be.
  charCount: Int

  # organizationName is the name of the organization.
  organizationName: String

  # organizationContactEmail is the email of the organization.
  organizationContactEmail: String

  # wordlist will return a given list of words.
  wordlist: Wordlist

  # domains will return a given list of domains.
  domains: Domains

  # karmaThresholds contains the currently set thresholds for triggering Trust
  # beheviour.
  karmaThresholds: KarmaThresholds
}

################################################################################
## Assets
################################################################################

# Where comments are made on.
type Asset {

  # The current ID of the asset.
  id: ID!

  # The scraped title of the asset.
  title: String

  # The URL that the asset is located on.
  url: String

  # The comments that are attached to the asset. When `deep` is true, the
  # comments returned will be at all depths.
  comments(query: CommentsQuery = {}, deep: Boolean = false): CommentConnection

  # A Comment from the Asset by comment's ID
  comment(id: ID!): Comment

  # The count of top level comments on the asset.
  commentCount(tags: [String!]): Int

  # The total count of all comments made on the asset.
  totalCommentCount(tags: [String!]): Int

  # The settings (rectified with the global settings) that should be applied to
  # this asset.
  settings: Settings!

  # The date that the asset was closed at.
  closedAt: Date

  # True if asset is closed.
  isClosed: Boolean!

  # Summary of all Actions against all entities associated with the Asset.
  # (likes, flags, etc.). Requires the `ADMIN` role.
  action_summaries: [AssetActionSummary!]

  # The date that the asset was created.
  created_at: Date

  # The tags on the asset
  tags: [TagLink!]

  # The author(s) of the asset.
  author: String
}

# AssetConnection represents a paginable subset of a asset list.
type AssetConnection {

  # Indicates that there are more assets after this subset.
  hasNextPage: Boolean!

  # Cursor of first asset in subset.
  startCursor: Cursor

  # Cursor of last asset in subset.
  endCursor: Cursor

  # Subset of assets.
  nodes: [Asset!]!
}

################################################################################
## Errors
################################################################################

# Any error rendered due to the user's input.
interface UserError {

  # Translation key relating to a translatable string containing details to be
  # displayed to the end user.
  translation_key: String!
}

# A generic error not related to validation reasons.
type GenericUserError implements UserError {

  # Translation key relating to a translatable string containing details to be
  # displayed to the end user.
  translation_key: String!
}

# A validation error that affects the input.
type ValidationUserError implements UserError {

  # Translation key relating to a translatable string containing details to be
  # displayed to the end user.
  translation_key: String!

  # The field in question that caused the error.
  field_name: String!
}

################################################################################
## Queries
################################################################################

# Establishes the ordering of the content by their created_at time stamp.
enum SORT_ORDER {

  # newest to oldest order.
  DESC

  # oldest to newer order.
  ASC
}

# SORT_COMMENTS_BY selects the means for which comments are ordered when
# sorting.
enum SORT_COMMENTS_BY {

  # Comments will be sorted by their created at date.
  CREATED_AT

  # Comments will be sorted by their immediate reply count (replies to the comment
  # in question only, not including descendants).
  REPLIES
}

type RootQuery {

  # Site wide settings and defaults.
  settings: Settings

  # Finds a specific comment based on it's id.
  comment(id: ID!): Comment

  # All assets. Requires the `ADMIN` role.
  assets(query: AssetsQuery): AssetConnection

  # Find or create an asset by url, or just find with the ID.
  asset(id: ID, url: String): Asset

  # Comments returned based on a query.
  comments(query: CommentsQuery!): CommentConnection

  # Return the count of comments satisfied by the query. Note that this edge is
  # expensive as it is not batched. Requires the `ADMIN` role.
  commentCount(query: CommentCountQuery!): Int

  # Return the count of users satisfied by the query. Note that this edge is
  # expensive as it is not batched. This field is restricted.
  userCount(query: UserCountQuery!): Int

  # The currently logged in user based on the request. Requires any logged in
  # role.
  me: User

  # Users returned based on a query. Requires the `ADMIN` role.
  users(query: UsersQuery!): UserConnection

  # a single User by id
  user(id: ID!): User
}

################################################################################
## Mutations
################################################################################

# Response defines what can be expected from any response to a mutation action.
interface Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# CreateCommentResponse is returned with the comment that was created and any
# errors that may have occurred in the attempt to create it.
type CreateCommentResponse implements Response {

  # The comment that was created.
  comment: Comment

  # Actions that was assigned during creation of the comment.
  actions: [Action]

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# Used to represent the item type for an action.
enum ACTION_ITEM_TYPE {

  # The action references a entity of type Asset.
  ASSETS

  # The action references a entity of type Comment.
  COMMENTS

  # The action references a entity of type User.
  USERS
}

# CreateCommentInput is the input content used to create a new comment.
input CreateCommentInput {

  # The asset id
  asset_id: ID!

  # The id of the parent comment
  parent_id: ID

  # The body of the comment
  body: String!

  # Tags
  tags: [String]
}

input CreateFlagInput {

  # The item's id for which we are to create a flag.
  item_id: ID!

  # The type of the item for which we are to create the flag.
  item_type: ACTION_ITEM_TYPE!

  # The reason for flagging the item.
  reason: FLAG_REASON

  # An optional message sent with the flagging action by the user.
  message: String
}

# CreateFlagResponse is the response returned with possibly some errors
# relating to the creating the flag action attempt and possibly the flag that
# was created.
type CreateFlagResponse implements Response {

  # The flag that was created.
  flag: FlagAction

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}


# CreateDontAgreeResponse is the response returned with possibly some errors
# relating to the creating the don't agree action attempt and possibly the don't agree that
# was created.
type CreateDontAgreeResponse implements Response {

  # The don't agree that was created.
  dontagree: DontAgreeAction

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

input CreateDontAgreeInput {

  # The item's id for which we are to create a don't agree.
  item_id: ID!

  # The type of the item for which we are to create the don't agree.
  item_type: ACTION_ITEM_TYPE!

  # An optional message sent with the don't agree action by the user.
  message: String
}

# Configurable settings that can be overridden for the Asset. You must specify
# all fields that should be updated.
input AssetSettingsInput {

  # premodLinksEnable will put all comments that contain links into premod.
  premodLinksEnable: Boolean

  # moderation is the moderation mode for the asset.
  moderation: MODERATION_MODE

  # questionBoxEnable will enable the Question Boxs' content to be visible above
  # The comment box.
  questionBoxEnable: Boolean

  # questionBoxContent is the content of the Question Box.
  questionBoxContent: String

  # questionBoxIcon is the icon for the Question Box.
  questionBoxIcon: String
}

# UpdateAssetStatusInput contains the input to change the status of a comment as
# it relates to being open/closed for commenting.
input UpdateAssetStatusInput {

  # closedAt is the time that the asset will be closed for commenting. If this
  # is null or in the future, it will be open for commenting.
  closedAt: Date

  # closedMessage is the message to be set on the asset when it is closed. If it
  # is null, then the message will default to the globally set `closedMessage`.
  closedMessage: String
}

# UpdateAssetStatusResponse is the response returned with possibly some errors
# relating to the update status attempt.
type UpdateAssetStatusResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# CloseAssetResponse is the response returned with possibly some errors
# relating to the update status attempt.
type CloseAssetResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# UpdateAssetSettingsResponse is the response returned with possibly some errors
# relating to the update settings attempt.
type UpdateAssetSettingsResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# DeleteActionResponse is the response returned with possibly some errors
# relating to the delete action attempt.
type DeleteActionResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# SetCommentStatusResponse is the response returned with possibly some errors
# relating to the delete action attempt.
type SetCommentStatusResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# ModifyTagInput is the input used to modify a tag.
input ModifyTagInput {

  # name is the actual tag to add to the model.
  name: String!

  # id is the ID of the model in question that we are modifying the tag of.
  id: ID!

  # item_type is the type of item that we are modifying the tag if.
  item_type: TAGGABLE_ITEM_TYPE!

  # asset_id is used when the item_type is `COMMENTS`, the is needed to rectify
  # The settings to get the asset specific tags/settings.
  asset_id: ID
}

# Response to the addTag or removeTag mutations.
type ModifyTagResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# Response to ignoreUser mutation
type IgnoreUserResponse implements Response {
  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# Response to stopIgnoringUser mutation
type StopIgnoringUserResponse implements Response {
  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# Input to editComment mutation.
input EditCommentInput {

  # Update body of the comment
  body: String!
}

# EditCommentResponse contains the updated comment and any errors that occurred.
type EditCommentResponse implements Response {

  # The edited comment.
  comment: Comment

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# UpdateSettingsInput is the input used to input the global site settings. This
# will override the existing settings, so all fields must be included.
input UpdateSettingsInput {

  # moderation is the moderation mode for all Asset's on the site.
  moderation: MODERATION_MODE

  # Enables a requirement for email confirmation before a user can login.
  requireEmailConfirmation: Boolean

  # infoBoxEnable will enable the Info Box content visible above the question
  # box.
  infoBoxEnable: Boolean

  # infoBoxContent is the content of the Info Box.
  infoBoxContent: String

  # questionBoxEnable will enable the Question Box's content to be visible above
  # The comment box.
  questionBoxEnable: Boolean

  # questionBoxContent is the content of the Question Box.
  questionBoxContent: String

  # premodLinksEnable will put all comments that contain links into premod.
  premodLinksEnable: Boolean

  # questionBoxIcon is the icon for the Question Box.
  questionBoxIcon: String

  # autoCloseStream when true will auto close the stream when the `closeTimeout`
  # amount of seconds have been reached.
  autoCloseStream: Boolean

  # customCssUrl is the URL of the custom CSS used to display on the frontend.
  customCssUrl: String

  # customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
  customAdminCssUrl: String

  # closedTimeout is the amount of seconds from the created_at timestamp that a
  # given asset will be considered closed.
  closedTimeout: Int

  # closedMessage is the message shown to the user when the given Asset is
  # closed.
  closedMessage: String

  # disableCommenting will disable commenting site-wide.
  disableCommenting: Boolean

  # disableCommentingMessage will be shown above the comment stream while
  # commenting is disabled site-wide.
  disableCommentingMessage: String

  # charCountEnable is true when the character count restriction is enabled.
  charCountEnable: Boolean

  # charCount is the maximum number of characters a comment may be.
  charCount: Int

  # organizationName is the name of the organization.
  organizationName: String

  # organizationContactEmail is the email of the organization.
  organizationContactEmail: String

  # editCommentWindowLength is the length of time (in milliseconds) after a
  # comment is posted that it can still be edited by the author.
  editCommentWindowLength: Int

  # wordlist allows changing the available wordlists.
  wordlist: UpdateWordlistInput

  # domains allows changing the available lists of domains.
  domains: UpdateDomainsInput
}

# UpdateSettingsResponse contains any errors that were rendered as a result
# of the mutation.
type UpdateSettingsResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# UpdateWordlistInput is the list of words that composes the Wordlist.
input UpdateWordlistInput {

  # banned words will by default reject the comment if it is found.
  banned: [String!]

  # suspect words will simply flag the comment.
  suspect: [String!]
}

# UpdateDomainsInput describes all the available lists of domains.
input UpdateDomainsInput {

  # whitelist is the list of domains that the embed is allowed to render on.
  whitelist: [String!]
}

# CreateTokenInput contains the input to create the token.
input CreateTokenInput {

  # Name is the description for the token.
  name: String!
}

# CreateTokenResponse contains the errors related to creating a token.
type CreateTokenResponse implements Response {

  # Token is the Token that was created, or null if it failed.
  token: Token

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# RevokeTokenInput contains the input to revoke the token.
input RevokeTokenInput {

  # ID is the JTI for the token.
  id: ID!
}

# RevokeTokenResponse contains the errors related to revoking a token.
type RevokeTokenResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

input BanUserInput {
  id: ID!
  message: String!
}

input UnbanUserInput {
  id: ID!
}

type BanUsersResponse implements Response {
  errors: [UserError!]
}

type UnbanUserResponse implements Response {
  errors: [UserError!]
}

input AlwaysPremodUserInput {
  id: ID!
}

input RemoveAlwaysPremodUserInput {
  id: ID!
}

type AlwaysPremodUserResponse implements Response {
  errors: [UserError!]
}

type RemoveAlwaysPremodUserResponse implements Response {
  errors: [UserError!]
}

input SuspendUserInput {
  id: ID!
  message: String!
  until: Date!
}

type SuspendUserResponse implements Response {
  errors: [UserError!]
}

input UnsuspendUserInput {
  id: ID!
}

# UnsuspendUserResponse is the response returned with possibly some
# errors relating to the suspend action attempt.
type UnsuspendUserResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type SetUsernameStatusResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type ChangeUsernameResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type SetUsernameResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type SetUserRoleResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type ForceScrapeAssetResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

type DelUserResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

input ChangePasswordInput {
  # oldPassword is the previous password set on the account. An incorrect
  # password here will result in an unauthorized error being thrown.
  oldPassword: String!

  # newPassword is the password we're changing it to.
  newPassword: String!
}

type ChangePasswordResponse implements Response {

  # An array of errors relating to the mutation that occurred.
  errors: [UserError!]
}

# All mutations for the application are defined on this object.
type RootMutation {

  # Creates a comment on the asset.
  createComment(input: CreateCommentInput!): CreateCommentResponse!

  # Creates a flag on an entity.
  createFlag(flag: CreateFlagInput!): CreateFlagResponse!

  # Creates a don't agree action on an entity.
  createDontAgree(dontagree: CreateDontAgreeInput!): CreateDontAgreeResponse!

  # Delete an action based on the action id.
  deleteAction(id: ID!): DeleteActionResponse

  # Edit a comment
  editComment(id: ID!, asset_id: ID!, edit: EditCommentInput): EditCommentResponse!

  # Sets the suspension status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  suspendUser(input: SuspendUserInput!): SuspendUserResponse

  # Sets the suspension status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  unsuspendUser(input: UnsuspendUserInput!): UnsuspendUserResponse

  # Sets the always premod status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  alwaysPremodUser(input: AlwaysPremodUserInput!): AlwaysPremodUserResponse

  # Sets the always premod status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  removeAlwaysPremodUser(input: RemoveAlwaysPremodUserInput!): RemoveAlwaysPremodUserResponse

  # Sets the ban status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  banUser(input: BanUserInput!): BanUsersResponse

  # Sets the ban status on a given user. Requires the `MODERATOR` role.
  # Mutation is restricted.
  unbanUser(input: UnbanUserInput!): UnbanUserResponse

  # Sets the username status on a given user to `APPROVED`. Requires the
  # `MODERATOR` role. Mutation is restricted.
  approveUsername(id: ID!): SetUsernameStatusResponse

  # Sets the username status on a given user to `REJECTED`. Requires the
  # `MODERATOR` role. Mutation is restricted.
  rejectUsername(id: ID!): SetUsernameStatusResponse

  # Changes the username to the desired username. Mutation is restricted to
  # those users with permission do to so.
  changeUsername(id: ID!, username: String!): ChangeUsernameResponse

  # Sets the username to the desired username if the user has not had a chance
  # to set their username. Mutation is restricted to those users with permission
  # do to so that have not done so before.
  setUsername(id: ID!, username: String!): SetUsernameResponse

  # Sets Comment status. Requires the `ADMIN` role.
  # Mutation is restricted.
  setCommentStatus(id: ID!, status: COMMENT_STATUS!): SetCommentStatusResponse

  # Add a tag.
  addTag(tag: ModifyTagInput!): ModifyTagResponse

  # Removes a tag.
  removeTag(tag: ModifyTagInput!): ModifyTagResponse

  # Set's a given users role to the one provided. If `null` is passed, the user
  # will not have any role.
  setUserRole(id: ID!, role: USER_ROLES): SetUserRoleResponse

  # Updates settings on a given asset.
  # Mutation is restricted.
  updateAssetSettings(id: ID!, input: AssetSettingsInput!): UpdateAssetSettingsResponse

  # Updates the status of an asset allowing you to close/reopen an asset for
  # commenting.
  # Mutation is restricted.
  updateAssetStatus(id: ID!, input: UpdateAssetStatusInput!): UpdateAssetStatusResponse

  # closeAsset will close the asset for commenting based on server time.
  closeAsset(id: ID!): CloseAssetResponse

  # updateSettings will update the global settings.
  # Mutation is restricted.
  updateSettings(input: UpdateSettingsInput!): UpdateSettingsResponse

  # Ignore comments by another user
  ignoreUser(id: ID!): IgnoreUserResponse

  # CreateToken will create a token that is attached to the current user.
  # Mutation is restricted.
  createToken(input: CreateTokenInput!): CreateTokenResponse!

  # RevokeToken will revoke an existing token.
  # Mutation is restricted.
  revokeToken(input: RevokeTokenInput!): RevokeTokenResponse

  # Stop Ignoring comments by another user.
  stopIgnoringUser(id: ID!): StopIgnoringUserResponse

  # forceScrapeAsset will force scrape the Asset with the given ID.
  forceScrapeAsset(id: ID!): ForceScrapeAssetResponse

  # delUser will delete the user with the specified id.
  delUser(id: ID!): DelUserResponse

  # changePassword allows the current user to change their password that have an
  # associated local user account.
  changePassword(input: ChangePasswordInput!): ChangePasswordResponse
}

type UsernameChangedPayload {
  previousUsername: String
  user: User
}

################################################################################
## Subscriptions
################################################################################

type Subscription {

  # Get an update whenever a comment was added.
  # `asset_id` is required except for users with the `ADMIN` or `MODERATOR` role.
  # Non privileged user can only subscribe to 'NONE' and/or 'ACCEPTED' statuses.
  commentAdded(asset_id: ID, statuses: [COMMENT_STATUS!] = [NONE, ACCEPTED]): Comment

  # Get an update whenever a comment was edited.
  # `asset_id` is required except for users with the `ADMIN` or `MODERATOR` role.
  commentEdited(asset_id: ID): Comment

  # Get an update whenever a comment was flagged.
  # Requires the `ADMIN` or `MODERATOR` role.
  commentFlagged(asset_id: ID): Comment

  # Get an update whenever a comment has been accepted.
  # Requires the `ADMIN` or `MODERATOR` role.
  commentAccepted(asset_id: ID): Comment

  # Get an update whenever a comment has been rejected.
  # Requires the `ADMIN` or `MODERATOR` role.
  commentRejected(asset_id: ID): Comment

  # Get an update whenever the status of a comment has been reset.
  # Requires the `ADMIN` or `MODERATOR` role.
  commentReset(asset_id: ID): Comment

  # Get an update whenever a user has been suspended.
  # `user_id` must match id of current user except for
  # users with the `ADMIN` or `MODERATOR` role.
  userSuspended(user_id: ID): User

  # Get an update whenever a user has been banned.
  # `user_id` must match id of current user except for
  # users with the `ADMIN` or `MODERATOR` role.
  userBanned(user_id: ID): User

  # Get an update whenever a username was flagged.
  # `user_id` must match id of current user except for
  # users with the `ADMIN` or `MODERATOR` role.
  usernameFlagged(user_id: ID): User

  # Get an update whenever a username has been rejected.
  # `user_id` must match id of current user except for
  # users with the `ADMIN` or `MODERATOR` role.
  usernameRejected(user_id: ID): User

  # Get an update whenever a username has been approved. `user_id` must match id
  # of current user except for users with the `ADMIN` or `MODERATOR` role.
  usernameApproved(user_id: ID): User

  # Get an update whenever a username has been changed. `user_id` must match id
  # of current user except for users with the `ADMIN` or `MODERATOR` role.
  usernameChanged(user_id: ID): UsernameChangedPayload

  # Get an update whenever a user is created. Only accessible to users with the
  # `ADMIN` or `MODERATOR` roles.
  userCreated: User
}

################################################################################
## Schema
################################################################################

schema {
  query: RootQuery
  mutation: RootMutation
  subscription: Subscription
}
