hmn/src/discord/README.md

7.4 KiB

Discord is crazy

This document describes the entire process of persisting Discord messages and handling:

  • showcase messages
  • library messages
  • snippets
  • backfills
  • admin commands
  • who even knows what else

If you want to just hop in and make a quick change to the Discord logic, don't. Not without reading this first, and in particular not without going through the user stories.

Constraints and design guidelines

We must never save message content for anyone without a linked Discord account.

We always have to respect rate limits, heartbeats, other gateway nuances.

Actions on Discord should never affect the website if the Discord account is not linked to an HMN profile.

Nothing should be added to a user's HMN profile without explicit user action. For example, linking your account should not result in snippets being automatically created from old #project-showcase posts.

We shouldn't assume that just because we have a message (or its contents) stored, we want to create a snippet from it. Sometimes messages could be saved for other reasons.

All the logic

On new/updated message:

  • if in a showcase channel and it doesn't fit the format, delete and return
  • if in a library channel and it doesn't fit the format, delete and return
  • if we care about the content of this message (see below):
    • persist mirror of message data (incl. content if allowed)
      • if persisting content, clean up message markdown
  • if user has a linked Discord account:
    • if this message is snippet-able (see below):
      • if snippet exists (in any channel):
        • update snippet
      • if no snippet exists:
        • check conditions for a new snippet:
          • the flag for snippet creation is set
          • any of the following is true:
            • in "showcase" channel, and the user has the setting enabled
            • an admin wants a snippet here
          • we have message content
          • SnippetCreated is false on the message
        • if conditions are met, create snippet
    • if this message is not snippet-able (see below):
      • delete any existing snippets that are connected to Discord (huzzah for edge cases)

On deleted message:

  • delete snippets, if the following conditions are true:
    • snippet is connected to Discord
    • the author has a Discord account linked
    • the author chooses not to keep captured snippets on Discord deletes (profile setting)
  • delete mirror of message data

On Discord account unlink:

  • DO NOT disconnect snippets from Discord.
    • There's no reason to.

We care about the content of the message if:

  • we already have content for this message, or
  • it is in a showcase channel or whatever, or
  • an admin said so (CLI command)

A message is snippet-able if:

  • It contains enough information to make a snippet. Namely:
    • it has media
  • Things that DO NOT affect snippetability:
    • whether a Discord account is linked
    • the user's settings for automatic snippet creation
    • other permissions or whatever

Things we do

These actions all fall into one of the two flows above - the create/update flow, or the delete flow. Some may require flags to modify the main flow behavior slightly.

Stuff for the create/update flow:

  • receive message creates/updates in real time
  • general backfill (1 hour) (exactly the same behavior as real-time)
  • new user backfill (5 seconds) (message content only, no snippets)
  • make snippets from #project-showcase posts (exactly the same behavior as real-time)
  • admin scrapechannel (fetch messages and content in arbitrary channels, no snippets)
  • admin makesnippet

Stuff for the delete flow:

  • receive message deletes in real time
  • IN THE FUTURE: delete messages in history backfill

:D user story time :D

Whenever touching the logic, consider all of these lovely edge cases!

  • bad showcase post

    • expected: post is immediately deleted
  • bad library post

    • expected: post is immediately deleted
  • good showcase post from an unlinked user

    • expected: lightweight message record is created, but no snippet is created
  • good showcase post, then the user unlinks their discord account

    • expected: the snippet remains on the user's profile
  • good showcase post, then the user unlinks their discord account, then edits the message

    • expected: the message edit has no effect on the snippet
  • good showcase post, then the user unlinks their discord account, then deletes the message

    • expected: the message delete has no effect on the snippet
  • good showcase post, then the user unlinks and re-links their discord account, then edits the showcase post

    • expected: the snippet remained connected to the discord message, and is updated
  • good showcase post, then the user unlinks their discord account and links a different one

    • expected: nothing happens to old snippets; new snippets get added as usual
  • good showcase post, then the user unlinks their discord account, then their discord account is linked to a different website profile

    • expected: snippets may be re-created on the new HMN profile
  • good showcase post, then the user unlinks their discord account, then we run a backfill on that specific message

    • expected: nothing happens because there is no discord account linked for that message
  • good showcase post gets edited to be bad

    • expected: the message and associated snippet are deleted
  • good library post gets edited to be bad

    • expected: the message is deleted
  • good showcase post gets edited and is still good

    • expected: the message record and associated snippet are updated
  • good library post gets edited and is still good

    • expected: nothing happens
  • Ryan posts like 50 things in #projects, and we want them to be on his profile

    • expected: an admin can run admin makesnippet on all the messages, and they will be added to Ryan's profile
  • Ryan edits his old posts in #projects

    • same as: someone edits their posts in #jam-showcase
    • expected: any associated snippets are updated, even though the edit was not in a showcase channel
  • Ryan edits an old post in #projects to no longer have a link

    • expected: the associated snippet is deleted, but the message persists.
  • Ryan edits an old post in #projects to no longer have a link, then edits it again to have a link again.

    • expected: the associated snippet is deleted, and not reinstated on the second edit. (oh well!)
  • an admin attempts to make a snippet for someone without a linked discord account

    • expected: nothing happens
  • an admin attempts to make a snippet for a message without media

    • expected: nothing happens
  • good showcase post is deleted

    • expected: any snippets are deleted, if the user wishes.
  • good showcase post, snippet is deleted from website, post is edited

    • expected: no new snippet is created
  • good showcase post, snippet is deleted from website, backfill runs

    • expected: no new snippet is created
  • good showcase post while the user has the showcase integration profile setting disabled, then they enable the showcase integration, then a backfill runs

    • expected: no new snippets are created for old showcase posts
  • good showcase post while the user has the integration disabled, then they enable the integration, then they explicitly create snippets from their showcase posts

    • expected: all user messages in showcase without snippets get snippets (subject to SnippetCreated)