2.2.0 / 2019-12-22
==================
## Notice
2.2.0 focuses on updating the front end of CTFd to use more modern programming practices and changes some aspects of core CTFd design. If your current installation is using a custom theme or custom plugin with ***any*** kind of JavaScript, it is likely that you will need to upgrade that theme/plugin to be useable with v2.2.0.
**General**
* Team size limits can now be enforced from the configuration panel
* Access tokens functionality for API usage
* Admins can now choose how to deliver their notifications
* Toast (new default)
* Alert
* Background
* Sound On / Sound Off
* There is now a notification counter showing how many unread notifications were received
* Setup has been redesigned to have multiple steps
* Added Description
* Added Start time and End time,
* Added MajorLeagueCyber integration
* Added Theme and color selection
* Fixes issue where updating dynamic challenges could change the value to an incorrect value
* Properly use a less restrictive regex to validate email addresses
* Bump Python dependencies to latest working versions
* Admins can now give awards to team members from the team's admin panel page
**API**
* Team member removals (`DELETE /api/v1/teams/[team_id]/members`) from the admin panel will now delete the removed members's Submissions, Awards, Unlocks
**Admin Panel**
* Admins can now user a color input box to specify a theme color which is injected as part of the CSS configuration. Theme developers can use this CSS value to change colors and styles accordingly.
* Challenge updates will now alert you if the challenge doesn't have a flag
* Challenge entry now allows you to upload files and enter simple flags from the initial challenge creation page
**Themes**
* Significant JavaScript and CSS rewrite to use ES6, Webpack, yarn, and babel
* Theme asset specially generated URLs
* Static theme assets are now loaded with either .dev.extension or .min.extension depending on production or development (i.e. debug server)
* Static theme assets are also given a `d` GET parameter that changes per server start. Used to bust browser caches.
* Use `defer` for script tags to not block page rendering
* Only show the MajorLeagueCyber button if configured in configuration
* The admin panel now links to https://help.ctfd.io/ in the top right
* Create an `ezToast()` function to use [Bootstrap's toasts](https://getbootstrap.com/docs/4.3/components/toasts/)
* The user-facing navbar now features icons
* Awards shown on a user's profile can now have award icons
* The default MarkdownIt render created by CTFd will now open links in new tabs
* Country flags can now be shown on the user pages
**Deployment**
* Switch `Dockerfile` from `python:2.7-alpine` to `python:3.7-alpine`
* Add `SERVER_SENT_EVENTS` config value to control whether Notifications are enabled
* Challenge ID is now recorded in the submission log
**Plugins**
* Add an endpoint parameter to `register_plugin_assets_directory()` and `register_plugin_asset()` to control what endpoint Flask uses for the added route
**Miscellaneous**
* `CTFd.utils.email.sendmail()` now allows the caller to specify subject as an argument
* The subject allows for injecting custom variable via the new `CTFd.utils.formatters.safe_format()` function
* Admin user information is now error checked during setup
* Added yarn to the toolchain and the yarn dev, yarn build, yarn verify, and yarn clean scripts
* Prevent old CTFd imports from being imported
2.1.5 / 2019-10-2
=================
**General**
* Fixes `flask run` debug server by not monkey patching in `wsgi.py`
* Fix CSV exports in Python 3 by converting StringIO to BytesIO
* Avoid exception on sessions without a valid user and force logout
* Fix several issues in Vagrant provisioning
**API**
* Prevent users from nulling out profile values and breaking certain pages
2.1.4 / 2019-08-30
==================
**General**
* Make user pages show the team's score and place information instead of the user's information if in team mode
* Allow admins to search users by IP address
* Require password for email address changes in the user profile
* The place indicator in `Teams Mode` on the team pages and user pages now correctly excludes hidden teams
* Fix scoreboard place ordinalization in Python 3
* Fix for a crash where imports will fail on SQLite due to lack of ALTER command support
* Fix for an issue where files downloaded via S3 would have the folder name in the filename
* Make `Users.get_place()` and `Teams.get_place()` for return None instead of 0 if the account has no rank/place
* Properly redirect users or 403 if the endpoint requires a team but the user isn't in one
* Show affiliation in user and team pages in the admin panel and public and private user and team pages
**Themes**
* Remove invalid `id='submit'` on submit buttons in various theme files
* Set `tabindex` to 0 since we don't really care for forcing tab order
* Rename `statistics.js` to `graphs.js` in the Admin Panel as it was identified that adblockers can sometimes block the file
**API**
* The team profile endpoint (`/api/v1/teams/me`) will now return 403 instead of 400 if the requesting user is not the captain
* The Challenge API will now properly freeze the solve count to freeze time
* The place indicator in Team Mode on the team pages and user pages now excludes counting hidden teams.
* Updated `flask-marshmallow` to 0.10.1, `marshmallow-sqlalchemy` to 0.17.0
* Pinned `marshmallow` to 2.20.2
* Closes#1093
* Closes#1088
* Show affiliation in user and team pages in the admin panel and public and private user and team pages.
* Make user pages show team information (score, place) instead of user information if in team mode.
* Make `Users.get_place()` and `Teams.get_place()` for return None instead of 0 if the account has no rank. (Closes#1039)
* Make `populate.py` randomly add affiliations and officials
* Only add `teams.team_captain_id` foreign key if the db backend isn't SQLite. SQLite does not support ALTER for the manipulation of columns/constraints.
* Closes#1041
2.1.3 / 2019-06-22
==================
**General**
* Fix issue with downloading files after CTF end when `view_after_ctf` is enabled
* Sort solves in admin challenge view by date
* Link to appropriate user and challenge in team, user, and challenge pages
* Redirect to `/team` instead of `/challenges` after a user registers in team mode
* Fixes bug where pages marked as `hidden` weren't loading
* Remove `data-href` from `pages.html` in the Admin Panel to fix the delete button
* Add UI to handle team member removal in Admin Panel
* Fixes account links on the scoreboard page created by `update()`. They now correctly point to the user instead of undefined when in user mode.
* `utils._get_config` will now return `KeyError` instead of `None` to avoid cache misses
**Deployment**
* Use `/dev/shm` for `--worker-tmp-dir` in gunicorn in Docker
* Cache `get_place` code for users and teams.
* Install `Flask-DebugToolbar` in development
* Cache the `/scoreboard` page to avoid having to rebuild the response so often
* Make unprivileged `ctfd` user usable for mysql connection in docker-compose by having the db image create the database instead of CTFd
* Fix bug causing apache2 + mod_wsgi deployments to break
**API**
* Change `/api/v1/teams/[team_id]/members` from taking `id` to `user_id`.
* Endpoint was unused so the API change is considered non-breaking.
* Add `account_type` and `account_url` field in `/api/v1/scoreboard`
* Separate `/api/v1/[users,teams]/[me,id]/[solves,fails,awards]` into seperate API endpoints
* Clear standings cache after award creation/deletion
**Exports**
* Temporarily disable foreign keys in MySQL, MariaDB, and Postgres during `import_ctf()`
* Add `cache_timeout` parameter to `send_file`response in `/admin/export` to prevent the browser from caching the export
**Tests**
* Fix score changing test helpers to clear standings cache when generating a score changing row
* Fixes account links on the scoreboard page created by `update()`. They now correctly point to the user instead of undefined when in user mode.
* Add `account_type` and `account_url` field in `/api/v1/scoreboard`
* Temporarily disable foreign keys in MySQL, MariaDB, and Postgres during `import_ctf()`
* Likely also disables SQLite but SQLite is permissive about foreign keys to begin with so irrelevant.
* Create a `flask_migrate.stamp()` wrapper in `CTFd.utils.migrations` that always references the migrations folder regardless of how CTFd is run or deployed.
* Closes#257 properly
* Cache the `/scoreboard` page to avoid having to rebuild the response so often
* Update `tests.api.v1.test_scoreboard:test_scoreboard_is_cached` to also test if `/scoreboard` is cached
* Cache get place code for users and teams.
* Fix score changing test helpers to clear standings cache when generating a score changing row
* `utils._get_config` will now return `KeyError` instead of None.
* Separate `/api/v1/[users,teams]/[me,id]/[solves,fails,awards]` into seperate API endpoints
* Install `Flask-DebugToolbar` in development
Main goals covered in #1012
* Change `/api/v1/teams/[team_id]/members` from taking `id` to `user_id`.
* Not even the admin panel was using this endpoint so doesn't seem that drastic of a change
* Add UI to handle team member removal
* Remove `data-href` from `pages.html` to fix the delete button
* The delete action propagates too much causing issues. This should be re-implemented on page editor rewrite.
* Fixes bug where pages marked as `hidden` weren't loading
* It's possible that some users used this behavior however this fix implements the correct behavior. The `draft` setting can be used to completely hide pages.