Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/initial project #2

Merged
merged 333 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 250 commits
Commits
Show all changes
333 commits
Select commit Hold shift + click to select a range
f09c15a
Test usage of same token
juuso-j May 9, 2023
aa7bb00
Add postal_code and optional_postal_code
juuso-j May 10, 2023
5220b77
Add profile update and minor fixes
juuso-j May 10, 2023
d176b96
Change idempotent endpoints to post
juuso-j May 10, 2023
82a6d66
Add initial profile tests
juuso-j May 10, 2023
e5442a9
Change get to post call for idempotent endpoints
juuso-j May 10, 2023
cc8c765
Test save email
juuso-j May 11, 2023
3770e65
Add unique email
juuso-j May 11, 2023
e9809a6
Add save email endpoint
juuso-j May 11, 2023
656174c
Add initial docker configuration
juuso-j May 15, 2023
3e3ec33
Add initial docker-entrypoint
juuso-j May 26, 2023
9a30adf
Add initial docker-compose.yml
juuso-j May 26, 2023
7afe8c7
Add info about docker
juuso-j May 26, 2023
903d437
Add MEDIA_ROOT, STATOR_ROOT, MEDIA_URL, STATIC_URL
juuso-j Jun 2, 2023
26ddd4c
Add MEDIA_ROOT, STATOR_ROOT, MEDIA_URL, STATIC_URL
juuso-j Jun 2, 2023
1f6da85
Add initial additional compose file for production
juuso-j Jun 2, 2023
a579cb7
Add production_server condition
juuso-j Jun 2, 2023
8a6d13b
Add docker ignore
juuso-j Jun 2, 2023
9113596
Add .django_secret
juuso-j Jun 2, 2023
4a918d3
Change app to mpbackend
juuso-j Jun 2, 2023
480c0c3
Add volume and args
juuso-j Jun 2, 2023
574aad5
Add initial docker nginx conf
juuso-j Jun 2, 2023
7001a88
Add initial uswgi settings
juuso-j Jun 2, 2023
1a26754
Add production requirements
juuso-j Jun 2, 2023
46ecd83
Add uwsgi params
juuso-j Jun 2, 2023
5f6099d
Move to docker/mpbackend/
juuso-j Jun 2, 2023
ea9ceec
Add mpbackend Dockerfile
juuso-j Jun 2, 2023
5d4cfd6
Add dockerfile for nginx
juuso-j Jun 2, 2023
5be3943
Add DEBUG, volumes
juuso-j Jun 6, 2023
272f7ea
Fix volumes
juuso-j Jun 6, 2023
9b01503
Fix uwsg_params path
juuso-j Jun 6, 2023
0fe94b5
Add env variables
juuso-j Jun 6, 2023
e0ddd15
Copy uwsi_params
juuso-j Jun 6, 2023
662e2e6
Add uid, gid and static-map
juuso-j Jun 6, 2023
249834c
Fix urls to django 4.2
juuso-j Jun 7, 2023
f5a8bf8
Change static volume to /mpbackend/static
juuso-j Jun 7, 2023
45cc699
Add docker info
juuso-j Jun 7, 2023
9b1d729
Change static alias to /mpbackend/static
juuso-j Jun 7, 2023
88c155b
Add DEFAULT_RENDERER_CLASSES
juuso-j Jun 9, 2023
6ef54d7
Add CustomBrowsableAPIRenderer
juuso-j Jun 9, 2023
70a7b42
Add renderer classes
juuso-j Jun 9, 2023
1fca814
Add drf-spectacular
juuso-j Jun 14, 2023
5ff8971
Add hook for filtering endpoints for drf-spectacular
juuso-j Jun 14, 2023
2038d46
Add drf-spectacular
juuso-j Jun 14, 2023
e159c8c
Add result
juuso-j Jun 15, 2023
13b5e43
Set is_generated=True when creating user
juuso-j Jun 15, 2023
f3f1194
Test that is_generated is true
juuso-j Jun 15, 2023
cff8bb2
Remove comment
juuso-j Jun 15, 2023
5e64827
Change router to DefaultRouter
juuso-j Jun 19, 2023
04eeeb7
Add schema urls
juuso-j Jun 19, 2023
f83e85b
Add orderings
juuso-j Jun 19, 2023
67747a5
Comment still unused account.api
juuso-j Jun 19, 2023
586195d
Add initial migrations
juuso-j Jun 20, 2023
4f64f46
Add initial migrations
juuso-j Jun 20, 2023
d139f24
Change FILENAME
juuso-j Jun 20, 2023
59ea2fb
Add initial (work on progress) question data
juuso-j Jun 20, 2023
dfc368d
Add answer
juuso-j Jun 20, 2023
357c7db
Add info
juuso-j Jun 22, 2023
b73d73e
Add documentation
juuso-j Jun 22, 2023
f3e077d
Add corsheaders
juuso-j Jul 17, 2023
abd6b86
Add django-cors-headers
juuso-j Jul 17, 2023
56aab2b
Add CustomAnswerSerializer
juuso-j Jul 31, 2023
ea1e859
Add translations, conditions and fixes
juuso-j Sep 19, 2023
82b7c49
Add major bugfixes and changes
juuso-j Sep 19, 2023
62710d5
Add importer tests
juuso-j Sep 19, 2023
8796adb
Move options to correct row for part2 questions
juuso-j Sep 20, 2023
c84417f
Add number_of_choices, QuestionCondition model and str functions
juuso-j Sep 20, 2023
15b6c61
Add topic for Result model
juuso-j Sep 20, 2023
0003725
Import QuestionConditions and refactor code
juuso-j Sep 20, 2023
b65d3ff
Add QuestionCondition test and option tests
juuso-j Sep 20, 2023
c0e9d65
Remove obsolete initial migration
juuso-j Sep 20, 2023
fb4664e
Add initial migration
juuso-j Sep 20, 2023
573c51e
Test number_of_choices and mandatory_number_of_sub_questions_to_answer
juuso-j Sep 20, 2023
06b7cb0
Fix number conflicts
juuso-j Sep 20, 2023
a0e8978
Import mandatory_number_of_sub_questions_to_answer
juuso-j Sep 20, 2023
2212740
Add mandatory_number_of_sub_questions_to_answer remove number_of_sub_…
juuso-j Sep 21, 2023
37eb4fe
Add check_if_condition_met
juuso-j Sep 21, 2023
5a7bdba
Rename QuestionNumberSerializer -> QuestionNumberIDSerializer
juuso-j Sep 21, 2023
208fccb
Add SubQuestions and QuestionConditions
juuso-j Sep 21, 2023
4cb22e3
Add QuestionCondition tests
juuso-j Sep 21, 2023
0b3e61a
Use Question id instead of number, fix description in check_if_condit…
juuso-j Sep 21, 2023
a96a430
Pass Question id to check_if_condition_met
juuso-j Sep 21, 2023
f6ec10b
Change question_id param to question
juuso-j Sep 21, 2023
7c9703c
Change check_if_condition_met request serializer
juuso-j Sep 21, 2023
6a13664
Add CustomCheckConditionSerializer
juuso-j Sep 21, 2023
12baf4f
Add question and sub_question to CustomAnswerSerializer
juuso-j Sep 21, 2023
94af055
Create answer takes question and sub_question as params
juuso-j Sep 21, 2023
42af9ab
Add num_sub_questions property
juuso-j Sep 21, 2023
fa48e88
Add more QuestionCondition tests and that duplicate answers are not c…
juuso-j Sep 21, 2023
0f82d55
Test question num_sub_questions property
juuso-j Sep 21, 2023
558134a
Add migration that adds field for mandatory sub question answers
juuso-j Sep 21, 2023
de2b3d7
Add migration that adds Question and SubQuestion to Answer model
juuso-j Sep 21, 2023
1407ced
Add migration
juuso-j Sep 22, 2023
1221995
Change '*' to '+' for number of options choices if >0
juuso-j Sep 22, 2023
b0b1ecf
Rename number_of_choices to number_of_options_to_choose
juuso-j Sep 22, 2023
01f56b3
Renamenumber_of_choices to number_of_options_to_choose
juuso-j Sep 22, 2023
e060554
Refactor reqeust serializers
juuso-j Sep 22, 2023
d78ef6a
Rename number_of_choices to number_of_options_to_choose
juuso-j Sep 22, 2023
02ea5ea
Add HasConditionResponseSerializer
juuso-j Sep 22, 2023
d657036
Add has_condition endpoint
juuso-j Sep 22, 2023
00652e9
Add topic to results
juuso-j Sep 26, 2023
18a2827
Add function to store PostalCodeResult
juuso-j Sep 27, 2023
e7c5fcb
Add postal_code_result_saved field
juuso-j Sep 27, 2023
706b791
Add model PostalCode and PostalCodeResult
juuso-j Sep 27, 2023
d4b00da
Add PostalCodeResultSerializer
juuso-j Sep 27, 2023
716ea0f
Add basic viewset for PostalCodeResult model
juuso-j Sep 27, 2023
e9e3ef5
Add test for PostalCodeResult model
juuso-j Sep 27, 2023
41a5b75
Add PostalCodeSerializer
juuso-j Sep 27, 2023
9c55399
Add basic viewset for PostalCode
juuso-j Sep 27, 2023
d25d6c7
Set CsrfViewMiddleware above CommonMiddleware
juuso-j Sep 27, 2023
d4dddd4
Move check_if_condition_met to QuestionViewSet
juuso-j Sep 27, 2023
432a481
Rename HasConditionResponseSerializer to InConditionResponseSerializer
juuso-j Sep 27, 2023
82669ed
Rename has_condition endpoint to in_condition and move to QuesitonVie…
juuso-j Sep 27, 2023
56325f4
Add in_condition endpoint tests
juuso-j Sep 27, 2023
a8d3899
Fix exception not catched in in_condition view
juuso-j Sep 27, 2023
5e69c0b
Update description for end_poll view
juuso-j Sep 27, 2023
46d592c
Update check_if_condition_met description
juuso-j Sep 27, 2023
c1cb9a1
Check related question and sub_question when posting answer
juuso-j Sep 28, 2023
269f014
Will not add count to PostalCodeResult if no result
juuso-j Sep 28, 2023
74d3b95
Test post answer with erroneous question id
juuso-j Sep 28, 2023
e3777fd
Discards rows that defines category 2
juuso-j Sep 29, 2023
7a20e16
Test that category 2 row is skipped
juuso-j Sep 29, 2023
89b1731
Add PostalCodeType model
juuso-j Sep 29, 2023
e649ad7
Add PostalCodeType model
juuso-j Sep 29, 2023
fac1ae3
Alter postal_code_type to Foreignkey
juuso-j Sep 29, 2023
d340c74
Get or create PostalCodeType and set relation to PostalCodeResult
juuso-j Sep 29, 2023
1a3d3dc
Add basic serializer for PostalCodeType
juuso-j Sep 29, 2023
44b0bb5
Add basic view for PostalCodeType
juuso-j Sep 29, 2023
d7c0a0d
Add results to options
juuso-j Sep 29, 2023
c751880
Add custom list for PostalCodeResultViewSet
juuso-j Sep 29, 2023
81a0f8b
Add order by id
juuso-j Sep 29, 2023
ceb82a5
Use PostalCodeType model
juuso-j Sep 29, 2023
443ba6c
Add tests for PostalCodeResul
juuso-j Sep 29, 2023
6800bbf
Add documentation to PostalCodeResult list view
juuso-j Sep 29, 2023
935018f
Add postalcoderesult
juuso-j Oct 2, 2023
96bd56f
Test question condition before saving answer to db
juuso-j Oct 2, 2023
c70df03
Add Options for question3
juuso-j Oct 2, 2023
f930f37
Test that condition is checked when posting answer
juuso-j Oct 2, 2023
72f960c
Add csrf/
juuso-j Oct 2, 2023
3f18b72
Add get_csrf
juuso-j Oct 2, 2023
ea37b85
Add CSRF_TRUSTED_ORIGINS
juuso-j Oct 2, 2023
352eda3
Return CSRF token in start_poll
juuso-j Oct 2, 2023
8a077c8
Add SubQuestionCondition model
juuso-j Dec 13, 2023
e36fdf2
Add SubQuestionCondition serializers
juuso-j Dec 13, 2023
bfc4fe3
Add sub question condition functionality
juuso-j Dec 13, 2023
d896f82
Add sub question conditions
juuso-j Dec 13, 2023
66288b9
Import sub question conditions
juuso-j Dec 13, 2023
6c14ce0
Alter question condition related names
juuso-j Dec 13, 2023
a7a23e2
Add model SubQuestionCondition
juuso-j Dec 13, 2023
cc71942
Add SubQuestionCondition fixtures
juuso-j Dec 13, 2023
0228b94
Add sub question condition tests
juuso-j Dec 13, 2023
7add306
Test sub question condition importing
juuso-j Dec 13, 2023
8039085
Add 'http://' prefix to CSRF_TRUSTED_ORIGINS
juuso-j Dec 14, 2023
343c341
Remove ./ prefix from postgres-data volume
juuso-j Dec 22, 2023
9df2994
Add check if postgres is running
juuso-j Dec 22, 2023
a00c95c
Add script for backuping the database
juuso-j Dec 22, 2023
448244e
Add script for updating and starting production containers
juuso-j Dec 22, 2023
ea29db1
Set relative location of docker-compose files
juuso-j Dec 22, 2023
cf6f6ab
Remove gender
juuso-j Jan 8, 2024
deed13b
Remove gender, add age, is_filled_for_fun and result_can_be_used
juuso-j Jan 8, 2024
45cb79b
Add age, is_filled_for_fun and result_can_be_used
juuso-j Jan 8, 2024
eb78880
Allow only put and patch methods in viewset
juuso-j Jan 8, 2024
ea4c05b
Add migration that deletes the gender
juuso-j Jan 8, 2024
c0ea48e
Add is_filled_for_fun
juuso-j Jan 8, 2024
8ac5280
Add field result_can_be_used
juuso-j Jan 8, 2024
e2dbfc4
Add age field
juuso-j Jan 8, 2024
1f5aa37
Add basic users and profiles fixtures
juuso-j Jan 8, 2024
bf46cd2
Add /api/account/
juuso-j Jan 8, 2024
48af41a
Add PostalCode, PostalCodeType and PostalCodeResult
juuso-j Jan 8, 2024
e7edc11
Add Profile API tests
juuso-j Jan 9, 2024
70a6a09
Serialize many conditions
juuso-j Jan 9, 2024
6e2890b
Add answers and users fixtures
juuso-j Jan 9, 2024
d90d3c0
Check is_filled_for_fun and result_can_be_used fields
juuso-j Jan 9, 2024
6e4172e
Test is_filled_for_fun and result_can_be_used fields
juuso-j Jan 9, 2024
bc0e8b6
Fix erroneous echo
juuso-j Jan 12, 2024
0825bb4
Add executable permission
juuso-j Jan 16, 2024
33ded30
Add MailingListAdmin
juuso-j Jan 16, 2024
2a7fbee
Add MailingList and MalingListEmail
juuso-j Jan 16, 2024
f5ce0f2
Add serializers for subscribe and unsubscibe requests
juuso-j Jan 16, 2024
f21853c
Add endpoint to subscribe and unsubscribe to mailing list
juuso-j Jan 16, 2024
b7c6025
Add MailingList model
juuso-j Jan 16, 2024
d3cdc0d
Add model MailingListEmail
juuso-j Jan 16, 2024
32bb021
Add results and mailing_lists fixtures
juuso-j Jan 16, 2024
888dae5
Test subscribe and unsubscribe endpoints
juuso-j Jan 16, 2024
9bf82c4
Add patch and check_method_status_codes functions
juuso-j Jan 16, 2024
1d1fdbd
Permission change
juuso-j Jan 16, 2024
33f3e65
Remove test_email_verify_process
juuso-j Jan 16, 2024
d60d964
Remove account email endpoints
juuso-j Jan 16, 2024
e154ae5
Format
juuso-j Jan 16, 2024
c31be4d
Fix erroneous API documentation specifications
juuso-j Jan 16, 2024
4708bfa
Restrict permissions to change/delete rows in models
juuso-j Jan 16, 2024
fa749f7
Load CsrfViwMiddleware before CorsMiddleware
juuso-j Jan 16, 2024
fbf6f24
Remove user_info from profile serializer
juuso-j Jan 17, 2024
7bf6588
Add throttling configuration
juuso-j Jan 17, 2024
8241d81
Add api_client_with_custom_ip_address
juuso-j Jan 17, 2024
4d46f73
Add throttling tests
juuso-j Jan 17, 2024
4b7a1ce
Add custom throttling rate to unsubscribe
juuso-j Jan 17, 2024
02085b4
Add unsubscribe throttling test
juuso-j Jan 17, 2024
f3e9b8b
Rename age to year_of_birth
juuso-j Jan 17, 2024
5ce39dc
Refactor test_questions into atomic tests
juuso-j Jan 17, 2024
28c5071
Fix AnswerViewSet documentation
juuso-j Jan 17, 2024
b0ce4bb
Make sub_question optional in AnswerRequestSerializer
juuso-j Jan 17, 2024
b6a814b
Replace SessionAuthentication with TokenAuthentication
juuso-j Jan 19, 2024
37e697b
Replace SessionAuthentication with TokenAuthentication
juuso-j Jan 19, 2024
969a6b8
Add api_client_authenticated fixture
juuso-j Jan 22, 2024
12b3a91
Work with token authentication
juuso-j Jan 22, 2024
5dde2f6
Use request.user as the authenticated user
juuso-j Jan 22, 2024
136638a
Add CORS settings
juuso-j Jan 22, 2024
3da9baa
Use request.user instead of get_user function
juuso-j Jan 23, 2024
b2ef81a
Refactor
juuso-j Jan 23, 2024
ec7aeb6
Get user by username
juuso-j Jan 23, 2024
694c23a
Deleted, as content refactored into separated files
juuso-j Jan 23, 2024
1a84d54
Delete token in end_poll endpoint
juuso-j Jan 23, 2024
30230fe
Add fixtures and refactor
juuso-j Jan 23, 2024
3f22119
Add answer endpoint tests
juuso-j Jan 23, 2024
3699445
Add postal_code_result endpoint tests
juuso-j Jan 23, 2024
4c97771
Add question endpoint tests
juuso-j Jan 23, 2024
3d293c4
Add Authorization to CORS_ALLOW_HEADERS
juuso-j Jan 23, 2024
f5aafa5
Add CORS_ORIGIN_WHITELIST to env
juuso-j Jan 23, 2024
6e3fdaf
Remove breakpoint
juuso-j Jan 23, 2024
269f0a3
Make AnswerViewSet create only viewset
juuso-j Jan 23, 2024
aaee983
Add ExpiringTokenAuthentication
juuso-j Jan 24, 2024
ecc6fb6
Add ExpiringTokenAuthentication
juuso-j Jan 24, 2024
37161ec
Add freezegun
juuso-j Jan 24, 2024
8784d3d
Add token expiration test
juuso-j Jan 24, 2024
8d40f01
Format
juuso-j Jan 24, 2024
56dbf32
Test get_questions_with_conditions
juuso-j Jan 24, 2024
535f075
Add get_question_with_conditions
juuso-j Jan 24, 2024
16b9891
Add QuestionsConditionsStatesSerializer
juuso-j Jan 26, 2024
980798e
Add get_questions_conditions_states
juuso-j Jan 26, 2024
f08b9f6
Test get_questions_conditions_states
juuso-j Jan 26, 2024
dddff89
Merge branch 'develop' into feature/initial-project
juuso-j Jan 30, 2024
2d91700
Format
juuso-j Jan 30, 2024
4e1c17a
Update run-tests.yml
juuso-j Jan 30, 2024
fbadd35
Change checkout to v3
juuso-j Jan 30, 2024
d643b26
Run apt-get update
juuso-j Jan 30, 2024
238c976
Change codecov-action to v3
juuso-j Jan 30, 2024
27ccd1f
Change actions v3 to v4
juuso-j Jan 30, 2024
d955f8f
Remove version from action
juuso-j Jan 30, 2024
ba5c5e8
Add v3
juuso-j Jan 30, 2024
1896dbb
Update run-tests.yml
juuso-j Jan 30, 2024
030a721
Update run-tests.yml
juuso-j Jan 30, 2024
ad749a5
Merge branch 'develop' into feature/initial-project
juuso-j Jan 30, 2024
178ba5f
Update run-tests.yml
juuso-j Jan 30, 2024
3b054c7
Fix comment
juuso-j Jan 30, 2024
7d153fe
Merge branch 'feature/initial-project' of https://github.com/City-of-…
juuso-j Jan 30, 2024
cfe8333
Remove temporarly: black --check .
juuso-j Jan 30, 2024
1db2698
Include mime.types
juuso-j Feb 1, 2024
0ff104a
Merge branch 'feature/initial-project' of https://github.com/City-of-…
juuso-j Feb 1, 2024
a77bc87
Change v2 to v3
juuso-j Feb 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
/postgres-data/
17 changes: 7 additions & 10 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,23 @@ jobs:


steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: 3.10.4
- name: Install required Ubuntu packages
run: |
sudo apt-get install gdal-bin

# - name: Create needed postgis extensions
# run: |
# psql -h localhost -U postgres template1 -c 'create extension postgis;'
sudo apt-get update && sudo apt-get install gdal-bin

- name: Install PyPI dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Python side code neatness tests
run: |
flake8
black --check .
# black --check .
isort . -c
- name: Run pytest code functionality tests
run: |
Expand All @@ -45,7 +42,7 @@ jobs:
pip install coverage
coverage report -m
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v3
# Majority of the tests require database
services:
# Label used to access the service container
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ dmypy.json

# Pyre type checker
.pyre/

# static files
static/

# Django project
.django_secret
56 changes: 54 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,54 @@
# mpbackend
Mobility Profile Backend
# Mobility Profile Backend
This is the backend for the Mobility Profile

## Installation with Docker Compose
First configure development environment settings as stated in `config_dev.env.example`.

### Running the application
Run application with `docker-compose up`
This will startup and bind local postgres and mobilityprofile backend.

### Runnig the application in production
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

### Importing questions
To import questions run: `docker-compose run mpbackend import_questions`


## Installation without Docker
1.
First, install the necessary Debian packages.
TODO, add packages.

2. Clone the repository.
```
git clone https://github.com/City-of-Turku/mpbackend.git
```
3. Install python 3.10 and pip requiremends
Be sure to load the **environment** before installing the requirements.
```
pip install pip-tools
pip install -r requirements.txt
```
4. Setup the PostGIS database.

