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

Models and signup & login views for consumer_user_poc #155

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
70c3abd
Models and signup & login views for consumer_user_poc
challabeehyv Feb 8, 2021
24660a8
pr suggestions and some fixes
challabeehyv Feb 9, 2021
ca0ff9c
send email on receiving sql_case_post_save signal. added unit tests a…
challabeehyv Feb 12, 2021
a2a4655
test case for send_email_case_changed_receiver
challabeehyv Feb 15, 2021
8f921e9
restricting access to patient user for domain and other page
challabeehyv Feb 15, 2021
4eab216
encoding invitation id in sign up url and some minor fixes
challabeehyv Feb 15, 2021
9259888
forgot password, update details, creating user
challabeehyv Feb 17, 2021
2e55a11
updated tests and refactored some code
challabeehyv Feb 18, 2021
bd1bc56
Removed htmls and made some changes based on suggestions
challabeehyv Feb 19, 2021
05ff960
fixed column name and merged both the migrations into one
challabeehyv Feb 19, 2021
71f200d
column name fixed
challabeehyv Feb 22, 2021
b6e3f86
removed unique_together constraint, consumer_user login as webuser ch…
challabeehyv Feb 23, 2021
3a48c03
Made changes suggested in PR. Did some formatting fixed some issues.
challabeehyv Feb 27, 2021
5b161a9
Made changes suggested in PR.
challabeehyv Mar 2, 2021
4132c62
Removed same email check in consumer user login form
challabeehyv Mar 2, 2021
6a43641
Made some changes to signals logic
challabeehyv Mar 2, 2021
1623156
PR suggestions and added a test for resending invitiation
challabeehyv Mar 3, 2021
33f8433
Created new column demographic_case_id in invitation model, squashed …
challabeehyv Mar 5, 2021
34b58ad
Added assertions to check active invitations and removed exception ha…
challabeehyv Mar 9, 2021
f8de41f
UI Changes
challabeehyv Mar 9, 2021
6c47746
Removed duplicate app config
challabeehyv Mar 9, 2021
aff9346
Changed templates based on PR suggestions
challabeehyv Mar 10, 2021
d90710e
Removed unused imports and variables
challabeehyv Mar 10, 2021
08d3e08
fixed couple of failing tests
challabeehyv Mar 12, 2021
fce58b3
Moved Templates to conusmer_user, CDN issue fix and changes suggested…
challabeehyv Mar 13, 2021
143bb10
Moved all the code except case type check from signals.py to tasks.py
challabeehyv Mar 13, 2021
08fb9e1
Moved GetOrNoneManger to model utils and made changes to get_invitati…
challabeehyv Mar 13, 2021
8706645
Fixed failing tests, Broke the test_send_email test to five different…
challabeehyv Mar 13, 2021
e60c146
Made changes to tasks.py and signals.py as per farid's suggestions
challabeehyv Mar 15, 2021
0e593cd
Fixed Inanctive InvitationError raising
challabeehyv Mar 15, 2021
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
2 changes: 1 addition & 1 deletion corehq/apps/consumer_user/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def login_required(view_func):
def _inner(request, *args, **kwargs):
user = request.user
if not (user.is_authenticated and user.is_active):
url = reverse('login')
url = reverse('consumer_user:patient_login')
return redirect_to_login(request.get_full_path(), url)

# User's login and domain have been validated - it's safe to call the view function
Expand Down
20 changes: 20 additions & 0 deletions corehq/apps/consumer_user/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.forms import ModelForm
from django.forms import PasswordInput
from django.contrib.auth.models import User


