aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Matteo Bertucci <[email protected]>2020-01-12 12:39:42 +0100
committerGravatar GitHub <[email protected]>2020-01-12 12:39:42 +0100
commitacc8b5e5de72e63c37959cd4e62b1e6e462b25ee (patch)
tree0e3ec2b9a6b45785d764f5e445626662618cbab6
parentMerge branch 'bot#549-show-attachments-staff' of https://github.com/python-di... (diff)
parentAdding iframe attributes to attribute whitelist (diff)
Merge branch 'master' into bot#549-show-attachments-staff
-rw-r--r--Pipfile2
-rw-r--r--Pipfile.lock178
-rw-r--r--README.md2
-rw-r--r--pydis_site/apps/api/admin.py2
-rw-r--r--pydis_site/apps/api/migrations/0049_offensivemessage.py25
-rw-r--r--pydis_site/apps/api/models/__init__.py1
-rw-r--r--pydis_site/apps/api/models/bot/__init__.py1
-rw-r--r--pydis_site/apps/api/models/bot/offensive_message.py48
-rw-r--r--pydis_site/apps/api/serializers.py11
-rw-r--r--pydis_site/apps/api/tests/test_models.py6
-rw-r--r--pydis_site/apps/api/tests/test_offensive_message.py155
-rw-r--r--pydis_site/apps/api/tests/test_validators.py12
-rw-r--r--pydis_site/apps/api/urls.py7
-rw-r--r--pydis_site/apps/api/views.py2
-rw-r--r--pydis_site/apps/api/viewsets/__init__.py1
-rw-r--r--pydis_site/apps/api/viewsets/bot/__init__.py1
-rw-r--r--pydis_site/apps/api/viewsets/bot/offensive_message.py61
-rw-r--r--pydis_site/settings.py3
-rw-r--r--pydis_site/static/css/base/base.css5
-rw-r--r--pydis_site/templates/home/index.html8
-rw-r--r--pydis_site/utils/account.py2
21 files changed, 434 insertions, 99 deletions
diff --git a/Pipfile b/Pipfile
index cb5776e0..c765d557 100644
--- a/Pipfile
+++ b/Pipfile
@@ -4,7 +4,7 @@ url = "https://pypi.org/simple"
verify_ssl = true
[packages]
-django = "~=2.2.0"
+django = "~=2.2.8"
django-crispy-forms = "~=1.7.2"
django-environ = "~=0.4.5"
django-filter = "~=2.1.0"
diff --git a/Pipfile.lock b/Pipfile.lock
index 06b49ce7..fea7251c 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "a4bfc709fcdecf5a3bd28326d51625c83a8a7661367cc69dbda20e3a55f1d9d3"
+ "sha256": "dc3468691aed07cf8a9238256cc1b273669d0331a11e105b2d6adc1e19803020"
},
"pipfile-spec": 6,
"requires": {
@@ -25,10 +25,10 @@
},
"certifi": {
"hashes": [
- "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
- "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
+ "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
+ "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
],
- "version": "==2019.9.11"
+ "version": "==2019.11.28"
},
"chardet": {
"hashes": [
@@ -46,11 +46,11 @@
},
"django": {
"hashes": [
- "sha256:4025317ca01f75fc79250ff7262a06d8ba97cd4f82e93394b2a0a6a4a925caeb",
- "sha256:a8ca1033acac9f33995eb2209a6bf18a4681c3e5269a878e9a7e0b7384ed1ca3"
+ "sha256:a4ad4f6f9c6a4b7af7e2deec8d0cbff28501852e5010d6c2dc695d3d1fae7ca0",
+ "sha256:fa98ec9cc9bf5d72a08ebf3654a9452e761fbb8566e3f80de199cbc15477e891"
],
"index": "pypi",
- "version": "==2.2.6"
+ "version": "==2.2.8"
},
"django-allauth": {
"hashes": [
@@ -121,10 +121,10 @@
},
"django-nyt": {
"hashes": [
- "sha256:187f2aae5088c4cf79e7a7caa55c2a9c292722f50cf185c5a738636713ae67ea",
- "sha256:5556e2de47a7b710325a33c49314ee3eff7021d638492e957ef2de15c9360143"
+ "sha256:a696a52a0b729465c062b4808d2ad8c43b439561b2f9654328040c646abb3732",
+ "sha256:b16bffcfcb468f7b5c70f61de79294a88b7df63859675721d3417507e3440d15"
],
- "version": "==1.1.3"
+ "version": "==1.1.5"
},
"django-sekizai": {
"hashes": [
@@ -171,24 +171,24 @@
},
"libsass": {
"hashes": [
- "sha256:175355d74bd040893d539154016153247ea9775d1655a36441c97a453887a0c0",
- "sha256:3113ef32eaf3662c162c250db6883d7a5f177856bfd8bb632a147cb0a95e4fee",
- "sha256:312d135e6bd1a137927fed781dab497c05930305265e3d3b1da3b3d916cd97a6",
- "sha256:32f8322aad9b6b864b826adb5e193d704d5fb2c816f85a5cc5bf775730e5d024",
- "sha256:4252e24c8869d6ce764052f200445331d1881b5c2d283d6131a30d0684b10403",
- "sha256:517324814f81cd2642cb1e9fd772e8e50e336c7c8833d50535a731e5b4c84606",
- "sha256:607ce32c3b31542e0bf1bc2409627dd7247a3849ba720ec34d23426b96346199",
- "sha256:6124594e72ba216b00131795ad5ea5de1e0cf8784e63a01e0c6a4e4c13fc7914",
- "sha256:6129063002fc8337b734f5963ac3eb01ead51e9c88c6d27e73ddc9236cb15b2e",
- "sha256:6d392ecd6e4de2ccfa3b1953f2da8461a2b7c8c8c17c24e1c335ab3040671c1a",
- "sha256:75b38c236be6ca03e3dd3789f3044180fc0836b7c9e4991fcc52a8570f47dc91",
- "sha256:9c711d4e4d003fec7f98fe87bb1faf7d88e6d648356413d8b8d9d76bd1844089",
- "sha256:b15a0e61bd54764e658bc6931015453fa34d954f87c3b6fd35624e13bcacf69d",
- "sha256:bc0c80a4e233b6b791a7f6f99415ab877e8a4d3a45085b68981c97d74dbfc8bf",
- "sha256:c22cdc37121b730e5fb87bc8d3eee8c4b1fe219a04d198a535fbd22895c99e27",
- "sha256:c5ba74babfb3a6976611312e0026c4668913cdf05e009921e1f54146ccdc02a4"
- ],
- "version": "==0.19.3"
+ "sha256:003a65b4facb4c5dbace53fb0f70f61c5aae056a04b4d112a198c3c9674b31f2",
+ "sha256:0fd8b4337b3b101c6e6afda9112cc0dc4bacb9133b59d75d65968c7317aa3272",
+ "sha256:338e9ae066bf1fde874e335324d5355c52d2081d978b4f74fc59536564b35b08",
+ "sha256:4dcfd561fb100250b89496e1362b96f2cc804f689a59731eb0f94f9a9e144f4a",
+ "sha256:50778d4be269a021ba2bf42b5b8f6ff3704ab96a82175a052680bddf3ba7cc9f",
+ "sha256:6a51393d75f6e3c812785b0fa0b7d67c54258c28011921f204643b55f7355ec0",
+ "sha256:74acd9adf506142699dfa292f0e569fdccbd9e7cf619e8226f7117de73566e32",
+ "sha256:81a013a4c2a614927fd1ef7a386eddabbba695cbb02defe8f31cf495106e974c",
+ "sha256:845a9573b25c141164972d498855f4ad29367c09e6d76fad12955ad0e1c83013",
+ "sha256:8b5b6d1a7c4ea1d954e0982b04474cc076286493f6af2d0a13c2e950fbe0be95",
+ "sha256:9b59afa0d755089c4165516400a39a289b796b5612eeef5736ab7a1ebf96a67c",
+ "sha256:a7e685466448c9b1bf98243339793978f654a1151eb5c975f09b83c7a226f4c1",
+ "sha256:c93df526eeef90b1ea4799c1d33b6cd5aea3e9f4633738fb95c1287c13e6b404",
+ "sha256:e318f06f06847ff49b1f8d086ac9ebce1e63404f7ea329adab92f4f16ba0e00e",
+ "sha256:fc5f8336750f76f1bfae82f7e9e89ae71438d26fc4597e3ab4c05ca8fcd41d8a",
+ "sha256:fcb7ab4dc81889e5fc99cafbc2017bc76996f9992fc6b175f7a80edac61d71df"
+ ],
+ "version": "==0.19.4"
},
"markdown": {
"hashes": [
@@ -206,34 +206,30 @@
},
"pillow": {
"hashes": [
- "sha256:00fdeb23820f30e43bba78eb9abb00b7a937a655de7760b2e09101d63708b64e",
- "sha256:01f948e8220c85eae1aa1a7f8edddcec193918f933fb07aaebe0bfbbcffefbf1",
- "sha256:08abf39948d4b5017a137be58f1a52b7101700431f0777bec3d897c3949f74e6",
- "sha256:099a61618b145ecb50c6f279666bbc398e189b8bc97544ae32b8fcb49ad6b830",
- "sha256:2c1c61546e73de62747e65807d2cc4980c395d4c5600ecb1f47a650c6fa78c79",
- "sha256:2ed9c4f694861642401f27dc3cb99772be67cd190e84845c749dae0a06c3bfae",
- "sha256:338581b30b908e111be578f0297255f6b57a51358cd16fa0e6f664c9a1f88bff",
- "sha256:38c7d48a21cd06fdeee93987147b9b1c55b73b4cfcbf83240568bfbd5adee447",
- "sha256:43fd026f613c8e48a25eba1a92f4d2ad7f3903c95d8c33a11611a7717d2ab654",
- "sha256:4548236844327a718ce3bb182ab32a16fa2050c61e334e959f554cac052fb0df",
- "sha256:5090857876c58885cfa388dc649e5db30aae98a068c26f3fd0ac9d7d9a4d9572",
- "sha256:5bbba34f97a26a93f5e8dec469ca4ddd712451418add43da946dbaed7f7a98d2",
- "sha256:65a28969a025a0eb4594637b6103201dc4ed2a9508bdab56ac33e43e3081c404",
- "sha256:892bb52b70bd5ea9dbbc3ac44f38e84f5a04e9d8b1bff48159d96cb795b81159",
- "sha256:8a9becd5cbd5062f973bcd2e7bc79483af310222de112b6541f8af1f93a3cc42",
- "sha256:972a7aaeb7c4a2795b52eef52ee991ef040b31009f36deca6207a986607b55f3",
- "sha256:97b119c436bfa96a92ac2ca525f7025836d4d4e64b1c9f9eff8dbaf3ff1d86f3",
- "sha256:9ba37698e242223f8053cc158f130aee046a96feacbeab65893dbe94f5530118",
- "sha256:b1b0e1f626a0f079c0d3696db70132fb1f29aa87c66aecb6501a9b8be64ce9f7",
- "sha256:c14c1224fd1a5be2733530d648a316974dbbb3c946913562c6005a76f21ca042",
- "sha256:c79a8546c48ae6465189e54e3245a97ddf21161e33ff7eaa42787353417bb2b6",
- "sha256:ceb76935ac4ebdf6d7bc845482a4450b284c6ccfb281e34da51d510658ab34d8",
- "sha256:e22bffaad04b4d16e1c091baed7f2733fc1ebb91e0c602abf1b6834d17158b1f",
- "sha256:ec883b8e44d877bda6f94a36313a1c6063f8b1997aa091628ae2f34c7f97c8d5",
- "sha256:f1baa54d50ec031d1a9beb89974108f8f2c0706f49798f4777df879df0e1adb6",
- "sha256:f53a5385932cda1e2c862d89460992911a89768c65d176ff8c50cddca4d29bed"
- ],
- "version": "==6.2.0"
+ "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be",
+ "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946",
+ "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837",
+ "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f",
+ "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00",
+ "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d",
+ "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533",
+ "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a",
+ "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358",
+ "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda",
+ "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435",
+ "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2",
+ "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313",
+ "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff",
+ "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317",
+ "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2",
+ "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614",
+ "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0",
+ "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386",
+ "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9",
+ "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636",
+ "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865"
+ ],
+ "version": "==7.0.0"
},
"psycopg2-binary": {
"hashes": [
@@ -259,11 +255,13 @@
"sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e",
"sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103",
"sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6",
+ "sha256:98e10634792ac0e9e7a92a76b4991b44c2325d3e7798270a808407355e7bb0a1",
"sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9",
"sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e",
"sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f",
"sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd",
"sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8",
+ "sha256:b8f490f5fad1767a1331df1259763b3bad7d7af12a75b950c2843ba319b2415f",
"sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4",
"sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964",
"sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08"
@@ -308,6 +306,7 @@
"sha256:861c94442b28cd64af033e88e0f63c66dbd5609f67952dc18694098b47a43f3a",
"sha256:957bc6316ffc8463795d56d9953d58e7f32aa5aad1c5ac80bc45c69f3299961e",
"sha256:9760c3f56fb5f15852d163429096600906478e9ed2c189a52f2bb21d8a2a986c",
+ "sha256:9fdfb98a2992de01e8efad2aeed22c825e36db628b144b2d6b93d81fb549f811",
"sha256:a4b24703ea818196d0be1dc64b3b57b79c67e8dee0cfa207a4216220912035a7",
"sha256:ad7f4968c1ddbf139a306d9b075360d959cc554d994ba5e1f512af9a40e62357",
"sha256:b1127d34b90f74faf1707718c57a4193ac028b9f4aec0238638983132297d456",
@@ -318,6 +317,7 @@
"sha256:ce777ebdf49ce736fc04abf555b5c41ab3f130127543a689dcf8d4871cd18fe4",
"sha256:d8b4bf930b6a19bc9ee982b9163d948c87501ad91b71516924e8ed25fe85d2ee",
"sha256:e2a420f2c4d35f3ec0b7e752a80d7bd385e2c5a64f67c05f2d2d74230e3114b6",
+ "sha256:ef5eb630f541af6b69378d58594be90a0922fa6d6a50a9248c25b9502585f6bf",
"sha256:fed899ce96f4f2b4d1b9f338dd145a4040ee1d8a5152213af0dd8d4a4d36e9fe"
],
"index": "pypi",
@@ -353,17 +353,17 @@
},
"requests-oauthlib": {
"hashes": [
- "sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57",
- "sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140"
+ "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
+ "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
],
- "version": "==1.2.0"
+ "version": "==1.3.0"
},
"six": {
"hashes": [
- "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
- "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
+ "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
+ "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
- "version": "==1.12.0"
+ "version": "==1.13.0"
},
"sorl-thumbnail": {
"hashes": [
@@ -381,10 +381,10 @@
},
"urllib3": {
"hashes": [
- "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398",
- "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86"
+ "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
+ "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
],
- "version": "==1.25.6"
+ "version": "==1.25.7"
},
"webencodings": {
"hashes": [
@@ -569,24 +569,24 @@
},
"gitpython": {
"hashes": [
- "sha256:631263cc670aa56ce3d3c414cf0fe2e840f2e913514b138ea28d88a477bbcd21",
- "sha256:6e97b9f0954807f30c2dd8e3165731ed6c477a1b365f194b69d81d7940a08332"
+ "sha256:9c2398ffc3dcb3c40b27324b316f08a4f93ad646d5a6328cafbb871aa79f5e42",
+ "sha256:c155c6a2653593ccb300462f6ef533583a913e17857cfef8fc617c246b6dc245"
],
- "version": "==3.0.3"
+ "version": "==3.0.5"
},
"identify": {
"hashes": [
- "sha256:4f1fe9a59df4e80fcb0213086fcf502bc1765a01ea4fe8be48da3b65afd2a017",
- "sha256:d8919589bd2a5f99c66302fec0ef9027b12ae150b0b0213999ad3f695fc7296e"
+ "sha256:6f44e637caa40d1b4cb37f6ed3b262ede74901d28b1cc5b1fc07360871edd65d",
+ "sha256:72e9c4ed3bc713c7045b762b0d2e2115c572b85abfc1f4604f5a4fd4c6642b71"
],
- "version": "==1.4.7"
+ "version": "==1.4.9"
},
"importlib-metadata": {
"hashes": [
- "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
- "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
+ "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45",
+ "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"
],
- "version": "==0.23"
+ "version": "==1.3.0"
},
"mccabe": {
"hashes": [
@@ -598,10 +598,10 @@
},
"more-itertools": {
"hashes": [
- "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832",
- "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"
+ "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d",
+ "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564"
],
- "version": "==7.2.0"
+ "version": "==8.0.2"
},
"nodeenv": {
"hashes": [
@@ -611,10 +611,10 @@
},
"pbr": {
"hashes": [
- "sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8",
- "sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9"
+ "sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b",
+ "sha256:61aa52a0f18b71c5cc58232d2cf8f8d09cd67fcad60b742a60124cb8d6951488"
],
- "version": "==5.4.3"
+ "version": "==5.4.4"
},
"pep8-naming": {
"hashes": [
@@ -641,10 +641,10 @@
},
"pydocstyle": {
"hashes": [
- "sha256:04c84e034ebb56eb6396c820442b8c4499ac5eb94a3bda88951ac3dc519b6058",
- "sha256:66aff87ffe34b1e49bff2dd03a88ce6843be2f3346b0c9814410d34987fbab59"
+ "sha256:4167fe954b8f27ebbbef2fbcf73c6e8ad1e7bb31488fce44a69fdfc4b0cd0fae",
+ "sha256:a0de36e549125d0a16a72a8c8c6c9ba267750656e72e466e994c222f1b6e92cb"
],
- "version": "==4.0.1"
+ "version": "==5.0.1"
},
"pyflakes": {
"hashes": [
@@ -674,10 +674,10 @@
},
"six": {
"hashes": [
- "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
- "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
+ "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
+ "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
- "version": "==1.12.0"
+ "version": "==1.13.0"
},
"smmap2": {
"hashes": [
@@ -742,10 +742,10 @@
},
"virtualenv": {
"hashes": [
- "sha256:3e3597e89c73df9313f5566e8fc582bd7037938d15b05329c232ec57a11a7ad5",
- "sha256:5d370508bf32e522d79096e8cbea3499d47e624ac7e11e9089f9397a0b3318df"
+ "sha256:0d62c70883c0342d59c11d0ddac0d954d0431321a41ab20851facf2b222598f3",
+ "sha256:55059a7a676e4e19498f1aad09b8313a38fcc0cdbe4fdddc0e9b06946d21b4bb"
],
- "version": "==16.7.6"
+ "version": "==16.7.9"
},
"zipp": {
"hashes": [
diff --git a/README.md b/README.md
index df0417e4..86509beb 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Python Discord: Site
-[![Discord](https://img.shields.io/discord/267624335836053506?color=%237289DA&label=Python%20Discord&logo=discord&logoColor=white)](https://discord.gg/2B963hn)
+[![Discord](https://img.shields.io/static/v1?label=Python%20Discord&logo=discord&message=%3E30k%20members&color=%237289DA&logoColor=white)](https://discord.gg/2B963hn)
[![Build Status](https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Site?branchName=master)](https://dev.azure.com/python-discord/Python%20Discord/_build/latest?definitionId=2&branchName=master)
[![Tests](https://img.shields.io/azure-devops/tests/python-discord/Python%20Discord/2?compact_message)](https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Site?branchName=master)
[![Coverage](https://img.shields.io/azure-devops/coverage/python-discord/Python%20Discord/2/master)](https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Site?branchName=master)
diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py
index 059f52eb..0333fefc 100644
--- a/pydis_site/apps/api/admin.py
+++ b/pydis_site/apps/api/admin.py
@@ -12,6 +12,7 @@ from .models import (
MessageDeletionContext,
Nomination,
OffTopicChannelName,
+ OffensiveMessage,
Role,
Tag,
User
@@ -60,6 +61,7 @@ admin.site.register(Infraction)
admin.site.register(LogEntry, LogEntryAdmin)
admin.site.register(MessageDeletionContext)
admin.site.register(Nomination)
+admin.site.register(OffensiveMessage)
admin.site.register(OffTopicChannelName)
admin.site.register(Role)
admin.site.register(Tag)
diff --git a/pydis_site/apps/api/migrations/0049_offensivemessage.py b/pydis_site/apps/api/migrations/0049_offensivemessage.py
new file mode 100644
index 00000000..fe4a1961
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0049_offensivemessage.py
@@ -0,0 +1,25 @@
+# Generated by Django 2.2.6 on 2019-11-07 18:08
+
+import django.core.validators
+from django.db import migrations, models
+import pydis_site.apps.api.models.bot.offensive_message
+import pydis_site.apps.api.models.utils
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0048_add_infractions_unique_constraints_active'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OffensiveMessage',
+ fields=[
+ ('id', models.BigIntegerField(help_text='The message ID as taken from Discord.', primary_key=True, serialize=False, validators=[django.core.validators.MinValueValidator(limit_value=0, message='Message IDs cannot be negative.')])),
+ ('channel_id', models.BigIntegerField(help_text='The channel ID that the message was sent in, taken from Discord.', validators=[django.core.validators.MinValueValidator(limit_value=0, message='Channel IDs cannot be negative.')])),
+ ('delete_date', models.DateTimeField(help_text='The date on which the message will be auto-deleted.', validators=[pydis_site.apps.api.models.bot.offensive_message.future_date_validator])),
+ ],
+ bases=(pydis_site.apps.api.models.utils.ModelReprMixin, models.Model),
+ ),
+ ]
diff --git a/pydis_site/apps/api/models/__init__.py b/pydis_site/apps/api/models/__init__.py
index a4656bc3..450d18cd 100644
--- a/pydis_site/apps/api/models/__init__.py
+++ b/pydis_site/apps/api/models/__init__.py
@@ -7,6 +7,7 @@ from .bot import (
Message,
MessageDeletionContext,
Nomination,
+ OffensiveMessage,
OffTopicChannelName,
Reminder,
Role,
diff --git a/pydis_site/apps/api/models/bot/__init__.py b/pydis_site/apps/api/models/bot/__init__.py
index 46219ea2..8ae47746 100644
--- a/pydis_site/apps/api/models/bot/__init__.py
+++ b/pydis_site/apps/api/models/bot/__init__.py
@@ -7,6 +7,7 @@ from .message import Message
from .message_deletion_context import MessageDeletionContext
from .nomination import Nomination
from .off_topic_channel_name import OffTopicChannelName
+from .offensive_message import OffensiveMessage
from .reminder import Reminder
from .role import Role
from .tag import Tag
diff --git a/pydis_site/apps/api/models/bot/offensive_message.py b/pydis_site/apps/api/models/bot/offensive_message.py
new file mode 100644
index 00000000..b466d9c2
--- /dev/null
+++ b/pydis_site/apps/api/models/bot/offensive_message.py
@@ -0,0 +1,48 @@
+import datetime
+
+from django.core.exceptions import ValidationError
+from django.core.validators import MinValueValidator
+from django.db import models
+
+from pydis_site.apps.api.models.utils import ModelReprMixin
+
+
+def future_date_validator(date: datetime.date) -> None:
+ """Raise ValidationError if the date isn't a future date."""
+ if date < datetime.datetime.now(datetime.timezone.utc):
+ raise ValidationError("Date must be a future date")
+
+
+class OffensiveMessage(ModelReprMixin, models.Model):
+ """A message that triggered a filter and that will be deleted one week after it was sent."""
+
+ id = models.BigIntegerField(
+ primary_key=True,
+ help_text="The message ID as taken from Discord.",
+ validators=(
+ MinValueValidator(
+ limit_value=0,
+ message="Message IDs cannot be negative."
+ ),
+ )
+ )
+ channel_id = models.BigIntegerField(
+ help_text=(
+ "The channel ID that the message was "
+ "sent in, taken from Discord."
+ ),
+ validators=(
+ MinValueValidator(
+ limit_value=0,
+ message="Channel IDs cannot be negative."
+ ),
+ )
+ )
+ delete_date = models.DateTimeField(
+ help_text="The date on which the message will be auto-deleted.",
+ validators=(future_date_validator,)
+ )
+
+ def __str__(self):
+ """Return some info on this message, for display purposes only."""
+ return f"Message {self.id}, will be deleted at {self.delete_date}"
diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py
index 2af04e0e..0d1a4684 100644
--- a/pydis_site/apps/api/serializers.py
+++ b/pydis_site/apps/api/serializers.py
@@ -8,6 +8,7 @@ from .models import (
DocumentationLink, Infraction,
LogEntry, MessageDeletionContext,
Nomination, OffTopicChannelName,
+ OffensiveMessage,
Reminder, Role,
Tag, User
)
@@ -248,3 +249,13 @@ class NominationSerializer(ModelSerializer):
fields = (
'id', 'active', 'actor', 'reason', 'user',
'inserted_at', 'end_reason', 'ended_at')
+
+
+class OffensiveMessageSerializer(ModelSerializer):
+ """A class providing (de-)serialization of `OffensiveMessage` instances."""
+
+ class Meta:
+ """Metadata defined for the Django REST Framework."""
+
+ model = OffensiveMessage
+ fields = ('id', 'channel_id', 'delete_date')
diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py
index b4a766d0..a97d3251 100644
--- a/pydis_site/apps/api/tests/test_models.py
+++ b/pydis_site/apps/api/tests/test_models.py
@@ -12,6 +12,7 @@ from ..models import (
ModelReprMixin,
Nomination,
OffTopicChannelName,
+ OffensiveMessage,
Reminder,
Role,
Tag,
@@ -69,6 +70,11 @@ class StringDunderMethodTests(SimpleTestCase):
DocumentationLink(
'test', 'http://example.com', 'http://example.com'
),
+ OffensiveMessage(
+ id=602951077675139072,
+ channel_id=291284109232308226,
+ delete_date=dt(3000, 1, 1)
+ ),
OffTopicChannelName(name='bob-the-builders-playground'),
Role(
id=5, name='test role',
diff --git a/pydis_site/apps/api/tests/test_offensive_message.py b/pydis_site/apps/api/tests/test_offensive_message.py
new file mode 100644
index 00000000..d5896714
--- /dev/null
+++ b/pydis_site/apps/api/tests/test_offensive_message.py
@@ -0,0 +1,155 @@
+import datetime
+
+from django_hosts.resolvers import reverse
+
+from .base import APISubdomainTestCase
+from ..models import OffensiveMessage
+
+
+class CreationTests(APISubdomainTestCase):
+ def test_accept_valid_data(self):
+ url = reverse('bot:offensivemessage-list', host='api')
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ data = {
+ 'id': '602951077675139072',
+ 'channel_id': '291284109232308226',
+ 'delete_date': delete_at.isoformat()[:-1]
+ }
+
+ aware_delete_at = delete_at.replace(tzinfo=datetime.timezone.utc)
+
+ response = self.client.post(url, data=data)
+ self.assertEqual(response.status_code, 201)
+
+ offensive_message = OffensiveMessage.objects.get(id=response.json()['id'])
+ self.assertAlmostEqual(
+ aware_delete_at,
+ offensive_message.delete_date,
+ delta=datetime.timedelta(seconds=1)
+ )
+ self.assertEqual(data['id'], str(offensive_message.id))
+ self.assertEqual(data['channel_id'], str(offensive_message.channel_id))
+
+ def test_returns_400_on_non_future_date(self):
+ url = reverse('bot:offensivemessage-list', host='api')
+ delete_at = datetime.datetime.now() - datetime.timedelta(days=1)
+ data = {
+ 'id': '602951077675139072',
+ 'channel_id': '291284109232308226',
+ 'delete_date': delete_at.isoformat()[:-1]
+ }
+ response = self.client.post(url, data=data)
+ self.assertEqual(response.status_code, 400)
+ self.assertEqual(response.json(), {
+ 'delete_date': ['Date must be a future date']
+ })
+
+ def test_returns_400_on_negative_id_or_channel_id(self):
+ url = reverse('bot:offensivemessage-list', host='api')
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ data = {
+ 'id': '602951077675139072',
+ 'channel_id': '291284109232308226',
+ 'delete_date': delete_at.isoformat()[:-1]
+ }
+ cases = (
+ ('id', '-602951077675139072'),
+ ('channel_id', '-291284109232308226')
+ )
+
+ for field, invalid_value in cases:
+ with self.subTest(fied=field, invalid_value=invalid_value):
+ test_data = data.copy()
+ test_data.update({field: invalid_value})
+
+ response = self.client.post(url, test_data)
+ self.assertEqual(response.status_code, 400)
+ self.assertEqual(response.json(), {
+ field: ['Ensure this value is greater than or equal to 0.']
+ })
+
+
+class ListTests(APISubdomainTestCase):
+ @classmethod
+ def setUpTestData(cls): # noqa
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ aware_delete_at = delete_at.replace(tzinfo=datetime.timezone.utc)
+
+ cls.messages = [
+ {
+ 'id': 602951077675139072,
+ 'channel_id': 91284109232308226,
+ },
+ {
+ 'id': 645298201494159401,
+ 'channel_id': 592000283102674944
+ }
+ ]
+
+ cls.of1 = OffensiveMessage.objects.create(
+ **cls.messages[0],
+ delete_date=aware_delete_at.isoformat()
+ )
+ cls.of2 = OffensiveMessage.objects.create(
+ **cls.messages[1],
+ delete_date=aware_delete_at.isoformat()
+ )
+
+ # Expected API answer :
+ cls.messages[0]['delete_date'] = delete_at.isoformat() + 'Z'
+ cls.messages[1]['delete_date'] = delete_at.isoformat() + 'Z'
+
+ def test_get_data(self):
+ url = reverse('bot:offensivemessage-list', host='api')
+
+ response = self.client.get(url)
+ self.assertEqual(response.status_code, 200)
+
+ self.assertEqual(response.json(), self.messages)
+
+
+class DeletionTests(APISubdomainTestCase):
+ @classmethod
+ def setUpTestData(cls): # noqa
+ delete_at = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=1)
+
+ cls.valid_offensive_message = OffensiveMessage.objects.create(
+ id=602951077675139072,
+ channel_id=291284109232308226,
+ delete_date=delete_at.isoformat()
+ )
+
+ def test_delete_data(self):
+ url = reverse(
+ 'bot:offensivemessage-detail', host='api', args=(self.valid_offensive_message.id,)
+ )
+
+ response = self.client.delete(url)
+ self.assertEqual(response.status_code, 204)
+
+ self.assertFalse(
+ OffensiveMessage.objects.filter(id=self.valid_offensive_message.id).exists()
+ )
+
+
+class NotAllowedMethodsTests(APISubdomainTestCase):
+ @classmethod
+ def setUpTestData(cls): # noqa
+ delete_at = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=1)
+
+ cls.valid_offensive_message = OffensiveMessage.objects.create(
+ id=602951077675139072,
+ channel_id=291284109232308226,
+ delete_date=delete_at.isoformat()
+ )
+
+ def test_returns_405_for_patch_and_put_requests(self):
+ url = reverse(
+ 'bot:offensivemessage-detail', host='api', args=(self.valid_offensive_message.id,)
+ )
+ not_allowed_methods = (self.client.patch, self.client.put)
+
+ for method in not_allowed_methods:
+ with self.subTest(method=method):
+ response = method(url, {})
+ self.assertEqual(response.status_code, 405)
diff --git a/pydis_site/apps/api/tests/test_validators.py b/pydis_site/apps/api/tests/test_validators.py
index 4222f0c0..241af08c 100644
--- a/pydis_site/apps/api/tests/test_validators.py
+++ b/pydis_site/apps/api/tests/test_validators.py
@@ -1,7 +1,10 @@
+from datetime import datetime, timezone
+
from django.core.exceptions import ValidationError
from django.test import TestCase
from ..models.bot.bot_setting import validate_bot_setting_name
+from ..models.bot.offensive_message import future_date_validator
from ..models.bot.tag import validate_tag_embed
@@ -245,3 +248,12 @@ class TagEmbedValidatorTests(TestCase):
'name': "Bob"
}
})
+
+
+class OffensiveMessageValidatorsTests(TestCase):
+ def test_accepts_future_date(self):
+ future_date_validator(datetime(3000, 1, 1, tzinfo=timezone.utc))
+
+ def test_rejects_non_future_date(self):
+ with self.assertRaises(ValidationError):
+ future_date_validator(datetime(1000, 1, 1, tzinfo=timezone.utc))
diff --git a/pydis_site/apps/api/urls.py b/pydis_site/apps/api/urls.py
index ac6704c8..4a0281b4 100644
--- a/pydis_site/apps/api/urls.py
+++ b/pydis_site/apps/api/urls.py
@@ -6,7 +6,8 @@ from .viewsets import (
BotSettingViewSet, DeletedMessageViewSet,
DocumentationLinkViewSet, InfractionViewSet,
LogEntryViewSet, NominationViewSet,
- OffTopicChannelNameViewSet, ReminderViewSet,
+ OffTopicChannelNameViewSet,
+ OffensiveMessageViewSet, ReminderViewSet,
RoleViewSet, TagViewSet, UserViewSet
)
@@ -34,6 +35,10 @@ bot_router.register(
NominationViewSet
)
bot_router.register(
+ 'offensive-messages',
+ OffensiveMessageViewSet
+)
+bot_router.register(
'off-topic-channel-names',
OffTopicChannelNameViewSet,
base_name='offtopicchannelname'
diff --git a/pydis_site/apps/api/views.py b/pydis_site/apps/api/views.py
index f0f7efa9..fd5a6d4d 100644
--- a/pydis_site/apps/api/views.py
+++ b/pydis_site/apps/api/views.py
@@ -110,7 +110,7 @@ class RulesView(APIView):
)
discord_tos = self._format_link(
'Terms Of Service',
- 'https://discordapp.com/guidelines',
+ 'https://discordapp.com/terms',
link_format
)
pydis_coc = self._format_link(
diff --git a/pydis_site/apps/api/viewsets/__init__.py b/pydis_site/apps/api/viewsets/__init__.py
index f9a186d9..3cf9f641 100644
--- a/pydis_site/apps/api/viewsets/__init__.py
+++ b/pydis_site/apps/api/viewsets/__init__.py
@@ -5,6 +5,7 @@ from .bot import (
DocumentationLinkViewSet,
InfractionViewSet,
NominationViewSet,
+ OffensiveMessageViewSet,
OffTopicChannelNameViewSet,
ReminderViewSet,
RoleViewSet,
diff --git a/pydis_site/apps/api/viewsets/bot/__init__.py b/pydis_site/apps/api/viewsets/bot/__init__.py
index f1851e32..b3e0fa4d 100644
--- a/pydis_site/apps/api/viewsets/bot/__init__.py
+++ b/pydis_site/apps/api/viewsets/bot/__init__.py
@@ -5,6 +5,7 @@ from .documentation_link import DocumentationLinkViewSet
from .infraction import InfractionViewSet
from .nomination import NominationViewSet
from .off_topic_channel_name import OffTopicChannelNameViewSet
+from .offensive_message import OffensiveMessageViewSet
from .reminder import ReminderViewSet
from .role import RoleViewSet
from .tag import TagViewSet
diff --git a/pydis_site/apps/api/viewsets/bot/offensive_message.py b/pydis_site/apps/api/viewsets/bot/offensive_message.py
new file mode 100644
index 00000000..54cb3a38
--- /dev/null
+++ b/pydis_site/apps/api/viewsets/bot/offensive_message.py
@@ -0,0 +1,61 @@
+from rest_framework.mixins import (
+ CreateModelMixin,
+ DestroyModelMixin,
+ ListModelMixin
+)
+from rest_framework.viewsets import GenericViewSet
+
+from pydis_site.apps.api.models.bot.offensive_message import OffensiveMessage
+from pydis_site.apps.api.serializers import OffensiveMessageSerializer
+
+
+class OffensiveMessageViewSet(
+ CreateModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet
+):
+ """
+ View providing CRUD access to offensive messages.
+
+ ## Routes
+ ### GET /bot/offensive-messages
+ Returns all offensive messages in the database.
+
+ #### Response format
+ >>> [
+ ... {
+ ... 'id': '631953598091100200',
+ ... 'channel_id': '291284109232308226',
+ ... 'delete_date': '2019-11-01T21:51:15.545000Z'
+ ... },
+ ... ...
+ ... ]
+
+ #### Status codes
+ - 200: returned on success
+
+ ### POST /bot/offensive-messages
+ Create a new offensive message object.
+
+ #### Request body
+ >>> {
+ ... 'id': int,
+ ... 'channel_id': int,
+ ... 'delete_date': datetime.datetime # ISO-8601-formatted date
+ ... }
+
+ #### Status codes
+ - 201: returned on success
+ - 400: if the body format is invalid
+
+ ### DELETE /bot/offensive-messages/<id:int>
+ Delete the offensive message object with the given `id`.
+
+ #### Status codes
+ - 204: returned on success
+ - 404: if a offensive message object with the given `id` does not exist
+
+ ## Authentication
+ Requires an API token.
+ """
+
+ serializer_class = OffensiveMessageSerializer
+ queryset = OffensiveMessage.objects.all()
diff --git a/pydis_site/settings.py b/pydis_site/settings.py
index 66376c4e..72cc0ab9 100644
--- a/pydis_site/settings.py
+++ b/pydis_site/settings.py
@@ -373,10 +373,11 @@ WIKI_MARKDOWN_HTML_ATTRIBUTES = {
'img': ['class', 'id', 'src', 'alt', 'width', 'height'],
'section': ['class', 'id'],
'article': ['class', 'id'],
+ 'iframe': ['width', 'height', 'src', 'frameborder', 'allow', 'allowfullscreen'],
}
WIKI_MARKDOWN_HTML_WHITELIST = [
- 'article', 'section', 'button'
+ 'article', 'section', 'button', 'iframe'
]
diff --git a/pydis_site/static/css/base/base.css b/pydis_site/static/css/base/base.css
index 75702d47..dc7c504d 100644
--- a/pydis_site/static/css/base/base.css
+++ b/pydis_site/static/css/base/base.css
@@ -106,3 +106,8 @@ button.is-size-navbar-menu, a.is-size-navbar-menu {
.modal-background {
z-index: 1010;
}
+
+/* Wiki style tweaks */
+.codehilite-wrap {
+ margin-bottom: 1em;
+}
diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html
index dfcc6715..3b150767 100644
--- a/pydis_site/templates/home/index.html
+++ b/pydis_site/templates/home/index.html
@@ -37,11 +37,11 @@
</p>
</div>
- {# Intro video #}
+ {# Code Jam banner #}
<div class="column is-half-desktop video-container">
- <iframe src="https://www.youtube.com/embed/DIBXg8Qh7bA" frameborder="0"
- allow="accelerometer; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen></iframe>
+ <a href="https://pythondiscord.com/pages/code-jams/code-jam-6/">
+ <img src="https://raw.githubusercontent.com/python-discord/branding/master/logos/logo_discord_banner/code%20jam%206%20-%20website%20banner.png"/>
+ </a>
</div>
</div>
diff --git a/pydis_site/utils/account.py b/pydis_site/utils/account.py
index e64919de..2d699c88 100644
--- a/pydis_site/utils/account.py
+++ b/pydis_site/utils/account.py
@@ -73,7 +73,7 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
"""
if social_login.account.provider == "discord":
discriminator = social_login.account.extra_data["discriminator"]
- data["username"] = f"{data['username']}#{discriminator}"
+ data["username"] = f"{data['username']}#{discriminator:0>4}"
data["name"] = data["username"]
return super().populate_user(request, social_login, data)