Giter Club home page Giter Club logo

hunttracker's Introduction

This is a puzzle hunt status tracking Slack app. Its user interface is implemented within Slack as much as possible, with a few external web views for features that are awkward or impossible to present within Slack itself. If your puzzle hunting team is really into Slack, this might be a good solution for you! If not, check out some of the other solutions tagged with #puzzle-hunt on Github.

Features

The app's Home tab is its main entry point. It contains a few buttons to access app functionality, as well as information about puzzles that are currently unsolved.

A "puzzle" may be used to represent a normal puzzle, a metapuzzle, an event, or any other solvable thing you want to track. This app maintains a Slack channel per puzzle. For each unsolved puzzle, the Home tab lists the puzzle channel's topic (useful as a quick summary of the puzzle content and current status of the solve), which team members are working on it, and any tags associated with the puzzle. It provides Join channel buttons to make it easy to start working on a puzzle from this view, but it's also OK for a user to join a puzzle's channel via normal Slack features.

The Register puzzle button on the Home tab is used to create a Slack channel, Google Sheet, and (if configured) a Google Meet for a puzzle. It presents a dialog for entering information about the puzzle including its name, a URL for the puzzle content, tags to associate with the puzzle, and an initial topic. All fields are optional other than a unique puzzle name, and tags and a topic can be set and changed later. The puzzle registration feature may be optionally configured only for "admin" users who are members of a private admin channel.

This app pins and maintains a status message at the top of each puzzle channel. This message contains links to the puzzle content and the Google Sheet for the puzzle, as well as tracking for how long the puzzle's been "idle" (no activity in its channel or spreadsheet, or no manual indication that its still being worked on), its tags and functionality to edit them, and functionality for recording the puzzle as solved and providing its answer. The status message is continuously updated by the app.

There are many more features that have not yet been thoroughly documented here:

  • the puzzles dashboard
  • details about how tagging works, and the metas dashboard
  • the tagger page
  • archiving channels of solved puzzles
  • the activity log channel
  • the admin channel
  • Google Meet integration

Serving requirements

