Skip to content
Snippets Groups Projects
Commit a1f50c5e authored by fu2662cw's avatar fu2662cw :speech_balloon:
Browse files

Merge with master

parents 2fb24aa9 61ba6f37
No related branches found
No related tags found
No related merge requests found
Showing
with 441 additions and 72 deletions
...@@ -45,9 +45,11 @@ before_script: ...@@ -45,9 +45,11 @@ before_script:
#SOURCE: https://stephen-olabode.medium.com/running-black-formatter-to-lint-a-python-file-in-gitlab-ci-cd-ae80111ab363 #SOURCE: https://stephen-olabode.medium.com/running-black-formatter-to-lint-a-python-file-in-gitlab-ci-cd-ae80111ab363
black: black:
image: milansuk/python-black:latest image: python:latest
before_script:
- pip install black
script: script:
- black --fast . - black --check .
#SOURCE: https://pypi.org/project/pylint-gitlab/ #SOURCE: https://pypi.org/project/pylint-gitlab/
pylint: pylint:
...@@ -57,23 +59,25 @@ pylint: ...@@ -57,23 +59,25 @@ pylint:
- python -V - python -V
- mkdir -p public/badges public/lint - mkdir -p public/badges public/lint
- echo undefined > public/badges/$CI_JOB_NAME.score - echo undefined > public/badges/$CI_JOB_NAME.score
- pip install pylint-gitlab - pip install pylint-django
- pip install -r requirements.txt - pip install -r requirements.txt
script: script:
- pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**") | tee /tmp/pylint.txt #Due to Problems with Pylint, Ignored Files need to be presented here for now.
- sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score - ./custom_linter.sh
- pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > codeclimate.json # - pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**") | tee /tmp/pylint.txt
- pylint --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > public/lint/index.html # - sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
after_script: # - pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > codeclimate.json
- anybadge --overwrite --label $CI_JOB_NAME --value=$(cat public/badges/$CI_JOB_NAME.score) --file=public/badges/$CI_JOB_NAME.svg 4=red 6=orange 8=yellow 10=green # - pylint --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > public/lint/index.html
- | # after_script:
echo "Your score is: $(cat public/badges/$CI_JOB_NAME.score)" # - anybadge --overwrite --label $CI_JOB_NAME --value=$(cat public/badges/$CI_JOB_NAME.score) --file=public/badges/$CI_JOB_NAME.svg 4=red 6=orange 8=yellow 10=green
artifacts: # - |
paths: # echo "Your score is: $(cat public/badges/$CI_JOB_NAME.score)"
- public # artifacts:
reports: # paths:
codequality: codeclimate.json # - public
when: always # reports:
# codequality: codeclimate.json
# when: always
#pages: #pages:
# stage: deploy # stage: deploy
......
[MASTER]
fail-under=10
[MESSAGES CONTROL]
disable=line-too-long,
django-not-configured
git ls-files | grep -v 'migrations\|manage.py\|course_scraper\|tests.py' | grep -E '.py$' | xargs pylint --load-plugins=pylint_django
\ No newline at end of file
...@@ -6,6 +6,7 @@ for http://www.buchsys.de for SWP UniSport-O-Mat. ...@@ -6,6 +6,7 @@ for http://www.buchsys.de for SWP UniSport-O-Mat.
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
def fetch_website(url): def fetch_website(url):
""" """
Helper function to fetch the content of a website. Helper function to fetch the content of a website.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Testing module, yo. Just for the course_scraper.py. Testing module, yo. Just for the course_scraper.py.
""" """
from django.test import TestCase from django.test import TestCase
from course_scraper import scraping #, fetch_website from course_scraper import scraping # , fetch_website
class ScraperTestCase(TestCase): class ScraperTestCase(TestCase):
...@@ -10,6 +10,7 @@ class ScraperTestCase(TestCase): ...@@ -10,6 +10,7 @@ class ScraperTestCase(TestCase):
Just a few tests, so pylint isn't getting a fit. Just a few tests, so pylint isn't getting a fit.
Because reasons. Because reasons.
""" """
def test_returns_dict(self): def test_returns_dict(self):
""" """
Testing return type of scraping(). Testing return type of scraping().
......
...@@ -6,7 +6,7 @@ import sys ...@@ -6,7 +6,7 @@ import sys
def main(): def main():
"""Run administrative tasks.""" """Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unisportomat.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "unisportomat.settings")
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:
...@@ -18,5 +18,5 @@ def main(): ...@@ -18,5 +18,5 @@ def main():
execute_from_command_line(sys.argv) execute_from_command_line(sys.argv)
if __name__ == '__main__': if __name__ == "__main__":
main() main()
# Generated by Django 3.2 on 2021-05-25 17:51
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Question",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
],
),
migrations.CreateModel(
name="Sport",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"sportart",
models.TextField(
choices=[
("After Work Fitness", "After Work Fitness"),
("Ballett", "Ballett"),
("Basketball", "Basketball"),
("Beachvolleyball", "Beachvolleyball"),
("Bouldern", "Bouldern"),
("Drachenfliegen", "Drachenfliegen"),
("Functional Fitness", "Functional Fitness"),
("Gerätturnen", "Gerätturnen"),
("HIIT", "HIIT"),
("Karate", "Karate"),
("Kickboxen", "Kickboxen"),
("Laufen", "Laufen"),
("Pilates", "Pilates"),
("Qigong", "Qigong"),
("Rückenfit", "Rückenfit"),
(
"Segeln Sportbootführerschein",
"Segeln Sportbootführerschein",
),
(
"Skilanglauf & Schneeschuhwandern",
"Skilanglauf & Schneeschuhwandern",
),
("Sweat & Relax", "Sweat & Relax"),
("Tennis", "Tennis"),
("Ultimate Frisbee", "Ultimate Frisbee"),
("Yoga", "Yoga"),
]
),
),
(
"field",
models.CharField(
choices=[("indoor", "indoor"), ("outdoor", "outdoor")],
default="outdoor",
max_length=50,
),
),
(
"einzelsport",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
(
"mannschaftssport",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
(
"ausdauer",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
(
"kraft",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
(
"kampfsport",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
(
"technischakrobatisch",
models.IntegerField(
choices=[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
],
default=1,
),
),
("url", models.TextField()),
],
),
migrations.CreateModel(
name="Wissensnack",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
],
),
]
# Generated by Django 3.2 on 2021-05-25 15:14
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("quiz", "0001_refactor_sport_and_add_criteria"),
]
operations = [
migrations.CreateModel(
name="Question",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField()),
],
),
migrations.AlterField(
model_name="criterionrating",
name="rating",
field=models.IntegerField(
validators=[
django.core.validators.MaxValueValidator(10),
django.core.validators.MinValueValidator(1),
]
),
),
]
# Generated by Django 3.2 on 2021-05-26 19:50
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("quiz", "0002_auto_20210525_1514"),
]
operations = [
migrations.AddField(
model_name="criterion",
name="question",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="quiz.question",
),
),
]
# Generated by Django 3.2 on 2021-05-26 20:14
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("quiz", "0003_criterion_question"),
]
operations = [
migrations.RemoveField(
model_name="criterion",
name="question",
),
migrations.RemoveField(
model_name="question",
name="id",
),
migrations.AddField(
model_name="question",
name="criterion",
field=models.OneToOneField(
default=None,
on_delete=django.db.models.deletion.CASCADE,
primary_key=True,
serialize=False,
to="quiz.criterion",
),
preserve_default=False,
),
]
# Generated by Django 3.2 on 2021-06-02 13:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('quiz', '0003_alter_calltomove_text'),
('quiz', '0004_auto_20210526_2014'),
]
operations = [
]
...@@ -68,3 +68,12 @@ class KnowledgeSnack(models.Model): ...@@ -68,3 +68,12 @@ class KnowledgeSnack(models.Model):
text = models.TextField() text = models.TextField()
image = models.ImageField(null=True, max_length=200) image = models.ImageField(null=True, max_length=200)
class Question(models.Model):
"""Defines a Question that is assigned to exactly one Criterion"""
text = models.TextField()
criterion = models.OneToOneField(
Criterion, on_delete=models.CASCADE, primary_key=True
)
...@@ -7,7 +7,7 @@ import tempfile ...@@ -7,7 +7,7 @@ import tempfile
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.conf import settings from django.conf import settings
from .models import Sport, Criterion, CallToMove, KnowledgeSnack from .models import Sport, Criterion, CallToMove, KnowledgeSnack, Question
class SportModelTest(TestCase): class SportModelTest(TestCase):
...@@ -71,17 +71,6 @@ class CriterionRatingTest(TestCase): ...@@ -71,17 +71,6 @@ class CriterionRatingTest(TestCase):
self.assertEqual(self.test_sport.get_rating(criterion=self.criterion), 8) self.assertEqual(self.test_sport.get_rating(criterion=self.criterion), 8)
class CriterionModelTest(TestCase):
"""Tests the Criterion model"""
def test_criterion_can_be_created(self):
"""New criterion is saved to the db"""
name = "Einzelsport"
Criterion(name=name).save()
test_criterion = Criterion.objects.first()
self.assertEqual(test_criterion.name, name)
FIXTURE_IMAGES = os.path.join(settings.BASE_DIR, "quiz", "fixtures", "images") FIXTURE_IMAGES = os.path.join(settings.BASE_DIR, "quiz", "fixtures", "images")
MEDIA_ROOT = tempfile.mkdtemp( MEDIA_ROOT = tempfile.mkdtemp(
suffix="testing" suffix="testing"
...@@ -157,3 +146,45 @@ class KnowledgeSnackTest(TestCase): ...@@ -157,3 +146,45 @@ class KnowledgeSnackTest(TestCase):
knowledge_snack = KnowledgeSnack.objects.first() knowledge_snack = KnowledgeSnack.objects.first()
self.assertEqual(knowledge_snack.text, self.text) self.assertEqual(knowledge_snack.text, self.text)
self.assertEqual(knowledge_snack.image.name, self.image.name) self.assertEqual(knowledge_snack.image.name, self.image.name)
class CriterionAndQuestionModelTest(TestCase):
"""Tests the Criterion and the Question model which have a One to One Relation"""
def setUp(self):
self.name = "Einzelsport"
self.criterion = Criterion(name=self.name)
self.criterion.save()
def test_criterion_can_be_saved_and_loaded(self):
"""New criterion can be loaded from the db"""
test_criterion = Criterion.objects.first()
self.assertEqual(test_criterion.name, self.name)
def test_question_can_be_added(self):
"""
If a question is added to a criterion, then it is accessible through the criterion.
"""
text = "Ich trainiere gerne mit anderen im Team"
question = Question(text=text, criterion=self.criterion)
question.save()
self.criterion.question = question
self.assertEqual(question, self.criterion.question)
def test_criterion_stays_if_question_deleted(self):
"""If assigned question is deleted the foreign key is set None"""
text = "Ich trainiere gerne mit anderen im Team"
question = Question(text=text, criterion=self.criterion)
question.save()
question.delete()
self.criterion = Criterion.objects.first()
with self.assertRaises(Criterion.question.RelatedObjectDoesNotExist):
self.criterion.question
def test_question_can_be_saved_and_loaded(self):
"""New Question is saved to the db and can be loaded"""
text = "Ich trainiere gerne mit anderen im Team"
Question(text=text, criterion=self.criterion).save()
test_question = Question.objects.first()
self.assertEqual(test_question.text, text)
...@@ -11,6 +11,6 @@ import os ...@@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unisportomat.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "unisportomat.settings")
application = get_asgi_application() application = get_asgi_application()
...@@ -22,7 +22,7 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'media') ...@@ -22,7 +22,7 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-vl*o#be$=k)9mbtm3!8k!6pe&38cdfg1*#_y3s)kgp$czt4ctm' SECRET_KEY = "django-insecure-vl*o#be$=k)9mbtm3!8k!6pe&38cdfg1*#_y3s)kgp$czt4ctm"
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
...@@ -32,52 +32,52 @@ ALLOWED_HOSTS = [] ...@@ -32,52 +32,52 @@ ALLOWED_HOSTS = []
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'quiz.apps.QuizConfig', "quiz.apps.QuizConfig",
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'unisportomat.urls' ROOT_URLCONF = "unisportomat.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [], "DIRS": [],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
], ],
}, },
}, },
] ]
WSGI_APPLICATION = 'unisportomat.wsgi.application' WSGI_APPLICATION = "unisportomat.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': BASE_DIR / 'db.sqlite3', "NAME": BASE_DIR / "db.sqlite3",
} }
} }
...@@ -86,25 +86,25 @@ DATABASES = { ...@@ -86,25 +86,25 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
}, },
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/ # https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = "en-us"
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
...@@ -115,9 +115,9 @@ USE_TZ = True ...@@ -115,9 +115,9 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/ # https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = "/static/"
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
...@@ -17,5 +17,5 @@ from django.contrib import admin ...@@ -17,5 +17,5 @@ from django.contrib import admin
from django.urls import path from django.urls import path
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
] ]
...@@ -11,6 +11,6 @@ import os ...@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unisportomat.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "unisportomat.settings")
application = get_wsgi_application() application = get_wsgi_application()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment