# 3.3.0 / UNRELEASED
**General**
- Don't require a team for viewing challenges if Challenge visibility is set to public
- Add a `THEME_FALLBACK` config to help develop themes. See **Themes** section for details.
**API**
- Implement a faster `/api/v1/scoreboard` endpoint in Teams Mode
- Add the `solves` item to both `/api/v1/challenges` and `/api/v1/challenges/[challenge_id]` to more easily determine how many solves a challenge has
- Add the `solved_by_me` item to both `/api/v1/challenges` and `/api/v1/challenges/[challenge_id]` to more easily determine if the current account has solved the challenge
- Prevent admins from deleting themselves through `DELETE /api/v1/users/[user_id]`
- Add length checking to some sensitive fields in the Pages and Challenges schemas
- Fix issue where `PATCH /api/v1/users[user_id]` returned a list instead of a dict
- Fix exception that occured on demoting admins through `PATCH /api/v1/users[user_id]`
- Add `team_id` to `GET /api/v1/users` to determine if a user is already in a team
**Themes**
- Add a `THEME_FALLBACK` config to help develop themes.
- `THEME_FALLBACK` will configure CTFd to try to find missing theme files in the default built-in `core` theme.
- This makes it easier to develop themes or use incomplete themes.
- Allow for one theme to reference and inherit from another theme through approaches like `{% extends "core/page.html" %}`
- Allow for the automatic date rendering format to be overridden by specifying a `data-time-format` attribute.
- Add styling for the `<blockquote>` element.
- Fix scoreboard table identifier to switch between User/Team depending on configured user mode
- Switch to using Bootstrap's scss in `core/main.scss` to allow using Bootstrap variables
- Consolidate Jinja error handlers into a single function and better handle issues where error templates can't be found
**Plugins**
- Set plugin migration version after successful migrations
- Fix issue where Page URLs injected into the navbar were relative instead of absolute
**Admin Panel**
- Add User standings as well as Teams standings to the admin scoreboard when in Teams Mode
- Add a UI for adding members to a team from the team's admin page
- Add ability for admins to disable public team creation
- Link directly to users who submitted something in the submissions page if the CTF is in Teams Mode
- Fix Challenge Requirements interface in Admin Panel to not allow empty/null requirements to be added
- Fixed an issue where config times (start, end, freeze times) could not be removed
- Fix an exception that occurred when demoting an Admin user
- Adds a temporary hack for re-enabling Javascript snippets in Flag editor templates. (See #1779)
**Deployment**
- Install `python3-dev` instead of `python-dev` in apt
- Bump lxml to 4.6.2
- Bump pip-compile to 5.4.0
**Miscellaneous**
- Cache Docker builds more by copying and installing Python dependencies before copying CTFd
- Change the default emails slightly and rework confirmation email page to make some recommendations clearer
- Use `examplectf.com` as testing/development domain instead of `ctfd.io`
- Fixes issue where user's name and email would not appear in logs properly
- Add more linting by also linting with `flake8-comprehensions` and `flake8-bugbear`
* Fix an exception that occurred when demoting an Admin user
* Fix the response from the above request from returning a list instead of a dict
* Closes#1794
* Add length checking to some sensitive fields in Pages and Challenges.
* Works on #1786
This is enough to fix most of the issues but this is really a systemic problem for most of the API endpoints. We should have something that verifies data consistency. Marshmallow is not good enough at this. Pydantic seems like it would be superior here.
* Works on #1779
* Adds a temporary hack for re-enabling Javascript snippets in Flag editor templates.
* In the future this will probably be separated out into a separate scripts file or something like using web components
# 3.2.0 / 2020-12-07
**General**
- Add Team invites.
- Team invites are links containing a token that allow a user to join a team without knowing the team password
- Captains can generate invite tokens for their teams
- Admins can generate Team invite links as well
- Improved Team handling
- Prevent team joining while already on a team
- Return 403 instead of 200 for team join/create errors
- Allow team captains whose teams haven't done anything to disband their team
- Allow for uploading navbar logo, favicon, and index page banner during initial setup
- Fixed issue in teams mode where a user couldn't unlock a hint despite their team having enough points
- The fix for this is essentially to allow the user's points to go negative
- Imports have been made more stable
- This is primarily done by killing MySQL processes that are locking metadta
- This is a subpar approach but it seems to be the only solution to avoid a metadata lock in MySQL. This approach did not appear to be needed under Postgres or SQLite
**API**
- Addition of `POST /api/v1/teams/me/members` to generate invite tokens for teams
- Fixed an issue in `POST /api/v1/awards` where CTFd would 500 when a user could not be found by the provided `user_id`
- `POST /api/v1/unlocks` in teams mode now uses the team's score to determine if a user can purchase a hint
- Properly check for existing unlocks in teams mode in `POST /api/v1/unlocks`
- `/api/v1/notifications` and `/api/v1/notifications/[notification_id]` now have an html parameter which specifies the rendered content of the notification content
**Themes**
- Add Team Invite icon and Disband Team icon to teams/private.html
- Add teams/invite.html file to handle team joining with invites
- Added syntax highlighting to challenge descriptions, pages, hints, notifications, comments, and markdown editors
- This is done with `highlight.js` which has been added to `package.json`
- Fix notifications to properly fix/support Markdown and HTML notifications
- Notifications SQL Model now has an html propery
- Notifications API schemas now has an html field
- Removed MomentJS (see https://momentjs.com/docs/#/-project-status/) in favor of dayjs
- dayjs is mostly API compatible with MomentJS. The only major changes were:
- dayjs always uses browser local time so you don't need to call `.local()`
- dayjs segments out some MomentJS functionality into plugins which need to be imported in before using those features
- Fixed issue in `challenge.html` where the current attempt count would have a typo
- Fixed issue in `challenge.html` where the max attempts for a challenge would not show if it was set to 1
- Edit donut charts to have easier to read legends and labels
- Make data zoom bars thinner and more transparent
- Add logo, banner, and favicon settings to the setup.html
**Plugins**
- The `auth.register` (`/register`) endpoint now accepts a `?next=` parameter to define where to redirect to after registration
- There is now a `registered_only` decorator to redirect users to `auth.register` (`/register`) instead of `auth.login` (`/login`)
- Don't run `db.create_all()` as much during plugin upgrade or during imports
- By avoiding this we can let alembic and migrations do more of the table creation work but this means that plugins specifically opt into `app.db.create_all()` and will not implicitly get it through `upgrade()`.
- This means plugins that run `upgrade()` without a migrations folder (no idea who would do this really) will need to upgrade their code.
- The plugin `upgrade()` function now accepts a `lower` parameter which specifies what lower revision should be used to start from.
- This is used to support plugin migrations during import so that we can import data directly at the point that the import was taken from
- `lower="current"` means to use the current revision and `lower=None` would mean to use the absolute base revision (e.g. plugin's first installation)
- By default this doesn't change `upgrade()` behavior
**Admin Panel**
- Add Favicon uploading to the Admin Panel
- Move Logo uploading to the Theme tab in the Admin Panel
- The challenge left side bar tabs have been rewritten into VueJS components.
- This fixes a number of issues with the consistency of what data is deleted/edited in the challenge editor
- This also prevents having to refresh the page in most challenge editing situations
- Fixed a possible bug where the update available alert wouldn't go away on server restart
- Examples for regex flags are now provided
- Wrong submissions has been renamed to Incorrect Submissions
- Graphs in the Admin Statistics page will now scroll with mouse wheel to improve browsing large datasets
- Fixed an issue where Users/Teams could be created with a null password
**Deployment**
- A restart policy set to `always` has been added to nginx in docker-compose
- Rename `requirements.txt` to `requirements.in` and generate `requirements.txt` using `pip-tools` under Python 3.6
- `UPLOAD_PROVIDER` no longer has a default `filesystem` set in config.ini. Instead it is defaulted through `config.py`
**Miscellaneous**
- The `psycopg2` dependency in development.txt has been removed in favor of `psycopg2-binary` which was updated to 2.8.6
- The `moto` dependency in development.txt has been updated to 1.3.16
- Add `pip-tools` to `development.txt`
- Add `import_ctf` and `export_ctf` commands to `manage.py` and deprecate `import.py` and `export.py`
- Override the `MAIL_SERVER` config with the `TESTING_MAIL_SERVER` envvar during tests
- `ping` events in the notification event handler have been fixed to not send duplicates
- The plugin `upgrade()` function now accepts a `lower` parameter which specifies what lower revision should be used to start from.
- This is used to support plugin migrations during import so that we can import data directly at the point that the import was taken from
- `lower="current"` means to use the current revision and `lower=None` would mean to use the absolute base revision (e.g. plugin's first installation)
- By default this doesn't change `upgrade()` behavior
# 3.2.0 / unreleased
**General**
- Add Team invites.
- Team invites are links containing a token that allow a user to join a team without knowing the team password
- Captains can generate invite tokens for their teams
- Admins can generate Team invite links as well
- Improved Team handling
- Prevent team joining while already on a team
- Return 403 instead of 200 for team join/create errors
- Allow team captains whose teams haven't done anything to disband their team
- Allow for uploading navbar logo, favicon, and index page banner during initial setup
- Fixed issue in teams mode where a user couldn't unlock a hint despite their team having enough points
- The fix for this is essentially to allow the user's points to go negative
- Imports have been made more stable
- This is primarily done by killing MySQL processes that are locking metadta
- This is a subpar approach but it seems to be the only solution to avoid a metadata lock in MySQL. This approach did not appear to be needed under Postgres or SQLite
- Update some migrations to first check if a table already exists.
**API**
- Addition of `POST /api/v1/teams/me/members` to generate invite tokens for teams
- Fixed an issue in `POST /api/v1/awards` where CTFd would 500 when a user could not be found by the provided `user_id`
- `POST /api/v1/unlocks` in teams mode now uses the team's score to determine if a user can purchase a hint
- Properly check for existing unlocks in teams mode in `POST /api/v1/unlocks`
- `/api/v1/notifications` and `/api/v1/notifications/[notification_id]` now have an html parameter which specifies the rendered content of the notification content
**Themes**
- Added syntax highlighting to challenge descriptions, pages, hints, notifications, comments, and markdown editors
- This is done with `highlight.js` which has been added to `package.json`
- Fix notifications to properly fix/support Markdown and HTML notifications
- Notifications SQL Model now has an html propery
- Notifications API schemas now has an html field
- Removed MomentJS (see https://momentjs.com/docs/#/-project-status/) in favor of dayjs
- dayjs is mostly API compatible with MomentJS. The only major changes were:
- dayjs always uses browser local time so you don't need to call `.local()`
- dayjs segments out some MomentJS functionality into plugins which need to be imported in before using those features
- Fixed issue in `challenge.html` where the current attempt count would have a typo
- Fixed issue in `challenge.html` where the max attempts for a challenge would not show if it was set to 1
- Edit donut charts to have easier to read legends and labels
- Make data zoom bars thinner and more transparent
**Plugins**
- Don't run `db.create_all()` as much during plugin upgrade or during imports
- By avoiding this we can let alembic and migrations do more of the table creation work but this means that plugins specifically opt into `app.db.create_all()` and will not implicitly get it through `upgrade()`.
- This means plugins that run `upgrade()` without a migrations folder (no idea who would do this really) will need to upgrade their code.
**Admin Panel**
- Add Favicon uploading to the Admin Panel
- Move Logo uploading to the Theme tab in the Admin Panel
- The challenge left side bar tabs have been rewritten into VueJS components.
- This fixes a number of issues with the consistency of what data is deleted/edited in the challenge editor
- This also prevents having to refresh the page in most challenge editing situations
- Fixed a possible bug where the update available alert wouldn't go away on server restart
- Examples for regex flags are now provided
- Wrong submissions has been renamed to Incorrect Submissions
- Graphs in the Admin Statistics page will now scroll with mouse wheel to improve browsing large datasets
**Deployment**
- A restart policy set to `always` has been added to nginx in docker-compose
- Rename `requirements.txt` to `requirements.in` and generate `requirements.txt` using `pip-tools` under Python 3.6
- `UPLOAD_PROVIDER` no longer has a default `filesystem` set in config.ini. Instead it is defaulted through `config.py`
**Miscellaneous**
- The `psycopg2` dependency in development.txt has been removed in favor of `psycopg2-binary` which was updated to 2.8.6
- The `moto` dependency in development.txt has been updated to 1.3.16
- Add `pip-tools` to `development.txt`
- Add `import_ctf` and `export_ctf` commands to `manage.py` and deprecate `import.py` and `export.py`
- Override the `MAIL_SERVER` config with the `TESTING_MAIL_SERVER` envvar during tests
- `ping` events in the notification event handler have been fixed to not send duplicates
* Prevent team joining while already on a team
* Return 403 instead of 200 for team join/create errors
* Allow team captains whose teams haven't done anything to disband their team
* Closes#1588
* Build `requirements.txt` on Python 3.7 to fix an issue with installing dataclasses.
* Closes#1729
I tested that this works in Python 3.6, 3.7, and 3.8. A useful project would be to add installing deps to Github Actions.
I'll subscribe to https://github.com/ericvsmith/dataclasses/pull/161 since this is IMO a bug in dataclasses.
* Fixed issue where the current attempt count would have a typo
* Fixed issue where the max attempts for a challenge would not show if it was set to 1
* Works on #1655
* Rename `requirements.txt` to `requirements.in`
* Generate `requirements.txt` using `pip-tools` under Python 3.6
* Add `pip-tools` to `development.txt`
* Closes#1679