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

Draft: 346: account management #384

Open
wants to merge 68 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
53a32d5
current changes (bug)
Aug 17, 2021
e74d564
add new libraries and change user files
Aug 26, 2021
ffb003d
fixed errors; new error
Aug 27, 2021
4ce062b
admin and user fields align; no more bug but fields need modifying
Aug 30, 2021
7c6ad99
add user registration endpoint
Sep 8, 2021
88f667a
add activation endpoint and email confirmation
Sep 9, 2021
602ab25
complete account management endpoints
Sep 9, 2021
1c4068a
change login and register pages
Sep 9, 2021
b942dd8
add new pages and routes
Sep 9, 2021
cf80df3
Merge branch 'develop' of https://github.com/openoakland/woeip into 3…
Sep 15, 2021
b948458
using env to get password
Sep 15, 2021
5b9dc84
beginning work on password pages
Sep 21, 2021
420d1e6
feat: add new pages and build out auth endpoints
wendy-wu-five9 Oct 22, 2021
bcbfe5e
Merge branch '346_signin' of https://github.com/openoakland/woeip int…
Oct 22, 2021
0e2d0dd
Merge branch 'develop' of https://github.com/openoakland/woeip into 3…
Oct 22, 2021
7cea1c2
cors test
Oct 22, 2021
3c82623
files where changes need to be made to handle cross origin cors error
Oct 23, 2021
d55f488
utils is normal; commented allowed hosts
Oct 23, 2021
95a3d03
login working on lvh.me
Nov 6, 2021
32c4d6c
adding some descriptions
Nov 10, 2021
100fffd
fix login page
wendy-wu-five9 Nov 10, 2021
764128f
logout
Nov 10, 2021
726158b
Merge branch '346_signin' of https://github.com/openoakland/woeip int…
Nov 10, 2021
dc392a4
fixed login bug
Nov 11, 2021
55fbd88
registration working
Nov 11, 2021
d30c77c
fixed activation url
Nov 12, 2021
e5a73d0
login/logout obvious to users
Nov 14, 2021
d61496e
changed log to sign
Nov 16, 2021
1e5f7ea
feat: add tests for new pages
wendy-wu-five9 Dec 1, 2021
273ff8d
feat: add tests for APIs
wendy-wu-five9 Dec 1, 2021
a3a0e79
fix: remedy tests
wendy-wu-five9 Dec 1, 2021
f030362
current changes (bug)
Aug 17, 2021
c86e8de
add new libraries and change user files
Aug 26, 2021
72b3b24
fixed errors; new error
Aug 27, 2021
777db75
admin and user fields align; no more bug but fields need modifying
Aug 30, 2021
c11434c
add user registration endpoint
Sep 8, 2021
2c723ae
add activation endpoint and email confirmation
Sep 9, 2021
2b686cb
complete account management endpoints
Sep 9, 2021
f533868
change login and register pages
Sep 9, 2021
87eda37
add new pages and routes
Sep 9, 2021
f0c666a
using env to get password
Sep 15, 2021
83a2c2c
beginning work on password pages
Sep 21, 2021
d9678b2
feat: add new pages and build out auth endpoints
wendy-wu-five9 Oct 22, 2021
5ef0fa1
cors test
Oct 22, 2021
fc06269
files where changes need to be made to handle cross origin cors error
Oct 23, 2021
dc99f33
utils is normal; commented allowed hosts
Oct 23, 2021
b60d103
login working on lvh.me
Nov 6, 2021
6df4fcd
adding some descriptions
Nov 10, 2021
28272ce
logout
Nov 10, 2021
467f27b
fix login page
wendy-wu-five9 Nov 10, 2021
6a0d1e9
fixed login bug
Nov 11, 2021
75f4236
registration working
Nov 11, 2021
2bbced9
login/logout obvious to users
Nov 14, 2021
0b272b9
changed log to sign
Nov 16, 2021
2ce607c
feat: add tests for new pages
wendy-wu-five9 Dec 1, 2021
4d483fb
feat: add tests for APIs
wendy-wu-five9 Dec 1, 2021
08fda7c
fix: remedy tests
wendy-wu-five9 Dec 1, 2021
a84b08d
fix: remediate merge conflicts
wendy-wu-five9 Dec 1, 2021
744a9bf
fix: delete duplicate lines
wendy-wu-five9 Dec 7, 2021
7ab3c40
address PR comments
wendy-wu-five9 Dec 15, 2021
f253b8a
working package-lock.json
Dec 15, 2021
13835ed
fix imports
wendy-wu-five9 Dec 15, 2021
64f7d1f
tidy up CSS
wendy-wu-five9 Dec 15, 2021
a0c78a2
reverse import changes
wendy-wu-five9 Dec 15, 2021
b7c5e23
added example.env
Jan 19, 2022
6b1d73c
feat: provide access tokens to requests
wendy-wu-five9 Feb 5, 2022
3b844f2
added return to getter method and refactored calls for token
Feb 6, 2022
7f8bbc9
adding authorization to file upload
Feb 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.mypy_cache/
/.env
.vscode
.vscode
.idea
15 changes: 14 additions & 1 deletion api/requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,33 @@ boto==2.49.0 # via django-boto
certifi==2019.9.11 # via requests
cffi==1.12.3 # via argon2-cffi
chardet==3.0.4 # via requests
charset-normalizer==2.0.4
coreapi==2.3.3 # via drf-yasg
coreschema==0.0.4 # via coreapi, drf-yasg
coverage==4.5.3
cryptography==3.4.8
defusedxml==0.7.1
django-boto==0.3.12
django-cors-headers==3.8.0
django-debug-toolbar==2.2.1
django-environ==0.4.5
django-extensions==2.1.9
django-model-utils==3.2.0
django-rest-auth==0.9.5
django-storages==1.7.1
django-templated-mail==1.1.1
django==3.1.12
djangorestframework==3.11.2
djangorestframework-simplejwt==4.4.0
djoser==2.1.0
drf-yasg==1.17.0
factory-boy==2.12.0
faker==2.0.0 # via factory-boy
gevent==1.4.0
greenlet==0.4.15 # via gevent
gunicorn==19.9.0
idna==2.8 # via requests
importlib-metadata==0.18 # via pluggy, pytest
importlib-metadata==1.3.0 # via pluggy, pytest
inflection==0.3.1 # via drf-yasg
itypes==1.1.0 # via coreapi
jinja2==2.11.3 # via coreschema
Expand All @@ -41,22 +49,27 @@ more-itertools==7.1.0 # via pytest
mypy-extensions==0.4.1 # via mypy
mypy==0.720
numpy==1.16.4
oauthlib==3.1.1
packaging==19.0 # via drf-yasg, pytest
pandas==0.24.2
pluggy==0.12.0 # via pytest
psycopg2-binary==2.8.3
py==1.10.0 # via pytest
pycparser==2.19 # via cffi
pyjwt==1.7.1
pynmea2==1.15.0
pyparsing==2.4.0 # via packaging
pytest-django==3.5.1
pytest==5.0.1 # via pytest-django
python-dateutil==2.8.0 # via django-boto, faker, pandas
pytz==2019.1 # via django, pandas
requests==2.22.0 # via coreapi
requests-oauthlib==1.3.0
ruamel.yaml.clib==0.2.0 # via ruamel.yaml
ruamel.yaml==0.16.5 # via drf-yasg
six==1.12.0 # via argon2-cffi, astroid, django-extensions, drf-yasg, faker, packaging, python-dateutil
social-auth-app-django==4.0.0
social-auth-core==4.0.2
sqlparse==0.3.0 # via django, django-debug-toolbar
text-unidecode==1.2 # via faker
typed-ast==1.4.0 # via astroid, mypy
Expand Down
11 changes: 11 additions & 0 deletions api/requirements/prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@ boto==2.49.0 # via django-boto
certifi==2019.9.11 # via requests
cffi==1.12.3 # via argon2-cffi
chardet==3.0.4 # via requests
charset-normalizer==2.0.4
coreapi==2.3.3 # via drf-yasg
coreschema==0.0.4 # via coreapi, drf-yasg
django-boto==0.3.12
django-cors-headers==3.8.0
django-environ==0.4.5
django-extensions==2.2.6
django-model-utils==3.2.0
django-rest-auth==0.9.5
django-storages==1.8
django-templated-mail==1.1.1
django==3.1.12
djangorestframework==3.11.2
djangorestframework-simplejwt==4.4.0
djoser==2.1.0
drf-yasg==1.17.0
gevent==1.4.0
greenlet==0.4.15 # via gevent
Expand All @@ -29,18 +35,23 @@ itypes==1.1.0 # via coreapi
jinja2==2.11.3 # via coreschema
markupsafe==1.1.1 # via jinja2
numpy==1.16.4
oauthlib==3.1.1
packaging==19.2 # via drf-yasg
pandas==0.24.2
psycopg2-binary==2.8.3
pycparser==2.19 # via cffi
pyjwt==1.7.1
pynmea2==1.15.0
pyparsing==2.4.5 # via packaging
python-dateutil==2.8.0 # via django-boto, pandas
pytz==2019.1 # via django, pandas
requests==2.22.0 # via coreapi
requests-oauthlib==1.3.0
ruamel.yaml.clib==0.2.0 # via ruamel.yaml
ruamel.yaml==0.16.5 # via drf-yasg
six==1.12.0 # via argon2-cffi, django-extensions, drf-yasg, packaging, python-dateutil
social-auth-app-django==4.0.0
social-auth-core==4.0.2
sqlparse==0.3.0 # via django
uritemplate==3.0.0 # via coreapi, drf-yasg
urllib3==1.25.8 # via requests
3 changes: 3 additions & 0 deletions api/woeip/.example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DJOSER_ACCESS_KEY=abcdefghijklmnop
ALLOWED_ORIGINS=http://lvh.me
ALLOWED_HOSTS=api.lvh.me
21 changes: 20 additions & 1 deletion api/woeip/apps/core/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from woeip.apps.core.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