class PatientSignUpForm(ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
widgets = {
'password': PasswordInput(),
}

def save(self, commit=True):
user = super(PatientSignUpForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
user.username = self.cleaned_data["email"]
if commit:
user.save()
return user
32 changes: 32 additions & 0 deletions corehq/apps/consumer_user/migrations/0002_auto_20210209_0743.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 2.2.16 on 2021-02-09 07:43

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('consumer_user', '0001_initial'),
]

operations = [
migrations.AlterField(
model_name='consumeruserinvitation',
name='accepted',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='consumeruserinvitation',
name='active',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='consumeruserinvitation',
name='invited_on',
field=models.DateTimeField(auto_now=True),
),
migrations.AlterUniqueTogether(
name='consumerusercaserelationship',
unique_together={('case_id', 'domain')},
),
]
12 changes: 9 additions & 3 deletions corehq/apps/consumer_user/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ class ConsumerUser(models.Model):

class ConsumerUserCaseRelationship(models.Model):
case_user = models.ForeignKey(ConsumerUser, on_delete=models.CASCADE)
case_id = models.CharField(max_length=255) # uuid for the `commcare-caseuser` case
case_id = models.CharField(max_length=255)
domain = models.CharField(max_length=255)

class Meta:
unique_together = ('case_id', 'domain',)


class ConsumerUserInvitation(models.Model):
email = models.EmailField() # the email address the invite was sent to
case_id = models.CharField(max_length=255) # uuid for the `commcare-caseuser` case
case_id = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
accepted = models.BooleanField(default=False)
invited_by = models.CharField(max_length=255) # UUID of the (Web|Commcare) User who created this invitation
invited_on = models.DateTimeField() # datetime when this invitation was created.
invited_on = models.DateTimeField(auto_now=True) # datetime when this invitation was created.
active = models.BooleanField(default=True)

class Meta:
unique_together = ('case_id', 'domain',)
8 changes: 8 additions & 0 deletions corehq/apps/consumer_user/templates/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
{% endblock %}
9 changes: 5 additions & 4 deletions corehq/apps/consumer_user/urls.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from django.urls import path

from .views import *
from .views import delete_view, detail_view, list_view, login_view, register_view, success_view

app_name = 'consumer_user'

urlpatterns = [
path('', list_view),
path('signup/', register_view),
path('login/', login_view, name='login'),
path('homepage/', success_view, name='homepage'),
path('signup/<invitation>/', register_view),
path('login/', login_view, name='patient_login'),
path('homepage/', success_view, name='patient_homepage'),
path('<int:consumer_user_id>/', detail_view),
path('<int:consumer_user_id>/delete/', delete_view),
]
120 changes: 64 additions & 56 deletions corehq/apps/consumer_user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,93 @@

from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.http import JsonResponse
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import JsonResponse
from django.urls import reverse
from .forms import PatientSignUpForm
from django.views.decorators.debug import sensitive_post_parameters
from corehq.apps.domain.decorators import two_factor_exempt
from two_factor.views import LoginView
from corehq.apps.consumer_user.models import ConsumerUser, ConsumerUserInvitation
from django.urls import reverse
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
from corehq.apps.consumer_user.models import ConsumerUser
from corehq.apps.consumer_user.models import ConsumerUserInvitation
from corehq.apps.consumer_user.models import ConsumerUserCaseRelationship
from corehq.apps.domain.decorators import two_factor_exempt
from .decorators import login_required


class PatientLoginView(LoginView):

def get_success_url(self):
url = self.get_redirect_url()
if url:
return url
url = reverse('consumer_user:patient_homepage')
return url


def list_view(request):
pass


@two_factor_exempt
@csrf_exempt
def register_view(request):
body = json.loads(request.body)

consumer_invitation_id = body.get('consumer_invitation_id')
full_name = body.get('full_name')
password = body.get('password')
obj = None
try:
obj = ConsumerUserInvitation.objects.get(id=consumer_invitation_id)
if obj.accepted:
url = reverse('login')
return HttpResponseRedirect(url)
email = obj.email
user = User.objects.get(username=email, email=email)
_ = ConsumerUser.objects.get(user=user)
if obj.accepted:
return JsonResponse({'message': "User already exists"}, status=400)
else:
url = reverse('login')
return HttpResponseRedirect(url)
except ConsumerUserInvitation.DoesNotExist:
return JsonResponse({'message': "Invalid invitation"}, status=400)
except User.DoesNotExist:
user = User.objects.create_user(username=email, email=email, password=password, first_name=full_name)
user.save()
except ConsumerUser.DoesNotExist:
pass
consumer_user = ConsumerUser.objects.create(user=user)
consumer_user.save()
if obj:
obj.accepted = True
obj.save()
return JsonResponse({'message': "User created successfully"}, status=201)
def register_view(request, invitation):
if request.method == "POST":
body = request.POST
entered_email = body.get('email')
password = body.get('password')
invitation_obj = None
consumer_user = None
try:
invitation_obj = ConsumerUserInvitation.objects.get(id=invitation)
if invitation_obj.accepted:
url = reverse('consumer_user:patient_login')
return HttpResponseRedirect(url)
email = invitation_obj.email
if email != entered_email:
return JsonResponse({'message': "Email is not same as the one that the invitation has been sent"},
status=400)
user = User.objects.get(username=email, email=email)
consumer_user = ConsumerUser.objects.get(user=user)
login_success = authenticate(request, username=entered_email, password=password)
if not login_success:
return JsonResponse({'message': "Existing user but password is different"}, status=400)
except ConsumerUserInvitation.DoesNotExist:
return JsonResponse({'message': "Invalid invitation"}, status=400)
except User.DoesNotExist:
form = PatientSignUpForm(body)
if form.is_valid():
user = form.save()
except ConsumerUser.DoesNotExist:
pass
if not consumer_user:
consumer_user = ConsumerUser.objects.create(user=user)
if invitation_obj:
invitation_obj.accepted = True
invitation_obj.save()
_ = ConsumerUserCaseRelationship.objects.create(case_id=invitation_obj.case_id,
domain=invitation_obj.domain,
case_user_id=consumer_user.id)
url = reverse('consumer_user:patient_login')
return HttpResponseRedirect(url)
else:
form = PatientSignUpForm()
return render(request, 'signup.html', {'form': form})


@two_factor_exempt
@sensitive_post_parameters('auth-password')
@csrf_exempt
def login_view(request):
try:
if request.user and request.user.is_authenticated:
url = reverse('homepage')
url = reverse('consumer_user:patient_homepage')
return HttpResponseRedirect(url)
if request.method == "POST":
body = json.loads(request.body)
body = request.POST
username = body.get('auth-username')
password = body.get('auth-password')
consumer_invitation_id = body.get('consumer_invitation_id')
user = User.objects.get(username=username)
_ = ConsumerUser.objects.get(user=user)
if consumer_invitation_id is not None:
obj = ConsumerUserInvitation.objects.get(id=consumer_invitation_id)
obj.accepted = True
obj.save()
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return JsonResponse({'message': 'Logged in successfully with username = ' + user.username}, status=200)
else:
return JsonResponse({'message': 'Invalid credentials'}, status=403)
return LoginView.as_view()(request)
return PatientLoginView.as_view()(request)
except (User.DoesNotExist, ConsumerUser.DoesNotExist):
return JsonResponse({'message': "Patient User does not exist with your email"}, status=400)

Expand Down
2 changes: 1 addition & 1 deletion urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
r'(?P<user_email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})/(?P<scheduled_report_secret>[\w-]+)/',
ReportNotificationUnsubscribeView.as_view(), name=ReportNotificationUnsubscribeView.urlname),
url(r'^phone/list_apps', list_apps, name="list_accessible_apps"),
url(r'^hq/consumer_user/', include('corehq.apps.consumer_user.urls')),
url(r'^hq/consumer_user/', include('corehq.apps.consumer_user.urls', namespace='consumer_user')),
] + LOCAL_APP_URLS

if settings.ENABLE_PRELOGIN_SITE:
Expand Down