aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Mark <[email protected]>2021-04-19 00:00:52 -0700
committerGravatar GitHub <[email protected]>2021-04-19 00:00:52 -0700
commitfc4a9e24dd23b520b9a5560215dea434ea2e03ea (patch)
tree8baba14d03013fa3155ba5a93d8b1c92d868e92d
parentUpdate tests to use trailing slashes on valid urls (diff)
parentMerge pull request #472 from python-discord/ks123/ghcr-token-to-github (diff)
Merge branch 'main' into doc-validator
-rw-r--r--.github/workflows/build.yaml4
-rw-r--r--.github/workflows/deploy.yaml1
-rw-r--r--CODE_OF_CONDUCT.md3
-rw-r--r--CONTRIBUTING.md125
-rw-r--r--Pipfile.lock282
-rw-r--r--SECURITY.md3
-rwxr-xr-xmanage.py4
-rw-r--r--postgres/init.sql109
-rw-r--r--pydis_site/apps/api/models/bot/metricity.py41
-rw-r--r--pydis_site/apps/api/tests/test_users.py39
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py31
-rw-r--r--pydis_site/static/css/home/index.css14
-rw-r--r--pydis_site/static/images/sponsors/streamyard.pngbin0 -> 86678 bytes
-rw-r--r--pydis_site/templates/home/index.html15
-rw-r--r--pydis_site/templates/home/timeline.html949
15 files changed, 937 insertions, 683 deletions
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 873bcda4..ab7321de 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -38,8 +38,8 @@ jobs:
uses: docker/login-action@v1
with:
registry: ghcr.io
- username: ${{ secrets.GHCR_USER }}
- password: ${{ secrets.GHCR_TOKEN }}
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
# Build the container, including an inline cache manifest to
# allow us to use the registry as a cache source.
diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index 8abf2bfb..efc08040 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -13,6 +13,7 @@ jobs:
if: github.event.workflow_run.conclusion == 'success'
name: Deploy to Kubernetes Cluster
runs-on: ubuntu-latest
+ environment: production
steps:
- name: Create SHA Container Tag
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..57ccd80e
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,3 @@
+# Code of Conduct
+
+The Python Discord Code of Conduct can be found [on our website](https://pydis.com/coc).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 84a59d54..f20b5316 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,124 +1,3 @@
-# Contributing to one of Our Projects
+# Contributing Guidelines
-Our projects are open-source and are automatically deployed whenever commits are pushed to the `main` branch on each repository, so we've created a set of guidelines in order to keep everything clean and in working order.
-
-Note that contributions may be rejected on the basis of a contributor failing to follow these guidelines.
-
-## Rules
-
-1. **No force-pushes** or modifying the Git history in any way.
-2. If you have direct access to the repository, **create a branch for your changes** and create a pull request for that branch. If not, create a branch on a fork of the repository and create a pull request from there.
- * It's common practice for a repository to reject direct pushes to `main`, so make branching a habit!
- * If PRing from your own fork, **ensure that "Allow edits from maintainers" is checked**. This gives permission for maintainers to commit changes directly to your fork, speeding up the review process.
-3. **Adhere to the prevailing code style**, which we enforce using [`flake8`](http://flake8.pycqa.org/en/latest/index.html) and [`pre-commit`](https://pre-commit.com/).
- * Run `flake8` and `pre-commit` against your code [**before** you push it](https://soundcloud.com/lemonsaurusrex/lint-before-you-push). Your commit will be rejected by the build server if it fails to lint.
- * [Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) are a powerful git feature for executing custom scripts when certain important git actions occur. The pre-commit hook is the first hook executed during the commit process and can be used to check the code being committed & abort the commit if issues, such as linting failures, are detected. While git hooks can seem daunting to configure, the `pre-commit` framework abstracts this process away from you and is provided as a dev dependency for this project. Run `pipenv run precommit` when setting up the project and you'll never have to worry about committing code that fails linting.
-4. **Make great commits**. A well structured git log is key to a project's maintainability; it efficiently provides insight into when and *why* things were done for future maintainers of the project.
- * Commits should be as narrow in scope as possible. Commits that span hundreds of lines across multiple unrelated functions and/or files are very hard for maintainers to follow. After about a week they'll probably be hard for you to follow too.
- * Avoid making minor commits for fixing typos or linting errors. Since you've already set up a `pre-commit` hook to run the linting pipeline before a commit, you shouldn't be committing linting issues anyway.
- * A more in-depth guide to writing great commit messages can be found in Chris Beam's [*How to Write a Git Commit Message*](https://chris.beams.io/posts/git-commit/)
-5. **Avoid frequent pushes to the main repository**. This goes for PRs opened against your fork as well. Our test build pipelines are triggered every time a push to the repository (or PR) is made. Try to batch your commits until you've finished working for that session, or you've reached a point where collaborators need your commits to continue their own work. This also provides you the opportunity to amend commits for minor changes rather than having to commit them on their own because you've already pushed.
- * This includes merging main into your branch. Try to leave merging from main for after your PR passes review; a maintainer will bring your PR up to date before merging. Exceptions to this include: resolving merge conflicts, needing something that was pushed to main for your branch, or something was pushed to main that could potentionally affect the functionality of what you're writing.
-6. **Don't fight the framework**. Every framework has its flaws, but the frameworks we've picked out have been carefully chosen for their particular merits. If you can avoid it, please resist reimplementing swathes of framework logic - the work has already been done for you!
-7. If someone is working on an issue or pull request, **do not open your own pull request for the same task**. Instead, collaborate with the author(s) of the existing pull request. Duplicate PRs opened without communicating with the other author(s) and/or PyDis staff will be closed. Communication is key, and there's no point in two separate implementations of the same thing.
- * One option is to fork the other contributor's repository and submit your changes to their branch with your own pull request. We suggest following these guidelines when interacting with their repository as well.
- * The author(s) of inactive PRs and claimed issues will be be pinged after a week of inactivity for an update. Continued inactivity may result in the issue being released back to the community and/or PR closure.
-8. **Work as a team** and collaborate wherever possible. Keep things friendly and help each other out - these are shared projects and nobody likes to have their feet trodden on.
-9. All API changes **must be validated against the bot** before PRing. Please don't leave this for reviewers to discover. Guides for setting up the developer environment can be [found below](#developer-environment).
-10. All static content, such as images or audio, **must be licensed for open public use**.
- * Static content must be hosted by a service designed to do so. Failing to do so is known as "leeching" and is frowned upon, as it generates extra bandwidth costs to the host without providing benefit. It would be best if appropriately licensed content is added to the repository itself so it can be served by PyDis' infrastructure.
-
-Above all, the needs of our community should come before the wants of an individual. Work together, build solutions to problems and try to do so in a way that people can learn from easily. Abuse of our trust may result in the loss of your Contributor role.
-
-## Changes to this Arrangement
-
-All projects evolve over time, and this contribution guide is no different. This document is open to pull requests or changes by contributors. If you believe you have something valuable to add or change, please don't hesitate to do so in a PR.
-
-## Supplemental Information
-### Developer Environment
-Instructions for setting up environments for both the site and the bot can be found on the PyDis Wiki:
- * [Site](https://pythondiscord.com/pages/contributing/site/)
- * [Bot](https://pythondiscord.com/pages/contributing/bot/)
-
-When pulling down changes from GitHub, remember to sync your environment using `pipenv sync --dev` to ensure you're using the most up-to-date versions the project's dependencies.
-
-### Type Hinting
-[PEP 484](https://www.python.org/dev/peps/pep-0484/) formally specifies type hints for Python functions, added to the Python Standard Library in version 3.5. Type hints are recognized by most modern code editing tools and provide useful insight into both the input and output types of a function, preventing the user from having to go through the codebase to determine these types.
-
-For example:
-
-```py
-import typing as t
-
-
-def foo(input_1: int, input_2: t.Dict[str, str]) -> bool:
- ...
-```
-
-Tells us that `foo` accepts an `int` and a `dict`, with `str` keys and values, and returns a `bool`.
-
-All function declarations should be type hinted in code contributed to the PyDis organization.
-
-For more information, see *[PEP 483](https://www.python.org/dev/peps/pep-0483/) - The Theory of Type Hints* and Python's documentation for the [`typing`](https://docs.python.org/3/library/typing.html) module.
-
-### AutoDoc Formatting Directives
-Many documentation packages provide support for automatic documentation generation from the codebase's docstrings. These tools utilize special formatting directives to enable richer formatting in the generated documentation.
-
-For example:
-
-```py
-import typing as t
-
-
-def foo(bar: int, baz: t.Optional[t.Dict[str, str]] = None) -> bool:
- """
- Does some things with some stuff.
-
- :param bar: Some input
- :param baz: Optional, some dictionary with string keys and values
-
- :return: Some boolean
- """
- ...
-```
-
-Since PyDis does not utilize automatic documentation generation, use of this syntax should not be used in code contributed to the organization. Should the purpose and type of the input variables not be easily discernable from the variable name and type annotation, a prose explanation can be used. Explicit references to variables, functions, classes, etc. should be wrapped with backticks (`` ` ``).
-
-For example, the above docstring would become:
-
-```py
-import typing as t
-
-
-def foo(bar: int, baz: t.Optional[t.Dict[str, str]] = None) -> bool:
- """
- Does some things with some stuff.
-
- This function takes an index, `bar` and checks for its presence in the database `baz`, passed as a dictionary. Returns `False` if `baz` is not passed.
- """
- ...
-```
-
-### Logging Levels
-The project currently defines [`logging`](https://docs.python.org/3/library/logging.html) levels as follows, from lowest to highest severity:
-* **TRACE:** These events should be used to provide a *verbose* trace of every step of a complex process. This is essentially the `logging` equivalent of sprinkling `print` statements throughout the code.
- * **Note:** This is a PyDis-implemented logging level.
-* **DEBUG:** These events should add context to what's happening in a development setup to make it easier to follow what's going while working on a project. This is in the same vein as **TRACE** logging but at a much lower level of verbosity.
-* **INFO:** These events are normal and don't need direct attention but are worth keeping track of in production, like checking which cogs were loaded during a start-up.
-* **WARNING:** These events are out of the ordinary and should be fixed, but have not caused a failure.
- * **NOTE:** Events at this logging level and higher should be reserved for events that require the attention of the DevOps team.
-* **ERROR:** These events have caused a failure in a specific part of the application and require urgent attention.
-* **CRITICAL:** These events have caused the whole application to fail and require immediate intervention.
-
-Ensure that log messages are succinct. Should you want to pass additional useful information that would otherwise make the log message overly verbose the `logging` module accepts an `extra` kwarg, which can be used to pass a dictionary. This is used to populate the `__dict__` of the `LogRecord` created for the logging event with user-defined attributes that can be accessed by a log handler. Additional information and caveats may be found [in Python's `logging` documentation](https://docs.python.org/3/library/logging.html#logging.Logger.debug).
-
-### Work in Progress (WIP) PRs
-Github [provides a PR feature](https://github.blog/2019-02-14-introducing-draft-pull-requests/) that allows the PR author to mark it as a WIP. This provides both a visual and functional indicator that the contents of the PR are in a draft state and not yet ready for formal review.
-
-This feature should be utilized in place of the traditional method of prepending `[WIP]` to the PR title.
-
-As stated earlier, **ensure that "Allow edits from maintainers" is checked**. This gives permission for maintainers to commit changes directly to your fork, speeding up the review process.
-
-## Footnotes
-
-This document was inspired by the [Glowstone contribution guidelines](https://github.com/GlowstoneMC/Glowstone/blob/dev/docs/CONTRIBUTING.md).
+The Contributing Guidelines for Python Discord projects can be found [on our website](https://pydis.com/contributing.md).
diff --git a/Pipfile.lock b/Pipfile.lock
index fe97c5dd..7c55a5d2 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -21,7 +21,6 @@
"sha256:5ee950735509d04eb673bd7f7120f8fa1c9e2df495394992c73234d526907e17",
"sha256:7162a3cb30ab0609f1a4c95938fd73e8604f63bdba516a7f7d64b83ff09478f0"
],
- "markers": "python_version >= '3.5'",
"version": "==3.3.1"
},
"bleach": {
@@ -29,7 +28,6 @@
"sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f",
"sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==3.1.5"
},
"certifi": {
@@ -41,79 +39,76 @@
},
"cffi": {
"hashes": [
- "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e",
- "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d",
- "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a",
- "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec",
- "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362",
- "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668",
- "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c",
- "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b",
- "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06",
- "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698",
- "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2",
- "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c",
- "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7",
- "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009",
- "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03",
- "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b",
- "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909",
- "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53",
- "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35",
- "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26",
- "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b",
- "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01",
- "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb",
- "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293",
- "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd",
- "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d",
- "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3",
- "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d",
- "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e",
- "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca",
- "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d",
- "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775",
- "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375",
- "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b",
- "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b",
- "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"
- ],
- "version": "==1.14.4"
+ "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
+ "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
+ "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
+ "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
+ "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
+ "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
+ "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
+ "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
+ "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
+ "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
+ "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
+ "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
+ "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5",
+ "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
+ "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
+ "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
+ "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
+ "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
+ "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
+ "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369",
+ "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827",
+ "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053",
+ "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa",
+ "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4",
+ "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322",
+ "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132",
+ "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62",
+ "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa",
+ "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0",
+ "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396",
+ "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
+ "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
+ "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
+ "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
+ "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
+ "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
+ "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
+ ],
+ "version": "==1.14.5"
},
"chardet": {
"hashes": [
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"cryptography": {
"hashes": [
- "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d",
- "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7",
- "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901",
- "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c",
- "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244",
- "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6",
- "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5",
- "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e",
- "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c",
- "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0",
- "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812",
- "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a",
- "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030",
- "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302"
- ],
- "version": "==3.3.1"
+ "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b",
+ "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336",
+ "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87",
+ "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7",
+ "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799",
+ "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b",
+ "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df",
+ "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0",
+ "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3",
+ "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724",
+ "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2",
+ "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"
+ ],
+ "version": "==3.4.6"
},
"defusedxml": {
"hashes": [
- "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93",
- "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"
+ "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
+ "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.6.0"
+ "version": "==0.7.1"
},
"django": {
"hashes": [
@@ -173,7 +168,6 @@
"sha256:90eb236eb4f1a92124bd7c37852bbe09c0d21158477cc237556d59842a91c509",
"sha256:dfdb3af75ad27cdd4458b0544ec8574174f2b90f99bc2cafab6a15b4bc1895a8"
],
- "markers": "python_version >= '3.5'",
"version": "==0.11.0"
},
"django-nyt": {
@@ -219,7 +213,6 @@
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"libsass": {
@@ -245,7 +238,6 @@
"sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17",
"sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59"
],
- "markers": "python_version >= '3.5'",
"version": "==3.2.2"
},
"oauthlib": {
@@ -253,50 +245,52 @@
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.1.0"
},
"packaging": {
"hashes": [
- "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858",
- "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"
+ "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
+ "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==20.8"
+ "version": "==20.9"
},
"pillow": {
"hashes": [
- "sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a",
- "sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae",
- "sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce",
- "sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e",
- "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140",
- "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb",
- "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021",
- "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6",
- "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302",
- "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c",
- "sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271",
- "sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09",
- "sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3",
- "sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015",
- "sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3",
- "sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544",
- "sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8",
- "sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792",
- "sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0",
- "sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3",
- "sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8",
- "sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11",
- "sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7",
- "sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11",
- "sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e",
- "sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039",
- "sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5",
- "sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==8.0.1"
+ "sha256:15306d71a1e96d7e271fd2a0737038b5a92ca2978d2e38b6ced7966583e3d5af",
+ "sha256:1940fc4d361f9cc7e558d6f56ff38d7351b53052fd7911f4b60cd7bc091ea3b1",
+ "sha256:1f93f2fe211f1ef75e6f589327f4d4f8545d5c8e826231b042b483d8383e8a7c",
+ "sha256:30d33a1a6400132e6f521640dd3f64578ac9bfb79a619416d7e8802b4ce1dd55",
+ "sha256:328240f7dddf77783e72d5ed79899a6b48bc6681f8d1f6001f55933cb4905060",
+ "sha256:46c2bcf8e1e75d154e78417b3e3c64e96def738c2a25435e74909e127a8cba5e",
+ "sha256:5762ebb4436f46b566fc6351d67a9b5386b5e5de4e58fdaa18a1c83e0e20f1a8",
+ "sha256:5a2d957eb4aba9d48170b8fe6538ec1fbc2119ffe6373782c03d8acad3323f2e",
+ "sha256:5cf03b9534aca63b192856aa601c68d0764810857786ea5da652581f3a44c2b0",
+ "sha256:5daba2b40782c1c5157a788ec4454067c6616f5a0c1b70e26ac326a880c2d328",
+ "sha256:63cd413ac52ee3f67057223d363f4f82ce966e64906aea046daf46695e3c8238",
+ "sha256:6efac40344d8f668b6c4533ae02a48d52fd852ef0654cc6f19f6ac146399c733",
+ "sha256:71b01ee69e7df527439d7752a2ce8fb89e19a32df484a308eca3e81f673d3a03",
+ "sha256:71f31ee4df3d5e0b366dd362007740106d3210fb6a56ec4b581a5324ba254f06",
+ "sha256:72027ebf682abc9bafd93b43edc44279f641e8996fb2945104471419113cfc71",
+ "sha256:74cd9aa648ed6dd25e572453eb09b08817a1e3d9f8d1bd4d8403d99e42ea790b",
+ "sha256:81b3716cc9744ffdf76b39afb6247eae754186838cedad0b0ac63b2571253fe6",
+ "sha256:8565355a29655b28fdc2c666fd9a3890fe5edc6639d128814fafecfae2d70910",
+ "sha256:87f42c976f91ca2fc21a3293e25bd3cd895918597db1b95b93cbd949f7d019ce",
+ "sha256:89e4c757a91b8c55d97c91fa09c69b3677c227b942fa749e9a66eef602f59c28",
+ "sha256:8c4e32218c764bc27fe49b7328195579581aa419920edcc321c4cb877c65258d",
+ "sha256:903293320efe2466c1ab3509a33d6b866dc850cfd0c5d9cc92632014cec185fb",
+ "sha256:90882c6f084ef68b71bba190209a734bf90abb82ab5e8f64444c71d5974008c6",
+ "sha256:98afcac3205d31ab6a10c5006b0cf040d0026a68ec051edd3517b776c1d78b09",
+ "sha256:a01da2c266d9868c4f91a9c6faf47a251f23b9a862dce81d2ff583135206f5be",
+ "sha256:aeab4cd016e11e7aa5cfc49dcff8e51561fa64818a0be86efa82c7038e9369d0",
+ "sha256:b07c660e014852d98a00a91adfbe25033898a9d90a8f39beb2437d22a203fc44",
+ "sha256:bead24c0ae3f1f6afcb915a057943ccf65fc755d11a1410a909c1fefb6c06ad1",
+ "sha256:d1d6bca39bb6dd94fba23cdb3eeaea5e30c7717c5343004d900e2a63b132c341",
+ "sha256:e2cd8ac157c1e5ae88b6dd790648ee5d2777e76f1e5c7d184eaddb2938594f34",
+ "sha256:e5739ae63636a52b706a0facec77b2b58e485637e1638202556156e424a02dc2",
+ "sha256:f36c3ff63d6fc509ce599a2f5b0d0732189eed653420e7294c039d342c6e204a",
+ "sha256:f91b50ad88048d795c0ad004abbe1390aa1882073b1dca10bfd55d0b8cf18ec5"
+ ],
+ "version": "==8.1.2"
},
"psycopg2-binary": {
"hashes": [
@@ -344,7 +338,6 @@
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.20"
},
"pygments": {
@@ -360,17 +353,16 @@
"crypto"
],
"hashes": [
- "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
- "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
+ "sha256:a5c70a06e1f33d81ef25eecd50d50bd30e34de1ca8b2b9fa3fe0daaabcf69bf7",
+ "sha256:b70b15f89dc69b993d8a8d32c299032d5355c82f9b5b7e851d1a6d706dffe847"
],
- "version": "==1.7.1"
+ "version": "==2.0.1"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"python3-openid": {
@@ -382,10 +374,10 @@
},
"pytz": {
"hashes": [
- "sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268",
- "sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd"
+ "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
+ "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
],
- "version": "==2020.4"
+ "version": "==2021.1"
},
"pyyaml": {
"hashes": [
@@ -417,8 +409,7 @@
"requests-oauthlib": {
"hashes": [
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
- "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
- "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
+ "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
],
"version": "==1.3.0"
},
@@ -435,7 +426,6 @@
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"sorl-thumbnail": {
@@ -443,7 +433,6 @@
"sha256:c56cd651feab3bdc415d5301600198e2e70c08234dad48b8f6cfa4746cc102c7",
"sha256:fbe6dfd66a1aceb7e0203895ff5622775e50266f8d8cfd841fe1500bd3e19018"
],
- "markers": "python_version >= '3.4'",
"version": "==12.7.0"
},
"sqlparse": {
@@ -451,16 +440,15 @@
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
],
- "markers": "python_version >= '3.5'",
"version": "==0.4.1"
},
"urllib3": {
"hashes": [
- "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08",
- "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"
+ "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80",
+ "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
- "version": "==1.26.2"
+ "index": "pypi",
+ "version": "==1.26.3"
},
"webencodings": {
"hashes": [
@@ -499,7 +487,6 @@
"sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
"sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.3.0"
},
"bandit": {
@@ -521,7 +508,6 @@
"sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d",
"sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1"
],
- "markers": "python_full_version >= '3.6.1'",
"version": "==3.2.0"
},
"chardet": {
@@ -529,7 +515,6 @@
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"coverage": {
@@ -697,31 +682,27 @@
"sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac",
"sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"
],
- "markers": "python_version >= '3.4'",
"version": "==4.0.5"
},
"gitpython": {
"hashes": [
- "sha256:6eea89b655917b500437e9668e4a12eabdcf00229a0df1762aabd692ef9b746b",
- "sha256:befa4d101f91bad1b632df4308ec64555db684c360bd7d2130b4807d49ce86b8"
+ "sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b",
+ "sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"
],
- "markers": "python_version >= '3.4'",
- "version": "==3.1.11"
+ "version": "==3.1.14"
},
"identify": {
"hashes": [
- "sha256:943cd299ac7f5715fcb3f684e2fc1594c1e0f22a90d15398e5888143bd4144b5",
- "sha256:cc86e6a9a390879dcc2976cef169dd9cc48843ed70b7380f321d1b118163c60e"
+ "sha256:99d40094d8c9fc0b88b379200ecb4f8345a593878656867fa5363abc850766ab",
+ "sha256:f516f69e62df018a3965a835dccfb3397ed02ddaf513584633c9acaf084be3f2"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.5.10"
+ "version": "==2.1.4"
},
"idna": {
"hashes": [
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"mccabe": {
@@ -744,7 +725,6 @@
"sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9",
"sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"
],
- "markers": "python_version >= '2.6'",
"version": "==5.5.1"
},
"pep8-naming": {
@@ -768,23 +748,20 @@
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.6.0"
},
"pydocstyle": {
"hashes": [
- "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325",
- "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"
+ "sha256:164befb520d851dbcf0e029681b91f4f599c62c5cd8933fd54b1bfbd50e89e1f",
+ "sha256:d4449cf16d7e6709f63192146706933c7a334af7c0f083904799ccb851c50f6d"
],
- "markers": "python_version >= '3.5'",
- "version": "==5.1.1"
+ "version": "==6.0.0"
},
"pyflakes": {
"hashes": [
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.2.0"
},
"pyyaml": {
@@ -819,30 +796,27 @@
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"smmap": {
"hashes": [
- "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4",
- "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"
+ "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714",
+ "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==3.0.4"
+ "version": "==3.0.5"
},
"snowballstemmer": {
"hashes": [
- "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
- "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
+ "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2",
+ "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"
],
- "version": "==2.0.0"
+ "version": "==2.1.0"
},
"stevedore": {
"hashes": [
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
],
- "markers": "python_version >= '3.6'",
"version": "==3.3.0"
},
"toml": {
@@ -850,24 +824,22 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"urllib3": {
"hashes": [
- "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08",
- "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"
+ "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80",
+ "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
- "version": "==1.26.2"
+ "index": "pypi",
+ "version": "==1.26.3"
},
"virtualenv": {
"hashes": [
- "sha256:54b05fc737ea9c9ee9f8340f579e5da5b09fb64fd010ab5757eb90268616907c",
- "sha256:b7a8ec323ee02fb2312f098b6b4c9de99559b462775bc8fe3627a73706603c1b"
+ "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107",
+ "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==20.2.2"
+ "version": "==20.4.3"
}
}
}
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..fa5a88a3
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,3 @@
+# Security Notice
+
+The Security Notice for Python Discord projects can be found [on our website](https://pydis.com/security.md).
diff --git a/manage.py b/manage.py
index fb5ee40c..71af23c4 100755
--- a/manage.py
+++ b/manage.py
@@ -7,7 +7,6 @@ import time
from typing import List
import django
-import gunicorn.app.wsgiapp
from django.contrib.auth import get_user_model
from django.core.management import call_command, execute_from_command_line
@@ -156,6 +155,9 @@ class SiteManager:
call_command("runserver", "0.0.0.0:8000")
return
+ # Import gunicorn only if we aren't in debug mode.
+ import gunicorn.app.wsgiapp
+
# Patch the arguments for gunicorn
sys.argv = [
"gunicorn",
diff --git a/postgres/init.sql b/postgres/init.sql
index 740063e7..190a705c 100644
--- a/postgres/init.sql
+++ b/postgres/init.sql
@@ -13,12 +13,63 @@ INSERT INTO users VALUES (
current_timestamp
);
+INSERT INTO users VALUES (
+ 1,
+ current_timestamp
+);
+
+CREATE TABLE channels (
+ id varchar,
+ name varchar,
+ primary key(id)
+);
+
+INSERT INTO channels VALUES(
+ '267659945086812160',
+ 'python-general'
+);
+
+INSERT INTO channels VALUES(
+ '11',
+ 'help-apple'
+);
+
+INSERT INTO channels VALUES(
+ '12',
+ 'help-cherry'
+);
+
+INSERT INTO channels VALUES(
+ '21',
+ 'ot0-hello'
+);
+
+INSERT INTO channels VALUES(
+ '22',
+ 'ot1-world'
+);
+
+INSERT INTO channels VALUES(
+ '31',
+ 'voice-chat-0'
+);
+
+INSERT INTO channels VALUES(
+ '32',
+ 'code-help-voice-0'
+);
+
+INSERT INTO channels VALUES(
+ '1234',
+ 'zebra'
+);
+
CREATE TABLE messages (
id varchar,
author_id varchar references users(id),
is_deleted boolean,
created_at timestamp,
- channel_id varchar,
+ channel_id varchar references channels(id),
primary key(id)
);
@@ -37,3 +88,59 @@ INSERT INTO messages VALUES(
now() + INTERVAL '10 minutes,',
'1234'
);
+
+INSERT INTO messages VALUES(
+ 2,
+ 0,
+ false,
+ now(),
+ '11'
+);
+
+INSERT INTO messages VALUES(
+ 3,
+ 0,
+ false,
+ now(),
+ '12'
+);
+
+INSERT INTO messages VALUES(
+ 4,
+ 1,
+ false,
+ now(),
+ '21'
+);
+
+INSERT INTO messages VALUES(
+ 5,
+ 1,
+ false,
+ now(),
+ '22'
+);
+
+INSERT INTO messages VALUES(
+ 6,
+ 1,
+ false,
+ now(),
+ '31'
+);
+
+INSERT INTO messages VALUES(
+ 7,
+ 1,
+ false,
+ now(),
+ '32'
+);
+
+INSERT INTO messages VALUES(
+ 8,
+ 1,
+ true,
+ now(),
+ '32'
+);
diff --git a/pydis_site/apps/api/models/bot/metricity.py b/pydis_site/apps/api/models/bot/metricity.py
index cae630f1..5daa5c66 100644
--- a/pydis_site/apps/api/models/bot/metricity.py
+++ b/pydis_site/apps/api/models/bot/metricity.py
@@ -1,3 +1,5 @@
+from typing import List, Tuple
+
from django.db import connections
BLOCK_INTERVAL = 10 * 60 # 10 minute blocks
@@ -89,3 +91,42 @@ class Metricity:
raise NotFound()
return values[0]
+
+ def top_channel_activity(self, user_id: str) -> List[Tuple[str, int]]:
+ """
+ Query the top three channels in which the user is most active.
+
+ Help channels are grouped under "the help channels",
+ and off-topic channels are grouped under "off-topic".
+ """
+ self.cursor.execute(
+ """
+ SELECT
+ CASE
+ WHEN channels.name ILIKE 'help-%%' THEN 'the help channels'
+ WHEN channels.name ILIKE 'ot%%' THEN 'off-topic'
+ WHEN channels.name ILIKE '%%voice%%' THEN 'voice chats'
+ ELSE channels.name
+ END,
+ COUNT(1)
+ FROM
+ messages
+ LEFT JOIN channels ON channels.id = messages.channel_id
+ WHERE
+ author_id = '%s' AND NOT messages.is_deleted
+ GROUP BY
+ 1
+ ORDER BY
+ 2 DESC
+ LIMIT
+ 3;
+ """,
+ [user_id]
+ )
+
+ values = self.cursor.fetchall()
+
+ if not values:
+ raise NotFound()
+
+ return values
diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py
index 69bbfefc..c43b916a 100644
--- a/pydis_site/apps/api/tests/test_users.py
+++ b/pydis_site/apps/api/tests/test_users.py
@@ -410,7 +410,7 @@ class UserMetricityTests(APISubdomainTestCase):
joined_at = "foo"
total_messages = 1
total_blocks = 1
- self.mock_metricity_user(joined_at, total_messages, total_blocks)
+ self.mock_metricity_user(joined_at, total_messages, total_blocks, [])
# When
url = reverse('bot:user-metricity-data', args=[0], host='api')
@@ -436,13 +436,24 @@ class UserMetricityTests(APISubdomainTestCase):
# Then
self.assertEqual(response.status_code, 404)
+ def test_no_metricity_user_for_review(self):
+ # Given
+ self.mock_no_metricity_user()
+
+ # When
+ url = reverse('bot:user-metricity-review-data', args=[0], host='api')
+ response = self.client.get(url)
+
+ # Then
+ self.assertEqual(response.status_code, 404)
+
def test_metricity_voice_banned(self):
cases = [
{'exception': None, 'voice_banned': True},
{'exception': ObjectDoesNotExist, 'voice_banned': False},
]
- self.mock_metricity_user("foo", 1, 1)
+ self.mock_metricity_user("foo", 1, 1, [["bar", 1]])
for case in cases:
with self.subTest(exception=case['exception'], voice_banned=case['voice_banned']):
@@ -455,7 +466,27 @@ class UserMetricityTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["voice_banned"], case["voice_banned"])
- def mock_metricity_user(self, joined_at, total_messages, total_blocks):
+ def test_metricity_review_data(self):
+ # Given
+ joined_at = "foo"
+ total_messages = 10
+ total_blocks = 1
+ channel_activity = [["bar", 4], ["buzz", 6]]
+ self.mock_metricity_user(joined_at, total_messages, total_blocks, channel_activity)
+
+ # When
+ url = reverse('bot:user-metricity-review-data', args=[0], host='api')
+ response = self.client.get(url)
+
+ # Then
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.json(), {
+ "joined_at": joined_at,
+ "top_channel_activity": channel_activity,
+ "total_messages": total_messages
+ })
+
+ def mock_metricity_user(self, joined_at, total_messages, total_blocks, top_channel_activity):
patcher = patch("pydis_site.apps.api.viewsets.bot.user.Metricity")
self.metricity = patcher.start()
self.addCleanup(patcher.stop)
@@ -463,6 +494,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.metricity.user.return_value = dict(joined_at=joined_at)
self.metricity.total_messages.return_value = total_messages
self.metricity.total_message_blocks.return_value = total_blocks
+ self.metricity.top_channel_activity.return_value = top_channel_activity
def mock_no_metricity_user(self):
patcher = patch("pydis_site.apps.api.viewsets.bot.user.Metricity")
@@ -472,3 +504,4 @@ class UserMetricityTests(APISubdomainTestCase):
self.metricity.user.side_effect = NotFound()
self.metricity.total_messages.side_effect = NotFound()
self.metricity.total_message_blocks.side_effect = NotFound()
+ self.metricity.top_channel_activity.side_effect = NotFound()
diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py
index 829e2694..25722f5a 100644
--- a/pydis_site/apps/api/viewsets/bot/user.py
+++ b/pydis_site/apps/api/viewsets/bot/user.py
@@ -119,6 +119,22 @@ class UserViewSet(ModelViewSet):
- 200: returned on success
- 404: if a user with the given `snowflake` could not be found
+ ### GET /bot/users/<snowflake:int>/metricity_review_data
+ Gets metricity data for a single user's review by ID.
+
+ #### Response format
+ >>> {
+ ... 'joined_at': '2020-08-26T08:09:43.507000',
+ ... 'top_channel_activity': [['off-topic', 15],
+ ... ['talent-pool', 4],
+ ... ['defcon', 2]],
+ ... 'total_messages': 22
+ ... }
+
+ #### Status codes
+ - 200: returned on success
+ - 404: if a user with the given `snowflake` could not be found
+
### POST /bot/users
Adds a single or multiple new users.
The roles attached to the user(s) must be roles known by the site.
@@ -262,3 +278,18 @@ class UserViewSet(ModelViewSet):
except NotFound:
return Response(dict(detail="User not found in metricity"),
status=status.HTTP_404_NOT_FOUND)
+
+ @action(detail=True)
+ def metricity_review_data(self, request: Request, pk: str = None) -> Response:
+ """Request handler for metricity_review_data endpoint."""
+ user = self.get_object()
+
+ with Metricity() as metricity:
+ try:
+ data = metricity.user(user.id)
+ data["total_messages"] = metricity.total_messages(user.id)
+ data["top_channel_activity"] = metricity.top_channel_activity(user.id)
+ return Response(data, status=status.HTTP_200_OK)
+ except NotFound:
+ return Response(dict(detail="User not found in metricity"),
+ status=status.HTTP_404_NOT_FOUND)
diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css
index 58ca8888..ee6f6e4c 100644
--- a/pydis_site/static/css/home/index.css
+++ b/pydis_site/static/css/home/index.css
@@ -45,6 +45,10 @@ h1 {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
+#wave-hero-centered {
+ margin: auto auto;
+}
+
#wave-hero-right img{
border-radius: 10px;
box-shadow: 0 1px 6px rgba(0,0,0,0.16), 0 1px 6px rgba(0,0,0,0.23);
@@ -206,9 +210,17 @@ h1 {
#sponsors .hero-body {
padding-top: 2rem;
padding-bottom: 3rem;
+
+ text-align: center;
+}
+
+#sponsors .columns {
+ justify-content: center;
+ margin: auto;
+ max-width: 80%;
}
#sponsors img {
height: 5rem;
- margin-right: 2rem;
+ margin: auto 1rem;
}
diff --git a/pydis_site/static/images/sponsors/streamyard.png b/pydis_site/static/images/sponsors/streamyard.png
new file mode 100644
index 00000000..a1527e8d
--- /dev/null
+++ b/pydis_site/static/images/sponsors/streamyard.png
Binary files differ
diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html
index 04815b7f..67f29e41 100644
--- a/pydis_site/templates/home/index.html
+++ b/pydis_site/templates/home/index.html
@@ -29,7 +29,7 @@
<div class="columns is-variable is-8">
{# Embedded Welcome video #}
- <div id="wave-hero-left" class="column is-half">
+ <div id="wave-hero-centered" class="column is-half">
<div class="force-aspect-container">
<iframe
class="force-aspect-content"
@@ -50,12 +50,6 @@
></iframe>
</div>
</div>
-
- {# Right side content #}
- <div id="wave-hero-right" class="column is-half">
- <img src="{% static "images/events/100k.png" %}" alt="100K members!">
- </div>
-
</div>
</div>
@@ -98,7 +92,7 @@
<section id="showcase" class="column is-half-desktop has-text-centered">
<article class="box">
- <header class="title">New Timeline!</header>
+ <header class="title">Interactive timeline</header>
<div class="mini-timeline">
<i class="fa fa-asterisk"></i>
@@ -110,7 +104,7 @@
</div>
<p class="subtitle">
- Start from our humble beginnings to discover the events that made our community what it is today.
+ Discover the history of our community, and learn about the events that made our community what it is today.
</p>
<div class="buttons are-large is-centered">
@@ -204,6 +198,9 @@
<a href="https://notion.so" class="column is-narrow">
<img src="{% static "images/sponsors/notion.png" %}" alt="Notion"/>
</a>
+ <a href="https://streamyard.com" class="column is-narrow">
+ <img src="{% static "images/sponsors/streamyard.png" %}" alt="StreamYard"/>
+ </a>
</div>
</div>
</div>
diff --git a/pydis_site/templates/home/timeline.html b/pydis_site/templates/home/timeline.html
index ece2e4e5..d9069aca 100644
--- a/pydis_site/templates/home/timeline.html
+++ b/pydis_site/templates/home/timeline.html
@@ -3,53 +3,53 @@
{% block title %}Timeline{% endblock %}
{% block head %}
-<link rel="stylesheet" href="{% static "css/home/timeline.css" %}">
-<link rel="stylesheet" href="{% static "css/home/index.css" %}">
+ <link rel="stylesheet" href="{% static "css/home/timeline.css" %}">
+ <link rel="stylesheet" href="{% static "css/home/index.css" %}">
{% endblock %}
{% block content %}
-{% include "base/navbar.html" %}
+ {% include "base/navbar.html" %}
-<section class="cd-timeline js-cd-timeline">
+ <section class="cd-timeline js-cd-timeline">
<div class="container max-width-lg cd-timeline__container">
- <div class="cd-timeline__block">
- <div class="cd-timeline__img cd-timeline__img--picture">
- <img src="{% static "images/timeline/cd-icon-picture.svg" %}" alt="Picture">
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img cd-timeline__img--picture">
+ <img src="{% static "images/timeline/cd-icon-picture.svg" %}" alt="Picture">
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord is created</h2>
- <p class="color-contrast-medium"><strong>joe</strong> becomes one of the owners around 3 days after it
- is created, and <strong>lemon</strong> joins the owner team later in the year, when the community
- has around 300 members.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord is created</h2>
+ <p class="color-contrast-medium"><strong>Joe Banks</strong> becomes one of the owners around 3 days after it
+ is created, and <strong>Leon Sandøy</strong> (lemon) joins the owner team later in the year, when the community
+ has around 300 members.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jan 8th, 2017</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jan 8th, 2017</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord hits 1,000 members</h2>
- <p class="color-contrast-medium">Our main source of new users at this point is a post on Reddit that
- happens to get very good SEO. We are one of the top 10 search engine hits for the search term
- "python discord".</p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord hits 1,000 members</h2>
+ <p class="color-contrast-medium">Our main source of new users at this point is a post on Reddit that
+ happens to get very good SEO. We are one of the top 10 search engine hits for the search term
+ "python discord".</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Nov 10th, 2017</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Nov 10th, 2017</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img cd-timeline__img--picture">
- <img src={% static "images/timeline/cd-icon-picture.svg" %} alt="Picture">
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img cd-timeline__img--picture">
+ <img src={% static "images/timeline/cd-icon-picture.svg" %} alt="Picture">
+ </div>
<div class="cd-timeline__content text-component">
<h2>Our logo is born. Thanks @Aperture!</h2>
@@ -57,464 +57,637 @@
src="https://raw.githubusercontent.com/python-discord/branding/main/logos/logo_banner/logo_site_banner.svg">
</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Feb 3rd, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Feb 3rd, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis hits 2,000 members; pythondiscord.com and @Python are live</h2>
- <p class="color-contrast-medium">The public moderation bot we're using at the time, Rowboat, announces
- it will be shutting down. We decide that we'll write our own bot to handle moderation, so that we
- can have more control over its features. We also buy a domain and start making a website in Flask.
- </p>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis hits 2,000 members; pythondiscord.com and @Python are live</h2>
+ <p class="color-contrast-medium">The public moderation bot we're using at the time, Rowboat, announces
+ it will be shutting down. We decide that we'll write our own bot to handle moderation, so that we
+ can have more control over its features. We also buy a domain and start making a website in Flask.
+ </p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Mar 4th, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 4th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
- <i class="fa fa-dice"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
+ <i class="fa fa-dice"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>First code jam with the theme “snakes”</h2>
- <p class="color-contrast-medium">Our very first Code Jam attracts a handful of users who work in random
- teams of 2. We ask our participants to write a snake-themed Discord bot. Most of the code written
- for this jam still lives on in SeasonalBot, and you can play with it by using the
- <code>.snakes</code> command. For more information on this event, see <a
- href="https://pythondiscord.com/pages/code-jams/code-jam-1-snakes-bot/">the event page</a></p>
+ <div class="cd-timeline__content text-component">
+ <h2>First code jam with the theme “snakes”</h2>
+ <p class="color-contrast-medium">Our very first Code Jam attracts a handful of users who work in random
+ teams of 2. We ask our participants to write a snake-themed Discord bot. Most of the code written
+ for this jam still lives on in Sir Lancebot, and you can play with it by using the
+ <code>.snakes</code> command. For more information on this event, see <a
+ href="https://pythondiscord.com/pages/code-jams/code-jam-1-snakes-bot/">the event page</a></p>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 23rd, 2018</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Mar 23rd, 2018</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-lime cd-timeline__img--picture">
+ <i class="fa fa-scroll"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-lime cd-timeline__img--picture">
- <i class="fa fa-scroll"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>The privacy policy is created</h2>
+ <p class="color-contrast-medium">Since data privacy is quite important to us, we create a privacy page
+ pretty much as soon as our new bot and site starts collecting some data. To this day, we keep <a
+ href="https://pythondiscord.com/pages/privacy/">our privacy policy</a> up to date with all
+ changes, and since April 2020 we've started doing <a
+ href="https://pythondiscord.com/pages/data-reviews/">monthly data reviews</a>.</p>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">May 21st, 2018</span>
+ </div>
+ </div>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>The privacy policy is created</h2>
- <p class="color-contrast-medium">Since data privacy is quite important to us, we create a privacy page
- pretty much as soon as our new bot and site starts collecting some data. To this day, we keep <a
- href="https://pythondiscord.com/pages/privacy/">our privacy policy</a> up to date with all
- changes, and since April 2020 we've started doing <a
- href="https://pythondiscord.com/pages/data-reviews/">monthly data reviews</a>.</p>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
+ <i class="fa fa-handshake"></i>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">May 21st, 2018</span>
- </div>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>Do You Even Python and PyDis merger</h2>
+ <p class="color-contrast-medium">At this point in time, there are only two serious Python communities on
+ Discord - Ours, and one called Do You Even Python. We approach the owners of DYEP with a bold
+ proposal - let's shut down their community, replace it with links to ours, and in return we will let
+ their staff join our staff. This gives us a big boost in members, and eventually leads to @eivl and
+ @Mr. Hemlock joining our Admin team</p>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jun 9th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
- <i class="fa fa-handshake"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Do You Even Python and PyDis merger</h2>
- <p class="color-contrast-medium">At this point in time, there are only two serious Python communities on
- Discord - Ours, and one called Do You Even Python. We approach the owners of DYEP with a bold
- proposal - let's shut down their community, replace it with links to ours, and in return we will let
- their staff join our staff. This gives us a big boost in members, and eventually leads to @eivl and
- @Mr. Hemlock joining our Admin team</p>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis hits 5,000 members and partners with r/Python</h2>
+ <p class="color-contrast-medium">As we continue to grow, we approach the r/Python subreddit and ask to
+ become their official Discord community. They agree, and we become listed in their sidebar, giving
+ us yet another source of new members.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jun 9th, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jun 20th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
+ <i class="fa fa-handshake"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis hits 5,000 members and partners with r/Python</h2>
- <p class="color-contrast-medium">As we continue to grow, we approach the r/Python subreddit and ask to
- become their official Discord community. They agree, and we become listed in their sidebar, giving
- us yet another source of new members.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis is now partnered with Discord; the vanity URL discord.gg/python is created</h2>
+ <p class="color-contrast-medium">After being rejected for their Partner program several times, we
+ finally get approved. The recent partnership with the r/Python subreddit plays a significant role in
+ qualifying us for this partnership.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jun 20th, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jul 10th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
- <i class="fa fa-handshake"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
+ <i class="fa fa-dice"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis is now partnered with Discord; the vanity URL discord.gg/python is created</h2>
- <p class="color-contrast-medium">After being rejected for their Partner program several times, we
- finally get approved. The recent partnership with the r/Python subreddit plays a significant role in
- qualifying us for this partnership.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>First Hacktoberfest PyDis event; @Sir Lancebot is created</h2>
+ <p class="color-contrast-medium">We create a second bot for our community and fill it up with simple,
+ fun and relatively easy issues. The idea is to create an approachable arena for our members to cut
+ their open-source teeth on, and to provide lots of help and hand-holding for those who get stuck.
+ We're training our members to be productive contributors in the open-source ecosystem.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jul 10th, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Oct 1st, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
- <i class="fa fa-dice"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>First Hacktoberfest PyDis event; @SeasonalBot is created</h2>
- <p class="color-contrast-medium">We create a second bot for our community and fill it up with simple,
- fun and relatively easy issues. The idea is to create an approachable arena for our members to cut
- their open-source teeth on, and to provide lots of help and hand-holding for those who get stuck.
- We're training our members to be productive contributors in the open-source ecosystem.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis hits 10,000 members</h2>
+ <p class="color-contrast-medium">We partner with RLBot, move from GitLab to GitHub, and start putting
+ together the first Advent of Code event.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Oct 1st, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Nov 24th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-orange cd-timeline__img--picture">
+ <i class="fa fa-code"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis hits 10,000 members</h2>
- <p class="color-contrast-medium">We partner with RLBot, move from GitLab to GitHub, and start putting
- together the first Advent of Code event.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>django-simple-bulma is released on PyPi</h2>
+ <p class="color-contrast-medium">Our very first package on PyPI, <a
+ href="https://pypi.org/project/django-simple-bulma/">django-simple-bulma</a> is a package that
+ sets up the Bulma CSS framework for your Django application and lets you configure everything in
+ settings.py.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Nov 24th, 2018</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Dec 19th, 2018</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-orange cd-timeline__img--picture">
- <i class="fa fa-code"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>django-simple-bulma is released on PyPi</h2>
- <p class="color-contrast-medium">Our very first package on PyPI, <a
- href="https://pypi.org/project/django-simple-bulma/">django-simple-bulma</a> is a package that
- sets up the Bulma CSS framework for your Django application and lets you configure everything in
- settings.py.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis hits 15,000 members; the “hot ones special” video is released</h2>
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/DIBXg8Qh7bA" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Apr 8th, 2019</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Dec 19th, 2018</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-orange cd-timeline__img--picture">
+ <i class="fa fa-code"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>The Django rewrite of pythondiscord.com is now live!</h2>
+ <p class="color-contrast-medium">The site is getting more and more complex, and it's time for a rewrite.
+ We decide to go for a different stack, and build a website based on Django, DRF, Bulma and
+ PostgreSQL.</p>
- <div class="cd-timeline__content text-component">
- <h2>PyDis hits 15,000 members; the “hot ones special” video is released</h2>
- <div class="force-aspect-container">
- <iframe class="force-aspect-content" src="https://www.youtube.com/embed/DIBXg8Qh7bA" frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Sep 15, 2019</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Apr 8th, 2019</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-lime cd-timeline__img--picture">
+ <i class="fa fa-scroll"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-orange cd-timeline__img--picture">
- <i class="fa fa-code"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>The code of conduct is created</h2>
+ <p class="color-contrast-medium">Inspired by the Adafruit, Rust and Django communities, an essential
+ community pillar is created; Our <a href="https://pythondiscord.com/pages/code-of-conduct/">Code of
+ Conduct.</a></p>
- <div class="cd-timeline__content text-component">
- <h2>The Django rewrite of pythondiscord.com is now live!</h2>
- <p class="color-contrast-medium">The site is getting more and more complex, and it's time for a rewrite.
- We decide to go for a different stack, and build a website based on Django, DRF, Bulma and
- PostgreSQL.</p>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Oct 26th, 2019</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Sep 15, 2019</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img cd-timeline__img--picture">
+ <img src={% static "images/timeline/cd-icon-picture.svg" %} alt="Picture">
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-lime cd-timeline__img--picture">
- <i class="fa fa-scroll"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>Sebastiaan Zeef becomes an owner</h2>
+ <p class="color-contrast-medium">After being a long time active contributor to our projects and the driving
+ force behind many of our events, Sebastiaan Zeef joins the Owners Team alongside Joe & Leon.</p>
- <div class="cd-timeline__content text-component">
- <h2>The code of conduct is created</h2>
- <p class="color-contrast-medium">Inspired by the Adafruit, Rust and Django communities, an essential
- community pillar is created; Our <a href="https://pythondiscord.com/pages/code-of-conduct/">Code of
- Conduct.</a></p>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Sept 22nd, 2019</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Oct 26th, 2019</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img cd-timeline__img--picture">
- <img src={% static "images/timeline/cd-icon-picture.svg" %} alt="Picture">
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis hits 30,000 members</h2>
+ <p class="color-contrast-medium">More than tripling in size since the year before, the community hits
+ 30000 users. At this point, we're probably the largest Python chat community on the planet.</p>
- <div class="cd-timeline__content text-component">
- <h2>Ves Zappa becomes an owner</h2>
- <p class="color-contrast-medium">After being a long time active contributor to our projects and the driving force behind our events, Ves Zappa joined the Owners team alongside joe & lemon.</p>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Dec 22nd, 2019</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Sept 22nd, 2019</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
+ <i class="fa fa-dice"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis sixth code jam with the theme “Ancient technology” and the technology Kivy</h2>
+ <p class="color-contrast-medium">Our Code Jams are becoming an increasingly big deal, and the Kivy core
+ developers join us to judge the event and help out our members during the event. One of them,
+ @tshirtman, even joins our staff!</p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/8fbZsGrqBzo" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jan 17, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis hits 30,000 members</h2>
- <p class="color-contrast-medium">More than tripling in size since the year before, the community hits
- 30000 users. At this point, we're probably the largest Python chat community on the planet.</p>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-green cd-timeline__img--picture">
+ <i class="fa fa-comments"></i>
+ </div>
+
+ <div class="cd-timeline__content text-component">
+ <h2>The new help channel system is live</h2>
+ <p class="color-contrast-medium">We release our dynamic help-channel system, which allows you to claim
+ your very own help channel instead of fighting over the static help channels. We release a <a
+ href="https://pythondiscord.com/pages/resources/guides/help-channels/">Help Channel Guide</a> to
+ help our members fully understand how the system works.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Dec 22nd, 2019</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Apr 5th, 2020</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
- <i class="fa fa-dice"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis sixth code jam with the theme “Ancient technology” and the technology Kivy</h2>
- <p class="color-contrast-medium">Our Code Jams are becoming an increasingly big deal, and the Kivy core
- developers join us to judge the event and help out our members during the event. One of them,
- @tshirtman, even joins our staff!</p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord hits 40,000 members, and is now bigger than Liechtenstein.</h2>
+ <p class="color-contrast-medium"><img
+ src="https://cdn.discordapp.com/attachments/354619224620138496/699666518476324954/unknown.png">
+ </p>
- <div class="force-aspect-container">
- <iframe class="force-aspect-content" src="https://www.youtube.com/embed/8fbZsGrqBzo" frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Apr 14, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jan 17, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-purple cd-timeline__img--picture">
+ <i class="fa fa-gamepad"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-green cd-timeline__img--picture">
- <i class="fa fa-comments"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis Game Jam 2020 with the “Three of a Kind” theme and Arcade as the technology</h2>
+ <p class="color-contrast-medium">The creator of Arcade, Paul Vincent Craven, joins us as a judge.
+ Several of the Code Jam participants also end up getting involved contributing to the Arcade
+ repository.</p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/KkLXMvKfEgs" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Apr 17th, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>The new help channel system is live</h2>
- <p class="color-contrast-medium">We release our dynamic help-channel system, which allows you to claim
- your very own help channel instead of fighting over the static help channels. We release a <a
- href="https://pythondiscord.com/pages/resources/guides/help-channels/">Help Channel Guide</a> to
- help our members fully understand how the system works.</p>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-green cd-timeline__img--picture">
+ <i class="fa fa-comments"></i>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Apr 5th, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>ModMail is now live</h2>
+ <p class="color-contrast-medium">Having originally planned to write our own ModMail bot from scratch, we
+ come across an exceptionally good <a href="https://github.com/kyb3r/modmail">ModMail bot by
+ kyb3r</a> and decide to just self-host that one instead.</p>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">May 25th, 2020</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
+ <i class="fa fa-handshake"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord hits 40,000 members, and is now bigger than Liechtenstein.</h2>
- <p class="color-contrast-medium"><img
- src="https://cdn.discordapp.com/attachments/354619224620138496/699666518476324954/unknown.png">
- </p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord is now listed on python.org/community</h2>
+ <p class="color-contrast-medium">After working towards this goal for months, we finally work out an
+ arrangement with the PSF that allows us to be listed on that most holiest of websites:
+ https://python.org/. <a href="https://youtu.be/yciX2meIkXI?t=3">There was much rejoicing.</a></p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Apr 14, 2020</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">May 28th, 2020</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-purple cd-timeline__img--picture">
- <i class="fa fa-gamepad"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-red cd-timeline__img--picture">
+ <i class="fa fa-chart-bar"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>PyDis Game Jam 2020 with the “Three of a Kind” theme and Arcade as the technology</h2>
- <p class="color-contrast-medium">The creator of Arcade, Paul Vincent Craven, joins us as a judge.
- Several of the Code Jam participants also end up getting involved contributing to the Arcade
- repository.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord Public Statistics are now live</h2>
+ <p class="color-contrast-medium">After getting numerous requests to publish beautiful data on member
+ count and channel use, we create <a href="https://stats.pythondiscord.com/">stats.pythondiscord.com</a> for
+ all to enjoy.</p>
- <div class="force-aspect-container">
- <iframe class="force-aspect-content" src="https://www.youtube.com/embed/KkLXMvKfEgs" frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jun 4th, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Apr 17th, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
+ <i class="fa fa-dice"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-green cd-timeline__img--picture">
- <i class="fa fa-comments"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>PyDis summer code jam 2020 with the theme “Early Internet” and Django as the technology</h2>
+ <p class="color-contrast-medium">Sponsored by the Django Software Foundation and JetBrains, the Summer
+ Code Jam for 2020 attracts hundreds of participants, and sees the creation of some fantastic
+ projects. Check them out in our judge stream below:</p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/OFtm8f2iu6c" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Jul 31st, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>ModMail is now live</h2>
- <p class="color-contrast-medium">Having originally planned to write our own ModMail bot from scratch, we
- come across an exceptionally good <a href="https://github.com/kyb3r/modmail">ModMail bot by
- kyb3r</a> and decide to just self-host that one instead.</p>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
+ <i class="fa fa-handshake"></i>
+ </div>
+
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord is now the new home of the PyWeek event!</h2>
+ <p class="color-contrast-medium">PyWeek, a game jam that has been running since 2005, joins Python
+ Discord as one of our official events. Find more information about PyWeek on <a
+ href="https://pyweek.org/">their official website</a>.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">May 25th, 2020</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Aug 16th, 2020</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
- <i class="fa fa-handshake"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img cd-timeline__img--picture">
+ <img src="{% static "images/timeline/cd-icon-picture.svg" %}" alt="Picture">
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord is now listed on python.org/community</h2>
- <p class="color-contrast-medium">After working towards this goal for months, we finally work out an
- arrangement with the PSF that allows us to be listed on that most holiest of websites:
- https://python.org/. <a href="https://youtu.be/yciX2meIkXI?t=3">There was much rejoicing.</a></p>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord hosts the 2020 CPython Core Developer Q&A</h2>
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/gXMdfBTcOfQ" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Oct 21st, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">May 28th, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-red cd-timeline__img--picture">
- <i class="fa fa-chart-bar"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>Python Discord hits 100,000 members!</h2>
+ <p class="color-contrast-medium">Only six months after hitting 40,000 users, we hit 100,000 users. A
+ monumental milestone,
+ and one we're very proud of. To commemorate it, we create this timeline.</p>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord Public Statistics are now live</h2>
- <p class="color-contrast-medium">After getting numerous requests to publish beautiful data on member
- count and channel use, we create <a href="https://stats.pythondiscord.com/">stats.pythondiscord.com</a> for all to enjoy.</p>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Oct 22nd, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jun 4th, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-orange cd-timeline__img--picture">
+ <i class="fa fa-wrench"></i>
</div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
- <i class="fa fa-dice"></i>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>We migrate all our infrastructure to Kubernetes</h2>
+ <p class="color-contrast-medium">As our tech stack grows, we decide to migrate all our services over to a
+ container orchestration paradigm via Kubernetes. This gives us better control and scalability.
+ <b>Joe Banks</b> takes on the role as DevOps Lead.
+ </p>
- <div class="cd-timeline__content text-component">
- <h2>PyDis summer code jam 2020 with the theme “Early Internet” and Django as the technology</h2>
- <p class="color-contrast-medium">Sponsored by the Django Software Foundation and JetBrains, the Summer
- Code Jam for 2020 attracts hundreds of participants, and sees the creation of some fantastic
- projects. Check them out in our judge stream below:</p>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Nov 29th, 2020</span>
+ </div>
+ </div>
+ </div>
- <div class="force-aspect-container">
- <iframe class="force-aspect-content" src="https://www.youtube.com/embed/OFtm8f2iu6c" frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-red cd-timeline__img--picture">
+ <i class="fa fa-snowflake-o"></i>
+ </div>
+
+ <div class="cd-timeline__content text-component">
+ <h2>Advent of Code attracts hundreds of participants</h2>
+ <p class="color-contrast-medium">
+ A total of 443 Python Discord members sign up to be part of
+ <a href="https://adventofcode.com/">Eric Wastl's excellent Advent of Code event</a>.
+ As always, we provide dedicated announcements, scoreboards, bot commands and channels for our members
+ to enjoy the event in.
+
+ </p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Jul 31st, 2020</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">December 1st - 25th, 2020</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
- <i class="fa fa-handshake"></i>
- </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord is now the new home of the PyWeek event!</h2>
- <p class="color-contrast-medium">PyWeek, a game jam that has been running since 2005, joins Python
- Discord as one of our official events. Find more information about PyWeek on <a
- href="https://pyweek.org/">their official website</a>.</p>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-blue cd-timeline__img--picture">
+ <i class="fa fa-music"></i>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Aug 16th, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>We release The PEP 8 song</h2>
+ <p class="color-contrast-medium">We release the PEP 8 song on our YouTube channel, which finds tens of
+ thousands of listeners!</p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/hgI0p1zf31k" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">February 8th, 2021</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img cd-timeline__img--picture">
- <img src="{% static "images/timeline/cd-icon-picture.svg" %}" alt="Picture">
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
+ <i class="fa fa-users"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord hosts the 2020 CPython Core Developer Q&A</h2>
- <div class="force-aspect-container">
- <iframe class="force-aspect-content" src="https://www.youtube.com/embed/gXMdfBTcOfQ" frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>We now have 150,000 members!</h2>
+ <p class="color-contrast-medium">Our growth continues to accelerate.</p>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Oct 21st, 2020</span>
- </div>
- </div>
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Feb 18th, 2021</span>
+ </div>
</div>
+ </div>
- <div class="cd-timeline__block">
- <div class="cd-timeline__img pastel-dark-blue cd-timeline__img--picture">
- <i class="fa fa-users"></i>
- </div>
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-green cd-timeline__img--picture">
+ <i class="fa fa-microphone"></i>
+ </div>
- <div class="cd-timeline__content text-component">
- <h2>Python Discord hits 100,000 members.</h2>
- <p class="color-contrast-medium">After years of hard work, we hit 100,000 users. A monumental milestone,
- and one we're very proud of. To commemorate it, we create this timeline.</p>
+ <div class="cd-timeline__content text-component">
+ <h2>Leon Sandøy appears on Talk Python To Me</h2>
+ <p class="color-contrast-medium">Leon goes on the Talk Python to Me podcast with Michael Kennedy
+ to discuss the history of Python Discord, the critical importance of culture, and how to run a massive
+ community. You can find the episode <a href="https://talkpython.fm/episodes/show/305/python-community-at-python-discord"> at talkpython.fm</a>.
+ </p>
+
+ <iframe width="100%" height="166" scrolling="no" frameborder="no"
+ src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/996083146&color=ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false">
+ </iframe>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 1st, 2021</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-pink cd-timeline__img--picture">
+ <i class="fa fa-microphone"></i>
+ </div>
- <div class="flex justify-between items-center">
- <span class="cd-timeline__date">Oct 22nd, 2020</span>
- </div>
- </div>
+ <div class="cd-timeline__content text-component">
+ <h2>We're on the Teaching Python podcast!</h2>
+ <p class="color-contrast-medium">Leon joins Sean and Kelly on the Teaching Python podcast to discuss how the pandemic has
+ changed the way we learn, and what role communities like Python Discord can play in this new world.
+ You can find the episode <a href="https://teachingpython.fm/63"> at teachingpython.fm</a>.
+ </p>
+
+ <iframe width="100%" height="166" frameborder="0" scrolling="no"
+ src="https://player.fireside.fm/v2/UIYXtbeL+qOjGAsKi?theme=dark"
+ ></iframe>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 13th, 2021</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-purple cd-timeline__img--picture">
+ <i class="fa fa-comment"></i>
+ </div>
+
+ <div class="cd-timeline__content text-component">
+ <h2>New feature: Weekly discussion channel</h2>
+ <p class="color-contrast-medium">Every week (or two weeks), we'll be posting a new topic to discuss in a
+ channel called <b>#weekly-topic-discussion</b>. Our inaugural topic is a PyCon talk by Anthony Shaw called
+ <b>Wily Python: Writing simpler and more maintainable Python.</b></a>.
+ </p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/dqdsNoApJ80" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 13th, 2021</span>
+ </div>
</div>
+ </div>
+
+ <div class="cd-timeline__block">
+ <div class="cd-timeline__img pastel-red cd-timeline__img--picture">
+ <i class="fa fa-youtube-play"></i>
+ </div>
+
+ <div class="cd-timeline__content text-component">
+ <h2>Summer Code Jam 2020 Highlights</h2>
+ <p class="color-contrast-medium">
+ We release a new video to our YouTube showing the best projects from the Summer Code Jam 2020.
+ Better late than never!
+ </p>
+
+ <div class="force-aspect-container">
+ <iframe class="force-aspect-content" src="https://www.youtube.com/embed/g9cnp4W0P54" frameborder="0"
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+ allowfullscreen></iframe>
+ </div>
+
+ <div class="flex justify-between items-center">
+ <span class="cd-timeline__date">Mar 21st, 2021</span>
+ </div>
+ </div>
+ </div>
+
</div>
-</section>
+ </section>
-<script src="{% static "js/timeline/main.js" %}"></script>
+ <script src="{% static "js/timeline/main.js" %}"></script>
{% endblock %}