class UserAdmin(BaseUserAdmin):
# add_form = UserCreationForm
model = User

list_display = ('first_name', 'last_name', 'email', 'is_staff')
list_filter = ('is_staff',)

fieldsets = (
(None, {'fields': ('first_name','last_name','email','password')}),

('Permissions', {'fields': ('is_staff',)}),
)

search_fields = ('first_name', 'last_name', 'email')
ordering = ('last_name','email')

filter_horizontal = ()

admin.site.register(User, UserAdmin)
2 changes: 2 additions & 0 deletions api/woeip/apps/core/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from django.contrib.auth.forms import UserCreationForm

55 changes: 55 additions & 0 deletions api/woeip/apps/core/migrations/0003_auto_20210908_0407.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 3.1.12 on 2021-09-08 04:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0002_auto_20210328_1247'),
]

operations = [
migrations.AlterModelOptions(
name='user',
options={},
),
migrations.AlterModelManagers(
name='user',
managers=[
],
),
migrations.RemoveField(
model_name='user',
name='date_joined',
),
migrations.RemoveField(
model_name='user',
name='username',
),
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(max_length=255, unique=True),
),
migrations.AlterField(
model_name='user',
name='first_name',
field=models.CharField(max_length=255),
),
migrations.AlterField(
model_name='user',
name='is_active',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='user',
name='is_staff',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='user',
name='last_name',
field=models.CharField(max_length=255),
),
]
37 changes: 33 additions & 4 deletions api/woeip/apps/core/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

