diff options
68 files changed, 851 insertions, 146 deletions
diff --git a/.dockerignore b/.dockerignore index 4ad7c8a7..18ea6955 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,10 +17,12 @@ pydis_site/apps/api/tests.py CHANGELOG.md CONTRIBUTING.md docker -!docker/app/migrate_and_boot.sh +!docker/app/scripts/migrate_and_boot.sh +!docker/app/scripts/migrate.sh !docker/app/uwsgi.ini docker-compose.yml Dockerfile +Dockerfile.local docs home/tests home/tests.py @@ -15,6 +15,7 @@ pep8-naming = "~=0.8.2" coverage = "~=4.5.3" unittest-xml-reporting = "~=2.5.1" flake8-docstrings = "~=1.3.0" +pydocstyle = "==3.0.0" [packages] django = "~=2.2" @@ -27,9 +28,11 @@ djangorestframework-bulk = "~=0.2.1" psycopg2-binary = "~=2.8" django-simple-bulma = ">=1.1.7,<2.0" django-crispy-bulma = ">=0.1.2,<2.0" +whitenoise = "==4.1.2" requests = "~=2.21" pygments = "~=2.3.1" wiki = {git = "https://github.com/python-discord/django-wiki.git"} +pyyaml = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index f3e58075..b40b06c1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "de8e753b689c949df77841cf8546c7a1c575d43a460c532faa01642b8773fd23" + "sha256": "2f1eaa80a71489a59f71001ad4af39e8e570f8d7ebca33b475d2c530811ad084" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", - "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" ], - "version": "==2019.3.9" + "version": "==2019.6.16" }, "chardet": { "hashes": [ @@ -32,11 +32,11 @@ }, "django": { "hashes": [ - "sha256:7c3543e4fb070d14e10926189a7fcf42ba919263b7473dceaefce34d54e8a119", - "sha256:a2814bffd1f007805b19194eb0b9a331933b82bd5da1c3ba3d7b7ba16e06dc4b" + "sha256:4d23f61b26892bac785f07401bc38cbf8fa4cec993f400e9cd9ddf28fd51c0ea", + "sha256:6e974d4b57e3b29e4882b244d40171d6a75202ab8d2402b8e8adbd182e25cf0c" ], "index": "pypi", - "version": "==2.2" + "version": "==2.2.3" }, "django-crispy-bulma": { "hashes": [ @@ -80,19 +80,19 @@ }, "django-simple-bulma": { "hashes": [ - "sha256:7dcc04a11b5a3aefb6ec57cb211c161df8421ea333638e03c9e7db87465fead2", - "sha256:f4bb4833c3272ec49e4901a53254de8e8d267da48b88f6f79af4c32f9f70c504" + "sha256:ca2e4dbda5cf2d697cef91701a9fd7e58cecec93a76897158c4d7e135aa13842", + "sha256:f3e4f47680ed6fad11c30ba932ecca95c66690204ee2be4dcd0525c07f64b06a" ], "index": "pypi", - "version": "==1.1.7" + "version": "==1.1.8" }, "djangorestframework": { "hashes": [ - "sha256:8a435df9007c8b7d8e69a21ef06650e3c0cbe0d4b09e55dd1bd74c89a75a9fcd", - "sha256:f7a266260d656e1cf4ca54d7a7349609dc8af4fe2590edd0ecd7d7643ea94a17" + "sha256:376f4b50340a46c15ae15ddd0c853085f4e66058f97e4dbe7d43ed62f5e60651", + "sha256:c12869cfd83c33d579b17b3cb28a2ae7322a53c3ce85580c2a2ebe4e3f56c4fb" ], "index": "pypi", - "version": "==3.9.2" + "version": "==3.9.4" }, "djangorestframework-bulk": { "hashes": [ @@ -110,58 +110,57 @@ }, "libsass": { "hashes": [ - "sha256:2ae3b061a7d250fb47e5fdad1a8191600ca15dc604e76b109b6d3bf8e08fd2ed", - "sha256:2ee186aa682a035a53c557b7e61ce562a1114f1a1a992d0ba962cbc3e82c490c", - "sha256:366f4fd5a5eab4a519beb583e9fa78718cf2c0f40e92ed835d7ed23b82e5d954", - "sha256:5511b3c62e8d97daf929c63bd516b794f0a06acd09dd261445d864e48290551b", - "sha256:7462da168c8fb997b31cb4dc3ee5adb9af2d106f7b92c2d57a1c68a56ae5a3a0", - "sha256:84a16ec5cf7842ff5bc2caed2c032ed624d587699797bc2a4d4a8e41f579b6e7", - "sha256:8fc0360ee99224f7a3cb09987e641171d34180759f467ba3d15934102ade396f", - "sha256:a6c5535a21a07d769151453270bc6a8373b821d1d2fd9810d84fccfe315ab188", - "sha256:b375bfbf3c86ec0f4a27f266b44b2753a4b8cab7e73649eed7afcad84bc56257", - "sha256:b548af46c1a606aed93da2566901146005d6065f73fefc63d256ba62ba1f803d", - "sha256:bb30fc7125350c64925a98cb90da7979f76bb0ea1a0157e8aeb268f8da38e296", - "sha256:c2f386677514f9fc758631328bd318dd3e9d839ad7b6e248ec4535a191bfd271", - "sha256:d1f301637ad5768aecc81d17dcf40a68f2e11b7ca8b427dbb9f8972c150d303e", - "sha256:e0cf54dddf2cc6e373005bed6e46ccdce1f3a77bd169ab505c3a8ad9023eee5f", - "sha256:e8941881063691d50f9cc8b8d6d8fd7bec86a8c461b2a4fc87188a5fc44d6ba4", - "sha256:f4b29b0c70d753c754a58aaad7c31ad3309ca4a26f9aa64e695157251f6832ad" - ], - "version": "==0.18.0" + "sha256:2457723fe04f4e690105f758aa125e809afc840812965095fa3f4edccd6275ef", + "sha256:2974772e7984b27a51a6d91ebc140183ddd574a9663bd02154ddfb75f13a3eed", + "sha256:2d067ce4f393fee2ce52bb810a364deac5454dfdb7945d31d1f4265f21f03ab8", + "sha256:57d0b99c4e3512233a44141f1bf852570d359724a606dfc4550eccd0f570460d", + "sha256:5b604e4f5befdecc76240c2ba243fd7e23c642ffc2dd86cbfd094a44ead6b08d", + "sha256:5dd647ffa1319a2a18572f41fee3bb561d7f77d8d4784074a00b2eb22c61a859", + "sha256:78f3f14e47612be4fa4b161278f2a3e880a19b6a3367f749e9ae240434b7e7f5", + "sha256:8d423e4b4c0e219488104b4ec4267688dbd816f3ae806beb4201918eff059b2d", + "sha256:a20473b0427d82e37fa68f0b3a8d219f0bb5ca6d3f7d93b0f5342219285e7064", + "sha256:c1f76c2a0993914f3c3088e9b6c7031f22e879c5d27a060cdc8c5aa1318eb9b6", + "sha256:c99fbc950f1955e8b6370aafdb9d84d324e4984a2e00a2b47f04dbcc3706a9d1", + "sha256:cb50f385117535f7671ac7ff3144c1ef0b8e088778c58d269ce6f31b87bfad72", + "sha256:f0f033a8154be60e1a2e1f79ee849ea69a1d62e5d476a78f69e4c7d8fd7c20e1", + "sha256:f2572b73b2e13e74b28388ae86c4fabb853ddbfc12279b4444243bd614710ce8", + "sha256:f8790db67e00c5bc7be1bdd81ed477563a4b191e839193ecc0c2c5ec679ec481" + ], + "version": "==0.19.2" }, "psycopg2-binary": { "hashes": [ - "sha256:007ca0df127b1862fc010125bc4100b7a630efc6841047bd11afceadb4754611", - "sha256:03c49e02adf0b4d68f422fdbd98f7a7c547beb27e99a75ed02298f85cb48406a", - "sha256:0a1232cdd314e08848825edda06600455ad2a7adaa463ebfb12ece2d09f3370e", - "sha256:131c80d0958c89273d9720b9adf9df1d7600bb3120e16019a7389ab15b079af5", - "sha256:2de34cc3b775724623f86617d2601308083176a495f5b2efc2bbb0da154f483a", - "sha256:2eddc31500f73544a2a54123d4c4b249c3c711d31e64deddb0890982ea37397a", - "sha256:484f6c62bdc166ee0e5be3aa831120423bf399786d1f3b0304526c86180fbc0b", - "sha256:4c2d9369ed40b4a44a8ccd6bc3a7db6272b8314812d2d1091f95c4c836d92e06", - "sha256:70f570b5fa44413b9f30dbc053d17ef3ce6a4100147a10822f8662e58d473656", - "sha256:7a2b5b095f3bd733aab101c89c0e1a3f0dfb4ebdc26f6374805c086ffe29d5b2", - "sha256:804914a669186e2843c1f7fbe12b55aad1b36d40a28274abe6027deffad9433d", - "sha256:8520c03172da18345d012949a53617a963e0191ccb3c666f23276d5326af27b5", - "sha256:90da901fc33ea393fc644607e4a3916b509387e9339ec6ebc7bfded45b7a0ae9", - "sha256:a582416ad123291a82c300d1d872bdc4136d69ad0b41d57dc5ca3df7ef8e3088", - "sha256:ac8c5e20309f4989c296d62cac20ee456b69c41fd1bc03829e27de23b6fa9dd0", - "sha256:b2cf82f55a619879f8557fdaae5cec7a294fac815e0087c4f67026fdf5259844", - "sha256:b59d6f8cfca2983d8fdbe457bf95d2192f7b7efdb2b483bf5fa4e8981b04e8b2", - "sha256:be08168197021d669b9964bd87628fa88f910b1be31e7010901070f2540c05fd", - "sha256:be0f952f1c365061041bad16e27e224e29615d4eb1fb5b7e7760a1d3d12b90b6", - "sha256:c1c9a33e46d7c12b9c96cf2d4349d783e3127163fd96254dcd44663cf0a1d438", - "sha256:d18c89957ac57dd2a2724ecfe9a759912d776f96ecabba23acb9ecbf5c731035", - "sha256:d7e7b0ff21f39433c50397e60bf0995d078802c591ca3b8d99857ea18a7496ee", - "sha256:da0929b2bf0d1f365345e5eb940d8713c1d516312e010135b14402e2a3d2404d", - "sha256:de24a4962e361c512d3e528ded6c7480eab24c655b8ca1f0b761d3b3650d2f07", - "sha256:e45f93ff3f7dae2202248cf413a87aeb330821bf76998b3cf374eda2fc893dd7", - "sha256:f046aeae1f7a845041b8661bb7a52449202b6c5d3fb59eb4724e7ca088811904", - "sha256:f1dc2b7b2748084b890f5d05b65a47cd03188824890e9a60818721fd492249fb", - "sha256:fcbe7cf3a786572b73d2cd5f34ed452a5f5fac47c9c9d1e0642c457a148f9f88" + "sha256:080c72714784989474f97be9ab0ddf7b2ad2984527e77f2909fcd04d4df53809", + "sha256:110457be80b63ff4915febb06faa7be002b93a76e5ba19bf3f27636a2ef58598", + "sha256:171352a03b22fc099f15103959b52ee77d9a27e028895d7e5fde127aa8e3bac5", + "sha256:19d013e7b0817087517a4b3cab39c084d78898369e5c46258aab7be4f233d6a1", + "sha256:249b6b21ae4eb0f7b8423b330aa80fab5f821b9ffc3f7561a5e2fd6bb142cf5d", + "sha256:2ac0731d2d84b05c7bb39e85b7e123c3a0acd4cda631d8d542802c88deb9e87e", + "sha256:2b6d561193f0dc3f50acfb22dd52ea8c8dfbc64bcafe3938b5f209cc17cb6f00", + "sha256:2bd23e242e954214944481124755cbefe7c2cf563b1a54cd8d196d502f2578bf", + "sha256:3e1239242ca60b3725e65ab2f13765fc199b03af9eaf1b5572f0e97bdcee5b43", + "sha256:3eb70bb697abbe86b1d2b1316370c02ba320bfd1e9e35cf3b9566a855ea8e4e5", + "sha256:51a2fc7e94b98bd1bb5d4570936f24fc2b0541b63eccadf8fdea266db8ad2f70", + "sha256:52f1bdafdc764b7447e393ed39bb263eccb12bfda25a4ac06d82e3a9056251f6", + "sha256:5b3581319a3951f1e866f4f6c5e42023db0fae0284273b82e97dfd32c51985cd", + "sha256:63c1b66e3b2a3a336288e4bcec499e0dc310cd1dceaed1c46fa7419764c68877", + "sha256:8123a99f24ecee469e5c1339427bcdb2a33920a18bb5c0d58b7c13f3b0298ba3", + "sha256:85e699fcabe7f817c0f0a412d4e7c6627e00c412b418da7666ff353f38e30f67", + "sha256:8dbff4557bbef963697583366400822387cccf794ccb001f1f2307ed21854c68", + "sha256:908d21d08d6b81f1b7e056bbf40b2f77f8c499ab29e64ec5113052819ef1c89b", + "sha256:af39d0237b17d0a5a5f638e9dffb34013ce2b1d41441fd30283e42b22d16858a", + "sha256:af51bb9f055a3f4af0187149a8f60c9d516cf7d5565b3dac53358796a8fb2a5b", + "sha256:b2ecac57eb49e461e86c092761e6b8e1fd9654dbaaddf71a076dcc869f7014e2", + "sha256:cd37cc170678a4609becb26b53a2bc1edea65177be70c48dd7b39a1149cabd6e", + "sha256:d17e3054b17e1a6cb8c1140f76310f6ede811e75b7a9d461922d2c72973f583e", + "sha256:d305313c5a9695f40c46294d4315ed3a07c7d2b55e48a9010dad7db7a66c8b7f", + "sha256:dd0ef0eb1f7dd18a3f4187226e226a7284bda6af5671937a221766e6ef1ee88f", + "sha256:e1adff53b56db9905db48a972fb89370ad5736e0450b96f91bcf99cadd96cfd7", + "sha256:f0d43828003c82dbc9269de87aa449e9896077a71954fbbb10a614c017e65737", + "sha256:f78e8b487de4d92640105c1389e5b90be3496b1d75c90a666edd8737cc2dbab7" ], "index": "pypi", - "version": "==2.8.2" + "version": "==2.8.3" }, "pygments": { "hashes": [ @@ -178,13 +177,30 @@ ], "version": "==2019.1" }, + "pyyaml": { + "hashes": [ + "sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3", + "sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043", + "sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7", + "sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265", + "sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391", + "sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778", + "sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225", + "sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955", + "sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e", + "sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190", + "sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd" + ], + "index": "pypi", + "version": "==5.1.1" + }, "requests": { "hashes": [ - "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", - "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" ], "index": "pypi", - "version": "==2.21.0" + "version": "==2.22.0" }, "six": { "hashes": [ @@ -202,10 +218,18 @@ }, "urllib3": { "hashes": [ - "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", - "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" ], - "version": "==1.24.2" + "version": "==1.25.3" + }, + "whitenoise": { + "hashes": [ + "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", + "sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a" + ], + "index": "pypi", + "version": "==4.1.2" }, "wiki": { "git": "https://github.com/python-discord/django-wiki.git", @@ -222,10 +246,10 @@ }, "bandit": { "hashes": [ - "sha256:6102b5d6afd9d966df5054e0bdfc2e73a24d0fea400ec25f2e54c134412158d7", - "sha256:9413facfe9de1e1bd291d525c784e1beb1a55c9916b51dae12979af63a69ba4c" + "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952", + "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065" ], - "version": "==1.5.1" + "version": "==1.6.2" }, "coverage": { "hashes": [ @@ -358,10 +382,10 @@ }, "pbr": { "hashes": [ - "sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843", - "sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824" + "sha256:36ebd78196e8c9588c972f5571230a059ff83783fabbbbedecc07be263ccd7e6", + "sha256:5a03f59455ad54f01a94c15829b8b70065462b7bd8d5d7e983306b59127fc841" ], - "version": "==5.1.3" + "version": "==5.4.0" }, "pep8-naming": { "hashes": [ @@ -384,6 +408,7 @@ "sha256:5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4", "sha256:ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039" ], + "index": "pypi", "version": "==3.0.0" }, "pyflakes": { @@ -395,19 +420,20 @@ }, "pyyaml": { "hashes": [ - "sha256:1adecc22f88d38052fb787d959f003811ca858b799590a5eaa70e63dca50308c", - "sha256:436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95", - "sha256:460a5a4248763f6f37ea225d19d5c205677d8d525f6a83357ca622ed541830c2", - "sha256:5a22a9c84653debfbf198d02fe592c176ea548cccce47553f35f466e15cf2fd4", - "sha256:7a5d3f26b89d688db27822343dfa25c599627bc92093e788956372285c6298ad", - "sha256:9372b04a02080752d9e6f990179a4ab840227c6e2ce15b95e1278456664cf2ba", - "sha256:a5dcbebee834eaddf3fa7366316b880ff4062e4bcc9787b78c7fbb4a26ff2dd1", - "sha256:aee5bab92a176e7cd034e57f46e9df9a9862a71f8f37cad167c6fc74c65f5b4e", - "sha256:c51f642898c0bacd335fc119da60baae0824f2cde95b0330b56c0553439f0673", - "sha256:c68ea4d3ba1705da1e0d85da6684ac657912679a649e8868bd850d2c299cce13", - "sha256:e23d0cc5299223dcc37885dae624f382297717e459ea24053709675a976a3e19" + "sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3", + "sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043", + "sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7", + "sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265", + "sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391", + "sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778", + "sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225", + "sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955", + "sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e", + "sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190", + "sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd" ], - "version": "==5.1" + "index": "pypi", + "version": "==5.1.1" }, "six": { "hashes": [ @@ -425,10 +451,9 @@ }, "snowballstemmer": { "hashes": [ - "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", - "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" + "sha256:9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9" ], - "version": "==1.2.1" + "version": "==1.9.0" }, "stevedore": { "hashes": [ diff --git a/docker-compose.yml b/docker-compose.yml index 0c504c40..d415340b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,8 +22,8 @@ services: web: build: context: . - dockerfile: docker/app/Dockerfile - command: docker/app/migrate_and_serve.sh + dockerfile: docker/app/Dockerfile.local + command: docker/app/scripts/migrate_and_serve.sh ports: - "127.0.0.1:8000:8000" depends_on: @@ -39,5 +39,3 @@ services: volumes: staticfiles: - -# vim: sw=2 ts=2: diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile index 52cc6b32..903e7dc6 100644 --- a/docker/app/Dockerfile +++ b/docker/app/Dockerfile @@ -1,14 +1,17 @@ FROM bitnami/python:3.7-prod +# I have no idea what this does. STOPSIGNAL SIGQUIT ARG EXTRAS=deploy +# Create a user. RUN adduser \ --disabled-login \ --no-create-home \ --uid 1500 \ pysite +# Install prerequisites needed to complete the dependency installation. RUN apt-get update -y \ && \ apt-get install --no-install-recommends -y \ @@ -21,24 +24,29 @@ RUN apt-get update -y \ && \ rm -rf /var/lib/apt/lists/* +# Set up the working directory. WORKDIR /app - COPY Pipfile Pipfile.lock /app/ +# Pip install the stuff we'll need. RUN rm -r /opt/bitnami/python/lib/python3.*/site-packages/setuptools* && \ pip install --no-cache-dir -U setuptools - RUN python3 -m pip install pipenv \ && python3 -m pipenv install --system --deploy \ && pip install uwsgi==2.0.18 +# Copy everything into the docker environment. COPY . . -RUN SECRET_KEY=placeholder DATABASE_URL=sqlite:// python3 manage.py collectstatic --no-input --clear --verbosity 0 +# RUN SECRET_KEY=placeholder DATABASE_URL=sqlite:// python3 manage.py collectstatic --no-input --clear --verbosity 0 +# Remove the prerequisites, dependency installation is now complete. RUN apt-get purge -y \ gcc \ libc-dev \ libpq-dev +# Migrate, collect and start the app. +RUN chmod +x /app/docker/app/scripts/migrate.sh +ENTRYPOINT ["/app/docker/app/scripts/migrate.sh"] CMD ["uwsgi", "--ini", "docker/app/uwsgi.ini"] diff --git a/docker/app/Dockerfile.local b/docker/app/Dockerfile.local new file mode 100644 index 00000000..c332c757 --- /dev/null +++ b/docker/app/Dockerfile.local @@ -0,0 +1,49 @@ +FROM bitnami/python:3.7-prod + +# I have no idea what this does. +STOPSIGNAL SIGQUIT +ARG EXTRAS=deploy + +# Create a user. +RUN adduser \ + --disabled-login \ + --no-create-home \ + --uid 1500 \ + pysite + +# Install prerequisites needed to complete the dependency installation. +RUN apt-get update -y \ + && \ + apt-get install --no-install-recommends -y \ + gcc \ + libc-dev \ + libpq-dev \ + git \ + && \ + apt-get clean \ + && \ + rm -rf /var/lib/apt/lists/* + +# Set up the working directory. +WORKDIR /app +COPY Pipfile Pipfile.lock /app/ + +# Pip install the stuff we'll need. +RUN rm -r /opt/bitnami/python/lib/python3.*/site-packages/setuptools* && \ + pip install --no-cache-dir -U setuptools +RUN python3 -m pip install pipenv \ + && python3 -m pipenv install --system --deploy \ + && pip install uwsgi==2.0.18 + +# Copy everything into the docker environment. +COPY . . + +RUN SECRET_KEY=placeholder DATABASE_URL=sqlite:// python3 manage.py collectstatic --no-input --clear --verbosity 0 + +# Remove the prerequisites, dependency installation is now complete. +RUN apt-get purge -y \ + gcc \ + libc-dev \ + libpq-dev + +CMD ["uwsgi", "--ini", "docker/app/uwsgi.ini"] diff --git a/docker/app/scripts/migrate.sh b/docker/app/scripts/migrate.sh new file mode 100755 index 00000000..22636c93 --- /dev/null +++ b/docker/app/scripts/migrate.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +echo --- Applying migrations --- +python manage.py migrate --verbosity 1 + +echo --- Collecting static files --- +python manage.py collectstatic --no-input --clear --verbosity 1 + +echo --- Starting uwsgi --- +exec "$@" # This runs the CMD at the end of the Dockerfile diff --git a/docker/app/migrate_and_serve.sh b/docker/app/scripts/migrate_and_serve.sh index 42bf67a3..0b54a2e5 100755 --- a/docker/app/migrate_and_serve.sh +++ b/docker/app/scripts/migrate_and_serve.sh @@ -11,7 +11,7 @@ echo [i] Applying migrations. python manage.py migrate --verbosity 1 echo [i] Collecting static files. -python manage.py collectstatic --no-input --clear --verbosity 0 +python manage.py collectstatic --no-input --clear --verbosity 1 echo [i] Creating a superuser. echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'admin', 'admin') if not User.objects.filter(username='admin').exists() else print('Admin user already exists')" | python manage.py shell diff --git a/docker/pysite.dockerapp b/docker/pysite.dockerapp index 2426008e..4e90ff87 100644 --- a/docker/pysite.dockerapp +++ b/docker/pysite.dockerapp @@ -13,7 +13,7 @@ services: django: build: context: . - command: docker/app/migrate_and_serve.sh + command: docker/app/scripts/migrate_and_serve.sh ports: - "127.0.0.1:4000:4000" environment: diff --git a/docs/deployment.md b/docs/deployment.md index 841e08c7..e561b5d0 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -20,7 +20,6 @@ An example Ansible task to deploy the site is shown below, it should read fairly humanly and give you a rough idea of steps needed to deploy the site. ```yml ---- - name: ensure the `{{ pysite_pg_username }}` postgres user exists become: yes become_user: postgres diff --git a/pydis_site/apps/api/tests/base.py b/pydis_site/apps/api/tests/base.py index 37459f70..b779256e 100644 --- a/pydis_site/apps/api/tests/base.py +++ b/pydis_site/apps/api/tests/base.py @@ -5,7 +5,7 @@ from rest_framework.test import APITestCase test_user, _created = User.objects.get_or_create( username='test', email='[email protected]', - password='testpass', # noqa: S106 + password='testpass', # noqa is_superuser=True, is_staff=True ) diff --git a/pydis_site/apps/home/resources/books/_category_info.yaml b/pydis_site/apps/home/resources/books/_category_info.yaml new file mode 100644 index 00000000..e3b89ad3 --- /dev/null +++ b/pydis_site/apps/home/resources/books/_category_info.yaml @@ -0,0 +1,2 @@ +description: The best books for learning Python or Python Frameworks +name: Books diff --git a/pydis_site/apps/home/resources/books/automate_the_boring_stuff.yaml b/pydis_site/apps/home/resources/books/automate_the_boring_stuff.yaml new file mode 100644 index 00000000..3a9045a5 --- /dev/null +++ b/pydis_site/apps/home/resources/books/automate_the_boring_stuff.yaml @@ -0,0 +1,16 @@ +description: One of the best books out there for Python beginners. This book will + teach you the basics of Python, while also teaching invaluable automation tools + and techniques for solving common problems. You'll learn how to go about scraping + the web, manipulating files and automating keyboard and mouse input. Ideal for an + office worker who wants to make himself more useful. +name: Automate the Boring Stuff with Python +payment: optional +payment_description: A free e-book is available on the website, but you can buy it + on Amazon if you want to support the author. +urls: +- icon: regular/link + title: E-book + url: https://automatetheboringstuff.com/ +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Automate-Boring-Stuff-Python-Programming/dp/1593275994/ diff --git a/pydis_site/apps/home/resources/books/byte_of_python.yaml b/pydis_site/apps/home/resources/books/byte_of_python.yaml new file mode 100644 index 00000000..f3eca902 --- /dev/null +++ b/pydis_site/apps/home/resources/books/byte_of_python.yaml @@ -0,0 +1,17 @@ +description: A free book on programming using the Python language. It serves as a + tutorial or guide to the Python language for a beginner audience. If all you know + about computers is how to save text files, then this is the book for you. +name: A Byte of Python +payment: optional +payment_description: A free e-book is available online, a paper version can be bought + from lulu.com. +urls: +- icon: regular/link + title: E-book + url: https://python.swaroopch.com/ +- icon: regular/book + title: Buy the book + url: http://www.lulu.com/shop/swaroop-c-h/a-byte-of-python/paperback/product-21142968.html +- icon: regular/tablet-alt + title: Kindle edition + url: https://www.amazon.com/Byte-Python-Swaroop-C-H-ebook/dp/B00FJ7S2JU/ diff --git a/pydis_site/apps/home/resources/books/effective_python.yaml b/pydis_site/apps/home/resources/books/effective_python.yaml new file mode 100644 index 00000000..ab782704 --- /dev/null +++ b/pydis_site/apps/home/resources/books/effective_python.yaml @@ -0,0 +1,14 @@ +description: A book that gives 59 best practices for writing excellent Python. Great + for intermediates. +name: Effective Python +payment: paid +urls: +- icon: regular/link + title: Website + url: https://effectivepython.com/ +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Effective-Python-Specific-Software-Development/dp/0134034287 +- icon: branding/github + title: GitHub + url: https://github.com/bslatkin/effectivepython diff --git a/pydis_site/apps/home/resources/books/flask_web_development.yaml b/pydis_site/apps/home/resources/books/flask_web_development.yaml new file mode 100644 index 00000000..613e0e50 --- /dev/null +++ b/pydis_site/apps/home/resources/books/flask_web_development.yaml @@ -0,0 +1,14 @@ +description: A comprehensive Flask walkthrough that has you building a complete social + blogging application from scratch. +name: Flask Web Development +payment: paid +urls: +- icon: regular/link + title: Website + url: http://shop.oreilly.com/product/0636920031116.do +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Flask-Web-Development-Developing-Applications/dp/1449372627 +- icon: branding/github + title: GitHub + url: https://github.com/miguelgrinberg/flasky diff --git a/pydis_site/apps/home/resources/books/fluent_python.yaml b/pydis_site/apps/home/resources/books/fluent_python.yaml new file mode 100644 index 00000000..ebfd5f91 --- /dev/null +++ b/pydis_site/apps/home/resources/books/fluent_python.yaml @@ -0,0 +1,14 @@ +description: A veritable tome of intermediate and advanced Python information. A must-read + for any Python professional. +name: Fluent Python +payment: paid +urls: +- icon: regular/link + title: Website + url: https://www.oreilly.com/library/view/fluent-python/9781491946237/ +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008 +- icon: branding/github + title: GitHub + url: https://github.com/fluentpython diff --git a/pydis_site/apps/home/resources/books/mission_python.yaml b/pydis_site/apps/home/resources/books/mission_python.yaml new file mode 100644 index 00000000..8cd91979 --- /dev/null +++ b/pydis_site/apps/home/resources/books/mission_python.yaml @@ -0,0 +1,13 @@ +description: Learn programming and Python while building a complete and awesome space-themed + game using cutting-edge Python 3.6 and Pygame Zero. Extensive use of code examples, + images, and walk-throughs make this a pleasure to both read and follow along. Excellent + book for beginners. +name: Mission Python +payment: paid +urls: +- icon: regular/link + title: Website + url: https://www.sean.co.uk/books/mission-python/index.shtm +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Mission-Python-Code-Space-Adventure/dp/1593278578 diff --git a/pydis_site/apps/home/resources/books/python_cookbook.yaml b/pydis_site/apps/home/resources/books/python_cookbook.yaml new file mode 100644 index 00000000..9fab8e48 --- /dev/null +++ b/pydis_site/apps/home/resources/books/python_cookbook.yaml @@ -0,0 +1,14 @@ +description: Complete with 'recipes' for various Python topics, including moving from + Python 2 to Python 3.3 +name: Python Cookbook +payment: paid +urls: +- icon: regular/link + title: Website + url: http://shop.oreilly.com/product/0636920027072.do +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Python-Cookbook-Third-David-Beazley/dp/1449340377 +- icon: branding/github + title: GitHub + url: https://github.com/dabeaz/python-cookbook diff --git a/pydis_site/apps/home/resources/books/python_tricks.yaml b/pydis_site/apps/home/resources/books/python_tricks.yaml new file mode 100644 index 00000000..0638058c --- /dev/null +++ b/pydis_site/apps/home/resources/books/python_tricks.yaml @@ -0,0 +1,12 @@ +description: Full of useful Python tips, tricks and features. Get this if you have + a good grasp of the basics and want to take your Python skills to the next level, + or are a experienced programmer looking to add to your toolbelt. +name: Python Tricks +payment: paid +urls: +- icon: regular/link + title: Website + url: https://realpython.com/products/python-tricks-book/ +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Python-Tricks-Buffet-Awesome-Features/dp/1775093301 diff --git a/pydis_site/apps/home/resources/books/two_scoops_of_django.yaml b/pydis_site/apps/home/resources/books/two_scoops_of_django.yaml new file mode 100644 index 00000000..85cfa0fc --- /dev/null +++ b/pydis_site/apps/home/resources/books/two_scoops_of_django.yaml @@ -0,0 +1,14 @@ +description: This book is chock-full of material that will help you with your Django + projects. +name: Two Scoops of Django +payment: paid +urls: +- icon: regular/link + title: Website + url: https://twoscoopspress.com/products/two-scoops-of-django-1-11 +- icon: branding/amazon + title: Amazon + url: https://www.amazon.com/Two-Scoops-Django-Best-Practices/dp/0981467342 +- icon: branding/github + title: GitHub + url: https://github.com/twoscoops/two-scoops-of-django-2.0-code-examples diff --git a/pydis_site/apps/home/resources/communities/_category_info.yaml b/pydis_site/apps/home/resources/communities/_category_info.yaml new file mode 100644 index 00000000..eccb8b80 --- /dev/null +++ b/pydis_site/apps/home/resources/communities/_category_info.yaml @@ -0,0 +1,2 @@ +description: Partnered communities that share part of our mission +name: Communities diff --git a/pydis_site/apps/home/resources/communities/adafruit.yaml b/pydis_site/apps/home/resources/communities/adafruit.yaml new file mode 100644 index 00000000..193f7364 --- /dev/null +++ b/pydis_site/apps/home/resources/communities/adafruit.yaml @@ -0,0 +1,14 @@ +description: 'Adafruit is an open-source electronics manufacturer that makes all the + components you need to start your own Python-powered hardware projects. + + + Their official community host regular show-and-tells, provide help with your projects, + and the Adafruit devs do all the CircuitPython development right out in the open. + Join the Maker Revolution today!' +name: 'Discord: Adafruit' +payment: free +payment_description: null +urls: +- icon: branding/discord + title: Adafruit Discord + url: https://discord.gg/adafruit diff --git a/pydis_site/apps/home/resources/communities/functional_programming.yaml b/pydis_site/apps/home/resources/communities/functional_programming.yaml new file mode 100644 index 00000000..ab99f264 --- /dev/null +++ b/pydis_site/apps/home/resources/communities/functional_programming.yaml @@ -0,0 +1,10 @@ +description: Functional Programming is a server for discussing functional languages + like Haskell, Idris, Elixir and Lisp as well as related academic fields such as + type theory, category theory, proof assistants, and more! +name: 'Discord: Functional Programming' +payment: free +payment_description: null +urls: +- icon: branding/discord + title: Functional Programming Discord + url: https://discord.gg/kWJYurV diff --git a/pydis_site/apps/home/resources/communities/pallets.yaml b/pydis_site/apps/home/resources/communities/pallets.yaml new file mode 100644 index 00000000..e5a18983 --- /dev/null +++ b/pydis_site/apps/home/resources/communities/pallets.yaml @@ -0,0 +1,10 @@ +description: The Pallets Projects develop Python libraries such as the Flask web framework, + the Jinja templating library, and the Click command line toolkit. Join to discuss + and get help from the Pallets community. +name: 'Discord: The Pallets Project' +payment: free +payment_description: null +urls: +- icon: branding/discord + title: The Pallets Project Discord + url: https://discord.gg/t6rrQZH diff --git a/pydis_site/apps/home/resources/communities/rlbot.yaml b/pydis_site/apps/home/resources/communities/rlbot.yaml new file mode 100644 index 00000000..c62e0260 --- /dev/null +++ b/pydis_site/apps/home/resources/communities/rlbot.yaml @@ -0,0 +1,11 @@ +description: RLBot is a community of programmers making awesome Rocket League bots. + They've created a framework that you can use to write bots in a number of languages + (including Python), and they host regular tournaments where botmakers can pit their + creations against each other. +name: 'Discord: RLBot' +payment: free +payment_description: null +urls: +- icon: branding/discord + title: RLBot Discord + url: https://discord.gg/4JJdJKb diff --git a/pydis_site/apps/home/resources/communities/subreddit.yaml b/pydis_site/apps/home/resources/communities/subreddit.yaml new file mode 100644 index 00000000..217a84ac --- /dev/null +++ b/pydis_site/apps/home/resources/communities/subreddit.yaml @@ -0,0 +1,8 @@ +description: News about the Python programming language, and language-related discussion +name: 'Subreddit: r/Python' +payment: free +payment_description: null +urls: +- icon: branding/reddit-alien + title: r/Python on Reddit + url: https://www.reddit.com/r/Python/ diff --git a/pydis_site/apps/home/resources/editors/_category_info.yaml b/pydis_site/apps/home/resources/editors/_category_info.yaml new file mode 100644 index 00000000..f8dc1413 --- /dev/null +++ b/pydis_site/apps/home/resources/editors/_category_info.yaml @@ -0,0 +1,2 @@ +description: Lightweight code editors supporting Python +name: Editors diff --git a/pydis_site/apps/home/resources/editors/atom.yaml b/pydis_site/apps/home/resources/editors/atom.yaml new file mode 100644 index 00000000..f05e45a3 --- /dev/null +++ b/pydis_site/apps/home/resources/editors/atom.yaml @@ -0,0 +1,12 @@ +description: A free Electron-based editor, a "hackable text editor for the 21st century", maintained + by the GitHub team. +name: Atom +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://atom.io/ +- icon: branding/github + title: GitHub + url: https://github.com/atom/atom diff --git a/pydis_site/apps/home/resources/editors/mu_editor.yaml b/pydis_site/apps/home/resources/editors/mu_editor.yaml new file mode 100644 index 00000000..cb44d750 --- /dev/null +++ b/pydis_site/apps/home/resources/editors/mu_editor.yaml @@ -0,0 +1,12 @@ +description: An editor aimed at beginners for the purpose of learning how to code + without the distractions more advanced editors sometimes cause. +name: Mu-Editor +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://codewith.mu/en/ +- icon: branding/github + title: GitHub + url: https://github.com/mu-editor/mu/ diff --git a/pydis_site/apps/home/resources/editors/sublime_text.yaml b/pydis_site/apps/home/resources/editors/sublime_text.yaml new file mode 100644 index 00000000..97952d35 --- /dev/null +++ b/pydis_site/apps/home/resources/editors/sublime_text.yaml @@ -0,0 +1,9 @@ +description: A powerful Python-backed editor with great community support and a wealth + of extensions. +name: Sublime Text +payment: optional +payment_description: Nagware; will ask you to buy the full version after every X saves +urls: +- icon: regular/link + title: Website + url: https://www.sublimetext.com/ diff --git a/pydis_site/apps/home/resources/editors/visual_studio_code.yaml b/pydis_site/apps/home/resources/editors/visual_studio_code.yaml new file mode 100644 index 00000000..4e1f946f --- /dev/null +++ b/pydis_site/apps/home/resources/editors/visual_studio_code.yaml @@ -0,0 +1,11 @@ +description: A fully-featured editor based on Electron, extendable with plugins. +name: Visual Studio Code +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://code.visualstudio.com/ +- icon: branding/github + title: GitHub + url: https://github.com/Microsoft/vscode diff --git a/pydis_site/apps/home/resources/ides/_category_info.yaml b/pydis_site/apps/home/resources/ides/_category_info.yaml new file mode 100644 index 00000000..d331c95d --- /dev/null +++ b/pydis_site/apps/home/resources/ides/_category_info.yaml @@ -0,0 +1,2 @@ +description: Fully-integrated development environments for serious Python work +name: IDEs diff --git a/pydis_site/apps/home/resources/ides/pycharm.yaml b/pydis_site/apps/home/resources/ides/pycharm.yaml new file mode 100644 index 00000000..4624cb41 --- /dev/null +++ b/pydis_site/apps/home/resources/ides/pycharm.yaml @@ -0,0 +1,10 @@ +description: The very best Python IDE, with a wealth of advanced features and convenience + functions. +name: PyCharm +payment: optional +payment_description: There's a free Community Edition and a paid-for Professional + Edition with more features available +urls: +- icon: regular/link + title: Website + url: https://www.jetbrains.com/pycharm/ diff --git a/pydis_site/apps/home/resources/ides/spyder.yaml b/pydis_site/apps/home/resources/ides/spyder.yaml new file mode 100644 index 00000000..146b3549 --- /dev/null +++ b/pydis_site/apps/home/resources/ides/spyder.yaml @@ -0,0 +1,12 @@ +description: The Scientific PYthon Development EnviRonment. Simpler and lighter than + PyCharm, but still packs a punch. +name: Spyder +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://www.spyder-ide.org/ +- icon: branding/github + title: GitHub + url: https://github.com/spyder-ide/spyder diff --git a/pydis_site/apps/home/resources/ides/thonny.yaml b/pydis_site/apps/home/resources/ides/thonny.yaml new file mode 100644 index 00000000..d660094b --- /dev/null +++ b/pydis_site/apps/home/resources/ides/thonny.yaml @@ -0,0 +1,12 @@ +description: A Python IDE specifially aimed at learning programming. Has a lot of + helpful features to help you understand your code. +name: Thonny +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://thonny.org/ +- icon: branding/github + title: GitHub + url: https://github.com/thonny/thonny/ diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/_category_info.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/_category_info.yaml new file mode 100644 index 00000000..08501627 --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/_category_info.yaml @@ -0,0 +1,3 @@ +description: Learn Python with interactive content like courses, games and programming + challenges. +name: Interactive Learning Tools diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/automate_the_boring_stuff.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/automate_the_boring_stuff.yaml new file mode 100644 index 00000000..02d76b3b --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/automate_the_boring_stuff.yaml @@ -0,0 +1,11 @@ +description: The interactive course version of Al Sweigart's excellent book for beginners, + taught by the author himself. This link has a discounted version of the course which + will always cost 10 dollars. Thanks, Al! +name: Automate the Boring Stuff with Python +payment: paid +payment_description: Paid course with a certificate of completion. Some sample videos + are available for free. +urls: +- icon: regular/graduation-cap + title: Udemy Course + url: https://www.udemy.com/automate/?couponCode=FOR_LIKE_10_BUCKS diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/code_combat.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/code_combat.yaml new file mode 100644 index 00000000..39c25f0d --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/code_combat.yaml @@ -0,0 +1,13 @@ +description: Learn Python while gaming - an open-source project with thousands of + contributors, which teaches you Python through a deep, top-down RPG. +name: Code Combat +payment: optional +payment_description: A wealth of free content is available, but you can also pay for + more +urls: +- icon: regular/link + title: Website + url: https://codecombat.com/ +- icon: branding/github + title: GitHub + url: https://github.com/codecombat/codecombat diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/exercism.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/exercism.yaml new file mode 100644 index 00000000..3adb4138 --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/exercism.yaml @@ -0,0 +1,14 @@ +description: Level up your programming skills with more than 2600 exercises across + 47 programming languages, Python included. The website provides a mentored mode, + where you can get your code reviewed for each solution you submit. The mentors will + give you insightful advice to make you a better programmer. +name: exercism.io +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://exercism.io/ +- icon: branding/github + title: GitHub + url: https://github.com/exercism/python diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/learn_to_program.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/learn_to_program.yaml new file mode 100644 index 00000000..265f1644 --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/learn_to_program.yaml @@ -0,0 +1,13 @@ +description: A 2-part course that teaches Python. Primarily intended for high school + students and first-year university students who want to learn programming. +name: 'University of Toronto: Learn to Program' +payment: optional +payment_description: You can pay to enroll for a graded certificate, or choose to + audit for free. +urls: +- icon: regular/graduation-cap + title: 'Part 1: The Fundamentals' + url: https://www.coursera.org/learn/learn-to-program +- icon: regular/graduation-cap + title: 'Part 2: Crafting Quality Code' + url: https://www.coursera.org/learn/program-code diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/mit_python.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/mit_python.yaml new file mode 100644 index 00000000..464b8d4a --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/mit_python.yaml @@ -0,0 +1,10 @@ +description: This MITx offering teaches computer science with Python. It covers computational + thinking, algorithms, data structures and the Python programming language itself. +name: 'MIT: Introduction to Computer Science and Programming Using Python' +payment: optional +payment_description: You can pay to enroll for a graded certificate, or choose to + take the full course for free. +urls: +- icon: regular/graduation-cap + title: edX Course + url: https://www.edx.org/course/introduction-computer-science-mitx-6-00-1x-11 diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/programming_for_everybody.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/programming_for_everybody.yaml new file mode 100644 index 00000000..a6d7abe1 --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/programming_for_everybody.yaml @@ -0,0 +1,10 @@ +description: A 5-part specialization course that teaches Python from scratch. The + course has no pre-requisites and avoids all but the simplest mathematics. +name: 'University of Michigan: Programming for Everybody' +payment: optional +payment_description: You can pay to enroll for a graded certificate and a capstone + project, or choose to audit for free. +urls: +- icon: regular/graduation-cap + title: Python for Everyone Specialization + url: https://www.coursera.org/learn/python diff --git a/pydis_site/apps/home/resources/interactive_learning_tools/python_morsels.yaml b/pydis_site/apps/home/resources/interactive_learning_tools/python_morsels.yaml new file mode 100644 index 00000000..f883f8b7 --- /dev/null +++ b/pydis_site/apps/home/resources/interactive_learning_tools/python_morsels.yaml @@ -0,0 +1,15 @@ +description: 'Learn to write more idiomatic Python code with deliberate practice! + + + Sign up for this service and receive one short Python exercise every week. After + you attempt to work through the exercise, you''ll receive a number of solutions + to the exercise with explanations of each one. Each exercise will include automated + tests and some may include bonuses for a little more of a challenge!' +name: Python Morsels +payment: paid +payment_description: Paid service with monthly and annual plans. A 4 week free trial + is available without needing to enter payment information. +urls: +- icon: regular/link + title: Website + url: https://www.pythonmorsels.com/ diff --git a/pydis_site/apps/home/resources/misc/_category_info.yaml b/pydis_site/apps/home/resources/misc/_category_info.yaml new file mode 100644 index 00000000..4fdc4bf7 --- /dev/null +++ b/pydis_site/apps/home/resources/misc/_category_info.yaml @@ -0,0 +1,2 @@ +description: Resources which do not fit into the other categories +name: Miscellaneous diff --git a/pydis_site/apps/home/resources/misc/good_first_issue_tag.yaml b/pydis_site/apps/home/resources/misc/good_first_issue_tag.yaml new file mode 100644 index 00000000..35d7a8a4 --- /dev/null +++ b/pydis_site/apps/home/resources/misc/good_first_issue_tag.yaml @@ -0,0 +1,10 @@ +description: Searching for opportunities to contribute to a Python project? GitHub + repository maintainers often mark issues appropriate for novice users with the 'Good + First Issue' tag. These issues can be explored directly on GitHub. +name: GitHub's 'Good First Issue' Tag +payment: free +payment_description: null +urls: +- icon: branding/github + title: GitHub + url: https://github.com/search?utf8=%E2%9C%93&q=label%3A%22good+first+issue%22+language%3APython+state%3Aopen&type=Issues&ref=advsearch&l=Python&l= diff --git a/pydis_site/apps/home/resources/misc/python_cheat_sheet.yaml b/pydis_site/apps/home/resources/misc/python_cheat_sheet.yaml new file mode 100644 index 00000000..8c82a5a9 --- /dev/null +++ b/pydis_site/apps/home/resources/misc/python_cheat_sheet.yaml @@ -0,0 +1,9 @@ +description: A Python 3 cheat sheet with useful information and tips, as well as common + pitfalls for beginners. This is a PDF. +name: Python Cheat Sheet +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://perso.limsi.fr/pointal/_media/python:cours:mementopython3-english.pdf diff --git a/pydis_site/apps/home/resources/podcasts/_category_info.yaml b/pydis_site/apps/home/resources/podcasts/_category_info.yaml new file mode 100644 index 00000000..a0f9025c --- /dev/null +++ b/pydis_site/apps/home/resources/podcasts/_category_info.yaml @@ -0,0 +1,2 @@ +description: Notable podcasts about the Python ecosystem +name: Podcasts diff --git a/pydis_site/apps/home/resources/podcasts/podcast_dunder_init.yaml b/pydis_site/apps/home/resources/podcasts/podcast_dunder_init.yaml new file mode 100644 index 00000000..8f0cac8b --- /dev/null +++ b/pydis_site/apps/home/resources/podcasts/podcast_dunder_init.yaml @@ -0,0 +1,9 @@ +description: The podcast about Python and the people who make it great. Weekly long-form + interviews with the creators of notable Python packages. +name: Podcast.__init__ +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://www.podcastinit.com/ diff --git a/pydis_site/apps/home/resources/podcasts/python_bytes.yaml b/pydis_site/apps/home/resources/podcasts/python_bytes.yaml new file mode 100644 index 00000000..a3368d23 --- /dev/null +++ b/pydis_site/apps/home/resources/podcasts/python_bytes.yaml @@ -0,0 +1,9 @@ +description: A byte-sized podcast where Michael Kennedy and Brian Okken work through + this week's notable Python headlines. +name: Python Bytes +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://pythonbytes.fm/ diff --git a/pydis_site/apps/home/resources/podcasts/talk_python_to_me.yaml b/pydis_site/apps/home/resources/podcasts/talk_python_to_me.yaml new file mode 100644 index 00000000..5ed101c4 --- /dev/null +++ b/pydis_site/apps/home/resources/podcasts/talk_python_to_me.yaml @@ -0,0 +1,9 @@ +description: The essential weekly Python podcast. Michael Kennedy and a prominent + name within the Python community dive into a topic that relates to their experience. +name: Talk Python To Me +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://talkpython.fm/ diff --git a/pydis_site/apps/home/resources/tutorials/_category_info.yaml b/pydis_site/apps/home/resources/tutorials/_category_info.yaml new file mode 100644 index 00000000..a9adc106 --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/_category_info.yaml @@ -0,0 +1,3 @@ +description: Tutorials and references for those that are just getting started with + python +name: Tutorials diff --git a/pydis_site/apps/home/resources/tutorials/corey_schafer.yaml b/pydis_site/apps/home/resources/tutorials/corey_schafer.yaml new file mode 100644 index 00000000..9fff4bbf --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/corey_schafer.yaml @@ -0,0 +1,7 @@ +description: An in-depth look at the Python programming language, from one of + YouTube's most popular Python tutors. +payment: free +urls: + - icon: branding/youtube, + title: YouTube, + url: https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU diff --git a/pydis_site/apps/home/resources/tutorials/get_started_with_flask.yaml b/pydis_site/apps/home/resources/tutorials/get_started_with_flask.yaml new file mode 100644 index 00000000..11dd2a4d --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/get_started_with_flask.yaml @@ -0,0 +1,9 @@ +description: A fully featured mega-tutorial for learning how to create web applications + with the Flask framework. +name: Get Started with Flask Web Development +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world diff --git a/pydis_site/apps/home/resources/tutorials/getting_started_with_python.yaml b/pydis_site/apps/home/resources/tutorials/getting_started_with_python.yaml new file mode 100644 index 00000000..777f2fe3 --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/getting_started_with_python.yaml @@ -0,0 +1,12 @@ +description: The list of resources for programmers and non-programmers from Python's + official beginners' guide +name: Getting Started with Python +payment: free +payment_description: null +urls: +- icon: regular/link + title: Beginners Guide for Non-Programmers + url: https://wiki.python.org/moin/BeginnersGuide/NonProgrammers +- icon: regular/link + title: Beginners Guide for Programmers + url: https://wiki.python.org/moin/BeginnersGuide/Programmers diff --git a/pydis_site/apps/home/resources/tutorials/hitchhikers_guide_to_python.yaml b/pydis_site/apps/home/resources/tutorials/hitchhikers_guide_to_python.yaml new file mode 100644 index 00000000..38eebb56 --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/hitchhikers_guide_to_python.yaml @@ -0,0 +1,10 @@ +description: This opinionated guide exists to provide both novice and expert Python + developers a best practice handbook to the installation, configuration, and usage + of Python on a daily basis. +name: The Hitchhiker's Guide to Python +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: https://python-guide.org/ diff --git a/pydis_site/apps/home/resources/tutorials/sentdex.yaml b/pydis_site/apps/home/resources/tutorials/sentdex.yaml new file mode 100644 index 00000000..cae2695b --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/sentdex.yaml @@ -0,0 +1,8 @@ +description: A Python basics tutorial based around Python 3.7. +name: Python Tutorials by Sentdex on YouTube +payment: free +payment_description: null +urls: +- icon: branding/youtube + title: YouTube + url: https://www.youtube.com/playlist?list=PLQVvvaa0QuDeAams7fkdcwOGBpGdHpXln diff --git a/pydis_site/apps/home/resources/tutorials/simple_guide_to_git.yaml b/pydis_site/apps/home/resources/tutorials/simple_guide_to_git.yaml new file mode 100644 index 00000000..acf76efe --- /dev/null +++ b/pydis_site/apps/home/resources/tutorials/simple_guide_to_git.yaml @@ -0,0 +1,8 @@ +description: A simple, no-nonsense guide to the basics of using Git. +name: A Simple Guide to Git +payment: free +payment_description: null +urls: +- icon: regular/link + title: Website + url: http://rogerdudler.github.io/git-guide/ diff --git a/pydis_site/apps/home/urls.py b/pydis_site/apps/home/urls.py index b22508d9..e65abea4 100644 --- a/pydis_site/apps/home/urls.py +++ b/pydis_site/apps/home/urls.py @@ -8,7 +8,7 @@ from .views import HomeView app_name = 'home' urlpatterns = [ path('', HomeView.as_view(), name='home'), + path('pages/', include('wiki.urls')), path('admin/', admin.site.urls), path('notifications/', include('django_nyt.urls')), - path('wiki/', include('wiki.urls')), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/pydis_site/settings.py b/pydis_site/settings.py index d6c7ed96..2050c6ab 100644 --- a/pydis_site/settings.py +++ b/pydis_site/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/2.1/ref/settings/ """ import os +import secrets import sys import environ @@ -20,11 +21,8 @@ env = environ.Env( DEBUG=(bool, False) ) - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - DEBUG = env('DEBUG') # Quick-start development settings - unsuitable for production @@ -39,11 +37,11 @@ if DEBUG: 'staff.pythondiscord.local', 'wiki.pythondiscord.local', ] - SECRET_KEY = "+_x00w3e94##2-qm-v(5&-x_@*l3t9zlir1etu+7$@4%!it2##" + SECRET_KEY = secrets.token_urlsafe(32) elif 'CI' in os.environ: ALLOWED_HOSTS = ['*'] - SECRET_KEY = "{©ø¬½.Þ7&Ñ`Q^Kº*~¢j<wxß¾±ðÛJ@q" + SECRET_KEY = secrets.token_urlsafe(32) else: ALLOWED_HOSTS = env.list( @@ -53,7 +51,8 @@ else: 'admin.pythondiscord.com', 'api.pythondiscord.com', 'staff.pythondiscord.local', - 'wiki.pythondiscord.local' + 'wiki.pythondiscord.local', + 'django.pythondiscord.com', ] ) SECRET_KEY = env('SECRET_KEY') @@ -98,6 +97,7 @@ MIDDLEWARE = [ 'django_hosts.middleware.HostsRequestMiddleware', 'django.middleware.security.SecurityMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -135,7 +135,6 @@ TEMPLATES = [ WSGI_APPLICATION = 'pydis_site.wsgi.application' - # Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases @@ -143,7 +142,6 @@ DATABASES = { 'default': env.db() } - # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators @@ -162,30 +160,23 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] - # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ - LANGUAGE_CODE = 'en-us' - TIME_ZONE = 'UTC' - USE_I18N = True - USE_L10N = True - USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'pydis_site', 'static')] -STATIC_ROOT = env('STATIC_ROOT', default='staticfiles') +STATIC_ROOT = env('STATIC_ROOT', default='/app/staticfiles') MEDIA_URL = '/media/' -MEDIA_ROOT = env('MEDIA_ROOT', default='media') +MEDIA_ROOT = env('MEDIA_ROOT', default='/app/media') STATICFILES_FINDERS = [ 'django.contrib.staticfiles.finders.FileSystemFinder', @@ -207,7 +198,7 @@ if DEBUG: else: ALLOWED_HOSTS.append(PARENT_HOST) else: - PARENT_HOST = env('PARENT_HOST', default='pythondiscord.com') + PARENT_HOST = env('PARENT_HOST', default='django.pythondiscord.com') # Django REST framework # http://www.django-rest-framework.org @@ -221,7 +212,6 @@ REST_FRAMEWORK = { 'TEST_REQUEST_DEFAULT_FORMAT': 'json' } - # Logging # https://docs.djangoproject.com/en/2.1/topics/logging/ LOGGING = { @@ -288,7 +278,7 @@ BULMA_SETTINGS = { } # Required for the wiki -LOGIN_URL = "/admin/login" # TODO: Update this when the real login system is in place +LOGIN_URL = "/admin/login" # Update this when the real login system is in place SITE_ID = 1 WIKI_ACCOUNT_HANDLING = False @@ -326,3 +316,22 @@ WIKI_MESSAGE_TAG_CSS_CLASS = { messages.SUCCESS: "is-success", messages.WARNING: "is-warning", } + +WIKI_MARKDOWN_HTML_STYLES = [ + 'max-width', + 'min-width', + 'margin', + 'padding', + 'width', + 'height', +] + +WIKI_MARKDOWN_HTML_ATTRIBUTES = { + 'img': ['class', 'id', 'src', 'alt', 'width', 'height'], + 'section': ['class', 'id'], + 'article': ['class', 'id'], +} + +WIKI_MARKDOWN_HTML_WHITELIST = [ + 'article', 'section', 'button' +] diff --git a/pydis_site/static/css/base/base.css b/pydis_site/static/css/base/base.css index 84af21f2..ce1503a3 100644 --- a/pydis_site/static/css/base/base.css +++ b/pydis_site/static/css/base/base.css @@ -42,6 +42,14 @@ div.card.has-equal-height { margin-left: 3rem; } +#navbar-banner { + background-color: transparent; +} + +#navbar-banner img { + max-height: 3rem; +} + #django-logo { padding-bottom: 2px; background: url(https://static.djangoproject.com/img/logos/django-logo-negative.png) no-repeat center; diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css index 3bcd39ab..a90a60d7 100644 --- a/pydis_site/static/css/home/index.css +++ b/pydis_site/static/css/home/index.css @@ -57,16 +57,12 @@ span.repo-language-dot.css { background-color: #563d7c; } -#repo-footer-item { - margin-left: 1.2rem; -} - -#navbar-banner { - background-color: transparent; +span.repo-language-dot.javascript { + background-color: #f1e05a; } -#navbar-banner img { - max-height: 3rem; +#repo-footer-item { + margin-left: 1.2rem; } #sponsors-hero { diff --git a/pydis_site/static/css/wiki/style.css b/pydis_site/static/css/wiki/style.css index db6b4050..9d619e8b 100644 --- a/pydis_site/static/css/wiki/style.css +++ b/pydis_site/static/css/wiki/style.css @@ -1,5 +1,6 @@ #wikiNavbar { min-height: 3rem; + z-index: 1; } #wikiNavbar .container { @@ -31,3 +32,58 @@ ul.pagination-list li + li { margin-top: 0.5rem; margin-bottom: 0.5rem; } + +/* FA icons used in wiki articles */ +i.is-orangered { + color: #FE640A; +} + +i.is-orangered:hover { + color: #fe9840; +} + +i.is-blurple { + color: #7289DA; +} + +i.is-blurple:hover { + color: #93a8da; +} + +i.is-black { + color: #000000; +} + +i.is-black:hover { + color: #191919; +} + +i.is-youtube-red { + color: #BB0000; +} + +i.is-youtube-red:hover { + color: #f80000; +} + +i.is-amazon-orange { + color: #FF9900; +} + +i.is-amazon-orange:hover { + color: #ffb71a; +} + +i.is-teal { + color: #95DBE5; +} + +i.is-teal:hover { + color: #a9f5ff; +} + + + +i.has-icon-padding { + padding: 0 10px 25px 0; +} diff --git a/pydis_site/templates/base/base.html b/pydis_site/templates/base/base.html index d7e764a2..a419521c 100644 --- a/pydis_site/templates/base/base.html +++ b/pydis_site/templates/base/base.html @@ -16,11 +16,7 @@ {% bulma %} {# Font-awesome here is defined explicitly so that we can have Pro #} - <link rel="stylesheet" - href="https://pro.fontawesome.com/releases/v5.7.2/css/all.css" - integrity="sha384-6jHF7Z3XI3fF4XZixAuSu0gGKrXwoX/w3uFPxC56OtjChio7wtTGJWRW53Nhx6Ev" - crossorigin="anonymous" - > + <script src="https://kit.fontawesome.com/ae6a3152d8.js"></script> <link rel="stylesheet" href="{% static "css/base/base.css" %}"> {% block head %}{% endblock %} diff --git a/pydis_site/templates/base/navbar.html b/pydis_site/templates/base/navbar.html index bee503ee..17edd60d 100644 --- a/pydis_site/templates/base/navbar.html +++ b/pydis_site/templates/base/navbar.html @@ -61,20 +61,23 @@ More </a> <div class="navbar-dropdown"> - <a class="navbar-item"> - Resources + <a class="navbar-item" href="{% url 'wiki:get' path="resources/" %}"> + Learning Resources </a> - <a class="navbar-item"> + <a class="navbar-item" href="{% url 'wiki:get' path="tools/" %}"> + Tools + </a> + <a class="navbar-item" href="{% url 'wiki:get' path="frequently-asked-questions/" %}"> FAQ </a> - <a class="navbar-item"> + <a class="navbar-item" href="{% url 'wiki:get' path="rules/" %}"> Rules </a> - <a class="navbar-item"> + <a class="navbar-item" href="{% url 'wiki:get' path="privacy/" %}"> Privacy </a> <hr class="navbar-divider"> - <a class="navbar-item"> + <a class="navbar-item" href="{% url 'wiki:get' path="code-jams/" %}"> Code Jams </a> </div> diff --git a/pydis_site/templates/wiki/base.html b/pydis_site/templates/wiki/base.html index 192c25f6..36349758 100644 --- a/pydis_site/templates/wiki/base.html +++ b/pydis_site/templates/wiki/base.html @@ -2,9 +2,7 @@ {% load static %} {% load wiki_tags %} -{% block title %} - Wiki | {% block wiki_pagetitle %}{% endblock %}{% block wiki_site_title %}{% endblock %} -{% endblock %} +{% block title %}{% block wiki_pagetitle %}{% endblock %}{% block wiki_site_title %}{% endblock %}{% endblock %} {% block head %} {{ block.super }} diff --git a/pydis_site/templates/wiki/create_root.html b/pydis_site/templates/wiki/create_root.html index 330fea33..2d09089d 100644 --- a/pydis_site/templates/wiki/create_root.html +++ b/pydis_site/templates/wiki/create_root.html @@ -32,11 +32,7 @@ <form method="POST" class="form-horizontal"> {% wiki_form form %} - <div class="field is-horizontal"> - <div class="field-label"> - {# Empty for spacing #} - </div> <div class="field-body"> <div class="control"> <button type="submit" class="button is-primary" name="save_changes"> diff --git a/pydis_site/utils/resources.py b/pydis_site/utils/resources.py new file mode 100644 index 00000000..ab0df9d7 --- /dev/null +++ b/pydis_site/utils/resources.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import glob +import typing +from dataclasses import dataclass + +import yaml + + +@dataclass +class URL: + """A class representing a link to a resource""" + icon: str + title: str + url: str + + +class Resource: + """A class representing a resource on the resource page""" + description: str + name: str + payment: str + payment_description: typing.Optional[str] + urls: typing.List[URL] + + def __repr__(self): + """Return a representation of the resource""" + return f"<Resource name={self.name}>" + + @classmethod + def construct_from_yaml(cls, yaml_data: str) -> Resource: # noqa + resource = cls() + + loaded = yaml.safe_load(yaml_data) + + resource.__dict__.update(loaded) + + resource.__dict__["urls"] = [] + + for url in loaded["urls"]: + resource.__dict__["urls"].append(URL(**url)) + + return resource + + +class Category: + """A class representing a resource on the resources page""" + resources: typing.List[Resource] + name: str + description: str + + def __repr__(self): + """Return a representation of the category""" + return f"<Category name={self.name}>" + + @classmethod + def construct_from_directory(cls, directory: str) -> Category: # noqa + category = cls() + + with open(f"{directory}/_category_info.yaml") as category_info: + category_data = yaml.safe_load(category_info) + + category.__dict__.update(category_data) + + category.resources = [] + + for resource in glob.glob(f"{directory}/*.yaml"): + if resource == f"{directory}/_category_info.yaml": + continue + + with open(resource) as res_file: + category.resources.append( + Resource.construct_from_yaml(res_file) + ) + + return category + + +def load_categories(order: typing.List[str]) -> typing.List[Category]: + """Load the categories specified in the order list and return them""" + categories = [] + for cat in order: + direc = "pydis_site/apps/home/resources/" + cat + categories.append(Category.construct_from_directory(direc)) + + return categories |