diff options
-rw-r--r-- | .coveragerc | 1 | ||||
-rw-r--r-- | .dockerignore | 7 | ||||
-rw-r--r-- | .gitattributes | 3 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Pipfile | 8 | ||||
-rw-r--r-- | Pipfile.lock | 122 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | azure-pipelines.yml | 171 | ||||
-rw-r--r-- | docker-compose.yml | 6 | ||||
-rw-r--r-- | docker/app/Dockerfile | 55 | ||||
-rw-r--r-- | docker/app/Dockerfile.local | 49 | ||||
-rw-r--r-- | docker/app/build-wiki.Dockerfile | 2 | ||||
-rw-r--r-- | docker/app/local.Dockerfile | 28 | ||||
-rw-r--r-- | docker/app/scripts/build-wiki.sh | 4 | ||||
-rwxr-xr-x | docker/app/scripts/migrate_and_serve.sh | 3 | ||||
-rw-r--r-- | docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl | bin | 0 -> 1287002 bytes | |||
-rw-r--r-- | pydis_site/apps/api/migrations/0042_infraction_add_default_ordering.py | 17 | ||||
-rw-r--r-- | pydis_site/apps/api/models/bot/infraction.py | 5 | ||||
-rw-r--r-- | pydis_site/apps/api/tests/test_infractions.py | 5 | ||||
-rw-r--r-- | pydis_site/apps/api/tests/test_off_topic_channel_names.py | 18 |
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 @@ -117,5 +117,7 @@ media/ pip-wheel-metadata/ staticfiles/ +!docker/app/wheels + *.js.tmp log.* @@ -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", @@ -1,4 +1,10 @@ # Python Discord: Site +[](https://discord.gg/2B963hn) +[](https://dev.azure.com/python-discord/Python%20Discord/_build/latest?definitionId=2&branchName=master) +[](https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Site?branchName=master) +[](https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Site?branchName=master) +[](LICENSE) +[](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 Binary files differnew file mode 100644 index 00000000..b7637e76 --- /dev/null +++ b/docker/app/wheels/wiki-0.5.dev20190420204942-py3-none-any.whl 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: |