class UserAccountManager(BaseUserManager):
def create_user(self, email, first_name, last_name, password=None):
if not email:
raise ValueError('Users must have an email address')

class User(AbstractUser):
class Meta:
get_latest_by = "date_joined"
email = self.normalize_email(email)
user = self.model(email=email, first_name=first_name, last_name=last_name)

user.set_password(password)
user.save()

return user

class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = UserAccountManager()

def get_full_name(self):
return self.first_name + self.last_name

def get_short_name(self):
return self.first_name

def __str__(self):
return self.email
11 changes: 6 additions & 5 deletions api/woeip/apps/core/serializers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from rest_framework import serializers
from woeip.apps.core.models import User
from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model

User = get_user_model()

class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ["username", "first_name", "last_name", "email"]
fields = ('id', 'email', 'first_name', 'last_name', 'password')
3 changes: 2 additions & 1 deletion api/woeip/apps/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from rest_framework import viewsets
from woeip.apps.core import models
from woeip.apps.core import serializers
from django.shortcuts import redirect, render


class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = serializers.UserSerializer
serializer_class = serializers.UserCreateSerializer

def get_queryset(self):
queryset = models.User.objects.all()
Expand Down
73 changes: 69 additions & 4 deletions api/woeip/settings.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import environ
import datetime
from django.core.exceptions import ImproperlyConfigured

