diff --git a/.github/workflows/qa-checks.yml b/.github/workflows/qa-checks.yml new file mode 100644 index 0000000..eebb155 --- /dev/null +++ b/.github/workflows/qa-checks.yml @@ -0,0 +1,22 @@ +name: Open Source Programs QA Checks + +on: [push, pull_request] + +jobs: + lint: + name: Linting and Code Formatting Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Installing QA-CHECKS Dependencies + run: | + python -m pip install --upgrade pip + pip install black==20.8b1 + pip install isort==5.7.0 + pip install flake8==3.8.4 + - name: Running QA-CHECKS + run: ./osp-qa-checks diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..95e430a --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,58 @@ +name: Tests Build + +on: [push, pull_request] + +jobs: + + build: + + name: Run tests + runs-on: ubuntu-latest + + services: + postgres: + image: postgres + env: + POSTGRES_USER: osp + POSTGRES_PASSWORD: osp + POSTGRES_DB: osp + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: Installing dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install coverage==5.4 + + - name: Creating Zulip API key + run: echo -e "${{ secrets.ZULIP_API_KEY }}" >> download + + - name: Migrating Test Database + run: python manage.py migrate + + - name: Run tests + run: coverage run manage.py test + + - name: Generate coverage report + run: coverage xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + file: ./coverage.xml + name: codecov-umbrella + fail_ci_if_error: true diff --git a/README.md b/README.md index 3e378be..c1ff45e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ # Open Source Programs (Backend) + +![Build Status](https://github.com/anitab-org/open-source-programs-backend/workflows/Tests%20Build/badge.svg) +[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://anitab-org.zulipchat.com/#narrow/stream/237907-open-source-progs) +[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) +[![Open Source Love](https://badges.frapsoft.com/os/v3/open-source.svg?v=103)](https://github.com/anitab-org/open-source-programs-backend/) +[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/anitab-org/open-source-programs-backend) +![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square) + Open Source Programs (OSP) is an application that simplifies the processing and selection procedure of Open Source Programs of AnitaB.org Open Source or other third-party programs. This is the Backend repo for OSP. ## Tech Stack @@ -36,33 +44,34 @@ Next follow these instructions. CREATE DATABASE osp; \c osp; GRANT ALL PRIVILEGES ON DATABASE osp to osp; + GRANT ALL PRIVILEGES ON DATABASE test_osp to osp; + ALTER USER osp CREATEDB; ``` -2. You need to download API key file from your user-settings on Zulip. The file you download is named as 'download' or rename that to 'download'. -3. Place that download file in the project's directory. +2. **Set the environment variables:** You need to download Zulip API key file from your user-settings on Zulip. The file you download is named as `download` or rename it to `download`. Place that download file in the project's directory. For more information follow [Environment Variables](#Environment-Variables) section. -4. Move into the project's directory. +3. Move into the project's directory. ``` cd open-source-programs-backend ``` -5. Create virtual environment (this is not a hard requirement, but its advisable) +4. Create virtual environment (this is not a hard requirement, but its advisable) ``` virtualenv venv source venv/bin/activate pip install -r requirements.txt ``` -6. To run the migrations run: +5. To run the migrations run: ``` python manage.py migrate ``` -7. To run the server: +6. To run the server: ``` python manage.py runserver ``` -8. Navigate to `http://localhost:8000/` in your browser. -9. To change the port you may run `python manage.py runserver ` -10. To run the migrations run: `python manage.py migrate` -11. You can terminate the process by `Ctrl+C` in your terminal. +7. Navigate to `http://localhost:8000/` in your browser. +8. To change the port you may run `python manage.py runserver ` +9. To run the migrations run: `python manage.py migrate` +10. You can terminate the process by `Ctrl+C` in your terminal. Follow the given instructions for Login into the app. @@ -74,10 +83,40 @@ Follow the given instructions for Login into the app. ```` Fill up the things it asked to and then Login into the app. +## Environment Variables + +1. `Zulip API KEY file` - You can go [Zulip](https://anitab-org.zulipchat.com) and follow [these instructions to get your API KEY](https://zulip.com/api/api-keys#get-your-api-key). Download the file and save it in the root folder of the project with the name `download`. + +2. `SENDGRID_API_KEY` - Follow the given steps to create a Sendgrid API key: + + 1. Go to [Sendgrid's website](https://app.sendgrid.com/guide) + 2. Navigate to Settings on the left navigation bar, and then - select API Keys. + 3. Click Create API Key. + 4. Give your API key a name. + 5. Select Full Access, Restricted Access, or Billing Access. If you're selecting Restricted Access, or Billing Access, select the specific permissions to give each category. For more information, see API key permissions. + 6. Click Create & View. + 7. The API KEY is generated and displayed to you just once. So be sure to copy and save it somewhere. + +Add it to your .env file as follows: +``` +export SENDGRID_API_KEY= +``` + ## Testing To run the tests run: `python manage.py test`. +## QA Checks + +Before creating a pull-request, always run QA checks to make your code more readable and error-free. Steps to run QA checks are: +1. Install QA checks dependencies: + ``` + pip install black==20.8b1 + pip install isort==5.7.0 + pip install flake8==3.8.4 + ``` +2. Run QA checks: `./osp-qa-checks`. + ### Run with Docker 1. Make sure the latest version of docker and docker-compose are installed. @@ -104,12 +143,12 @@ Run ``sudo docker-compose up`` from the root directory of project. Navigate to ` ## Documentation -- Read the [Meeting minutes](https://docs.google.com/document/d/1YF13IbBrU1ln4ZF1fOpgb-xGRgIF6tZLSjIBQgDmN7k/edit) notes from our open sessions about the project. +- Read the [Meeting minutes](https://docs.google.com/document/d/1JSyAr9bO4hJJxFvThvn_LVjW0KcEspXpzvWULRC_xJE/edit) notes from our open sessions about the project. - For setting up the project locally watch [this video](https://youtu.be/_b2RQGbYN9w). - To learn about the project's initial features, watch the video of [project demonstration](https://youtu.be/3A746GppZ0Y). - [Design and Mocks Google Drive folder](https://drive.google.com/drive/folders/1MybSH3f8peXGUSRxhDydDtoAi8WJL1th). - [Timeline deliverables for the project during GSoC 2020](https://docs.google.com/document/d/1xl9F5kMZrKo4mNhnP0SKpk7WkQc8PLca1ym7EZMpjSc/edit). -- [GSoC 2020 Project Meeting Minutes](https://docs.google.com/document/d/1YF13IbBrU1ln4ZF1fOpgb-xGRgIF6tZLSjIBQgDmN7k/edit). +- [GSoC 2020 Project Meeting Minutes](https://docs.google.com/document/d/1YF13IbBrU1ln4ZF1fOpgb-xGRgIF6tZLSjIBQgDmN7k/edit) [Old]. For more information, you can read [backend project wiki](https://github.com/anitab-org/open-source-programs-backend/wiki) and the [web project wiki](https://github.com/anitab-org/open-source-programs-web/wiki). diff --git a/docs/github_actions.md b/docs/github_actions.md new file mode 100644 index 0000000..cc77302 --- /dev/null +++ b/docs/github_actions.md @@ -0,0 +1,15 @@ +# GitHub Actions + +The purpose of using GitHub actions is to run tests and QA-checks. + +## Configuration + +There is currently one environment variable needed for configuring the GitHub actions. Details are mentioned below: + +1. `ZULIP_API_KEY`: This secret variable is needed to run tests. This is the API key that we get from zulip to access ZULIP API. To get this key follow t[hese instructions from official documentation](https://zulip.com/api/api-keys#get-your-api-key). The content of this secret variable should look like: + ``` + [api] + email=example@example.com + key=******************************************** + site=https://anitab-org.zulipchat.com + ``` diff --git a/main/asgi.py b/main/asgi.py index fabf75e..e5b9bb2 100644 --- a/main/asgi.py +++ b/main/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main.settings") application = get_asgi_application() diff --git a/main/settings.py b/main/settings.py index ffaa56a..fe6b161 100644 --- a/main/settings.py +++ b/main/settings.py @@ -12,7 +12,9 @@ import os from datetime import timedelta + from dotenv import load_dotenv + load_dotenv() # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -23,7 +25,7 @@ # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '7ibm!g0j@gs7kszwav!6$*lar(+!!l3tpm@09s%csl2bj)l+p4' +SECRET_KEY = "7ibm!g0j@gs7kszwav!6$*lar(+!!l3tpm@09s%csl2bj)l+p4" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -34,92 +36,93 @@ # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', - 'corsheaders', - 'osp', - 'token_auth' + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", + "corsheaders", + "osp", + "token_auth", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'main.urls' +ROOT_URLCONF = "main.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - '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', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "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", ], }, }, ] REST_FRAMEWORK = { - "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated",], - "DEFAULT_PARSER_CLASSES": ["rest_framework.parsers.JSONParser", ], - "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework.authentication.SessionAuthentication", - "rest_framework_simplejwt.authentication.JWTAuthentication", + "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"], + "DEFAULT_PARSER_CLASSES": ["rest_framework.parsers.JSONParser"], + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework.authentication.SessionAuthentication", + "rest_framework_simplejwt.authentication.JWTAuthentication", ), + "TEST_REQUEST_DEFAULT_FORMAT": "json", } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(days=2), - 'REFRESH_TOKEN_LIFETIME': timedelta(days=30), + "ACCESS_TOKEN_LIFETIME": timedelta(days=2), + "REFRESH_TOKEN_LIFETIME": timedelta(days=30), } CORS_ORIGIN_WHITELIST = [ - 'http://127.0.0.1:3000', - 'http://localhost:3000', + "http://127.0.0.1:3000", + "http://localhost:3000", ] -SENDGRID_API_KEY = os.getenv('SENDGRID_API_KEY') +SENDGRID_API_KEY = os.getenv("SENDGRID_API_KEY") SENDGRID_SANDBOX_MODE_IN_DEBUG = False SENDGRID_ECHO_TO_STDOUT = True -EMAIL_HOST = 'smtp.sendgrid.net' -EMAIL_HOST_USER = 'apikey' +EMAIL_HOST = "smtp.sendgrid.net" +EMAIL_HOST_USER = "apikey" EMAIL_HOST_PASSWORD = SENDGRID_API_KEY EMAIL_PORT = 587 EMAIL_USE_TLS = True -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -AUTH_USER_MODEL = 'token_auth.User' +AUTH_USER_MODEL = "token_auth.User" -WSGI_APPLICATION = 'main.wsgi.application' +WSGI_APPLICATION = "main.wsgi.application" # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': "osp", - 'USER': "osp", - 'PASSWORD': "osp", - 'HOST': "localhost", # Change to db for docker-compose - 'PORT': 5432, + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": "osp", + "USER": "osp", + "PASSWORD": "osp", + "HOST": "localhost", # Change to db for docker-compose + "PORT": 5432, } } @@ -128,27 +131,19 @@ # https://docs.djangoproject.com/en/3.0/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', - }, + {"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.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -160,4 +155,4 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" diff --git a/main/urls.py b/main/urls.py index 1ccbdc2..b229d2b 100644 --- a/main/urls.py +++ b/main/urls.py @@ -14,11 +14,11 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path, include +from django.urls import include, path urlpatterns = [ - path('admin/', admin.site.urls), - path('api/', include('osp.urls')), - path('auth/', include('rest_framework.urls')), - path('api/token_auth/', include('token_auth.urls')) + path("admin/", admin.site.urls), + path("api/", include("osp.urls")), + path("auth/", include("rest_framework.urls")), + path("api/token_auth/", include("token_auth.urls")), ] diff --git a/main/wsgi.py b/main/wsgi.py index 6512615..3cb5eb5 100644 --- a/main/wsgi.py +++ b/main/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main.settings") application = get_wsgi_application() diff --git a/manage.py b/manage.py index 063eacc..62ddce0 100755 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -17,5 +17,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/osp-qa-checks b/osp-qa-checks new file mode 100755 index 0000000..ebc7a79 --- /dev/null +++ b/osp-qa-checks @@ -0,0 +1,35 @@ +#!/bin/bash + +black-check(){ + black --check --quiet . && echo "Black Check ✅" || { + >&2 echo "Black Check ❌" + echo "Suggestion: Run - black ." + echo "" + FAILURE=1 + } +} + +isort-check(){ + isort --check -rc --quiet . && echo "Isort Check ✅" || { + >&2 echo "Isort Check ❌" + echo "Suggestion: Run - isort -rc ." + echo "" + FAILURE=1 + } +} + +flake8-check() { + flake8 && echo "Flake8 Check ✅" ||{ + >&2 echo "Flake8 Check ❌" + echo "Suggestion: Run - flake8 ." + echo "" + FAILURE=1 + } +} + +black-check +echo "" +isort-check +echo "" +flake8-check +exit $FAILURE diff --git a/osp/admin.py b/osp/admin.py index 140b383..d282049 100644 --- a/osp/admin.py +++ b/osp/admin.py @@ -1,19 +1,53 @@ from django.contrib import admin from osp.models import ( - UserInformation, Form, Question, Choice, - Checkbox, Dropdown, Paragraph, ShortAnswer, - Date, Time, FileUpload, Answer, ChoiceValue, - CheckboxValue, DropdownValue, ParagraphValue, ShortAnswerValue, - DateValue, TimeValue, FileUploadValue, FormFeedback, ZulipStat + Answer, + Checkbox, + CheckboxValue, + Choice, + ChoiceValue, + Date, + DateValue, + Dropdown, + DropdownValue, + FileUpload, + FileUploadValue, + Form, + FormFeedback, + Paragraph, + ParagraphValue, + Question, + ShortAnswer, + ShortAnswerValue, + Time, + TimeValue, + UserInformation, + ZulipStat, ) models = [ - UserInformation, Form, Question, Choice, - Checkbox, Dropdown, Paragraph, ShortAnswer, - Date, Time, FileUpload, Answer, ChoiceValue, - CheckboxValue, DropdownValue, ParagraphValue, ShortAnswerValue, - DateValue, TimeValue, FileUploadValue, FormFeedback, ZulipStat + UserInformation, + Form, + Question, + Choice, + Checkbox, + Dropdown, + Paragraph, + ShortAnswer, + Date, + Time, + FileUpload, + Answer, + ChoiceValue, + CheckboxValue, + DropdownValue, + ParagraphValue, + ShortAnswerValue, + DateValue, + TimeValue, + FileUploadValue, + FormFeedback, + ZulipStat, ] admin.site.register(models) diff --git a/osp/apps.py b/osp/apps.py index ee8154b..2bd18b8 100644 --- a/osp/apps.py +++ b/osp/apps.py @@ -2,4 +2,4 @@ class OspConfig(AppConfig): - name = 'osp' + name = "osp" diff --git a/osp/migrations/0001_initial.py b/osp/migrations/0001_initial.py index 9f7bf6a..0d84726 100644 --- a/osp/migrations/0001_initial.py +++ b/osp/migrations/0001_initial.py @@ -1,8 +1,8 @@ # Generated by Django 3.0.6 on 2020-06-02 19:37 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): @@ -15,12 +15,12 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='UserInformation', + name="UserInformation", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('user_type', models.CharField(choices=[('admin', 'Admin'), ('student', 'Student')], max_length=7)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("user_type", models.CharField(choices=[("admin", "Admin"), ("student", "Student")], max_length=7)), + ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), ] diff --git a/osp/migrations/0002_auto_20200609_1626.py b/osp/migrations/0002_auto_20200609_1626.py index ec86513..f481a44 100644 --- a/osp/migrations/0002_auto_20200609_1626.py +++ b/osp/migrations/0002_auto_20200609_1626.py @@ -6,13 +6,15 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0001_initial'), + ("osp", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='userinformation', - name='user_type', - field=models.CharField(choices=[('admin', 'Admin'), ('student', 'Student')], default='student', max_length=7), + model_name="userinformation", + name="user_type", + field=models.CharField( + choices=[("admin", "Admin"), ("student", "Student")], default="student", max_length=7 + ), ), ] diff --git a/osp/migrations/0003_form_question.py b/osp/migrations/0003_form_question.py index c1c3553..ef98767 100644 --- a/osp/migrations/0003_form_question.py +++ b/osp/migrations/0003_form_question.py @@ -6,40 +6,62 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0002_auto_20200609_1626'), + ("osp", "0002_auto_20200609_1626"), ] operations = [ migrations.CreateModel( - name='Question', + name="Question", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('updated_on', models.DateTimeField(auto_now=True)), - ('label', models.CharField(max_length=255)), - ('data_type', models.CharField(choices=[('char', 'Short Answer'), ('text', 'Paragraph Answer'), ('choice', 'Choice'), ('checkbox', 'Checkbox'), ('dropdown', 'Dropdown'), ('file', 'File Upload'), ('date', 'Date'), ('time', 'Time')], max_length=8)), - ('description', models.TextField(blank=True)), - ('order', models.PositiveIntegerField()), - ('required', models.BooleanField(default=False)), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_on", models.DateTimeField(auto_now_add=True)), + ("updated_on", models.DateTimeField(auto_now=True)), + ("label", models.CharField(max_length=255)), + ( + "data_type", + models.CharField( + choices=[ + ("char", "Short Answer"), + ("text", "Paragraph Answer"), + ("choice", "Choice"), + ("checkbox", "Checkbox"), + ("dropdown", "Dropdown"), + ("file", "File Upload"), + ("date", "Date"), + ("time", "Time"), + ], + max_length=8, + ), + ), + ("description", models.TextField(blank=True)), + ("order", models.PositiveIntegerField()), + ("required", models.BooleanField(default=False)), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Form', + name="Form", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('description', models.TextField(blank=True)), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('updated_on', models.DateTimeField(auto_now=True)), - ('published_status', models.BooleanField(default=False)), - ('target_user', models.CharField(choices=[('all', 'All Users'), ('admin', 'Admin'), ('student', 'Student')], default='all', max_length=7)), - ('form_fields', models.ManyToManyField(blank=True, default=None, to='osp.Question')), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ("created_on", models.DateTimeField(auto_now_add=True)), + ("updated_on", models.DateTimeField(auto_now=True)), + ("published_status", models.BooleanField(default=False)), + ( + "target_user", + models.CharField( + choices=[("all", "All Users"), ("admin", "Admin"), ("student", "Student")], + default="all", + max_length=7, + ), + ), + ("form_fields", models.ManyToManyField(blank=True, default=None, to="osp.Question")), ], options={ - 'abstract': False, + "abstract": False, }, ), ] diff --git a/osp/migrations/0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time.py b/osp/migrations/0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time.py index df642b5..9c4bdbe 100644 --- a/osp/migrations/0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time.py +++ b/osp/migrations/0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time.py @@ -1,98 +1,193 @@ # Generated by Django 3.0.7 on 2020-06-20 15:27 import django.contrib.postgres.fields -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('osp', '0003_form_question'), + ("osp", "0003_form_question"), ] operations = [ migrations.CreateModel( - name='Checkbox', + name="Checkbox", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), - ('options', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255), size=None)), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), + ( + "options", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=255), size=None + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='Choice', + name="Choice", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), - ('options', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255), size=None)), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), + ( + "options", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=255), size=None + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='Date', + name="Date", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='Dropdown', + name="Dropdown", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), - ('options', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255), size=None)), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), + ( + "options", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=255), size=None + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='FileUpload', + name="FileUpload", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='Paragraph', + name="Paragraph", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='ShortAnswer', + name="ShortAnswer", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), migrations.CreateModel( - name='Time', + name="Time", fields=[ - ('question_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Question')), + ( + "question_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Question", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.question',), + bases=("osp.question",), ), ] diff --git a/osp/migrations/0005_auto_20200625_1656.py b/osp/migrations/0005_auto_20200625_1656.py index 218d4c8..a43eefb 100644 --- a/osp/migrations/0005_auto_20200625_1656.py +++ b/osp/migrations/0005_auto_20200625_1656.py @@ -6,13 +6,26 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time'), + ("osp", "0004_checkbox_choice_date_dropdown_fileupload_paragraph_shortanswer_time"), ] operations = [ migrations.AlterField( - model_name='question', - name='data_type', - field=models.CharField(choices=[('char', 'Short Answer'), ('text', 'Paragraph Answer'), ('choice', 'Choice'), ('checkbox', 'Checkbox'), ('dropdown', 'Dropdown'), ('file', 'File Upload'), ('date', 'Date'), ('time', 'Time')], default='char', max_length=8), + model_name="question", + name="data_type", + field=models.CharField( + choices=[ + ("char", "Short Answer"), + ("text", "Paragraph Answer"), + ("choice", "Choice"), + ("checkbox", "Checkbox"), + ("dropdown", "Dropdown"), + ("file", "File Upload"), + ("date", "Date"), + ("time", "Time"), + ], + default="char", + max_length=8, + ), ), ] diff --git a/osp/migrations/0006_auto_20200707_1707.py b/osp/migrations/0006_auto_20200707_1707.py index d3682be..2cdf811 100644 --- a/osp/migrations/0006_auto_20200707_1707.py +++ b/osp/migrations/0006_auto_20200707_1707.py @@ -6,16 +6,16 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0005_auto_20200625_1656'), + ("osp", "0005_auto_20200625_1656"), ] operations = [ migrations.AlterModelOptions( - name='form', - options={'ordering': ['-created_on']}, + name="form", + options={"ordering": ["-created_on"]}, ), migrations.AlterModelOptions( - name='question', - options={'ordering': ['order']}, + name="question", + options={"ordering": ["order"]}, ), ] diff --git a/osp/migrations/0007_auto_20200708_1714.py b/osp/migrations/0007_auto_20200708_1714.py index a8d500f..441b458 100644 --- a/osp/migrations/0007_auto_20200708_1714.py +++ b/osp/migrations/0007_auto_20200708_1714.py @@ -6,13 +6,13 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0006_auto_20200707_1707'), + ("osp", "0006_auto_20200707_1707"), ] operations = [ migrations.AlterField( - model_name='form', - name='form_fields', - field=models.ManyToManyField(blank=True, default=None, related_name='form_fields', to='osp.Question'), + model_name="form", + name="form_fields", + field=models.ManyToManyField(blank=True, default=None, related_name="form_fields", to="osp.Question"), ), ] diff --git a/osp/migrations/0008_auto_20200708_1817.py b/osp/migrations/0008_auto_20200708_1817.py index eba180d..762698f 100644 --- a/osp/migrations/0008_auto_20200708_1817.py +++ b/osp/migrations/0008_auto_20200708_1817.py @@ -6,17 +6,17 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0007_auto_20200708_1714'), + ("osp", "0007_auto_20200708_1714"), ] operations = [ migrations.RemoveField( - model_name='form', - name='form_fields', + model_name="form", + name="form_fields", ), migrations.AddField( - model_name='form', - name='questions', - field=models.ManyToManyField(blank=True, default=None, related_name='forms', to='osp.Question'), + model_name="form", + name="questions", + field=models.ManyToManyField(blank=True, default=None, related_name="forms", to="osp.Question"), ), ] diff --git a/osp/migrations/0009_form_close.py b/osp/migrations/0009_form_close.py index cdd3ed7..8acb7ab 100644 --- a/osp/migrations/0009_form_close.py +++ b/osp/migrations/0009_form_close.py @@ -6,13 +6,13 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0008_auto_20200708_1817'), + ("osp", "0008_auto_20200708_1817"), ] operations = [ migrations.AddField( - model_name='form', - name='close', + model_name="form", + name="close", field=models.BooleanField(default=False), ), ] diff --git a/osp/migrations/0010_auto_20200713_1843.py b/osp/migrations/0010_auto_20200713_1843.py index e01f83f..6080fb1 100644 --- a/osp/migrations/0010_auto_20200713_1843.py +++ b/osp/migrations/0010_auto_20200713_1843.py @@ -6,17 +6,21 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0009_form_close'), + ("osp", "0009_form_close"), ] operations = [ migrations.RemoveField( - model_name='form', - name='close', + model_name="form", + name="close", ), migrations.AlterField( - model_name='form', - name='published_status', - field=models.CharField(choices=[('published', 'Published'), ('unpublished', 'Unpublished'), ('closed', 'Closed')], default='unpublished', max_length=11), + model_name="form", + name="published_status", + field=models.CharField( + choices=[("published", "Published"), ("unpublished", "Unpublished"), ("closed", "Closed")], + default="unpublished", + max_length=11, + ), ), ] diff --git a/osp/migrations/0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue.py b/osp/migrations/0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue.py index 794f06b..c7e14e0 100644 --- a/osp/migrations/0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue.py +++ b/osp/migrations/0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue.py @@ -1,128 +1,228 @@ # Generated by Django 3.0.7 on 2020-07-23 14:21 -from django.conf import settings import django.contrib.postgres.fields -from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('osp', '0010_auto_20200713_1843'), + ("osp", "0010_auto_20200713_1843"), ] operations = [ migrations.CreateModel( - name='Answer', + name="Answer", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('updated_on', models.DateTimeField(auto_now=True)), - ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osp.Question')), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_on", models.DateTimeField(auto_now_add=True)), + ("updated_on", models.DateTimeField(auto_now=True)), + ("question", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="osp.Question")), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='CheckboxValue', + name="CheckboxValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255), size=None)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ( + "value", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=255), size=None + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='ChoiceValue', + name="ChoiceValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.CharField(max_length=255)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.CharField(max_length=255)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='DateValue', + name="DateValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.DateField(default=django.utils.timezone.now)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.DateField(default=django.utils.timezone.now)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='DropdownValue', + name="DropdownValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.CharField(max_length=255)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.CharField(max_length=255)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='FileUploadValue', + name="FileUploadValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.TextField()), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.TextField()), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='ParagraphValue', + name="ParagraphValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.TextField()), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.TextField()), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='ShortAnswerValue', + name="ShortAnswerValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.CharField(max_length=255)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.CharField(max_length=255)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='TimeValue', + name="TimeValue", fields=[ - ('answer_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='osp.Answer')), - ('value', models.TimeField(default=django.utils.timezone.now)), + ( + "answer_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="osp.Answer", + ), + ), + ("value", models.TimeField(default=django.utils.timezone.now)), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('osp.answer',), + bases=("osp.answer",), ), migrations.CreateModel( - name='FormFeedback', + name="FormFeedback", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('acceptance_status', models.CharField(choices=[('accepted', 'Accepted'), ('rejected', 'Rejected'), ('waitlisted', 'Waitlisted'), ('pending', 'Pending')], default='pending', max_length=10)), - ('answers', models.ManyToManyField(blank=True, default=None, related_name='form_answers', to='osp.Answer')), - ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osp.Form')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "acceptance_status", + models.CharField( + choices=[ + ("accepted", "Accepted"), + ("rejected", "Rejected"), + ("waitlisted", "Waitlisted"), + ("pending", "Pending"), + ], + default="pending", + max_length=10, + ), + ), + ( + "answers", + models.ManyToManyField(blank=True, default=None, related_name="form_answers", to="osp.Answer"), + ), + ("form", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="osp.Form")), + ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), ] diff --git a/osp/migrations/0012_auto_20200723_1626.py b/osp/migrations/0012_auto_20200723_1626.py index 8f92a33..e9db539 100644 --- a/osp/migrations/0012_auto_20200723_1626.py +++ b/osp/migrations/0012_auto_20200723_1626.py @@ -6,33 +6,36 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue'), + ( + "osp", + "0011_answer_checkboxvalue_choicevalue_datevalue_dropdownvalue_fileuploadvalue_formfeedback_paragraphvalue", + ), ] operations = [ migrations.AlterField( - model_name='choicevalue', - name='value', + model_name="choicevalue", + name="value", field=models.CharField(blank=True, max_length=255), ), migrations.AlterField( - model_name='dropdownvalue', - name='value', + model_name="dropdownvalue", + name="value", field=models.CharField(blank=True, max_length=255), ), migrations.AlterField( - model_name='fileuploadvalue', - name='value', + model_name="fileuploadvalue", + name="value", field=models.TextField(blank=True), ), migrations.AlterField( - model_name='paragraphvalue', - name='value', + model_name="paragraphvalue", + name="value", field=models.TextField(blank=True), ), migrations.AlterField( - model_name='shortanswervalue', - name='value', + model_name="shortanswervalue", + name="value", field=models.CharField(blank=True, max_length=255), ), ] diff --git a/osp/migrations/0013_auto_20200810_1406.py b/osp/migrations/0013_auto_20200810_1406.py index d8540f4..094912a 100644 --- a/osp/migrations/0013_auto_20200810_1406.py +++ b/osp/migrations/0013_auto_20200810_1406.py @@ -1,21 +1,23 @@ # Generated by Django 3.0.7 on 2020-08-10 14:06 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('osp', '0012_auto_20200723_1626'), + ("osp", "0012_auto_20200723_1626"), ] operations = [ migrations.AlterField( - model_name='userinformation', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_name', to=settings.AUTH_USER_MODEL), + model_name="userinformation", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="user_name", to=settings.AUTH_USER_MODEL + ), ), ] diff --git a/osp/migrations/0014_auto_20200824_1924.py b/osp/migrations/0014_auto_20200824_1924.py index 24fda86..30d4996 100644 --- a/osp/migrations/0014_auto_20200824_1924.py +++ b/osp/migrations/0014_auto_20200824_1924.py @@ -1,31 +1,34 @@ # Generated by Django 3.0.7 on 2020-08-24 19:24 -from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('osp', '0013_auto_20200810_1406'), + ("osp", "0013_auto_20200810_1406"), ] operations = [ migrations.AddField( - model_name='userinformation', - name='zulip_id', + model_name="userinformation", + name="zulip_id", field=models.BigIntegerField(blank=True, default=1), preserve_default=False, ), migrations.CreateModel( - name='ZulipStat', + name="ZulipStat", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('zulip_username', models.TextField(blank=True)), - ('total_messages', models.BigIntegerField(default=0)), - ('last_activity', models.DateTimeField(default=django.utils.timezone.now)), - ('user_information', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='osp.UserInformation')), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("zulip_username", models.TextField(blank=True)), + ("total_messages", models.BigIntegerField(default=0)), + ("last_activity", models.DateTimeField(default=django.utils.timezone.now)), + ( + "user_information", + models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to="osp.UserInformation"), + ), ], ), ] diff --git a/osp/migrations/0015_zulipstat_first_activity.py b/osp/migrations/0015_zulipstat_first_activity.py index 81b17dd..aab48f0 100644 --- a/osp/migrations/0015_zulipstat_first_activity.py +++ b/osp/migrations/0015_zulipstat_first_activity.py @@ -1,19 +1,19 @@ # Generated by Django 3.0.7 on 2020-08-24 19:32 -from django.db import migrations, models import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('osp', '0014_auto_20200824_1924'), + ("osp", "0014_auto_20200824_1924"), ] operations = [ migrations.AddField( - model_name='zulipstat', - name='first_activity', + model_name="zulipstat", + name="first_activity", field=models.DateTimeField(default=django.utils.timezone.now), ), ] diff --git a/osp/migrations/0016_zulipstat_updated_on.py b/osp/migrations/0016_zulipstat_updated_on.py index 57eba0a..2082ef0 100644 --- a/osp/migrations/0016_zulipstat_updated_on.py +++ b/osp/migrations/0016_zulipstat_updated_on.py @@ -6,13 +6,13 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0015_zulipstat_first_activity'), + ("osp", "0015_zulipstat_first_activity"), ] operations = [ migrations.AddField( - model_name='zulipstat', - name='updated_on', + model_name="zulipstat", + name="updated_on", field=models.DateTimeField(auto_now=True), ), ] diff --git a/osp/migrations/0017_auto_20200824_2008.py b/osp/migrations/0017_auto_20200824_2008.py index 0988dfa..f9300ee 100644 --- a/osp/migrations/0017_auto_20200824_2008.py +++ b/osp/migrations/0017_auto_20200824_2008.py @@ -6,33 +6,33 @@ class Migration(migrations.Migration): dependencies = [ - ('osp', '0016_zulipstat_updated_on'), + ("osp", "0016_zulipstat_updated_on"), ] operations = [ migrations.AddField( - model_name='zulipstat', - name='celebrate_messages', + model_name="zulipstat", + name="celebrate_messages", field=models.BigIntegerField(default=0), ), migrations.AddField( - model_name='zulipstat', - name='general_messages', + model_name="zulipstat", + name="general_messages", field=models.BigIntegerField(default=0), ), migrations.AddField( - model_name='zulipstat', - name='newcomers_messages', + model_name="zulipstat", + name="newcomers_messages", field=models.BigIntegerField(default=0), ), migrations.AddField( - model_name='zulipstat', - name='opportunities_messages', + model_name="zulipstat", + name="opportunities_messages", field=models.BigIntegerField(default=0), ), migrations.AddField( - model_name='zulipstat', - name='questions_messages', + model_name="zulipstat", + name="questions_messages", field=models.BigIntegerField(default=0), ), ] diff --git a/osp/models/__init__.py b/osp/models/__init__.py index 124b49e..f34b7fa 100644 --- a/osp/models/__init__.py +++ b/osp/models/__init__.py @@ -1,15 +1,18 @@ -from osp.models.user_information import UserInformation -from osp.models.form import Form -from osp.models.question import Question from osp.models.abstract_timestamp import AbstractTimestamp -from osp.models.field import ( - Choice, Dropdown, Checkbox, Paragraph, - ShortAnswer, Date, Time, FileUpload -) from osp.models.answer import Answer +from osp.models.field import Checkbox, Choice, Date, Dropdown, FileUpload, Paragraph, ShortAnswer, Time +from osp.models.form import Form +from osp.models.form_feedback import FormFeedback +from osp.models.question import Question +from osp.models.user_information import UserInformation from osp.models.value import ( - ChoiceValue, DropdownValue, CheckboxValue, ParagraphValue, - ShortAnswerValue, DateValue, TimeValue, FileUploadValue + CheckboxValue, + ChoiceValue, + DateValue, + DropdownValue, + FileUploadValue, + ParagraphValue, + ShortAnswerValue, + TimeValue, ) -from osp.models.form_feedback import FormFeedback from osp.models.zulip_stat import ZulipStat diff --git a/osp/models/abstract_timestamp.py b/osp/models/abstract_timestamp.py index b84f020..4537b83 100644 --- a/osp/models/abstract_timestamp.py +++ b/osp/models/abstract_timestamp.py @@ -1,13 +1,14 @@ from django.db import models + class AbstractTimestamp(models.Model): """ Abstract model for Created Time and Updated Time fields - """ + """ created_on = models.DateTimeField(auto_now_add=True) updated_on = models.DateTimeField(auto_now=True) class Meta: - + abstract = True diff --git a/osp/models/answer.py b/osp/models/answer.py index 247dbee..c23f3e5 100644 --- a/osp/models/answer.py +++ b/osp/models/answer.py @@ -3,6 +3,7 @@ from osp.models.abstract_timestamp import AbstractTimestamp from osp.models.question import Question + class Answer(AbstractTimestamp): question = models.ForeignKey( diff --git a/osp/models/field.py b/osp/models/field.py index a3775f4..ac0d969 100644 --- a/osp/models/field.py +++ b/osp/models/field.py @@ -1,62 +1,53 @@ -from django.db import models from django.contrib.postgres.fields import ArrayField +from django.db import models from osp.models.question import Question + class Choice(Question): - - options = ArrayField( - models.CharField( - max_length=255, - blank=True - )) + + options = ArrayField(models.CharField(max_length=255, blank=True)) def __str__(self): return self.label + class Dropdown(Question): - - options = ArrayField( - models.CharField( - max_length=255, - blank=True - )) + + options = ArrayField(models.CharField(max_length=255, blank=True)) def __str__(self): return self.label + class Checkbox(Question): - - options = ArrayField( - models.CharField( - max_length=255, - blank=True - )) + + options = ArrayField(models.CharField(max_length=255, blank=True)) def __str__(self): return self.label -class Paragraph(Question): +class Paragraph(Question): def __str__(self): return self.label -class ShortAnswer(Question): +class ShortAnswer(Question): def __str__(self): return self.label -class Date(Question): +class Date(Question): def __str__(self): return self.label -class Time(Question): +class Time(Question): def __str__(self): return self.label -class FileUpload(Question): +class FileUpload(Question): def __str__(self): return self.label diff --git a/osp/models/form.py b/osp/models/form.py index cfb4936..87124a8 100644 --- a/osp/models/form.py +++ b/osp/models/form.py @@ -1,33 +1,21 @@ from django.db import models -from osp.models.question import Question from osp.models.abstract_timestamp import AbstractTimestamp +from osp.models.question import Question from osp.utils import choices + class Form(AbstractTimestamp): name = models.CharField(max_length=255) description = models.TextField(blank=True) - published_status = models.CharField( - max_length=11, - choices=choices.STATUS_TYPES, - default='unpublished' - ) - questions = models.ManyToManyField( - to=Question, - default=None, - blank=True, - related_name='forms' - ) - target_user = models.CharField( - max_length=7, - choices=choices.TARGET_USERS, - default='all' - ) + published_status = models.CharField(max_length=11, choices=choices.STATUS_TYPES, default="unpublished") + questions = models.ManyToManyField(to=Question, default=None, blank=True, related_name="forms") + target_user = models.CharField(max_length=7, choices=choices.TARGET_USERS, default="all") class Meta: - ordering = ['-created_on'] + ordering = ["-created_on"] def __str__(self): - return f'{self.name}' + return f"{self.name}" diff --git a/osp/models/form_feedback.py b/osp/models/form_feedback.py index 2af84ae..8c89aef 100644 --- a/osp/models/form_feedback.py +++ b/osp/models/form_feedback.py @@ -1,29 +1,17 @@ from django.conf import settings -from django.contrib.auth.models import User from django.db import models -from osp.models.form import Form from osp.models.answer import Answer +from osp.models.form import Form from osp.utils import choices + class FormFeedback(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, - ) - form = models.ForeignKey( - Form, - on_delete=models.CASCADE - ) - answers = models.ManyToManyField( - to=Answer, - default=None, - blank=True, - related_name='form_answers' - ) - acceptance_status = models.CharField( - max_length=10, - choices=choices.ACCEPTANCE_STATUSES, - default='pending' ) + form = models.ForeignKey(Form, on_delete=models.CASCADE) + answers = models.ManyToManyField(to=Answer, default=None, blank=True, related_name="form_answers") + acceptance_status = models.CharField(max_length=10, choices=choices.ACCEPTANCE_STATUSES, default="pending") diff --git a/osp/models/question.py b/osp/models/question.py index 2bb14b3..bbc2cc7 100644 --- a/osp/models/question.py +++ b/osp/models/question.py @@ -3,21 +3,18 @@ from osp.models.abstract_timestamp import AbstractTimestamp from osp.utils import choices + class Question(AbstractTimestamp): label = models.CharField(max_length=255) - data_type = models.CharField( - max_length=8, - choices=choices.DATA_TYPES, - default='char' - ) + data_type = models.CharField(max_length=8, choices=choices.DATA_TYPES, default="char") description = models.TextField(blank=True) order = models.PositiveIntegerField() required = models.BooleanField(default=False) class Meta: - ordering = ['order'] - + ordering = ["order"] + def __str__(self): return self.label diff --git a/osp/models/user_information.py b/osp/models/user_information.py index 6408fff..69269ae 100644 --- a/osp/models/user_information.py +++ b/osp/models/user_information.py @@ -1,25 +1,19 @@ from django.conf import settings -from django.contrib.auth.models import User from django.db import models from osp.utils import user_types + class UserInformation(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, - related_name='user_name', + related_name="user_name", ) name = models.CharField(max_length=255) - user_type = models.CharField( - max_length=7, - choices=user_types.USERS, - default='student' - ) - zulip_id = models.BigIntegerField( - blank=True - ) + user_type = models.CharField(max_length=7, choices=user_types.USERS, default="student") + zulip_id = models.BigIntegerField(blank=True) def __str__(self): - return f'{self.name}: {self.user_type}' + return f"{self.name}: {self.user_type}" diff --git a/osp/models/value.py b/osp/models/value.py index 8c015c5..8451aaf 100644 --- a/osp/models/value.py +++ b/osp/models/value.py @@ -1,34 +1,34 @@ -from django.db import models from django.contrib.postgres.fields import ArrayField +from django.db import models from django.utils import timezone from osp.models.answer import Answer + class ChoiceValue(Answer): - + value = models.CharField(max_length=255, blank=True) def __str__(self): return self.value + class DropdownValue(Answer): - + value = models.CharField(max_length=255, blank=True) def __str__(self): return self.value + class CheckboxValue(Answer): - - value = ArrayField( - models.CharField( - max_length=255, - blank=True - )) + + value = ArrayField(models.CharField(max_length=255, blank=True)) def __str__(self): return self.value + class ParagraphValue(Answer): value = models.TextField(blank=True) @@ -36,6 +36,7 @@ class ParagraphValue(Answer): def __str__(self): return self.value + class ShortAnswerValue(Answer): value = models.CharField(max_length=255, blank=True) @@ -43,6 +44,7 @@ class ShortAnswerValue(Answer): def __str__(self): return self.value + class DateValue(Answer): value = models.DateField(default=timezone.now) @@ -50,6 +52,7 @@ class DateValue(Answer): def __str__(self): return self.value + class TimeValue(Answer): value = models.TimeField(default=timezone.now) @@ -57,6 +60,7 @@ class TimeValue(Answer): def __str__(self): return self.value + class FileUploadValue(Answer): value = models.TextField(blank=True) diff --git a/osp/models/zulip_stat.py b/osp/models/zulip_stat.py index f271cf7..f1bcf2d 100644 --- a/osp/models/zulip_stat.py +++ b/osp/models/zulip_stat.py @@ -1,16 +1,12 @@ -from django.conf import settings -from django.contrib.auth.models import User from django.db import models from django.utils import timezone from osp.models.user_information import UserInformation + class ZulipStat(models.Model): - user_information = models.OneToOneField( - UserInformation, - on_delete=models.CASCADE - ) + user_information = models.OneToOneField(UserInformation, on_delete=models.CASCADE) zulip_username = models.TextField(blank=True) total_messages = models.BigIntegerField(default=0) first_activity = models.DateTimeField(default=timezone.now) @@ -21,5 +17,3 @@ class ZulipStat(models.Model): questions_messages = models.BigIntegerField(default=0) opportunities_messages = models.BigIntegerField(default=0) celebrate_messages = models.BigIntegerField(default=0) - - diff --git a/osp/permissions/admin.py b/osp/permissions/admin.py index 2f5a0c5..0cb987c 100644 --- a/osp/permissions/admin.py +++ b/osp/permissions/admin.py @@ -2,9 +2,9 @@ from osp.models import UserInformation -class IsAdmin(permissions.BasePermission): +class IsAdmin(permissions.BasePermission): def has_permission(self, request, view): user = request.user user_type = UserInformation.objects.get(user_id=user.id).user_type - return user_type == 'admin' + return user_type == "admin" diff --git a/osp/serializers/answer.py b/osp/serializers/answer.py index 516a04e..6d8e02a 100644 --- a/osp/serializers/answer.py +++ b/osp/serializers/answer.py @@ -3,6 +3,7 @@ from osp.models import Answer from osp.serializers.question import QuestionSerializer + class AnswerReadSerializer(serializers.ModelSerializer): question = QuestionSerializer(read_only=True) @@ -10,15 +11,11 @@ class AnswerReadSerializer(serializers.ModelSerializer): class Meta: model = Answer - fields = [ - 'id', 'question', 'created_on', 'updated_on' - ] + fields = ["id", "question", "created_on", "updated_on"] -class AnswerWriteSerializer(serializers.ModelSerializer): +class AnswerWriteSerializer(serializers.ModelSerializer): class Meta: model = Answer - fields = [ - 'id', 'question', 'created_on', 'updated_on' - ] + fields = ["id", "question", "created_on", "updated_on"] diff --git a/osp/serializers/fields.py b/osp/serializers/fields.py index f7bec0a..6f91686 100644 --- a/osp/serializers/fields.py +++ b/osp/serializers/fields.py @@ -1,62 +1,57 @@ -from rest_framework import serializers - -from osp.models import ( - Question, Choice, Checkbox, Dropdown, - Paragraph, ShortAnswer, Date, Time, FileUpload -) +from osp.models import Checkbox, Choice, Date, Dropdown, FileUpload, Paragraph, ShortAnswer, Time from osp.serializers.question import QuestionSerializer -class ChoiceSerializer(QuestionSerializer): +class ChoiceSerializer(QuestionSerializer): class Meta: model = Choice - fields = QuestionSerializer.Meta.fields + ['options'] + fields = QuestionSerializer.Meta.fields + ["options"] -class CheckboxSerializer(QuestionSerializer): +class CheckboxSerializer(QuestionSerializer): class Meta: model = Checkbox - fields = QuestionSerializer.Meta.fields + ['options'] + fields = QuestionSerializer.Meta.fields + ["options"] -class DropdownSerializer(QuestionSerializer): +class DropdownSerializer(QuestionSerializer): class Meta: model = Dropdown - fields = QuestionSerializer.Meta.fields + ['options'] + fields = QuestionSerializer.Meta.fields + ["options"] -class ParagraphSerializer(QuestionSerializer): +class ParagraphSerializer(QuestionSerializer): class Meta: model = Paragraph fields = QuestionSerializer.Meta.fields -class ShortAnswerSerializer(QuestionSerializer): +class ShortAnswerSerializer(QuestionSerializer): class Meta: model = ShortAnswer fields = QuestionSerializer.Meta.fields -class DateSerializer(QuestionSerializer): +class DateSerializer(QuestionSerializer): class Meta: model = Date fields = QuestionSerializer.Meta.fields -class TimeSerializer(QuestionSerializer): +class TimeSerializer(QuestionSerializer): class Meta: model = Time fields = QuestionSerializer.Meta.fields -class FileUploadSerializer(QuestionSerializer): +class FileUploadSerializer(QuestionSerializer): class Meta: model = FileUpload diff --git a/osp/serializers/form.py b/osp/serializers/form.py index e1172b3..09f0129 100644 --- a/osp/serializers/form.py +++ b/osp/serializers/form.py @@ -2,12 +2,9 @@ from osp.models import Form -class FormSerializer(serializers.ModelSerializer): +class FormSerializer(serializers.ModelSerializer): class Meta: - + model = Form - fields = [ - 'id', 'name', 'description', 'published_status', - 'questions', 'target_user', 'created_on', 'updated_on' - ] + fields = "__all__" diff --git a/osp/serializers/form_feedback.py b/osp/serializers/form_feedback.py index 1e5a673..f1e1855 100644 --- a/osp/serializers/form_feedback.py +++ b/osp/serializers/form_feedback.py @@ -1,11 +1,11 @@ from rest_framework import serializers -from osp.models import FormFeedback, Answer, Question +from osp.models import FormFeedback from osp.serializers.form import FormSerializer from osp.serializers.user import UserSerializer -from osp.serializers.answer import AnswerReadSerializer from osp.utils.answer_function import get_model_and_serializer + class FormFeedbackReadSerializer(serializers.ModelSerializer): form = FormSerializer(read_only=True) @@ -15,21 +15,20 @@ class FormFeedbackReadSerializer(serializers.ModelSerializer): class Meta: model = FormFeedback - fields = [ - 'id', 'user', 'form', 'answers', 'acceptance_status' - ] + fields = "__all__" def get_answers(self, obj): answers = [] for answer in obj.answers.all(): value = get_model_and_serializer(answer.question.data_type) - serializer = value['serializer'] - model = value['model'] + serializer = value["serializer"] + model = value["model"] instance = model.objects.get(id=answer.id) instance = serializer(instance) answers.append(instance.data) return answers + class FormFeedbackWriteSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) @@ -37,6 +36,4 @@ class FormFeedbackWriteSerializer(serializers.ModelSerializer): class Meta: model = FormFeedback - fields = [ - 'id', 'user', 'form', 'answers', 'acceptance_status' - ] + fields = "__all__" diff --git a/osp/serializers/question.py b/osp/serializers/question.py index 0568179..46c154a 100644 --- a/osp/serializers/question.py +++ b/osp/serializers/question.py @@ -2,12 +2,9 @@ from osp.models import Question -class QuestionSerializer(serializers.ModelSerializer): +class QuestionSerializer(serializers.ModelSerializer): class Meta: model = Question - fields = [ - 'id', 'label', 'data_type', 'description', 'order', 'required', - 'created_on', 'updated_on', 'forms' - ] + fields = ["id", "label", "data_type", "description", "order", "required", "created_on", "updated_on", "forms"] diff --git a/osp/serializers/user.py b/osp/serializers/user.py index b4c7448..18bbd6b 100644 --- a/osp/serializers/user.py +++ b/osp/serializers/user.py @@ -3,17 +3,14 @@ User = get_user_model() + class UserSerializer(serializers.ModelSerializer): - user_name = serializers.SlugRelatedField(many=True, read_only=True, slug_field='name') + user_name = serializers.SlugRelatedField(many=True, read_only=True, slug_field="name") class Meta: model = User - fields = [ - 'id', - 'username', - 'email', - 'user_name' + fields = ["id", "username", "email", "user_name"] + read_only_fields = [ + "id", ] - read_only_fields = ['id',] - diff --git a/osp/serializers/user_information.py b/osp/serializers/user_information.py index d4fe938..cd7946d 100644 --- a/osp/serializers/user_information.py +++ b/osp/serializers/user_information.py @@ -3,17 +3,11 @@ from osp.models import UserInformation from osp.serializers.user import UserSerializer + class UserInformationSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) class Meta: model = UserInformation - fields = [ - 'id', - 'name', - 'user', - 'user_type', - 'zulip_id' - ] - + fields = ["id", "name", "user", "user_type", "zulip_id"] diff --git a/osp/serializers/value.py b/osp/serializers/value.py index e12ae5a..86a7afb 100644 --- a/osp/serializers/value.py +++ b/osp/serializers/value.py @@ -1,121 +1,125 @@ -from rest_framework import serializers - from osp.models import ( - Answer, ChoiceValue, CheckboxValue, DropdownValue, - ParagraphValue, ShortAnswerValue, DateValue, TimeValue, FileUploadValue + CheckboxValue, + ChoiceValue, + DateValue, + DropdownValue, + FileUploadValue, + ParagraphValue, + ShortAnswerValue, + TimeValue, ) from osp.serializers.answer import AnswerReadSerializer, AnswerWriteSerializer + # read serializers class ChoiceValueReadSerializer(AnswerReadSerializer): - class Meta: model = ChoiceValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class CheckboxValueReadSerializer(AnswerReadSerializer): +class CheckboxValueReadSerializer(AnswerReadSerializer): class Meta: model = CheckboxValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class DropdownValueReadSerializer(AnswerReadSerializer): +class DropdownValueReadSerializer(AnswerReadSerializer): class Meta: model = DropdownValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class ParagraphValueReadSerializer(AnswerReadSerializer): +class ParagraphValueReadSerializer(AnswerReadSerializer): class Meta: model = ParagraphValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class ShortAnswerValueReadSerializer(AnswerReadSerializer): +class ShortAnswerValueReadSerializer(AnswerReadSerializer): class Meta: model = ShortAnswerValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class DateValueReadSerializer(AnswerReadSerializer): +class DateValueReadSerializer(AnswerReadSerializer): class Meta: model = DateValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class TimeValueReadSerializer(AnswerReadSerializer): +class TimeValueReadSerializer(AnswerReadSerializer): class Meta: model = TimeValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] -class FileUploadValueReadSerializer(AnswerReadSerializer): +class FileUploadValueReadSerializer(AnswerReadSerializer): class Meta: model = FileUploadValue - fields = AnswerReadSerializer.Meta.fields + ['value'] + fields = AnswerReadSerializer.Meta.fields + ["value"] + # write serializers class ChoiceValueWriteSerializer(AnswerWriteSerializer): - class Meta: model = ChoiceValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class CheckboxValueWriteSerializer(AnswerWriteSerializer): +class CheckboxValueWriteSerializer(AnswerWriteSerializer): class Meta: model = CheckboxValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class DropdownValueWriteSerializer(AnswerWriteSerializer): +class DropdownValueWriteSerializer(AnswerWriteSerializer): class Meta: model = DropdownValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class ParagraphValueWriteSerializer(AnswerWriteSerializer): +class ParagraphValueWriteSerializer(AnswerWriteSerializer): class Meta: model = ParagraphValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class ShortAnswerValueWriteSerializer(AnswerWriteSerializer): +class ShortAnswerValueWriteSerializer(AnswerWriteSerializer): class Meta: model = ShortAnswerValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class DateValueWriteSerializer(AnswerWriteSerializer): +class DateValueWriteSerializer(AnswerWriteSerializer): class Meta: model = DateValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class TimeValueWriteSerializer(AnswerWriteSerializer): +class TimeValueWriteSerializer(AnswerWriteSerializer): class Meta: model = TimeValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] -class FileUploadValueWriteSerializer(AnswerWriteSerializer): +class FileUploadValueWriteSerializer(AnswerWriteSerializer): class Meta: model = FileUploadValue - fields = AnswerWriteSerializer.Meta.fields + ['value'] + fields = AnswerWriteSerializer.Meta.fields + ["value"] diff --git a/osp/serializers/zulip_stat.py b/osp/serializers/zulip_stat.py index 8981414..d7856b2 100644 --- a/osp/serializers/zulip_stat.py +++ b/osp/serializers/zulip_stat.py @@ -2,18 +2,25 @@ from osp.models import ZulipStat + class ZulipStatSerializer(serializers.ModelSerializer): - zulip_user_id = serializers.CharField( - source='user_information.zulip_id', - read_only=True - ) + zulip_user_id = serializers.CharField(source="user_information.zulip_id", read_only=True) class Meta: model = ZulipStat fields = [ - 'id', 'zulip_user_id', 'zulip_username', 'total_messages', 'first_activity', - 'last_activity', 'updated_on', 'newcomers_messages', 'general_messages', - 'questions_messages', 'opportunities_messages', 'celebrate_messages' + "id", + "zulip_user_id", + "zulip_username", + "total_messages", + "first_activity", + "last_activity", + "updated_on", + "newcomers_messages", + "general_messages", + "questions_messages", + "opportunities_messages", + "celebrate_messages", ] diff --git a/osp/serializers/zulip_stat_user.py b/osp/serializers/zulip_stat_user.py index c7ef668..20c096c 100644 --- a/osp/serializers/zulip_stat_user.py +++ b/osp/serializers/zulip_stat_user.py @@ -2,17 +2,20 @@ from osp.models import ZulipStat + class ZulipStatUserSerializer(serializers.ModelSerializer): - zulip_user_id = serializers.CharField( - source='user_information.zulip_id', - read_only=True - ) + zulip_user_id = serializers.CharField(source="user_information.zulip_id", read_only=True) class Meta: model = ZulipStat fields = [ - 'id', 'zulip_user_id', 'zulip_username', 'total_messages', 'first_activity', - 'last_activity', 'updated_on' + "id", + "zulip_user_id", + "zulip_username", + "total_messages", + "first_activity", + "last_activity", + "updated_on", ] diff --git a/osp/urls.py b/osp/urls.py index 1b5cd3f..f5093e5 100644 --- a/osp/urls.py +++ b/osp/urls.py @@ -1,27 +1,23 @@ -from django.urls import path, include -from django.conf.urls import url from rest_framework import routers -from osp.views.user import UserView -from osp.views.user_information import UserInformationView -from osp.views.form import FormView -from osp.views.question import QuestionView from osp.views.answer import AnswerView +from osp.views.form import FormView from osp.views.form_feedback import FormFeedbackView +from osp.views.question import QuestionView +from osp.views.user import UserView +from osp.views.user_information import UserInformationView from osp.views.zulip_stat import ZulipStatView router = routers.DefaultRouter() -router.register(r'user', UserView, basename='user') -router.register(r'info', UserInformationView, basename='information') -router.register(r'form', FormView, basename='form') -router.register(r'questions', QuestionView, basename='questions') -router.register(r'answers', AnswerView, basename='answers') -router.register(r'feedback', FormFeedbackView, basename='form_feedback') -router.register(r'zulip_stat', ZulipStatView, basename='zulip_stat') - -urlpatterns = [ -] +router.register(r"user", UserView, basename="user") +router.register(r"info", UserInformationView, basename="information") +router.register(r"form", FormView, basename="form") +router.register(r"questions", QuestionView, basename="questions") +router.register(r"answers", AnswerView, basename="answers") +router.register(r"feedback", FormFeedbackView, basename="form_feedback") +router.register(r"zulip_stat", ZulipStatView, basename="zulip_stat") -urlpatterns +=router.urls +urlpatterns = [] +urlpatterns += router.urls diff --git a/osp/utils/answer_function.py b/osp/utils/answer_function.py index 0002ef7..0f37532 100644 --- a/osp/utils/answer_function.py +++ b/osp/utils/answer_function.py @@ -1,89 +1,100 @@ -from rest_framework.response import Response - from osp.models import ( - ChoiceValue, CheckboxValue, DropdownValue, ParagraphValue, - ShortAnswerValue, DateValue, TimeValue, FileUploadValue + CheckboxValue, + ChoiceValue, + DateValue, + DropdownValue, + FileUploadValue, + ParagraphValue, + ShortAnswerValue, + TimeValue, ) from osp.serializers.value import ( - ChoiceValueReadSerializer, ChoiceValueWriteSerializer, CheckboxValueReadSerializer, CheckboxValueWriteSerializer, - DropdownValueReadSerializer, DropdownValueWriteSerializer, ParagraphValueReadSerializer, ParagraphValueWriteSerializer, - ShortAnswerValueReadSerializer, ShortAnswerValueWriteSerializer, DateValueReadSerializer, DateValueWriteSerializer, - TimeValueReadSerializer, TimeValueWriteSerializer, FileUploadValueReadSerializer, FileUploadValueWriteSerializer + CheckboxValueReadSerializer, + CheckboxValueWriteSerializer, + ChoiceValueReadSerializer, + ChoiceValueWriteSerializer, + DateValueReadSerializer, + DateValueWriteSerializer, + DropdownValueReadSerializer, + DropdownValueWriteSerializer, + FileUploadValueReadSerializer, + FileUploadValueWriteSerializer, + ParagraphValueReadSerializer, + ParagraphValueWriteSerializer, + ShortAnswerValueReadSerializer, + ShortAnswerValueWriteSerializer, + TimeValueReadSerializer, + TimeValueWriteSerializer, ) + def get_create_model_and_serializer(data_type): - if data_type == 'char': + if data_type == "char": model = ShortAnswerValue serializer = ShortAnswerValueWriteSerializer - elif data_type == 'text': + elif data_type == "text": model = ParagraphValue serializer = ParagraphValueWriteSerializer - elif data_type == 'choice': + elif data_type == "choice": model = ChoiceValue serializer = ChoiceValueWriteSerializer - elif data_type == 'checkbox': + elif data_type == "checkbox": model = CheckboxValue serializer = CheckboxValueWriteSerializer - elif data_type == 'dropdown': + elif data_type == "dropdown": model = DropdownValue serializer = DropdownValueWriteSerializer - elif data_type == 'date': + elif data_type == "date": model = DateValue serializer = DateValueWriteSerializer - elif data_type == 'time': + elif data_type == "time": model = TimeValue serializer = TimeValueWriteSerializer - elif data_type == 'file': + elif data_type == "file": model = FileUploadValue serializer = FileUploadValueWriteSerializer - return { - "model": model, - "serializer": serializer - } + return {"model": model, "serializer": serializer} + def get_model_and_serializer(data_type): - if data_type == 'char': + if data_type == "char": model = ShortAnswerValue serializer = ShortAnswerValueReadSerializer - elif data_type == 'text': + elif data_type == "text": model = ParagraphValue serializer = ParagraphValueReadSerializer - elif data_type == 'choice': + elif data_type == "choice": model = ChoiceValue serializer = ChoiceValueReadSerializer - elif data_type == 'checkbox': + elif data_type == "checkbox": model = CheckboxValue serializer = CheckboxValueReadSerializer - elif data_type == 'dropdown': + elif data_type == "dropdown": model = DropdownValue serializer = DropdownValueReadSerializer - elif data_type == 'date': + elif data_type == "date": model = DateValue serializer = DateValueReadSerializer - elif data_type == 'time': + elif data_type == "time": model = TimeValue serializer = TimeValueReadSerializer - elif data_type == 'file': + elif data_type == "file": model = FileUploadValue serializer = FileUploadValueReadSerializer - return { - "model": model, - "serializer": serializer - } - + return {"model": model, "serializer": serializer} diff --git a/osp/utils/choices.py b/osp/utils/choices.py index 83c5f85..d5aed3a 100644 --- a/osp/utils/choices.py +++ b/osp/utils/choices.py @@ -1,47 +1,47 @@ -SA = 'char' -PA = 'text' -CF = 'choice' -CH = 'checkbox' -DD = 'dropdown' -FI = 'file' -DA = 'date' -TI = 'time' +SA = "char" +PA = "text" +CF = "choice" +CH = "checkbox" +DD = "dropdown" +FI = "file" +DA = "date" +TI = "time" DATA_TYPES = ( - (SA, 'Short Answer'), - (PA, 'Paragraph Answer'), - (CF, 'Choice'), - (CH, 'Checkbox'), - (DD, 'Dropdown'), - (FI, 'File Upload'), - (DA, 'Date'), - (TI, 'Time') + (SA, "Short Answer"), + (PA, "Paragraph Answer"), + (CF, "Choice"), + (CH, "Checkbox"), + (DD, "Dropdown"), + (FI, "File Upload"), + (DA, "Date"), + (TI, "Time"), ) -PUB = 'published' -UNP = 'unpublished' -CLO = 'closed' +PUB = "published" +UNP = "unpublished" +CLO = "closed" STATUS_TYPES = ( - (PUB, 'Published'), - (UNP, 'Unpublished'), - (CLO, 'Closed'), + (PUB, "Published"), + (UNP, "Unpublished"), + (CLO, "Closed"), ) -ALL = 'all' -ADM = 'admin' -STU = 'student' +ALL = "all" +ADM = "admin" +STU = "student" TARGET_USERS = ( - (ALL, 'All Users'), - (ADM, 'Admin'), - (STU, 'Student'), + (ALL, "All Users"), + (ADM, "Admin"), + (STU, "Student"), ) -ACC = 'accepted' -REJ = 'rejected' -WAI = 'waitlisted' -PEN = 'pending' +ACC = "accepted" +REJ = "rejected" +WAI = "waitlisted" +PEN = "pending" ACCEPTANCE_STATUSES = ( - (ACC, 'Accepted'), - (REJ, 'Rejected'), - (WAI, 'Waitlisted'), - (PEN, 'Pending'), + (ACC, "Accepted"), + (REJ, "Rejected"), + (WAI, "Waitlisted"), + (PEN, "Pending"), ) diff --git a/osp/utils/question.py b/osp/utils/question.py index 41dd450..bdefaa1 100644 --- a/osp/utils/question.py +++ b/osp/utils/question.py @@ -1,50 +1,47 @@ -from rest_framework.response import Response - -from osp.models import ( - Choice, Checkbox, Dropdown, - Paragraph, ShortAnswer, - Date, Time, FileUpload -) +from osp.models import Checkbox, Choice, Date, Dropdown, FileUpload, Paragraph, ShortAnswer, Time from osp.serializers.fields import ( - ChoiceSerializer, CheckboxSerializer, DropdownSerializer, - ParagraphSerializer, ShortAnswerSerializer, ParagraphSerializer, - DateSerializer, TimeSerializer, FileUploadSerializer + CheckboxSerializer, + ChoiceSerializer, + DateSerializer, + DropdownSerializer, + FileUploadSerializer, + ParagraphSerializer, + ShortAnswerSerializer, + TimeSerializer, ) + def get_model_and_serializer(data_type): - if data_type == 'char': + if data_type == "char": model = ShortAnswer serializer = ShortAnswerSerializer - elif data_type == 'text': + elif data_type == "text": model = Paragraph serializer = ParagraphSerializer - elif data_type == 'choice': + elif data_type == "choice": model = Choice serializer = ChoiceSerializer - elif data_type == 'checkbox': + elif data_type == "checkbox": model = Checkbox serializer = CheckboxSerializer - elif data_type == 'dropdown': + elif data_type == "dropdown": model = Dropdown serializer = DropdownSerializer - elif data_type == 'date': + elif data_type == "date": model = Date serializer = DateSerializer - elif data_type == 'time': + elif data_type == "time": model = Time serializer = TimeSerializer - elif data_type == 'file': + elif data_type == "file": model = FileUpload serializer = FileUploadSerializer - return { - "model": model, - "serializer": serializer - } + return {"model": model, "serializer": serializer} diff --git a/osp/utils/user_types.py b/osp/utils/user_types.py index de73407..1bd2f98 100644 --- a/osp/utils/user_types.py +++ b/osp/utils/user_types.py @@ -1,6 +1,6 @@ -ADM = 'admin' -STU = 'student' +ADM = "admin" +STU = "student" USERS = ( - (ADM, 'Admin'), - (STU, 'Student'), + (ADM, "Admin"), + (STU, "Student"), ) diff --git a/osp/utils/zulip_api.py b/osp/utils/zulip_api.py index c0fbd32..0fa54cc 100644 --- a/osp/utils/zulip_api.py +++ b/osp/utils/zulip_api.py @@ -1,53 +1,50 @@ -import os from zulip import Client -from rest_framework.response import Response - # By default the API key file you download is named as 'download' by Zulip. You can place # this file one directory previous to the cuurent directory your file is in -client = Client(config_file='download') +client = Client(config_file="download") + def get_zulip_user(zulip_id): result = client.get_user_by_id(zulip_id) print(result) - return result['user'] + return result["user"] + def get_messages(zulip_id): request = { - 'anchor': 'newest', - 'num_before': 5000, - 'num_after': 0, - 'narrow': [ - { 'operator': 'sender', 'operand': f'user{zulip_id}@zulipchat.com' }, - ] + "anchor": "newest", + "num_before": 5000, + "num_after": 0, + "narrow": [{"operator": "sender", "operand": f"user{zulip_id}@zulipchat.com"}], } result = client.get_messages(request) - result = len(result['messages']) + result = len(result["messages"]) return result + def get_newest_message(zulip_id): request = { - 'anchor': 'newest', - 'num_before': 1, - 'num_after': 0, - 'narrow': [ - { 'operator': 'sender', 'operand': f'user{zulip_id}@zulipchat.com' }, - ] + "anchor": "newest", + "num_before": 1, + "num_after": 0, + "narrow": [{"operator": "sender", "operand": f"user{zulip_id}@zulipchat.com"}], } result = client.get_messages(request) - result = result['messages'] + result = result["messages"] return result + def get_stream_messages(stream, zulip_id): request = { - 'anchor': 'newest', - 'num_before': 1, - 'num_after': 0, - 'narrow': [ - { 'operator': 'sender', 'operand': f'user{zulip_id}@zulipchat.com' }, - { 'operator': 'stream', 'operand': f'{stream}' }, - ] + "anchor": "newest", + "num_before": 1, + "num_after": 0, + "narrow": [ + {"operator": "sender", "operand": f"user{zulip_id}@zulipchat.com"}, + {"operator": "stream", "operand": f"{stream}"}, + ], } result = client.get_messages(request) - result = len(result['messages']) + result = len(result["messages"]) return result diff --git a/osp/views/answer.py b/osp/views/answer.py index 903d6d0..ef1d7f3 100644 --- a/osp/views/answer.py +++ b/osp/views/answer.py @@ -1,26 +1,23 @@ -from rest_framework import viewsets, status +from rest_framework import status, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from osp.models import ( - Question, Answer, ChoiceValue, CheckboxValue, DropdownValue, DateValue, - TimeValue, FileUploadValue, ShortAnswerValue, ParagraphValue, FormFeedback -) -from osp.serializers.answer import AnswerReadSerializer, AnswerWriteSerializer -from osp.serializers.form_feedback import FormFeedbackWriteSerializer -from osp.utils.answer_function import get_model_and_serializer, get_create_model_and_serializer +from osp.models import Answer +from osp.serializers.answer import AnswerReadSerializer +from osp.utils.answer_function import get_model_and_serializer + class AnswerView(viewsets.ModelViewSet): serializer_class = AnswerReadSerializer permission_classes = [IsAuthenticated] - queryset = Answer.objects.all().order_by('question__order') + queryset = Answer.objects.all().order_by("question__order") def get_queryset(self): queryset = self.queryset - form_id = self.request.query_params.get('form_id', None) - question_id = self.request.query_params.get('question_id', None) - user_id = self.request.query_params.get('user_id', None) + form_id = self.request.query_params.get("form_id", None) + question_id = self.request.query_params.get("question_id", None) + user_id = self.request.query_params.get("user_id", None) user = self.request.user if form_id is not None: queryset = queryset.filter(form_answers__form_id=form_id) @@ -30,7 +27,7 @@ def get_queryset(self): queryset = queryset.filter(form_answers__user_id=user.id) if question_id is not None: queryset = queryset.filter(question_id=question_id) - + # response return queryset @@ -41,8 +38,8 @@ def list(self, request): for obj in objs: value = get_model_and_serializer(obj.question.data_type) - model = value['model'] - serializer = value['serializer'] + model = value["model"] + serializer = value["serializer"] instance = model.objects.get(id=obj.id) results.append(serializer(instance).data) diff --git a/osp/views/form.py b/osp/views/form.py index 8054c85..a4d03c4 100644 --- a/osp/views/form.py +++ b/osp/views/form.py @@ -1,10 +1,10 @@ -from rest_framework import viewsets, status +from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response from osp.models import Form, UserInformation -from osp.serializers.form import FormSerializer from osp.permissions.admin import IsAdmin +from osp.serializers.form import FormSerializer + class FormView(viewsets.ModelViewSet): @@ -13,7 +13,7 @@ class FormView(viewsets.ModelViewSet): # override permissions for different request methods def get_permissions(self): - if self.request.method == 'GET': + if self.request.method == "GET": self.permission_classes = [IsAuthenticated] else: self.permission_classes = [IsAuthenticated, IsAdmin] @@ -22,12 +22,14 @@ def get_permissions(self): def get_queryset(self): queryset = self.queryset - status = self.request.query_params.get('status', None) + status = self.request.query_params.get("status", None) user = self.request.user user_type = UserInformation.objects.get(user_id=user.id).user_type if status: - status = status.split(',') + status = status.split(",") queryset = queryset.filter(published_status__in=status) - if user_type == 'student': - queryset = queryset.filter(published_status__in=['published', 'closed'], target_user__in=['all', 'student']) + if user_type == "student": + queryset = queryset.filter( + published_status__in=["published", "closed"], target_user__in=["all", "student"] + ) return queryset diff --git a/osp/views/form_feedback.py b/osp/views/form_feedback.py index e49acb2..ddcb8b0 100644 --- a/osp/views/form_feedback.py +++ b/osp/views/form_feedback.py @@ -1,15 +1,12 @@ from django.db.models import Q -from rest_framework import viewsets, status +from rest_framework import status, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from osp.models import ( - Question, Answer, ChoiceValue, CheckboxValue, DropdownValue, DateValue, - TimeValue, FileUploadValue, ShortAnswerValue, ParagraphValue, FormFeedback -) -from osp.serializers.answer import AnswerReadSerializer, AnswerWriteSerializer -from osp.serializers.form_feedback import FormFeedbackWriteSerializer, FormFeedbackReadSerializer -from osp.utils.answer_function import get_model_and_serializer, get_create_model_and_serializer +from osp.models import FormFeedback, Question +from osp.serializers.form_feedback import FormFeedbackReadSerializer, FormFeedbackWriteSerializer +from osp.utils.answer_function import get_create_model_and_serializer, get_model_and_serializer + class FormFeedbackView(viewsets.ModelViewSet): @@ -19,20 +16,22 @@ class FormFeedbackView(viewsets.ModelViewSet): def get_queryset(self): queryset = self.queryset - form_id = self.request.query_params.get('form_id', None) - user_name = self.request.query_params.get('user_name', None) - user_id = self.request.query_params.get('user_id', None) + form_id = self.request.query_params.get("form_id", None) + user_name = self.request.query_params.get("user_name", None) + user_id = self.request.query_params.get("user_id", None) user = self.request.user if form_id is not None: - form_id = form_id.split(',') + form_id = form_id.split(",") queryset = queryset.filter(form_id__in=form_id) if user_name is not None: - queryset = queryset.filter(Q(user__user_name__name__icontains=user_name) | Q(user__username__icontains=user_name)) + queryset = queryset.filter( + Q(user__user_name__name__icontains=user_name) | Q(user__username__icontains=user_name) + ) if user_id is not None: queryset = queryset.filter(user_id=user_id) else: queryset = queryset.filter(user_id=user.id) - + # response return queryset @@ -41,31 +40,31 @@ def create(self, request): user = self.request.user answers = [] - for obj in request.data['answers']: - data_type = Question.objects.get(id=obj['question']).data_type + for obj in request.data["answers"]: + data_type = Question.objects.get(id=obj["question"]).data_type create_value = get_create_model_and_serializer(data_type) - create_model = create_value['model'] - create_serializer = create_value['serializer'] + create_model = create_value["model"] + create_serializer = create_value["serializer"] value = get_model_and_serializer(data_type) - model = value['model'] - serializer = value['serializer'] - id = obj.get('id', None) + model = value["model"] + serializer = value["serializer"] + id = obj.get("id", None) if id is not None: instance = create_model.objects.get(id=id) instance = create_serializer(instance, data=obj) instance.is_valid(raise_exception=True) instance.save() - obj = model.objects.get(id=instance.data['id']) + obj = model.objects.get(id=instance.data["id"]) instance = serializer(obj) else: instance = create_serializer(data=obj) instance.is_valid(raise_exception=True) instance.save() - obj = model.objects.get(id=instance.data['id']) + obj = model.objects.get(id=instance.data["id"]) instance = serializer(obj) - answers.append(instance.data['id']) + answers.append(instance.data["id"]) - request.data['answers'] = answers + request.data["answers"] = answers if FormFeedback.objects.filter(user_id=user.id).exists(): instance = FormFeedback.objects.get(user_id=user.id) serializer = FormFeedbackWriteSerializer(instance, data=request.data) @@ -76,7 +75,7 @@ def create(self, request): serializer.is_valid(raise_exception=True) serializer.save(user_id=user.id) - obj = FormFeedback.objects.get(id=serializer.data['id']) + obj = FormFeedback.objects.get(id=serializer.data["id"]) # response return Response(self.serializer_class(obj).data, status=status.HTTP_201_CREATED) diff --git a/osp/views/question.py b/osp/views/question.py index 15f3e6b..2e06abc 100644 --- a/osp/views/question.py +++ b/osp/views/question.py @@ -1,21 +1,13 @@ -from rest_framework import viewsets, status +from rest_framework import status, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from osp.models import ( - UserInformation, Form, Question, Choice, - Checkbox, Dropdown, Paragraph, ShortAnswer, - Date, Time, FileUpload -) -from osp.serializers.question import QuestionSerializer -from osp.serializers.fields import ( - ChoiceSerializer, CheckboxSerializer, DropdownSerializer, - ParagraphSerializer, ShortAnswerSerializer, ParagraphSerializer, - DateSerializer, TimeSerializer, FileUploadSerializer -) +from osp.models import Question, UserInformation from osp.permissions.admin import IsAdmin +from osp.serializers.question import QuestionSerializer from osp.utils.question import get_model_and_serializer + class QuestionView(viewsets.ViewSet): serializer_class = QuestionSerializer @@ -23,24 +15,24 @@ class QuestionView(viewsets.ViewSet): # override permissions for different request methods def get_permissions(self): - if self.request.method == 'GET': + if self.request.method == "GET": self.permission_classes = [IsAuthenticated] else: self.permission_classes = [IsAuthenticated, IsAdmin] return super(QuestionView, self).get_permissions() - + def get_queryset(self): queryset = self.queryset - form_id = self.request.query_params.get('form_id', None) + form_id = self.request.query_params.get("form_id", None) user = self.request.user user_type = UserInformation.objects.get(user_id=user.id).user_type if form_id: queryset = queryset.filter(forms__id=form_id) - if user_type == 'student': - queryset = queryset.filter(forms__published_status='published') + if user_type == "student": + queryset = queryset.filter(forms__published_status="published") return queryset - + # GET request def list(self, request): objs = self.get_queryset() @@ -48,24 +40,23 @@ def list(self, request): for obj in objs: value = get_model_and_serializer(obj.data_type) - model = value['model'] - serializer = value['serializer'] + model = value["model"] + serializer = value["serializer"] instance = model.objects.get(id=obj.id) results.append(serializer(instance).data) - - #response - return Response(results, status=status.HTTP_200_OK) + # response + return Response(results, status=status.HTTP_200_OK) # POST request def create(self, request): results = [] for obj in request.data: - value = get_model_and_serializer(obj['data_type']) - model = value['model'] - serializer = value['serializer'] - id = obj.get('id', None) + value = get_model_and_serializer(obj["data_type"]) + model = value["model"] + serializer = value["serializer"] + id = obj.get("id", None) if id is not None: instance = model.objects.get(id=id) instance = serializer(instance, data=obj) @@ -79,4 +70,3 @@ def create(self, request): # response return Response(results, status=status.HTTP_201_CREATED) - diff --git a/osp/views/user.py b/osp/views/user.py index c169d42..6ec3d27 100644 --- a/osp/views/user.py +++ b/osp/views/user.py @@ -1,20 +1,21 @@ from django.contrib.auth import get_user_model -from rest_framework import viewsets, status +from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response from osp.serializers.user import UserSerializer User = get_user_model() + class UserView(viewsets.ModelViewSet): - permission_classes = [IsAuthenticated, ] + permission_classes = [ + IsAuthenticated, + ] serializer_class = UserSerializer - http_method_names = ['get'] + http_method_names = ["get"] def get_queryset(self): user = self.request.user queryset = User.objects.filter(id=user.id) return queryset - diff --git a/osp/views/user_information.py b/osp/views/user_information.py index a10f164..262c71b 100644 --- a/osp/views/user_information.py +++ b/osp/views/user_information.py @@ -1,4 +1,4 @@ -from rest_framework import viewsets, status +from rest_framework import status, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -6,15 +6,18 @@ from osp.serializers.user_information import UserInformationSerializer from osp.utils.zulip_api import get_zulip_user + class UserInformationView(viewsets.ModelViewSet): - permission_classes = [IsAuthenticated, ] + permission_classes = [ + IsAuthenticated, + ] serializer_class = UserInformationSerializer queryset = UserInformation.objects.all() def get_queryset(self): queryset = self.queryset - user_id = self.request.query_params.get('user_id', None) + user_id = self.request.query_params.get("user_id", None) user = self.request.user if user_id is not None: queryset = queryset.filter(user_id=user_id) @@ -27,10 +30,10 @@ def create(self, request): serializer = UserInformationSerializer(data=request.data) if UserInformation.objects.filter(user_id=user.id).exists(): return Response("Information already filled", status=status.HTTP_409_CONFLICT) - response = get_zulip_user(request.data['zulip_id']) + response = get_zulip_user(request.data["zulip_id"]) if response: serializer.is_valid(raise_exception=True) serializer.save(user_id=user.id) return Response(serializer.data, status=status.HTTP_201_CREATED) - + return Response("No user found with the Zulip ID entered.", status=status.HTTP_404_NOT_FOUND) diff --git a/osp/views/zulip_stat.py b/osp/views/zulip_stat.py index 7ae1551..f75793c 100644 --- a/osp/views/zulip_stat.py +++ b/osp/views/zulip_stat.py @@ -1,33 +1,36 @@ from datetime import datetime -from django.utils import timezone + from django.utils.timezone import make_aware -from rest_framework import viewsets, status +from rest_framework import status, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from osp.models import ZulipStat, UserInformation +from osp.models import UserInformation, ZulipStat from osp.serializers.zulip_stat import ZulipStatSerializer from osp.serializers.zulip_stat_user import ZulipStatUserSerializer -from osp.utils.zulip_api import get_zulip_user, get_messages, get_newest_message, get_stream_messages +from osp.utils.zulip_api import get_messages, get_newest_message, get_stream_messages, get_zulip_user + class ZulipStatView(viewsets.ModelViewSet): - permission_classes = [IsAuthenticated,] + permission_classes = [ + IsAuthenticated, + ] queryset = ZulipStat.objects.all() def get_serializer_class(self): user = self.request.user user_type = UserInformation.objects.get(user=user.id).user_type - if user_type=='admin': + if user_type == "admin": self.serializer_class = ZulipStatSerializer else: self.serializer_class = ZulipStatUserSerializer return super(ZulipStatView, self).get_serializer_class() - + def get_queryset(self): queryset = self.queryset user = self.request.user - user_id = self.request.query_params.get('user_id', None) + user_id = self.request.query_params.get("user_id", None) if user_id is not None: queryset = queryset.filter(user_information__user_id=user_id) else: @@ -37,65 +40,63 @@ def get_queryset(self): def create(self, request): user = self.request.user user_info = UserInformation.objects.get(user_id=user.id) - user_type = user_info.user_type # update on existing if ZulipStat.objects.filter(user_information__user_id=user.id).exists(): zulip_id = user_info.zulip_id zulip_user = get_zulip_user(zulip_id) for z in zulip_user: - if z=='full_name': + if z == "full_name": full_name = zulip_user[z] recent_message = get_newest_message(zulip_id) for r in recent_message: - last_activity = r['timestamp'] - - request.data['zulip_username'] = full_name - request.data['total_messages'] = get_messages(zulip_id) - request.data['last_activity'] = make_aware(datetime.fromtimestamp(last_activity)) - request.data['newcomers_messages'] = get_stream_messages('newcomers', zulip_id) - request.data['general_messages'] = get_stream_messages('general', zulip_id) - request.data['questions_messages'] = get_stream_messages('questions', zulip_id) - request.data['opportunities_messages'] = get_stream_messages('opportunities', zulip_id) - request.data['celebrate_messages'] = get_stream_messages('celebrate', zulip_id) + last_activity = r["timestamp"] + + request.data["zulip_username"] = full_name + request.data["total_messages"] = get_messages(zulip_id) + request.data["last_activity"] = make_aware(datetime.fromtimestamp(last_activity)) + request.data["newcomers_messages"] = get_stream_messages("newcomers", zulip_id) + request.data["general_messages"] = get_stream_messages("general", zulip_id) + request.data["questions_messages"] = get_stream_messages("questions", zulip_id) + request.data["opportunities_messages"] = get_stream_messages("opportunities", zulip_id) + request.data["celebrate_messages"] = get_stream_messages("celebrate", zulip_id) instance = ZulipStat.objects.get(user_information_id=user_info.id) serializer = ZulipStatSerializer(instance, data=request.data) serializer.is_valid(raise_exception=True) serializer.save() - + # create if field does not exist else: zulip_id = user_info.zulip_id zulip_user = get_zulip_user(zulip_id) for z in zulip_user: - if z=='full_name': + if z == "full_name": full_name = zulip_user[z] - if z=='date_joined': + if z == "date_joined": first_activity = zulip_user[z] - + recent_message = get_newest_message(zulip_id) for r in recent_message: - last_activity = r['timestamp'] - - request.data['zulip_username'] = full_name - request.data['total_messages'] = get_messages(zulip_id) - request.data['last_activity'] = make_aware(datetime.fromtimestamp(last_activity)) - request.data['first_activity'] = first_activity - request.data['newcomers_messages'] = get_stream_messages('newcomers', zulip_id) - request.data['general_messages'] = get_stream_messages('general', zulip_id) - request.data['questions_messages'] = get_stream_messages('questions', zulip_id) - request.data['opportunities_messages'] = get_stream_messages('opportunities', zulip_id) - request.data['celebrate_messages'] = get_stream_messages('celebrate', zulip_id) + last_activity = r["timestamp"] + + request.data["zulip_username"] = full_name + request.data["total_messages"] = get_messages(zulip_id) + request.data["last_activity"] = make_aware(datetime.fromtimestamp(last_activity)) + request.data["first_activity"] = first_activity + request.data["newcomers_messages"] = get_stream_messages("newcomers", zulip_id) + request.data["general_messages"] = get_stream_messages("general", zulip_id) + request.data["questions_messages"] = get_stream_messages("questions", zulip_id) + request.data["opportunities_messages"] = get_stream_messages("opportunities", zulip_id) + request.data["celebrate_messages"] = get_stream_messages("celebrate", zulip_id) serializer = ZulipStatSerializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save(user_information_id=user_info.id) - obj = ZulipStat.objects.get(id=serializer.data['id']) + obj = ZulipStat.objects.get(id=serializer.data["id"]) self.get_serializer_class() - #response + # response return Response(self.serializer_class(obj).data, status=status.HTTP_201_CREATED) - diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4e610e8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,13 @@ +[tool.black] +line-length = 119 +exclude = ''' + +( + /( + \.git + | \.mypy_cache + | \.venv + | venv + )/ +) +''' diff --git a/requirements.txt b/requirements.txt index c554155..e31b442 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,4 +33,4 @@ toml==0.10.1 typed-ast==1.4.1 urllib3==1.25.10 wrapt==1.12.1 -zulip==0.7.0 +zulip==0.7.0 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..97ec614 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,11 @@ +[flake8] +exclude=.git, venv/, *migrations* +max-line-length=119 +per-file-ignores=__init__.py:F401 + + +[isort] +profile=black +line_length=119 +multi_line_output = 3 +include_trailing_comma = True diff --git a/tests/test_api_user_info.py b/tests/test_api_user_info.py new file mode 100644 index 0000000..54fe9e4 --- /dev/null +++ b/tests/test_api_user_info.py @@ -0,0 +1,66 @@ +from django.contrib.auth import get_user_model +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + +User = get_user_model() + + +class UserInfoTests(APITestCase): + def setUp(self): + + # Needed for token auths + self.client = APIClient() + + # Register + self.register_data = { + "username": "testuser1", + "email": "testuser1@gmail.com", + "password": "hello", + "confirm_password": "hello", + } + test_user = User(username=self.register_data["username"], email=self.register_data["email"], is_active=True) + test_user.set_password(self.register_data["password"]) + test_user.save() + + # Login and get real token + login_data = {"username": self.register_data["username"], "password": self.register_data["password"]} + response = self.client.post( + "http://localhost:8000/api/token_auth/token/", + login_data, + format="json", + headers={"Content-Type": "application/json"}, + ) + self.access_token = response.json()["access"] + self.client.credentials(HTTP_AUTHORIZATION="Bearer " + self.access_token) + + def test_get_user_info_successfully_empty(self): + + response = self.client.get("http://localhost:8000/api/info/", format="json") + self.assertEqual(response.data, []) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_post_user_info_successfully(self): + + body = {"name": "Test User 1 Full Name", "user_type": "admin", "zulip_id": 334084} + response = self.client.post("http://localhost:8000/api/info/", body, format="json") + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + def test_get_user_info_successfully(self): + + response = self.client.get("http://localhost:8000/api/info/", format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_api_wrong_token(self): + + self.client.credentials() + response = self.client.get("http://localhost:8000/api/info/", format="json") + self.assertEqual(response.data["detail"], "Authentication credentials were not provided.") + self.assertEqual(response.status_code, 403) + + def test_multiple_post_user_info(self): + + self.client.credentials(HTTP_AUTHORIZATION="Bearer " + self.access_token) + body = {"name": "Test User 1 Full Name", "user_type": "admin", "zulip_id": 334084} + for _ in range(2): + response = self.client.post("http://localhost:8000/api/info/", body, format="json") + self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) diff --git a/tests/test_serializer_register.py b/tests/test_serializer_register.py index 662035f..b82d6af 100644 --- a/tests/test_serializer_register.py +++ b/tests/test_serializer_register.py @@ -1,6 +1,7 @@ from django.contrib.auth import get_user_model from django.test import TestCase from rest_framework.serializers import ValidationError + from token_auth.serializers.register import RegisterSerializer User = get_user_model() @@ -14,10 +15,10 @@ class RegisterSerializerTests(TestCase): def setUp(self): self.test_user = self.__create_user("test", "test@test.com", "test") self.test_data = { - 'username': 'testuser2', - 'email': 'test2@test.com', - 'password': 'test', - 'confirm_password': 'test' + "username": "testuser2", + "email": "test2@test.com", + "password": "test", + "confirm_password": "test", } def __create_user(self, username, email, password): @@ -30,10 +31,7 @@ def test_get_serializer(self): Testing Response of Register Serializer. """ actual_response = RegisterSerializer(self.test_user).data - expected_response = { - 'username': self.test_user.username, - 'email': self.test_user.email - } + expected_response = {"username": self.test_user.username, "email": self.test_user.email} self.assertEqual(actual_response, expected_response) def test_create_serializer(self): @@ -43,8 +41,7 @@ def test_create_serializer(self): serializer = RegisterSerializer(data=self.test_data) if serializer.is_valid(): user = serializer.save() - self.assertEquals(user, User.objects.get( - email=self.test_data['email'])) + self.assertEquals(user, User.objects.get(email=self.test_data["email"])) def test_create_serializer_with_same_email_id(self): """ @@ -61,7 +58,7 @@ def test_create_serializer_with_different_passwords(self): Testing Validation Error in create method of Register Serializer when password and confirm password are not equal. """ - self.test_data['password'] = 'different' + self.test_data["password"] = "different" serializer = RegisterSerializer(data=self.test_data) if serializer.is_valid(): with self.assertRaises(ValidationError): diff --git a/token_auth/admin.py b/token_auth/admin.py index 3b7036b..1422994 100644 --- a/token_auth/admin.py +++ b/token_auth/admin.py @@ -1,5 +1,5 @@ -from django.contrib.auth import get_user_model from django.contrib import admin +from django.contrib.auth import get_user_model # Register your models here. diff --git a/token_auth/apps.py b/token_auth/apps.py index b08b2a7..366fb89 100644 --- a/token_auth/apps.py +++ b/token_auth/apps.py @@ -2,4 +2,4 @@ class TokenAuthConfig(AppConfig): - name = 'token_auth' + name = "token_auth" diff --git a/token_auth/migrations/0001_initial.py b/token_auth/migrations/0001_initial.py index 2eee85a..4c95822 100644 --- a/token_auth/migrations/0001_initial.py +++ b/token_auth/migrations/0001_initial.py @@ -2,8 +2,8 @@ import django.contrib.auth.models import django.contrib.auth.validators -from django.db import migrations, models import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): @@ -11,34 +11,85 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0011_update_proxy_permissions'), + ("auth", "0011_update_proxy_permissions"), ] operations = [ migrations.CreateModel( - name='User', + 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')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ("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")), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={"unique": "A user with that username already exists."}, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], + verbose_name="username", + ), + ), + ("first_name", models.CharField(blank=True, max_length=30, verbose_name="first name")), + ("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")), + ("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, }, managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), ] diff --git a/token_auth/models/__init__.py b/token_auth/models/__init__.py index 0c5feba..87b6b07 100644 --- a/token_auth/models/__init__.py +++ b/token_auth/models/__init__.py @@ -1 +1 @@ -from token_auth.models.user import User \ No newline at end of file +from token_auth.models.user import User diff --git a/token_auth/models/user.py b/token_auth/models/user.py index d13eb70..3d30525 100644 --- a/token_auth/models/user.py +++ b/token_auth/models/user.py @@ -1,5 +1,5 @@ -from django.db import models from django.contrib.auth.models import AbstractUser + class User(AbstractUser): - pass \ No newline at end of file + pass diff --git a/token_auth/serializers/register.py b/token_auth/serializers/register.py index c1f5356..ac7e0f7 100644 --- a/token_auth/serializers/register.py +++ b/token_auth/serializers/register.py @@ -4,16 +4,11 @@ User = get_user_model() + class RegisterSerializer(serializers.ModelSerializer): - password = PasswordField( - write_only=True, - required=True - ) - confirm_password = PasswordField( - write_only=True, - required=True - ) + password = PasswordField(write_only=True, required=True) + confirm_password = PasswordField(write_only=True, required=True) class Meta: model = User @@ -26,12 +21,12 @@ class Meta: def create(self, validated_data): - username = validated_data.get('username', None) - email = validated_data.get('email', None) - password = validated_data.get('password', None) - confirm_password = validated_data.get('confirm_password', None) + username = validated_data.get("username", None) + email = validated_data.get("email", None) + password = validated_data.get("password", None) + confirm_password = validated_data.get("confirm_password", None) - if (email and User.objects.filter(email=email).exclude(username=username).exists()): + if email and User.objects.filter(email=email).exclude(username=username).exists(): raise serializers.ValidationError("Email addresses must be unique.") if password != confirm_password: @@ -42,4 +37,3 @@ def create(self, validated_data): user.save() return user - diff --git a/token_auth/urls.py b/token_auth/urls.py index 0abccce..bc2a6b6 100644 --- a/token_auth/urls.py +++ b/token_auth/urls.py @@ -1,16 +1,17 @@ -from django.urls import path, include from django.conf.urls import url +from django.urls import path from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView from token_auth.views.register import RegisterView - urlpatterns = [ - path('register/', RegisterView.as_view()), - url(r'^activate/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', RegisterView.activate, name='activate'), - + path("register/", RegisterView.as_view()), + url( + r"^activate/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$", + RegisterView.activate, + name="activate", + ), # login URLs - path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), - path('refresh/', TokenRefreshView.as_view(), name='token_refresh'), + path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), + path("refresh/", TokenRefreshView.as_view(), name="token_refresh"), ] - diff --git a/token_auth/views/register.py b/token_auth/views/register.py index a541235..bafb2ce 100644 --- a/token_auth/views/register.py +++ b/token_auth/views/register.py @@ -1,22 +1,19 @@ from django.contrib.auth import get_user_model from django.core.mail import send_mail -from django.template.loader import render_to_string -from django.contrib.sites.shortcuts import get_current_site from django.utils.encoding import force_bytes, force_text from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode - from rest_framework import status from rest_framework.decorators import api_view from rest_framework.permissions import AllowAny -from rest_framework.views import APIView from rest_framework.response import Response -from rest_framework_simplejwt.tokens import RefreshToken +from rest_framework.views import APIView from token_auth.serializers.register import RegisterSerializer from token_auth.views.token import account_activation_token User = get_user_model() + class RegisterView(APIView): permission_classes = [AllowAny] @@ -29,20 +26,20 @@ def post(self, request, *args, **kwargs): # Account Creation serializer = RegisterSerializer(data=request.data) if not serializer.is_valid(): - return Response(serializer.errors, status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status.HTTP_400_BAD_REQUEST) user = serializer.save() - + url = f"{urlsafe_base64_encode(force_bytes(user.pk))}/{account_activation_token.make_token(user)}" # Send Email for confirmation send_mail( - 'Confirmation Email', - f'Please click on the link to confirm the link: http://localhost:3000/{urlsafe_base64_encode(force_bytes(user.pk))}/{account_activation_token.make_token(user)}', - 'AnitaB Open Source ', - [request.data['email']], + "Confirmation Email", + f"Please click on the link to confirm the link: http://localhost:3000/{url} ", + "AnitaB Open Source ", + [request.data["email"]], fail_silently=False, ) return Response({"Please confirm your email to Login succesfully"}, status.HTTP_201_CREATED) - @api_view(('GET',)) + @api_view(("GET",)) def activate(request, uidb64, token): """ Function for account activation @@ -51,13 +48,12 @@ def activate(request, uidb64, token): try: uid = force_text(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) - except(TypeError, ValueError, OverflowError, User.DoesNotExist): + except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None - + if user is not None and account_activation_token.check_token(user, token): user.is_active = True user.save() return Response({"Your email is confirmed!"}, status=status.HTTP_200_OK) else: return Response({"Invalid link"}, status=status.HTTP_400_BAD_REQUEST) - diff --git a/token_auth/views/token.py b/token_auth/views/token.py index 6902a8e..4d1d88d 100644 --- a/token_auth/views/token.py +++ b/token_auth/views/token.py @@ -1,6 +1,8 @@ from django.contrib.auth.tokens import PasswordResetTokenGenerator + # from django.utils import six + class TokenGenerator(PasswordResetTokenGenerator): """ @@ -9,9 +11,7 @@ class TokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): - return ( - str(user.pk) + str(timestamp) + str(user.is_active) - ) + return str(user.pk) + str(timestamp) + str(user.is_active) -account_activation_token = TokenGenerator() +account_activation_token = TokenGenerator()