From b790dfbe0aa82b6a96c8fa90cc0749297116cef3 Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 13:50:25 +0100 Subject: [PATCH 1/7] Changes --- README.md | 0 SOITA/__init__.py | 0 SOITA/asgi.py | 16 ------ SOITA/settings.py | 126 ---------------------------------------------- SOITA/urls.py | 21 -------- SOITA/wsgi.py | 16 ------ manage.py | 2 +- 7 files changed, 1 insertion(+), 180 deletions(-) delete mode 100644 README.md delete mode 100644 SOITA/__init__.py delete mode 100644 SOITA/asgi.py delete mode 100644 SOITA/settings.py delete mode 100644 SOITA/urls.py delete mode 100644 SOITA/wsgi.py mode change 100644 => 100755 manage.py diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/SOITA/__init__.py b/SOITA/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/SOITA/asgi.py b/SOITA/asgi.py deleted file mode 100644 index 2ace8f4..0000000 --- a/SOITA/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for SOITA project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SOITA.settings') - -application = get_asgi_application() diff --git a/SOITA/settings.py b/SOITA/settings.py deleted file mode 100644 index 07017d9..0000000 --- a/SOITA/settings.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -Django settings for SOITA project. - -Generated by 'django-admin startproject' using Django 3.2.9. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/3.2/ref/settings/ -""" - -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-&bro7o3+h4mu-stibpc_$pen0+b^5t)!thrlj61u9v8_y6ec1)' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'SOITA.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')] - , - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'SOITA.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/3.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } -} - - -# Password validation -# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/3.2/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.2/howto/static-files/ - -STATIC_URL = '/static/' - -# Default primary key field type -# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/SOITA/urls.py b/SOITA/urls.py deleted file mode 100644 index 3bf6d9b..0000000 --- a/SOITA/urls.py +++ /dev/null @@ -1,21 +0,0 @@ -"""SOITA URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/3.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" -from django.contrib import admin -from django.urls import path - -urlpatterns = [ - path('admin/', admin.site.urls), -] diff --git a/SOITA/wsgi.py b/SOITA/wsgi.py deleted file mode 100644 index f0c2d7c..0000000 --- a/SOITA/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for SOITA project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SOITA.settings') - -application = get_wsgi_application() diff --git a/manage.py b/manage.py old mode 100644 new mode 100755 index 74258f0..8e7ac79 --- a/manage.py +++ b/manage.py @@ -6,7 +6,7 @@ import sys def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SOITA.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: From 539c4690cb59f43179a3d0cc90253801c074d48f Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 13:50:34 +0100 Subject: [PATCH 2/7] changers --- answers/__init__.py | 0 answers/migrations/0001_initial.py | 29 ++++ answers/migrations/__init__.py | 0 answers/models.py | 27 ++++ answers/serializers.py | 14 ++ answers/urls.py | 8 ++ answers/views.py | 9 ++ config/__init__.py | 0 config/asgi.py | 16 +++ config/settings.py | 189 +++++++++++++++++++++++++++ config/urls.py | 25 ++++ config/wsgi.py | 16 +++ questions/__init__.py | 0 questions/apps.py | 0 questions/migrations/0001_initial.py | 25 ++++ questions/migrations/__init__.py | 0 questions/models.py | 19 +++ questions/serializers.py | 21 +++ questions/urls.py | 8 ++ questions/views.py | 9 ++ requirements.txt | 36 +++++ templates/generic_test.html | 48 +++++++ trials/__init__.py | 0 trials/apps.py | 0 trials/migrations/0001_initial.py | 21 +++ trials/migrations/__init__.py | 0 trials/models.py | 26 ++++ trials/serializers.py | 18 +++ trials/urls.py | 16 +++ trials/views.py | 50 +++++++ users/.DS_Store | Bin 0 -> 6148 bytes users/__init__.py | 0 users/migrations/.DS_Store | Bin 0 -> 6148 bytes users/migrations/0001_initial.py | 32 +++++ users/migrations/__init__.py | 0 users/models.py | 26 ++++ users/serializers.py | 16 +++ users/urls.py | 16 +++ users/views.py | 9 ++ 39 files changed, 729 insertions(+) create mode 100644 answers/__init__.py create mode 100644 answers/migrations/0001_initial.py create mode 100644 answers/migrations/__init__.py create mode 100644 answers/models.py create mode 100644 answers/serializers.py create mode 100644 answers/urls.py create mode 100644 answers/views.py create mode 100644 config/__init__.py create mode 100644 config/asgi.py create mode 100644 config/settings.py create mode 100644 config/urls.py create mode 100644 config/wsgi.py create mode 100644 questions/__init__.py create mode 100644 questions/apps.py create mode 100644 questions/migrations/0001_initial.py create mode 100644 questions/migrations/__init__.py create mode 100644 questions/models.py create mode 100644 questions/serializers.py create mode 100644 questions/urls.py create mode 100644 questions/views.py create mode 100644 requirements.txt create mode 100644 templates/generic_test.html create mode 100644 trials/__init__.py create mode 100644 trials/apps.py create mode 100644 trials/migrations/0001_initial.py create mode 100644 trials/migrations/__init__.py create mode 100644 trials/models.py create mode 100644 trials/serializers.py create mode 100644 trials/urls.py create mode 100644 trials/views.py create mode 100644 users/.DS_Store create mode 100644 users/__init__.py create mode 100644 users/migrations/.DS_Store create mode 100644 users/migrations/0001_initial.py create mode 100644 users/migrations/__init__.py create mode 100644 users/models.py create mode 100644 users/serializers.py create mode 100644 users/urls.py create mode 100644 users/views.py diff --git a/answers/__init__.py b/answers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/answers/migrations/0001_initial.py b/answers/migrations/0001_initial.py new file mode 100644 index 0000000..0461f63 --- /dev/null +++ b/answers/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1.1 on 2021-12-01 18:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('questions', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Answer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField()), + ('is_correct', models.BooleanField(default=False)), + ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='questions.question')), + ], + ), + migrations.AddConstraint( + model_name='answer', + constraint=models.UniqueConstraint(condition=models.Q(is_correct=True), fields=('question',), name='only_one_correct_answer'), + ), + ] diff --git a/answers/migrations/__init__.py b/answers/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/answers/models.py b/answers/models.py new file mode 100644 index 0000000..e8e1e12 --- /dev/null +++ b/answers/models.py @@ -0,0 +1,27 @@ +from django.db import models +from django.db.models import Q +from django.db.models import UniqueConstraint + + +class Answer(models.Model): + question = models.ForeignKey( + "questions.Question", + on_delete=models.CASCADE, + null=False, + related_name="answers" + ) + description = models.TextField() + is_correct = models.BooleanField(default=False) + + def get_secret_answer(self): + return { + "id": self.id, + "description": self.description, + } + + class Meta: + constraints = [UniqueConstraint( + fields=["question"], + condition=Q(is_correct=True), + name="only_one_correct_answer" + )] diff --git a/answers/serializers.py b/answers/serializers.py new file mode 100644 index 0000000..131ac22 --- /dev/null +++ b/answers/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers + +from answers.models import Answer + + +class AnswerSerializer(serializers.ModelSerializer): + class Meta: + model = Answer + fields = ( + "id", + "description", + "is_correct", + "question" + ) diff --git a/answers/urls.py b/answers/urls.py new file mode 100644 index 0000000..e9553b2 --- /dev/null +++ b/answers/urls.py @@ -0,0 +1,8 @@ +from rest_framework.routers import DefaultRouter + +from answers.views import AnswerModelViewSet + +router = DefaultRouter() +router.register("items", AnswerModelViewSet) + +urlpatterns = router.urls diff --git a/answers/views.py b/answers/views.py new file mode 100644 index 0000000..c14ee50 --- /dev/null +++ b/answers/views.py @@ -0,0 +1,9 @@ +from rest_framework import viewsets + +from answers.models import Answer +from answers.serializers import AnswerSerializer + + +class AnswerModelViewSet(viewsets.ModelViewSet): + serializer_class = AnswerSerializer + queryset = Answer.objects.all() diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/asgi.py b/config/asgi.py new file mode 100644 index 0000000..82ae9c0 --- /dev/null +++ b/config/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for testMe project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + +application = get_asgi_application() diff --git a/config/settings.py b/config/settings.py new file mode 100644 index 0000000..66b57e0 --- /dev/null +++ b/config/settings.py @@ -0,0 +1,189 @@ +import json +import os +""" +Django settings for config project. + +Generated by 'django-admin startproject' using Django 3.1.1. + +For more information on this file, see +https://docs.djangoproject.com/en/3.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.1/ref/settings/ +""" + +from pathlib import Path + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +secrets = BASE_DIR + "/secrets.json" + +with open(secrets) as f: + keys = json.loads(f.read()) + + +def get_secret(setting, keys=keys): + return keys[setting] + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = get_secret("SECRET_KEY") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = get_secret("DEBUG") + +ALLOWED_HOSTS = get_secret("ALLOWED_HOSTS") + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.staticfiles', + "django.contrib.gis", + "rest_framework", + "rest_framework_simplejwt", + + "users", + "trials", + "answers", + "questions" +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + "corsheaders.middleware.CorsMiddleware", + # "`debug_toolbar.middleware.DebugToolbarMiddleware`", + 'django.middleware.common.CommonMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = get_secret("ROOT_URLCONF") + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': os.path.join(BASE_DIR, "templates"), + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'config.wsgi.application' + +# User model +AUTH_USER_MODEL = "users.User" + +# Database +# https://docs.djangoproject.com/en/3.1/ref/settings/#databases + +DATABASES = { + 'default': { + "ENGINE": "django.contrib.gis.db.backends.postgis", + "NAME": get_secret("DB_NAME"), + "USER": get_secret("DB_USER"), + "PASSWORD": get_secret("DB_PASSWORD"), + "HOST": get_secret("DB_HOST"), + "PORT": get_secret("DB_PORT"), + } +} + +REST_FRAMEWORK = { + "DEFAULT_PERMISSION_CLASSES": ( + # "rest_framework.permissions.IsAuthenticated", + ), + "DEFAULT_AUTHENTICATION_CLASSES": ( + # "rest_framework_simplejwt.authentication.JWTAuthentication", + ), + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", + "DEFAULT_FILTER_BACKENDS": ( + "django_filters.rest_framework.DjangoFilterBackend", + "rest_framework.filters.SearchFilter", + "rest_framework.filters.OrderingFilter", + ), + "NON_FIELD_ERRORS_KEY": "message", + 'DEFAULT_THROTTLE_CLASSES': [ + 'rest_framework.throttling.AnonRateThrottle', + 'rest_framework.throttling.UserRateThrottle' + ], + 'DEFAULT_THROTTLE_RATES': { + 'anon': '100/day', + 'user': '10000/day' + }, + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", +} + +# Password validation +# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators + +DEVELOPMENT = get_secret("DEVELOPMENT") + +if not DEVELOPMENT: + REST_FRAMEWORK.update({ + "DEFAULT_RENDERER_CLASSES": ( + "djangorestframework_camel_case.render.CamelCaseJSONRenderer", + "djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer", + ), + "DEFAULT_PARSER_CLASSES": ( + "djangorestframework_camel_case.parser.CamelCaseJSONParser", + "djangorestframework_camel_case.parser.CamelCaseMultiPartParser", + "djangorestframework_camel_case.parser.CamelCaseFormParser", + ), + "JSON_UNDERSCOREIZE": { + "no_underscore_before_number": True, + }, + }) + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.1/topics/i18n/ + +LANGUAGE_CODE = "pl" + +TIME_ZONE = "Europe/Warsaw" + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.1/howto/static-files/ + +STATIC_URL = "/static/" +MEDIA_ROOT = "/media/" +STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),) +STATIC_ROOT = os.path.join(BASE_DIR, "../static") +CORS_ORIGIN_ALLOW_ALL = True + +CORS_ALLOW_HEADERS = ('content-disposition', 'accept-encoding', + 'content-type', 'accept', 'origin', 'authorization') + +MEDIA_URL = "/media/" diff --git a/config/urls.py b/config/urls.py new file mode 100644 index 0000000..a40f86d --- /dev/null +++ b/config/urls.py @@ -0,0 +1,25 @@ +"""testMe URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include +from django.urls import path + +urlpatterns = [ + path('users/', include("users.urls")), + path('questions/', include("questions.urls")), + path('answers/', include("answers.urls")), + path('tests/', include("trials.urls")), +] diff --git a/config/wsgi.py b/config/wsgi.py new file mode 100644 index 0000000..7781ac0 --- /dev/null +++ b/config/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for testMe project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + +application = get_wsgi_application() diff --git a/questions/__init__.py b/questions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/questions/apps.py b/questions/apps.py new file mode 100644 index 0000000..e69de29 diff --git a/questions/migrations/0001_initial.py b/questions/migrations/0001_initial.py new file mode 100644 index 0000000..710c384 --- /dev/null +++ b/questions/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2021-12-01 18:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('trials', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Question', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=200)), + ('description', models.TextField()), + ('test', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='questions', to='trials.test')), + ], + ), + ] diff --git a/questions/migrations/__init__.py b/questions/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/questions/models.py b/questions/models.py new file mode 100644 index 0000000..c839628 --- /dev/null +++ b/questions/models.py @@ -0,0 +1,19 @@ +from django.db import models + + +class Question(models.Model): + test = models.ForeignKey( + "trials.Test", + on_delete=models.SET_NULL, + null=True, + related_name="questions" + ) + name = models.CharField(max_length=200, default="") + description = models.TextField() + points = models.PositiveSmallIntegerField(default=1) + + def get_answers_secret(self): + return [ + answer.get_secret_answer() + for answer in self.answers.all() + ] diff --git a/questions/serializers.py b/questions/serializers.py new file mode 100644 index 0000000..fa42a9a --- /dev/null +++ b/questions/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from questions.models import Question + + +class QuestionSerializer(serializers.ModelSerializer): + + answers = serializers.SerializerMethodField() + + def get_answers(self, instance: Question): + return instance.get_answers_secret() + + class Meta: + model = Question + fields = ( + "id", + "name", + "description", + "answers", + "test" + ) diff --git a/questions/urls.py b/questions/urls.py new file mode 100644 index 0000000..7e61cf7 --- /dev/null +++ b/questions/urls.py @@ -0,0 +1,8 @@ +from rest_framework.routers import DefaultRouter + +from questions.views import QuestionModelViewSet + +router = DefaultRouter() +router.register("items", QuestionModelViewSet) + +urlpatterns = router.urls diff --git a/questions/views.py b/questions/views.py new file mode 100644 index 0000000..33c4537 --- /dev/null +++ b/questions/views.py @@ -0,0 +1,9 @@ +from rest_framework import viewsets + +from questions.models import Question +from questions.serializers import QuestionSerializer + + +class QuestionModelViewSet(viewsets.ModelViewSet): + queryset = Question.objects.all() + serializer_class = QuestionSerializer diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5c552e3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,36 @@ +appdirs==1.4.4 +asgiref==3.4.1 +attrs==21.2.0 +botocore==1.21.15 +distlib==0.3.2 +Django==3.2.9 +django-cors-headers==3.10.0 +django-debug-toolbar==3.2.2 +django-filter==21.1 +djangorestframework==3.12.4 +djangorestframework-simplejwt==5.0.0 +drf-spectacular==0.21.0 +filelock==3.0.12 +GDAL==3.3.3 +git-remote-codecommit==1.15.1 +inflection==0.5.1 +jmespath==0.10.0 +jsonschema==4.2.1 +numpy==1.21.4 +pbr==5.6.0 +Pillow==8.4.0 +protobuf==3.17.3 +psycopg2-binary==2.9.2 +PyJWT==2.3.0 +pyrsistent==0.18.0 +python-dateutil==2.8.2 +pytz==2021.3 +PyYAML==6.0 +six==1.16.0 +sqlparse==0.4.2 +stevedore==3.3.0 +uritemplate==4.1.1 +urllib3==1.26.6 +virtualenv==20.4.7 +virtualenv-clone==0.5.4 +virtualenvwrapper==4.8.4 diff --git a/templates/generic_test.html b/templates/generic_test.html new file mode 100644 index 0000000..0a815ae --- /dev/null +++ b/templates/generic_test.html @@ -0,0 +1,48 @@ + + + + + {{ test.name }} + + + + +
+
+
+ {{ test.name }} +
+{% for question in test.questions.all %} + +
+ {{ question.description }} +
+ +
+ {% for answer in question.answers.all %} + + {% endfor %} +
+ +{% endfor %} +
+
+ + + diff --git a/trials/__init__.py b/trials/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trials/apps.py b/trials/apps.py new file mode 100644 index 0000000..e69de29 diff --git a/trials/migrations/0001_initial.py b/trials/migrations/0001_initial.py new file mode 100644 index 0000000..c7c1c39 --- /dev/null +++ b/trials/migrations/0001_initial.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.1 on 2021-12-01 18:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Test', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + ] diff --git a/trials/migrations/__init__.py b/trials/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/trials/models.py b/trials/models.py new file mode 100644 index 0000000..0661aca --- /dev/null +++ b/trials/models.py @@ -0,0 +1,26 @@ +from django.db import models + + +class Test(models.Model): + name = models.CharField(max_length=100) + passing_score = models.PositiveSmallIntegerField() + + def get_score(self, answers): + """ + [ + { + "question": 1, + "answer": 1 + }, + { + "question": 2, + "answer": 1 + } + ] + """ + points = 0 + for answer in answers: + question = self.questions.get(id=answer["question"]) + if question.answers.get(id=answer["answer"]).is_correct: + points += question.points + return points diff --git a/trials/serializers.py b/trials/serializers.py new file mode 100644 index 0000000..52fce74 --- /dev/null +++ b/trials/serializers.py @@ -0,0 +1,18 @@ +from rest_framework import serializers + +from questions.serializers import QuestionSerializer +from trials.models import Test + + +class TestSerializer(serializers.ModelSerializer): + + questions = QuestionSerializer(many=True, required=False) + + class Meta: + model = Test + fields = ( + "id", + "name", + "passing_score", + "questions" + ) diff --git a/trials/urls.py b/trials/urls.py new file mode 100644 index 0000000..3ebf009 --- /dev/null +++ b/trials/urls.py @@ -0,0 +1,16 @@ +from django.urls import path +from rest_framework.routers import DefaultRouter + +from trials.views import TestModelViewSet +from trials.views import TestTemplateView +from trials.views import TestValidateAPIView + +router = DefaultRouter() +router.register("items", TestModelViewSet) + +urlpatterns = [ + path('/show/', TestTemplateView.as_view()), + path('/mark/', TestValidateAPIView.as_view()) +] + +urlpatterns += router.urls diff --git a/trials/views.py b/trials/views.py new file mode 100644 index 0000000..12dcd13 --- /dev/null +++ b/trials/views.py @@ -0,0 +1,50 @@ +from django.views.generic import TemplateView +from rest_framework import views +from rest_framework import viewsets +from rest_framework.response import Response + +from config.settings import BASE_DIR +from trials.models import Test +from trials.serializers import TestSerializer + + +class TestModelViewSet(viewsets.ModelViewSet): + queryset = Test.objects.all() + serializer_class = TestSerializer + + +class TestTemplateView(TemplateView): + + permission_classes = [] + template_name = BASE_DIR + f"/templates/generic_test.html" + + def get_queryset(self): + return Test.objects.all() + + def get_context_data(self, test_id, **kwargs): + context = super().get_context_data(**kwargs) + context["test"] = self.get_queryset().filter(id=test_id).prefetch_related("questions__answers").first() + return context + + +class TestValidateAPIView(views.APIView): + PASSED = "passed" + FAILED = "failed" + UNKNOWN = "unknown" + + PASSED = { + True: PASSED, + False: FAILED + } + + def get_score(self, test: Test, answers): + return test.get_score(answers) + + def post(self, request, test_id, **kwargs): + test = Test.objects.get(id=test_id) + score = self.get_score(test, request.data["answers"]) + status = score >= test.passing_score + return Response({ + "status": self.PASSED.get(status, self.UNKNOWN), + "points": score + }) diff --git a/users/.DS_Store b/users/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d94f02db993843517afa31d92cbe4b4d94ce1a8a GIT binary patch literal 6148 zcmeHKL2uJA6n^dsb29-wAdL%BF5IT6V`CBrq)^6TH>4mq0O}GFZIQCLYSKkp*C}`Y z09^Pz`~!XqC-|OiP`h>#r->oI$o`(~_u0;;*p7)v^vB5-QJ07$5@Xv#w#2xd(}J~Z z4L1tiM@AJ5@NCj>A=*_q1)Ku^ngYCb*YujrsG!;Pd%B;ik8!SIMDX_T9BK2XHh4rH z9V7mbMigPyXQaR{=Q-lx-*Do(9NKZd#lt)+t6uNBXsxtw-CmW_linTgLwKa>u!^d2 z*^fr=xb!Njj$-S-Rx1DFNAa61tq0xvFH})QS&@!3IZIN6ynmY&iK_c*TqLFLCo~OG zc4TMJU7t+0pX_eYkG7ue9~_^aP0ptmpS1!cu!@RO(&xlIr3UqGnaUi?|e;XHY#yex^&yxj!y(S7{99 z6(hBHPO~FPIzj&_)yrq5zlX0g-vj8*Zj=J{>y>LaYSwPDP64ODbtu65gO9`*SZoaH ztpl090sz~n)&`${7MSB(3@kPV(E<~O3N%zlU{8tKy_FlNx$1B;hb>Zdsto4x& rkk~k`F{mlX>~X9eK8hb8X+xXO4luCT7(@-s{Rn6oT;>$GRt0_mdBdkX literal 0 HcmV?d00001 diff --git a/users/__init__.py b/users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/migrations/.DS_Store b/users/migrations/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4f9740ebc2dd784389d1db9b83251ebb789ee993 GIT binary patch literal 6148 zcmeHKyH3ME5S)b+ky4N{4bpuB2LP4DmAP*WOi%>v8=Z?>Y*#{(!K}tmdyVma9 zW5;JtaeD_q<}dd%U<_bLSHzo!zUjPr&(2~*QS2Rec)%n5nSPon_X1b;%y7tGqrntU zc)e|Q+fB3EFq5Atm&ED2nJqCQYtPg6H!NHqv5cA_6-WhAfm9$B_=gIxW~&WHju}&d zR3H`jQb6~ILRYMTt)p!n40?Rm`GKMu+jf^Amgv{O){!$baVpWN5?2gyI>$@o)xg%# z=@46)?}?QqZYW}_bG%qOq&j9y1yX^o0_WZxYyH2W|8W2BlCqZyqym3R0U0coi#dNO yYHRQ3wAL2-ivDTLwRDEgA%Gn%#gl`)qHX5Yz}C^|95*^K4+5%7S}O1x3VZ-%ttsjN literal 0 HcmV?d00001 diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 0000000..c77fb1e --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 3.1.1 on 2021-12-01 18:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('first_name', models.CharField(max_length=100)), + ('last_name', models.CharField(max_length=100)), + ('email', models.EmailField(db_index=True, max_length=50, unique=True)), + ('is_active', models.BooleanField(default=False)), + ('confirmation_number', models.CharField(max_length=100)), + ('reset_code', models.CharField(max_length=100)), + ('avatar', models.ImageField(null=True, upload_to='avatars/')), + ], + options={ + 'ordering': ('id',), + }, + ), + ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/models.py b/users/models.py new file mode 100644 index 0000000..af77d96 --- /dev/null +++ b/users/models.py @@ -0,0 +1,26 @@ +from django.contrib.auth.base_user import AbstractBaseUser +from django.db import models + + +class User(AbstractBaseUser): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + + email = models.EmailField(db_index=True, unique=True, max_length=50) + is_active = models.BooleanField(default=False) + + confirmation_number = models.CharField(max_length=100) + reset_code = models.CharField(max_length=100) + avatar = models.ImageField(upload_to="avatars/", null=True) + + USERNAME_FIELD = "email" + + class Meta: + ordering = ("id", ) + + def get_details(self): + return { + "first_name": self.first_name, + "last_name": self.last_name, + "email": self.email + } diff --git a/users/serializers.py b/users/serializers.py new file mode 100644 index 0000000..89b380b --- /dev/null +++ b/users/serializers.py @@ -0,0 +1,16 @@ +from rest_framework import serializers + +from users.models import User + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ( + "id", + "email", + "first_name", + "last_name", + "is_active", + "password" + ) diff --git a/users/urls.py b/users/urls.py new file mode 100644 index 0000000..35daf75 --- /dev/null +++ b/users/urls.py @@ -0,0 +1,16 @@ +from rest_framework.routers import DefaultRouter +from django.urls import include +from django.urls import path +from users.views import UserModelViewSet +from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.views import TokenRefreshView + + +router = DefaultRouter() +router.register("items", UserModelViewSet) + +urlpatterns = [ + path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), +] + diff --git a/users/views.py b/users/views.py new file mode 100644 index 0000000..a441865 --- /dev/null +++ b/users/views.py @@ -0,0 +1,9 @@ +from rest_framework import viewsets + +from users.models import User +from users.serializers import UserSerializer + + +class UserModelViewSet(viewsets.ModelViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer From e9950631750148e92a229d76a6703ba43bc792f7 Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 14:01:13 +0100 Subject: [PATCH 3/7] Aligment gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 56a04c3..aac87cd 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,6 @@ GitHub.sublime-settings !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -.history \ No newline at end of file +.history + +secrets.json \ No newline at end of file From 955804a5d3115cc1388c648f1b2c2a3a0409f97f Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 15:23:29 +0100 Subject: [PATCH 4/7] Added shell_plus --- .idea/SOITA.iml | 2 +- .idea/misc.xml | 2 +- answers/urls.py | 2 +- config/settings.py | 5 +-- requirements.txt | 74 ++++++++++++++++++++++++++++++++++++++++++++ trials/models.py | 2 +- users/managers.py | 9 ++++++ users/models.py | 4 +++ users/querysets.py | 7 +++++ users/serializers.py | 10 ++++++ users/urls.py | 7 +++-- 11 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 users/managers.py create mode 100644 users/querysets.py diff --git a/.idea/SOITA.iml b/.idea/SOITA.iml index 66ca8ca..19acda8 100644 --- a/.idea/SOITA.iml +++ b/.idea/SOITA.iml @@ -14,7 +14,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index be60604..2161090 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/answers/urls.py b/answers/urls.py index e9553b2..e6f4956 100644 --- a/answers/urls.py +++ b/answers/urls.py @@ -2,7 +2,7 @@ from rest_framework.routers import DefaultRouter from answers.views import AnswerModelViewSet -router = DefaultRouter() +router = DefaultRouter(trailing_slash=False) router.register("items", AnswerModelViewSet) urlpatterns = router.urls diff --git a/config/settings.py b/config/settings.py index 66b57e0..b6a07f7 100644 --- a/config/settings.py +++ b/config/settings.py @@ -46,6 +46,7 @@ INSTALLED_APPS = [ "django.contrib.gis", "rest_framework", "rest_framework_simplejwt", + "django_extensions", "users", "trials", @@ -100,10 +101,10 @@ DATABASES = { REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": ( - # "rest_framework.permissions.IsAuthenticated", + "rest_framework.permissions.IsAuthenticated", ), "DEFAULT_AUTHENTICATION_CLASSES": ( - # "rest_framework_simplejwt.authentication.JWTAuthentication", + "rest_framework_simplejwt.authentication.JWTAuthentication", ), "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", "DEFAULT_FILTER_BACKENDS": ( diff --git a/requirements.txt b/requirements.txt index 5c552e3..12c912c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,36 +1,110 @@ +alabaster==0.7.12 appdirs==1.4.4 +appnope==0.1.2 +argon2-cffi==21.1.0 asgiref==3.4.1 attrs==21.2.0 +Babel==2.9.1 +backcall==0.2.0 +bleach==4.1.0 botocore==1.21.15 +certifi==2021.10.8 +cffi==1.15.0 +charset-normalizer==2.0.9 +debugpy==1.5.1 +decorator==5.1.0 +defusedxml==0.7.1 distlib==0.3.2 Django==3.2.9 django-cors-headers==3.10.0 django-debug-toolbar==3.2.2 +django-extensions==3.1.5 django-filter==21.1 +django-shell-plus==1.1.7 djangorestframework==3.12.4 djangorestframework-simplejwt==5.0.0 +docutils==0.17.1 drf-spectacular==0.21.0 +entrypoints==0.3 filelock==3.0.12 GDAL==3.3.3 git-remote-codecommit==1.15.1 +idna==3.3 +imagesize==1.3.0 +importlib-metadata==4.8.2 inflection==0.5.1 +ipykernel==6.6.0 +ipyparallel==8.0.0 +ipython==7.30.1 +ipython-genutils==0.2.0 +ipywidgets==7.6.5 +jedi==0.18.1 +Jinja2==3.0.3 jmespath==0.10.0 jsonschema==4.2.1 +jupyter-client==7.1.0 +jupyter-core==4.9.1 +jupyterlab-pygments==0.1.2 +jupyterlab-widgets==1.0.2 +Markdown==3.3.6 +MarkupSafe==2.0.1 +matplotlib-inline==0.1.3 +mistune==0.8.4 +nbclient==0.5.9 +nbconvert==6.3.0 +nbformat==5.1.3 +nest-asyncio==1.5.4 +nose==1.3.7 +notebook==6.4.6 numpy==1.21.4 +packaging==21.3 +pandocfilters==1.5.0 +parso==0.8.3 pbr==5.6.0 +pexpect==4.8.0 +pickleshare==0.7.5 Pillow==8.4.0 +prometheus-client==0.12.0 +prompt-toolkit==3.0.23 protobuf==3.17.3 +psutil==5.8.0 psycopg2-binary==2.9.2 +ptyprocess==0.7.0 +pycparser==2.21 +Pygments==2.10.0 PyJWT==2.3.0 +pyparsing==3.0.6 pyrsistent==0.18.0 python-dateutil==2.8.2 pytz==2021.3 PyYAML==6.0 +pyzmq==22.3.0 +qtconsole==5.2.1 +QtPy==1.11.3 +requests==2.26.0 +Send2Trash==1.8.0 six==1.16.0 +snowballstemmer==2.2.0 +Sphinx==4.3.1 +sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 sqlparse==0.4.2 stevedore==3.3.0 +terminado==0.12.1 +testpath==0.5.0 +tornado==6.1 +tqdm==4.62.3 +traitlets==5.1.1 uritemplate==4.1.1 urllib3==1.26.6 virtualenv==20.4.7 virtualenv-clone==0.5.4 virtualenvwrapper==4.8.4 +wcwidth==0.2.5 +webencodings==0.5.1 +widgetsnbextension==3.5.2 +zipp==3.6.0 diff --git a/trials/models.py b/trials/models.py index 0661aca..014c00c 100644 --- a/trials/models.py +++ b/trials/models.py @@ -3,7 +3,7 @@ from django.db import models class Test(models.Model): name = models.CharField(max_length=100) - passing_score = models.PositiveSmallIntegerField() + passing_score = models.PositiveSmallIntegerField(default=0) def get_score(self, answers): """ diff --git a/users/managers.py b/users/managers.py new file mode 100644 index 0000000..93aacfd --- /dev/null +++ b/users/managers.py @@ -0,0 +1,9 @@ +from django.contrib.auth.base_user import BaseUserManager + +from .querysets import UserQuerySet + + +class UserManager(BaseUserManager): + + def get_queryset(self): + return UserQuerySet(self.model, using=self._db) \ No newline at end of file diff --git a/users/models.py b/users/models.py index af77d96..886360f 100644 --- a/users/models.py +++ b/users/models.py @@ -1,6 +1,8 @@ from django.contrib.auth.base_user import AbstractBaseUser from django.db import models +from .managers import UserManager + class User(AbstractBaseUser): first_name = models.CharField(max_length=100) @@ -15,6 +17,8 @@ class User(AbstractBaseUser): USERNAME_FIELD = "email" + objects = UserManager() + class Meta: ordering = ("id", ) diff --git a/users/querysets.py b/users/querysets.py new file mode 100644 index 0000000..d4323d9 --- /dev/null +++ b/users/querysets.py @@ -0,0 +1,7 @@ +from django.db.models import QuerySet + + +class UserQuerySet(QuerySet): + + def activated(self, **kwargs): + return self.filter(is_activated=True) \ No newline at end of file diff --git a/users/serializers.py b/users/serializers.py index 89b380b..2209870 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -4,6 +4,16 @@ from users.models import User class UserSerializer(serializers.ModelSerializer): + + password = serializers.CharField( + write_only=True, + required=False, + min_length=8, + style={"input_type": "password"}, + ) + #todo + # avatar = serializers.ImageField(allow_empty_file=True, source="profile.avatar", read_only=True) + class Meta: model = User fields = ( diff --git a/users/urls.py b/users/urls.py index 35daf75..cf7ca52 100644 --- a/users/urls.py +++ b/users/urls.py @@ -6,11 +6,12 @@ from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.views import TokenRefreshView -router = DefaultRouter() +router = DefaultRouter(trailing_slash=False) router.register("items", UserModelViewSet) urlpatterns = [ - path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), - path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), + path("", include(router.urls)), + path('api/token', TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('api/token/refresh', TokenRefreshView.as_view(), name='token_refresh'), ] From d9be36b73df6ab9874a260bc70026795894ca430 Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 15:23:40 +0100 Subject: [PATCH 5/7] migrations --- questions/migrations/0002_question_points.py | 18 ++++++++++++++++++ trials/migrations/0002_test_passing_score.py | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 questions/migrations/0002_question_points.py create mode 100644 trials/migrations/0002_test_passing_score.py diff --git a/questions/migrations/0002_question_points.py b/questions/migrations/0002_question_points.py new file mode 100644 index 0000000..350d1cb --- /dev/null +++ b/questions/migrations/0002_question_points.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-05 13:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('questions', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='question', + name='points', + field=models.PositiveSmallIntegerField(default=1), + ), + ] diff --git a/trials/migrations/0002_test_passing_score.py b/trials/migrations/0002_test_passing_score.py new file mode 100644 index 0000000..ae4fdf4 --- /dev/null +++ b/trials/migrations/0002_test_passing_score.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-05 13:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trials', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='test', + name='passing_score', + field=models.PositiveSmallIntegerField(default=0), + ), + ] From 45a4171d95702cdbf7ef684576a48c75fa9fceae Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 15:50:15 +0100 Subject: [PATCH 6/7] Added authorization --- users/managers.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/users/managers.py b/users/managers.py index 93aacfd..d4dece3 100644 --- a/users/managers.py +++ b/users/managers.py @@ -6,4 +6,16 @@ from .querysets import UserQuerySet class UserManager(BaseUserManager): def get_queryset(self): - return UserQuerySet(self.model, using=self._db) \ No newline at end of file + return UserQuerySet(self.model, using=self._db) + + def create(self, email, password=None, **kwargs): + + if password is None: + message = "User must have valid password" + raise ValueError(message) + + user = self.model(email=email, **kwargs) + user.set_password(password) + user.save() + + return user From e550d49932b6e26179ab0e6b48020be779d73ac0 Mon Sep 17 00:00:00 2001 From: Hubert Jankowski Date: Sun, 5 Dec 2021 16:02:46 +0100 Subject: [PATCH 7/7] remove idea --- .idea/.gitignore | 8 ----- .idea/SOITA.iml | 30 ------------------- .idea/encodings.xml | 4 --- .../inspectionProfiles/profiles_settings.xml | 6 ---- .idea/misc.xml | 7 ----- .idea/modules.xml | 8 ----- .idea/vcs.xml | 6 ---- 7 files changed, 69 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/SOITA.iml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 73f69e0..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/SOITA.iml b/.idea/SOITA.iml deleted file mode 100644 index 19acda8..0000000 --- a/.idea/SOITA.iml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b2..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 2161090..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 19e9fd9..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file