Please note, we recommend PostgreSQL version 13 or higher.
Local setup:

```
sudo su postgres
psql template1 -c 'CREATE EXTENSION IF NOT EXISTS postgis;'
createuser -RSPd mobilityprofile
createdb -O mobilityprofile -T template1 -l fi_FI.UTF-8 -E utf8 mobilityprofile
```

5. Create database tables.
```
./manage.py migrate
```

6. Import questions
```
./manage.py import_questions
```

Empty file added account/__init__.py
Empty file.
54 changes: 54 additions & 0 deletions account/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django import forms
from django.contrib import admin

from .models import MailingList, Profile, User

admin.site.register(User)


class ProfileAdmin(admin.ModelAdmin):
list_display = ("user", "result")

def result(self, obj):
if obj.user.result:
return obj.user.result.value
else:
return None


class MailingListAdminForm(forms.ModelForm):
csv_emails = forms.CharField(widget=forms.Textarea(attrs={"rows": 20, "cols": 120}))

class Meta:
model = MailingList
fields = ["result"]


class MailingListAdmin(admin.ModelAdmin):
list_display = ("result", "csv_emails")

readonly_fields = ("result",)
form = MailingListAdminForm

def csv_emails(self, obj):
return obj.csv_emails

def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
form.base_fields["csv_emails"].initial = self.csv_emails(obj)
return form

def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {}
extra_context["show_save_and_add_another"] = False
extra_context["show_save_and_continue"] = False
return super().change_view(
request, object_id, form_url, extra_context=extra_context
)

def has_delete_permission(self, request, obj=None):
return False


admin.site.register(Profile, ProfileAdmin)
admin.site.register(MailingList, MailingListAdmin)
Empty file added account/api/__init__.py
Empty file.
55 changes: 55 additions & 0 deletions account/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers

from account.models import MailingListEmail, Profile


class SubscribeSerializer(serializers.Serializer):
email = serializers.CharField()
result = serializers.IntegerField()


class UnSubscribeSerializer(serializers.Serializer):
email = serializers.CharField()


class PublicUserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ["id"]


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = [
"id",
"username",
"email",
"first_name",
"last_name",
"last_login",
"date_joined",
"is_staff",
"is_active",
"email_verified",
]


class ProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Profile
fields = [
"id",
"year_of_birth",
"postal_code",
"optional_postal_code",
"is_filled_for_fun",
"result_can_be_used",
]


class MailingListEmailSerializer(serializers.ModelSerializer):
class Meta:
model = MailingListEmail
fields = "__all__"
13 changes: 13 additions & 0 deletions account/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.urls import include, path
from rest_framework import routers

from . import views

app_name = "account"

# Create a router and register our viewsets with it.
router = routers.DefaultRouter()
router.register("profile", views.ProfileViewSet, "profiles")

# The API URLs are now determined automatically by the router.
urlpatterns = [path("", include(router.urls), name="account")]
122 changes: 122 additions & 0 deletions account/api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from django import db
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from drf_spectacular.utils import extend_schema, OpenApiResponse
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.mixins import UpdateModelMixin
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle

from account.models import MailingList, MailingListEmail, Profile
from profiles.models import Result

from .serializers import ProfileSerializer, SubscribeSerializer, UnSubscribeSerializer

all_views = []


class UnsubscribeRateThrottle(AnonRateThrottle):
"""
The AnonRateThrottle will only ever throttle unauthenticated users.
The IP address of the incoming request is used to generate a unique key to throttle against.
"""

rate = "10/day"


class ProfileViewSet(UpdateModelMixin, viewsets.GenericViewSet):
queryset = Profile.objects.all().select_related("user").order_by("id")
serializer_class = ProfileSerializer

def get_permissions(self):
if self.action in ["unsubscribe"]:
permission_classes = [AllowAny]
else:
permission_classes = [IsAuthenticated]

return [permission() for permission in permission_classes]

def update(self, request, *args, **kwargs):
user = request.user
instance = user.profile
serializer = self.serializer_class(
instance=instance, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data, status=status.HTTP_200_OK)
else:
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@extend_schema(
description="Subscribe the email to the mailing list attached to the result.",
request=SubscribeSerializer,
responses={
201: OpenApiResponse(description="subscribed"),
400: OpenApiResponse(
description="Validation error, detailed information in response"
),
},
)
@action(
detail=False,
methods=["POST"],
permission_classes=[IsAuthenticated],
)
@db.transaction.atomic
def subscribe(self, request):
result = Result.objects.filter(id=request.data.get("result", None)).first()
if not result:
return Response("'result' not found", status=status.HTTP_400_BAD_REQUEST)

email = request.data.get("email", None)
if not email:
return Response("No 'email' provided", status=status.HTTP_400_BAD_REQUEST)
if MailingListEmail.objects.filter(email=email).count() > 0:
return Response("'email' exists", status=status.HTTP_400_BAD_REQUEST)
try:
validate_email(email)
except ValidationError as e:
return Response(f"Invalid email: {e}", status=status.HTTP_400_BAD_REQUEST)
Dismissed Show dismissed Hide dismissed
mailing_list = MailingList.objects.filter(result=result).first()
if not mailing_list:
# In case mailing list is not created for the result, it is created.
mailing_list = MailingList.objects.create(result=result)

MailingListEmail.objects.create(mailing_list=mailing_list, email=email)
return Response("subscribed", status=status.HTTP_201_CREATED)

@extend_schema(
description="Unaubscribe the email from the mailing list attached to the result."
f"Note, there is a rate-limit of {UnsubscribeRateThrottle.rate} requests.",
request=UnSubscribeSerializer,
responses={
200: OpenApiResponse(description="unsubscribed"),
400: OpenApiResponse(
description="Validation error, detailed information in response"
),
},
)
@action(
detail=False,
methods=["POST"],
permission_classes=[AllowAny],
throttle_classes=[UnsubscribeRateThrottle],
)
def unsubscribe(self, request):
email = request.data.get("email", None)
if not email:
return Response("No 'email' provided", status=status.HTTP_400_BAD_REQUEST)
qs = MailingListEmail.objects.filter(email=email)
if not qs.exists():
return Response(
f"{email} does not exists", status=status.HTTP_400_BAD_REQUEST
)

qs.delete()
return Response(f"unsubscribed {email}", status=status.HTTP_200_OK)


all_views.append({"class": ProfileViewSet, "name": "profile"})
6 changes: 6 additions & 0 deletions account/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "account"
Loading
Loading