repo_root = environ.Path(__file__) - 2
project_root = environ.Path(__file__) - 1
env = environ.Env(DEBUG=(bool, False))
env.read_env() #needed to read .env file. TODO: store DJOSER password with other passwords.

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY")
Expand All @@ -14,7 +16,7 @@
# NOTE: This setting assumes all requests are proxied through a web server (e.g. nginx). If that is not the case,
# ensure this is set to a more restrictive value. See https://docs.djangoproject.com/en/2.1/ref/settings/#allowed-hosts
# for more information.
ALLOWED_HOSTS = ["*"]
# ALLOWED_HOSTS = ["*"]

# Application definition

Expand All @@ -30,7 +32,14 @@
"django.contrib.gis",
]

THIRD_PARTY_APPS = ["django_extensions", "rest_framework", "storages", "drf_yasg"]
THIRD_PARTY_APPS = [
"django_extensions",
"rest_framework",
"storages",
"drf_yasg",
"djoser",
"corsheaders"
]

LOCAL_APPS = ["woeip.apps.core", "woeip.apps.air_quality"]

Expand All @@ -55,22 +64,33 @@


MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"corsheaders.middleware.CorsPostCsrfMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.contrib.flatpages.middleware.FlatpageFallbackMiddleware",
]

# Origin host/header names that are authorized to send cross-site HTTP requests.
CORS_ALLOWED_ORIGINS = [env("ALLOWED_ORIGINS")]

# Host/domain names that can recieve requests from this Django site.
ALLOWED_HOSTS = [env("ALLOWED_HOSTS")]

CORS_ALLOW_CREDENTIALS = True

ROOT_URLCONF = "woeip.urls"

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [str(project_root.path("templates"))],
# "DIRS": [os.path.join(BASE_DIR, 'build')]
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
Expand Down Expand Up @@ -193,5 +213,50 @@ def generate_file_handler(filename):
LOGIN_REDIRECT_URL = "upload"
LOGOUT_REDIRECT_URL = "login"

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = str(project_root.path("sent_emails"))
# EMAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'openoakland.woaq@gmail.com'
EMAIL_HOST_PASSWORD = env("DJOSER_ACCESS_KEY")
EMAIL_USE_TLS = True

SITE_NAME = ('WOAQ')
DOMAIN = ('lvh.me')
#DJOSER
DJOSER = {
'LOGIN_FIELD': 'email',
'USER_CREATE_PASSWORD_RETYPE': True,
'USERNAME_CHANGED_EMAIL_CONFIRMATION': True,
'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True,
'SEND_ACTIVATION_EMAIL': True,
'SEND_CONFIRMATION_EMAIL': True,
'SET_USERNAME_RETYPE': True,
'SET_PASSWORD_RETYPE': True,
'PASSWORD_RESET_CONFIRM_URL': 'password/reset/confirm/{uid}/{token}',
'USERNAME_RESET_CONFIRM_URL': 'email/reset/confirm/{uid}/{token}',
'ACTIVATION_URL': 'activate/{uid}/{token}',
'END_ACTIVATION_EMAIL': True,
'SERIALIZERS': {
'user_create': 'woeip.apps.core.serializers.UserCreateSerializer',
'user': 'woeip.apps.core.serializers.UserCreateSerializer',
'user_delete': 'djoser.serializers.UserDeleteSerializer',
}
}

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}

SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('JWT',),
'JWT_ALLOW_REFRESH': True,
'JWT_EXPIRATION_DELTA': datetime.timedelta(minutes=60),
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
}