To set up this app, you'll need:

  • A Slack workspace
  • Your own new Slack app to configure and install in your workspace
  • A PostgreSQL database
  • A Javascript serving solution (I've successfully set this up with AWS Lambda and with Google App Engine)
  • A Google Cloud Platform service account for accessing the Google Drive and Calendar (for Google Meet creation) APIs

Environment variables

Everything is configured using environment variables, and they need to be set for anything to work.

  • PORT: The server HTTP port. The default is 3000.
  • APP_NAME: The user-visible name of this deployment of this application.
  • WEB_SERVER_URL: The publicly accessible URL for this server, with trailing slash. Used to build links.
  • HELP_URL: A link to help instructions for how to use this.
  • SESSION_SECRET: A secret string used to sign the session cookie to prevent tampering.
  • SLACK_TEAM_ID: This is your Slack workspace Team ID (prefixed with T) which can be found in the Slack app URL.
  • SLACK_CLIENT_ID: This is the "Client ID" you can get from the "Basic Information" page in the "Your Apps" section of https://api.slack.com/.
  • SLACK_CLIENT_SECRET: This is the "Client Secret" you can get from the "Basic Information" page in the "Your Apps" section of https://api.slack.com/.
  • SLACK_SIGNING_SECRET: This is the "Signing Secret" you can get from the "Basic Information" page in the "Your Apps" section of https://api.slack.com/.
  • SLACK_BOT_TOKEN: This is the "Bot User OAUth Access Token" you can get from the "OAuth & Permissions" page in the "Your Apps" section of https://api.slack.com/.
  • SLACK_USER_TOKEN: This is the "OAuth Access Token" you can get from the "OAuth & Permissions" page in the "Your Apps" section of https://api.slack.com/. So far, I have been somewhat cavalier about whether to use the bot token or the user token in various calls, we can clean this up later.
  • GOOGLE_SERVICE_ACCOUNT_EMAIL: This is the e-mail address of a Google Cloud Platform service account used to access the Google Drive API for managing spreadsheets and the Google Calendar API for creating Google Meets. You can create a service account for a GCP project here. The Google Drive folder storing the spreadsheets should be shared with this account.
  • GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY: This is the private_key associated with the Google Cloud Platform service account. It should be downloaded when you create the service account.
  • PGHOST: The PostgreSQL database hostname.
  • PGPORT: The PostgreSQL database port. The default is 5432.
  • PGUSER: The PostgreSQL database username.
  • PGPASSWORD: The PostgreSQL database password for the given user.
  • PGDATABASE: The name of the PostgreSQL database to use.
  • SLACK_ACTIVITY_LOG_CHANNEL_NAME: A Slack channel name (without the leading #) where puzzle creations, topic changes, and solves will be announced.
  • SLACK_SOLVE_ANNOUNCEMENT_CHANNEL_NAME: A Slack channel name (without the leading #) where puzzle solves will be announced (in addition to within the activity log channel).
  • SLACK_ERROR_CHANNEL_NAME: A Slack channel name (without the leading #) where errors that occur related to this software will be posted.
  • SLACK_ADMIN_CHANNEL_ID: A Slack channel ID (not name!). Only members of this channel will be able to register puzzles. Leave this unset to allow any user to register puzzles. The app user must be a member of this channel for this to work.
  • SLACK_IGNORED_USER_IDS: A comma-separated list of Slack user IDs to be ignored for the purposes of tracking channel membership. Useful for ignoring the "bot" user (who cannot be detected automatically, because they're not really a bot, because they need to be able to create channels).
  • HUNT_PREFIX: A string that will be prepended to all generated puzzle channel names.
  • PUZZLE_SHEET_TEMPLATE_URL: A link to a Google Sheet that will be copied to create per-puzzle spreadsheets. It should be in a folder editable by the Google Cloud Platform service account, and this folder is where the spreadsheets will be created as well.
  • PUZZLE_DRAWING_TEMPLATE_URL: If set, a link to a Google Drawing that will be copied to create per-puzzle drawings. It should be in a folder editable by the Google Cloud Platform service account, and this folder is where the drawings will be created as well.
  • PUZZLE_TRACKING_SHEET_ID: If set, then each time a puzzle is registered, a row containing the name of the puzzle will be appended to the Google Spreadsheet with this sheet ID.
  • ENABLE_GOOGLE_MEET: If set, creates a calendar event with a Google Meet entry point for each puzzle.
  • GOOGLE_MEET_CALENDAR_ID: The Google Calendar ID of the calendar where per-puzzle events should be created. The Google service account must have permissions to make changes to this calendar.
  • ENABLE_SHEET_EDITOR_INVITES: If set, will attempt to automatically invite a user to the puzzle channel associated with a puzzle sheet they edit if they're not already a member of the channel. Requires both the Google Drive Activity API and the Google People API to be enabled.
  • ENABLE_RECORD_ACTIVITY: If set, a table of user puzzle interactions will be maintained, enabling features that report data such as the latest puzzle each user is working on, a user's solving history over time, etc.
  • AUTO_ARCHIVE: If set, then puzzle channels will be automatically archived as they become solved.
  • ALLOW_RESET_DATABASE: If set, then the admin page will have an option to reset the database.
  • NEW_PUZZLE_MINUTES: The maximum number of minutes for which a puzzle is considered to be new.
  • MINIMUM_IDLE_MINUTES: The number of minutes of inactivity on a puzzle for it to be considered idle.
  • MINIMUM_TOPIC_IDLE_MINUTES: The number of minutes for which a topic may be unmodified before it is considered stale.
  • REFRESH_POLLING_MINUTES: The frequency with which to internally poll for changes that aren't detected using events (e.g. spreadsheet edits). Alternatively, you can set up an external process to periodically GET /refresh, and leave this unset.
  • AWS_SNS_TOPIC_REGION: The AWS region containing the SNS topic for task queue notifications, or unset to not use SNS.
  • AWS_NOTIFY_TASK_QUEUE_SNS_TOPIC_ARN: The AWS SNS topic for task queue notifications, or unset to not use SNS.
  • LOG_DATABASE_CLIENT_USAGE: If set, logs debugging information about database client creation and reuse.
  • LOG_MESSAGE_EVENTS: If set, logs debugging information about incoming Slack requests and event messages. Currently only implemented for the AWS handler.
  • DISABLE_WEB_AUTH: If set, the web interface won't check for user authentication at all. Only enable this for local testing.

Required Slack configuration

The following scopes to be added to the Slack app on the "OAuth & Permissions" page in the "Your Apps" section of https://api.slack.com/. Your web server URL plus "/auth/slack/callback" must be added as a "Redirect URL" on the "OAuth & Permissions" page.

  • bot
  • bookmarks:read
  • bookmarks:write
  • channels:read
  • channels:write
  • channels:history
  • chat:write:bot
  • chat:write:user
  • groups:history
  • groups:read
  • pins:write
  • users:read
  • users:read.email

The following workspace events need to be added on the "Event Subscriptions" page in the "Your Apps" section of https://api.slack.com/. The "Request URL" on the "Event Subscriptions" page should be set to your web server URL plus "/slack/events".

  • app_home_opened
  • channel_archive
  • channel_unarchive
  • member_joined_channel
  • member_left_channel
  • message.channels
  • message.groups
  • user_change

The "Request URL" on the "Interactive Components" page should be set to your web server URL plus "/slack/events".

Setup and run locally

Make sure the environment variables above are set before starting the server.

To receive incoming Slack events while testing locally, you'll need to use something like ngrok.

$ npm install
$ npm run build
$ npm run start

The first time you run it, you'll need to initialize the database by going to http://localhost:3000/admin/initdatabase. The database will be erased each time this button is clicked.

HTTP pages

  • / doesn't contain much. It has a sign out link.
  • /puzzles is a dashboard of all puzzles.
  • /tagger is a tool for adding and removing tags on multiple puzzles at once.
  • /admin has controls to trigger some administrative functions.
  • /taskqueue can be used to manage the queue of asynchronous background tasks.

hunttracker's People

Contributors

auran98 avatar dependabot[bot] avatar jwmclaren avatar obijywk avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hunttracker's Issues

Add topic: puzzle-hunt

Hello! Would you be open to adding the topic puzzle-hunt to this repository? I've been looking for puzzle hunt organization tools, and they're rather scattered right now. Cardinality's Small Board project uses this topic already, so I thought I'd ask the projects I've seen so far to start using it, too.

Thank you very much!

Automatically add a person to a puzzle channel when they edit its spreadsheet

  • document the scopes we need to add for Google Drive Activity API and Google People API
  • add googlePersonResourceName to the users table schema
  • when we synchronize users with Slack, also create a contact for each user in the Google service account with their name and email address, via people.batchCreateContacts... but don't store the people resourceName returned from that call, it's different from the one the Drive Activity API returns
  • add an environment var for the Google Drive folder ID and document it
  • periodically call activity.query with the Google Drive folder ID as ancestorName and filter restricted to edits within the past N minutes
  • for each actor in the response, see if their knownUser personName already exists as a googlePersonResourceName in the users table. for the ones that aren't there, call people.getBatchGet to look them up, and update their googlePersonResourceNames in the users table.
  • look up the puzzles and puzzle_users for the driveItems in the activity.query response
  • if the puzzle isn't archived, for each actor in the activity.query response associated with that puzzle's driveItem, check if they are a user associated with the puzzle
  • if they're not, and they've also never joined the puzzle channel before, invite them to the puzzle channel

[Discussion] Tag system changes for puzzle grouping.

One thing that a few previous hunts have shown is that our system for sorting puzzles into groups is not necessarily as flexible as it ideally could be.

Part of this is the distinction we currently have where we tag puzzles as being in/<group> and then tag a meta meta/<group> then have code to process the tag names to extract just <group> where we need that for sorting purposes.

My proposal is to separate out the ability to tag puzzles as meta or not based solely on that tag without additions, and instead have all puzzles in a logical group indicated by group/<group> - this maintains the usefulness of the Meta view (where we would just display puzzles by group and sort any tagged metas to the top) and allows for simpler logic for filtering the Puzzle view.

For example, this year's Mystery Hunt had one round that contained three metapuzzles and we did not change any of the tagging in that round, so as the first meta for that group had been solved, the group was sorted to the end in meta-view despite having at least one open metapuzzle in it for the entirety of the post-solve process. It is my proposal that sorting those by group and displaying the metapuzzles at the top would show there was still meta-work to be done in that round as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.