aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.coveragerc1
-rw-r--r--.dockerignore7
-rw-r--r--.gitattributes3
-rw-r--r--.gitignore2
-rw-r--r--Pipfile8
-rw-r--r--Pipfile.lock122
-rw-r--r--README.md6
-rw-r--r--azure-pipelines.yml171
-rw-r--r--docker-compose.yml6
-rw-r--r--docker/app/Dockerfile55
-rw-r--r--docker/app/Dockerfile.local49
-rw-r--r--docker/app/build-wiki.Dockerfile2
-rw-r--r--docker/app/local.Dockerfile28
-rw-r--r--docker/app/scripts/build-wiki.sh4
-rwxr-xr-xdocker/app/scripts/migrate_and_serve.sh3
-rw-r--r--docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whlbin0 -> 1287002 bytes
-rw-r--r--pydis_site/apps/api/migrations/0042_infraction_add_default_ordering.py17
-rw-r--r--pydis_site/apps/api/models/bot/infraction.py5
-rw-r--r--pydis_site/apps/api/tests/test_infractions.py5
-rw-r--r--pydis_site/apps/api/tests/test_off_topic_channel_names.py18
20 files changed, 301 insertions, 211 deletions
diff --git a/.coveragerc b/.coveragerc
index 68f8305a..a49af74e 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -8,6 +8,7 @@ source =
pydis_site/apps/staff
pydis_site/apps/wiki
omit =
+ */migrations/*
*/admin.py
*/apps.py
*/urls.py
diff --git a/.dockerignore b/.dockerignore
index f2475d80..771913a3 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -11,21 +11,16 @@
.venv
__pycache__
pydis_site/apps/admin/tests
-pydis_site/apps/admin/tests.py
pydis_site/apps/api/tests
-pydis_site/apps/api/tests.py
pydis_site/apps/home/tests
-pydis_site/apps/home/tests.py
pydis_site/apps/staff/tests
-pydis_site/apps/staff/tests.py
CHANGELOG.md
CONTRIBUTING.md
docker
-!docker/app/scripts/migrate_and_boot.sh
!docker/app/scripts/migrate.sh
!docker/app/uwsgi.ini
+!docker/app/wheels
docker-compose.yml
-Dockerfile
Dockerfile.local
docs
htmlcov
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..a90a0a96
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+# Declare files that will always have LF line endings on checkout
+# This prevents git on Windows from automatically inserting CRLF line endings
+* text=auto eol=lf \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2888775d..24bdf199 100644
--- a/.gitignore
+++ b/.gitignore
@@ -117,5 +117,7 @@ media/
pip-wheel-metadata/
staticfiles/
+!docker/app/wheels
+
*.js.tmp
log.*
diff --git a/Pipfile b/Pipfile
index 2346ae99..af5165df 100644
--- a/Pipfile
+++ b/Pipfile
@@ -17,7 +17,8 @@ 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"}
+#wiki = {git = "https://github.com/python-discord/django-wiki.git"}
+wiki = {path = "./docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl"}
pyyaml = "*"
[dev-packages]
@@ -42,6 +43,7 @@ python_version = "3.7"
[scripts]
makemigrations = "python manage.py makemigrations"
django_shell = "python manage.py shell"
-test = "python manage.py test"
-lint = "flake8 pydis_site"
+test = "coverage run manage.py test"
+report = "coverage report -m"
+lint = "flake8"
precommit = "pre-commit install"
diff --git a/Pipfile.lock b/Pipfile.lock
index c9cd758f..01345754 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "db7c552ce1bfd18819d21f7c2832c19f007d210d292dbaac158e47f2a1e18295"
+ "sha256": "d0e378fcea422eb28537a91e60e7faab8ae08a4ad9e3f1bd71fe89d377d36a8d"
},
"pipfile-spec": 6,
"requires": {
@@ -16,6 +16,13 @@
]
},
"default": {
+ "bleach": {
+ "hashes": [
+ "sha256:0ee95f6167129859c5dce9b1ca291ebdb5d8cd7e382ca0e237dfd0dad63f63d8",
+ "sha256:24754b9a7d530bf30ce7cbc805bc6cce785660b4a10ff3a43633728438c105ab"
+ ],
+ "version": "==2.1.4"
+ },
"certifi": {
"hashes": [
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
@@ -38,6 +45,12 @@
"index": "pypi",
"version": "==2.2.5"
},
+ "django-classy-tags": {
+ "hashes": [
+ "sha256:38b4546a8053499e2fef7af679a58d7c868298717d645b8b8227acba5fd4bf2b"
+ ],
+ "version": "==0.9.0"
+ },
"django-crispy-bulma": {
"hashes": [
"sha256:0d982e217a95706e0bbecd9f43990c191b071a20287478c7847ff096567e6e64",
@@ -78,6 +91,33 @@
"index": "pypi",
"version": "==3.0"
},
+ "django-js-asset": {
+ "hashes": [
+ "sha256:8ec12017f26eec524cab436c64ae73033368a372970af4cf42d9354fcb166bdd",
+ "sha256:c163ae80d2e0b22d8fb598047cd0dcef31f81830e127cfecae278ad574167260"
+ ],
+ "version": "==1.2.2"
+ },
+ "django-mptt": {
+ "hashes": [
+ "sha256:18a41d1b56ca7c02a5b04d246e33ee2d18f6ee5459c02ed1d945f5abdef23a2e",
+ "sha256:689a04cce0981671d6061a9928c33a16b47abb0d4cd43cf7dec31ae284fdae9d"
+ ],
+ "version": "==0.9.1"
+ },
+ "django-nyt": {
+ "hashes": [
+ "sha256:187f2aae5088c4cf79e7a7caa55c2a9c292722f50cf185c5a738636713ae67ea",
+ "sha256:5556e2de47a7b710325a33c49314ee3eff7021d638492e957ef2de15c9360143"
+ ],
+ "version": "==1.1.3"
+ },
+ "django-sekizai": {
+ "hashes": [
+ "sha256:642a3356fe92fe9b5ccc97f320b64edd2cfcb3b2fbb113e8a26dad9a1f3b5e14"
+ ],
+ "version": "==1.0.0"
+ },
"django-simple-bulma": {
"hashes": [
"sha256:ca2e4dbda5cf2d697cef91701a9fd7e58cecec93a76897158c4d7e135aa13842",
@@ -101,6 +141,13 @@
"index": "pypi",
"version": "==0.2.1"
},
+ "html5lib": {
+ "hashes": [
+ "sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3",
+ "sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"
+ ],
+ "version": "==1.0.1"
+ },
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
@@ -128,6 +175,44 @@
],
"version": "==0.19.2"
},
+ "markdown": {
+ "hashes": [
+ "sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa",
+ "sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"
+ ],
+ "version": "==3.0.1"
+ },
+ "pillow": {
+ "hashes": [
+ "sha256:0804f77cb1e9b6dbd37601cee11283bba39a8d44b9ddb053400c58e0c0d7d9de",
+ "sha256:0ab7c5b5d04691bcbd570658667dd1e21ca311c62dcfd315ad2255b1cd37f64f",
+ "sha256:0b3e6cf3ea1f8cecd625f1420b931c83ce74f00c29a0ff1ce4385f99900ac7c4",
+ "sha256:365c06a45712cd723ec16fa4ceb32ce46ad201eb7bbf6d3c16b063c72b61a3ed",
+ "sha256:38301fbc0af865baa4752ddae1bb3cbb24b3d8f221bf2850aad96b243306fa03",
+ "sha256:3aef1af1a91798536bbab35d70d35750bd2884f0832c88aeb2499aa2d1ed4992",
+ "sha256:3fe0ab49537d9330c9bba7f16a5f8b02da615b5c809cdf7124f356a0f182eccd",
+ "sha256:45a619d5c1915957449264c81c008934452e3fd3604e36809212300b2a4dab68",
+ "sha256:49f90f147883a0c3778fd29d3eb169d56416f25758d0f66775db9184debc8010",
+ "sha256:571b5a758baf1cb6a04233fb23d6cf1ca60b31f9f641b1700bfaab1194020555",
+ "sha256:5ac381e8b1259925287ccc5a87d9cf6322a2dc88ae28a97fe3e196385288413f",
+ "sha256:6153db744a743c0c8c91b8e3b9d40e0b13a5d31dbf8a12748c6d9bfd3ddc01ad",
+ "sha256:6fd63afd14a16f5d6b408f623cc2142917a1f92855f0df997e09a49f0341be8a",
+ "sha256:70acbcaba2a638923c2d337e0edea210505708d7859b87c2bd81e8f9902ae826",
+ "sha256:70b1594d56ed32d56ed21a7fbb2a5c6fd7446cdb7b21e749c9791eac3a64d9e4",
+ "sha256:76638865c83b1bb33bcac2a61ce4d13c17dba2204969dedb9ab60ef62bede686",
+ "sha256:7b2ec162c87fc496aa568258ac88631a2ce0acfe681a9af40842fc55deaedc99",
+ "sha256:7cee2cef07c8d76894ebefc54e4bb707dfc7f258ad155bd61d87f6cd487a70ff",
+ "sha256:7d16d4498f8b374fc625c4037742fbdd7f9ac383fd50b06f4df00c81ef60e829",
+ "sha256:b50bc1780681b127e28f0075dfb81d6135c3a293e0c1d0211133c75e2179b6c0",
+ "sha256:bd0582f831ad5bcad6ca001deba4568573a4675437db17c4031939156ff339fa",
+ "sha256:cfd40d8a4b59f7567620410f966bb1f32dc555b2b19f82a91b147fac296f645c",
+ "sha256:e3ae410089de680e8f84c68b755b42bc42c0ceb8c03dbea88a5099747091d38e",
+ "sha256:e9046e559c299b395b39ac7dbf16005308821c2f24a63cae2ab173bd6aa11616",
+ "sha256:ef6be704ae2bc8ad0ebc5cb850ee9139493b0fc4e81abcc240fb392a63ebc808",
+ "sha256:f8dc19d92896558f9c4317ee365729ead9d7bbcf2052a9a19a3ef17abbb8ac5b"
+ ],
+ "version": "==6.1.0"
+ },
"psycopg2-binary": {
"hashes": [
"sha256:080c72714784989474f97be9ab0ddf7b2ad2984527e77f2909fcd04d4df53809",
@@ -211,6 +296,13 @@
],
"version": "==1.12.0"
},
+ "sorl-thumbnail": {
+ "hashes": [
+ "sha256:8dfe5fda91a5047d1d35a0b9effe7b000764a01d648e15ca076f44e9c34b6dbd",
+ "sha256:d9e3f018d19293824803e4ffead96b19dfcd44fa7987cea392f50436817bef34"
+ ],
+ "version": "==12.5.0"
+ },
"sqlparse": {
"hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
@@ -220,10 +312,17 @@
},
"urllib3": {
"hashes": [
- "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
- "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
+ "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398",
+ "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86"
],
- "version": "==1.25.3"
+ "version": "==1.25.6"
+ },
+ "webencodings": {
+ "hashes": [
+ "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
+ "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
+ ],
+ "version": "==0.5.1"
},
"whitenoise": {
"hashes": [
@@ -234,8 +333,11 @@
"version": "==4.1.2"
},
"wiki": {
- "git": "https://github.com/python-discord/django-wiki.git",
- "ref": "66d443248279fb8decf23f68c5363ecf6362ee09"
+ "hashes": [
+ "sha256:73a53bc770ce6b1d2ea6916d81ccefe40751d87b30556fa3b992c85b7fde8534"
+ ],
+ "path": "./docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl",
+ "version": "==0.5.dev20190420204942"
}
},
"develop": {
@@ -267,6 +369,14 @@
],
"version": "==2.0.1"
},
+ "colorama": {
+ "hashes": [
+ "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d",
+ "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"
+ ],
+ "markers": "platform_system == 'Windows'",
+ "version": "==0.4.1"
+ },
"coverage": {
"hashes": [
"sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6",
diff --git a/README.md b/README.md
index 31efc202..df0417e4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,10 @@
# Python Discord: Site
+[![Discord](https://img.shields.io/discord/267624335836053506?color=%237289DA&label=Python%20Discord&logo=discord&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)
+[![License](https://img.shields.io/github/license/python-discord/site)](LICENSE)
+[![Status](https://img.shields.io/website?url=https%3A%2F%2Fpythondiscord.com)](https://pythondiscord.com)
This is all of the code that is responsible for maintaining
[our website](https://pythondiscord.com), and all of its subdomains.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index de6237d8..b3d4e6da 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,97 +1,80 @@
# https://aka.ms/yaml
jobs:
-- job: python_lint
- displayName: 'Lint Job'
- pool:
- vmImage: ubuntu-16.04
-
- variables:
- PIP_CACHE_DIR: .cache/pip
-
- steps:
- - task: UsePythonVersion@0
- displayName: 'Set Python Version'
- inputs:
- versionSpec: '3.7.x'
- addToPath: true
-
- - script: python3 -m pip install pipenv && pipenv install --dev --system && python3 -m pip install flake8-formatter-junit-xml
- displayName: 'Install Project Environment'
-
- - script: python3 -m flake8 --format junit-xml --output-file test-lint.xml
- displayName: 'Run Linter'
-
- - task: PublishTestResults@2
- condition: succeededOrFailed()
- inputs:
- testResultsFiles: '**/test-*.xml'
- testRunTitle: 'Site-Django Lint Results'
-
-- job: coverage_test
- displayName: 'Test Job'
- dependsOn: python_lint
- pool:
- vmImage: ubuntu-16.04
-
- steps:
- - task: UsePythonVersion@0
- inputs:
- versionSpec: '3.7.x'
- architecture: x64
-
- - script: |
- curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
- sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
- sudo apt-get update -y
- sudo apt-get install -y postgresql-11
- displayName: 'Install PostgreSQL'
-
- - script: |
- echo "$USER_CREATE_COMMAND;" > pgscript.sql
- echo "CREATE DATABASE pysite OWNER pysite;" >> pgscript.sql
- sudo su postgres -c "psql < pgscript.sql"
- env:
- USER_CREATE_COMMAND: CREATE USER pysite WITH PASSWORD 'pysite' CREATEDB
- displayName: 'Setup Database'
-
- - script: python3 -m pip install pipenv && pipenv install --dev --system
- displayName: 'Install Project Environment'
-
- - script: |
- python manage.py makemigrations --check
- python manage.py migrate
- coverage run --branch manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
- env:
- CI: azure
- DATABASE_URL: postgres://pysite:pysite@localhost/pysite
- displayName: 'Run Test'
-
- - script: coverage report
- displayName: 'Show Coverage Results'
-
- - task: PublishTestResults@2
- inputs:
- testResultsFiles: "**/TEST-*.xml"
- testRunTitle: 'Site-Django Test Results'
-
-- job: docker
- displayName: 'Build & Push Job'
- dependsOn: coverage_test
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- pool:
- vmImage: ubuntu-16.04
-
- steps:
- - task: Docker@1
- displayName: Login to Docker Hub
-
- inputs:
- containerregistrytype: 'Container Registry'
- dockerRegistryEndpoint: 'DockerHub'
- command: 'login'
-
- - script: |
- docker build -t pythondiscord/site:latest -f docker/app/Dockerfile .
- docker push pythondiscord/site:latest
- displayName: 'Build & Push Docker Image'
+ - job: test
+ displayName: 'Test & Lint'
+ pool:
+ vmImage: ubuntu-16.04
+
+ variables:
+ PIP_CACHE_DIR: .cache/pip
+
+ steps:
+ - task: UsePythonVersion@0
+ displayName: 'Set Python Version'
+ inputs:
+ versionSpec: '3.7.x'
+ addToPath: true
+
+ - task: DockerCompose@0
+ displayName: 'Setup Database'
+ inputs:
+ action: Run a specific service
+ dockerComposeFile: docker-compose.yml
+ projectName: pydis_web
+ serviceName: postgres
+ ports: '7777:5432'
+
+ - script: |
+ pip install pipenv
+ pipenv install --dev --system
+ pip install flake8-formatter-junit-xml
+ displayName: 'Install Project Environment'
+
+ - script: flake8 --format junit-xml --output-file TEST-lint.xml
+ displayName: 'Run Linter'
+
+ - script: |
+ python3 manage.py makemigrations --check
+ python3 manage.py migrate
+ coverage run \
+ manage.py test \
+ --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner \
+ --no-input
+ env:
+ CI: azure
+ DATABASE_URL: postgres://pysite:pysite@localhost:7777/pysite
+ displayName: 'Run Tests'
+
+ - script: coverage report -m && coverage xml
+ displayName: 'Generate Coverage Reports'
+
+ - task: PublishTestResults@2
+ condition: succeededOrFailed()
+ displayName: 'Publish Test & Linting Results'
+ inputs:
+ testResultsFiles: '**/TEST-*.xml'
+ testRunTitle: 'Site Test Results'
+
+ - task: PublishCodeCoverageResults@1
+ displayName: 'Publish Coverage Results'
+ condition: succeededOrFailed()
+ inputs:
+ codeCoverageTool: Cobertura
+ summaryFileLocation: '**/coverage.xml'
+
+ - job: build
+ displayName: 'Build & Push Container'
+ dependsOn: test
+ condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
+
+ steps:
+ - task: Docker@2
+ displayName: 'Build & Push Container'
+ inputs:
+ containerRegistry: 'DockerHub'
+ repository: 'pythondiscord/site'
+ command: 'buildAndPush'
+ Dockerfile: 'docker/app/Dockerfile'
+ buildContext: '.'
+ tags: 'latest'
diff --git a/docker-compose.yml b/docker-compose.yml
index d415340b..4ea110c4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -16,13 +16,13 @@ services:
- "127.0.0.1:7777:5432"
environment:
POSTGRES_DB: pysite
- POSTGRES_PASSWORD: supersecretpassword
+ POSTGRES_PASSWORD: pysite
POSTGRES_USER: pysite
web:
build:
context: .
- dockerfile: docker/app/Dockerfile.local
+ dockerfile: docker/app/local.Dockerfile
command: docker/app/scripts/migrate_and_serve.sh
ports:
- "127.0.0.1:8000:8000"
@@ -32,7 +32,7 @@ services:
- .:/app:ro
- staticfiles:/var/www/static
environment:
- DATABASE_URL: postgres://pysite:supersecretpassword@postgres:5432/pysite
+ DATABASE_URL: postgres://pysite:pysite@postgres:5432/pysite
DEBUG: "true"
SECRET_KEY: suitable-for-development-only
STATIC_ROOT: /var/www/static
diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile
index 903e7dc6..a6986fb2 100644
--- a/docker/app/Dockerfile
+++ b/docker/app/Dockerfile
@@ -1,52 +1,27 @@
-FROM bitnami/python:3.7-prod
+FROM python:3.7-slim
-# I have no idea what this does.
+# Allow service to handle stops gracefully
STOPSIGNAL SIGQUIT
-ARG EXTRAS=deploy
-# Create a user.
-RUN adduser \
- --disabled-login \
- --no-create-home \
- --uid 1500 \
- pysite
+# Set pip to have cleaner logs and no saved cache
+ENV PIP_NO_CACHE_DIR=false \
+ PIPENV_HIDE_EMOJIS=1 \
+ PIPENV_NOSPIN=1
-# 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/*
+# Create non-root user.
+RUN useradd --system --shell /bin/false --uid 1500 pysite
-# 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
+# Install pipenv & pyuwsgi
+RUN pip install -U pipenv pyuwsgi
-# Copy everything into the docker environment.
+# Copy the project files into working directory
+WORKDIR /app
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
+# Install project dependencies
+RUN pipenv install --system --deploy
-# Migrate, collect and start the app.
+# 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
deleted file mode 100644
index c332c757..00000000
--- a/docker/app/Dockerfile.local
+++ /dev/null
@@ -1,49 +0,0 @@
-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/build-wiki.Dockerfile b/docker/app/build-wiki.Dockerfile
new file mode 100644
index 00000000..92003377
--- /dev/null
+++ b/docker/app/build-wiki.Dockerfile
@@ -0,0 +1,2 @@
+FROM python:3.7
+RUN pip --no-cache-dir wheel --wheel-dir=/wheels "wiki @ git+https://github.com/python-discord/django-wiki.git"
diff --git a/docker/app/local.Dockerfile b/docker/app/local.Dockerfile
new file mode 100644
index 00000000..9e15c438
--- /dev/null
+++ b/docker/app/local.Dockerfile
@@ -0,0 +1,28 @@
+FROM python:3.7-slim
+
+# Allow service to handle stops gracefully
+STOPSIGNAL SIGQUIT
+
+# Set pip to have cleaner logs and no saved cache
+ENV PIP_NO_CACHE_DIR=false \
+ PIPENV_HIDE_EMOJIS=1 \
+ PIPENV_NOSPIN=1
+
+# Create non-root user
+RUN useradd --system --shell /bin/false --uid 1500 pysite
+
+# Install pipenv & pyuwsgi
+RUN pip install -U pipenv pyuwsgi
+
+# Copy the project files into working directory
+WORKDIR /app
+COPY . .
+
+# Install project dependencies
+RUN pipenv install --system --deploy
+
+# Prepare static files for site
+RUN SECRET_KEY=placeholder DATABASE_URL=sqlite:// \
+ python3 manage.py collectstatic --no-input --clear --verbosity 0
+
+CMD ["uwsgi", "--ini", "docker/app/uwsgi.ini"]
diff --git a/docker/app/scripts/build-wiki.sh b/docker/app/scripts/build-wiki.sh
new file mode 100644
index 00000000..07c54f66
--- /dev/null
+++ b/docker/app/scripts/build-wiki.sh
@@ -0,0 +1,4 @@
+docker build -t build_uwsgi -f docker/app/build-wiki.Dockerfile .
+CONTAINER=$(docker run -itd build_uwsgi /bin/bash)
+docker cp "$CONTAINER:/wheels" docker/app
+docker stop "$CONTAINER"
diff --git a/docker/app/scripts/migrate_and_serve.sh b/docker/app/scripts/migrate_and_serve.sh
index 0b54a2e5..c30d7e04 100755
--- a/docker/app/scripts/migrate_and_serve.sh
+++ b/docker/app/scripts/migrate_and_serve.sh
@@ -1,4 +1,5 @@
-#!/bin/sh -eu
+#!/bin/sh
+set -eu
### NOTE
# This file is intended to be used by local setups.
diff --git a/docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl b/docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl
new file mode 100644
index 00000000..b7637e76
--- /dev/null
+++ b/docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl
Binary files differ
diff --git a/pydis_site/apps/api/migrations/0042_infraction_add_default_ordering.py b/pydis_site/apps/api/migrations/0042_infraction_add_default_ordering.py
new file mode 100644
index 00000000..1a0dbb34
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0042_infraction_add_default_ordering.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.2.3 on 2019-09-17 14:07
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0041_add_default_ordering_deleted_messages'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='infraction',
+ options={'ordering': ['-inserted_at']},
+ ),
+ ]
diff --git a/pydis_site/apps/api/models/bot/infraction.py b/pydis_site/apps/api/models/bot/infraction.py
index da91d6c2..dfb32a97 100644
--- a/pydis_site/apps/api/models/bot/infraction.py
+++ b/pydis_site/apps/api/models/bot/infraction.py
@@ -66,3 +66,8 @@ class Infraction(ModelReprMixin, models.Model):
if self.hidden:
s += " (hidden)"
return s
+
+ class Meta:
+ """Defines the meta options for the infraction model."""
+
+ ordering = ['-inserted_at']
diff --git a/pydis_site/apps/api/tests/test_infractions.py b/pydis_site/apps/api/tests/test_infractions.py
index 7c370c17..0092d355 100644
--- a/pydis_site/apps/api/tests/test_infractions.py
+++ b/pydis_site/apps/api/tests/test_infractions.py
@@ -63,6 +63,7 @@ class InfractionTests(APISubdomainTestCase):
)
def test_list_all(self):
+ """Tests the list-view, which should be ordered by inserted_at (newest first)."""
url = reverse('bot:infraction-list', host='api')
response = self.client.get(url)
@@ -70,8 +71,8 @@ class InfractionTests(APISubdomainTestCase):
infractions = response.json()
self.assertEqual(len(infractions), 2)
- self.assertEqual(infractions[0]['id'], self.ban_hidden.id)
- self.assertEqual(infractions[1]['id'], self.ban_inactive.id)
+ self.assertEqual(infractions[0]['id'], self.ban_inactive.id)
+ self.assertEqual(infractions[1]['id'], self.ban_hidden.id)
def test_filter_search(self):
url = reverse('bot:infraction-list', host='api')
diff --git a/pydis_site/apps/api/tests/test_off_topic_channel_names.py b/pydis_site/apps/api/tests/test_off_topic_channel_names.py
index 60af1f62..9ab71409 100644
--- a/pydis_site/apps/api/tests/test_off_topic_channel_names.py
+++ b/pydis_site/apps/api/tests/test_off_topic_channel_names.py
@@ -88,16 +88,20 @@ class CreationTests(APISubdomainTestCase):
super().setUp()
url = reverse('bot:offtopicchannelname-list', host='api')
- self.name = "lemonade-shop"
+ self.name = "abcdefghijklmnopqrstuvwxyz-0123456789"
response = self.client.post(f'{url}?name={self.name}')
self.assertEqual(response.status_code, 201)
- def test_name_in_full_list(self):
+ def test_returns_201_for_unicode_chars(self):
url = reverse('bot:offtopicchannelname-list', host='api')
- response = self.client.get(url)
+ names = (
+ '𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹',
+ 'ǃ?’',
+ )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(response.json(), [self.name])
+ for name in names:
+ response = self.client.post(f'{url}?name={name}')
+ self.assertEqual(response.status_code, 201)
def test_returns_400_for_missing_name_param(self):
url = reverse('bot:offtopicchannelname-list', host='api')
@@ -111,8 +115,8 @@ class CreationTests(APISubdomainTestCase):
url = reverse('bot:offtopicchannelname-list', host='api')
invalid_names = (
'space between words',
- 'UPPERCASE',
- '$$$$$$$$'
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+ '!?\'@#$%^&*()',
)
for name in invalid_names: