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 16 commits
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
12 changes: 12 additions & 0 deletions corehq/apps/consumer_user/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.apps import AppConfig


class ConsumerUserAppConfig(AppConfig):
name = 'corehq.apps.consumer_user'

def ready(self):
from corehq.apps.consumer_user.signals import connect_signals
connect_signals()


default_app_config = 'corehq.apps.consumer_user.ConsumerUserAppConfig'
5 changes: 5 additions & 0 deletions corehq/apps/consumer_user/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.contrib import admin

from corehq.apps.consumer_user.models import ConsumerUser

admin.site.register(ConsumerUser)
5 changes: 5 additions & 0 deletions corehq/apps/consumer_user/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class ConsumerUserConfig(AppConfig):
name = 'consumer_user'
5 changes: 5 additions & 0 deletions corehq/apps/consumer_user/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CONSUMER_INVITATION_CASE_TYPE = 'commcare-consumeruserinvitation'

CONSUMER_INVITATION_STATUS = 'status'
CONSUMER_INVITATION_SENT = 'sent'
CONSUMER_INVITATION_ACCEPTED = 'accepted'
19 changes: 19 additions & 0 deletions corehq/apps/consumer_user/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from functools import wraps

from django.contrib.auth.views import redirect_to_login
from django.urls import reverse

from corehq.apps.consumer_user.models import ConsumerUser


def consumer_user_login_required(view_func):
@wraps(view_func)
def _inner(request, *args, **kwargs):
user = request.user
if not (user.is_authenticated and user.is_active and ConsumerUser.objects.get_or_none(user=user)):
url = reverse('consumer_user:consumer_user_login')
return redirect_to_login(request.get_full_path(), url)

# User login validated and verified corresponding ConsumerUser exists- it's safe to call the view function
return view_func(request, *args, **kwargs)
return _inner
Empty file.
16 changes: 16 additions & 0 deletions corehq/apps/consumer_user/forms/change_contact_details_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.contrib.auth.models import User
from django.forms import ModelForm


class ChangeContactDetailsForm(ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name']

def save(self, commit=True):
user = super(ChangeContactDetailsForm, self).save(commit=False)
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
if commit:
user.save()
return user
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _

from corehq.apps.consumer_user.const import (
CONSUMER_INVITATION_ACCEPTED,
CONSUMER_INVITATION_STATUS,
)
from corehq.apps.consumer_user.models import (
ConsumerUser,
ConsumerUserCaseRelationship,
)
from corehq.apps.domain.forms import NoAutocompleteMixin
from corehq.apps.hqcase.utils import update_case


class ConsumerUserAuthenticationForm(NoAutocompleteMixin, AuthenticationForm):
username = forms.EmailField(label=_("Email Address"),
widget=forms.TextInput(attrs={'class': 'form-control'}),
required=True)
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput(attrs={'class': 'form-control'}),
required=True)

def __init__(self, *args, **kwargs):
self.invitation = kwargs.pop('invitation', None)
super().__init__(*args, **kwargs)

def clean(self):
username = self.cleaned_data.get('username')
if username is None:
raise ValidationError(_('Please enter a valid email address.'))

password = self.cleaned_data.get('password')
if not password:
raise ValidationError(_("Please enter a password."))
cleaned_data = super(ConsumerUserAuthenticationForm, self).clean()
consumer_user = ConsumerUser.objects.get_or_create(user=self.user_cache)
if self.invitation and not self.invitation.accepted:
self.invitation.accept()
ConsumerUserCaseRelationship.objects.create(case_id=self.invitation.case_id,
domain=self.invitation.domain,
consumer_user=consumer_user[0])
update_case(self.invitation.domain,
self.invitation.case_id,
{CONSUMER_INVITATION_STATUS: CONSUMER_INVITATION_ACCEPTED})
return cleaned_data
54 changes: 54 additions & 0 deletions corehq/apps/consumer_user/forms/consumer_user_signup_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.forms import ModelForm, PasswordInput
from django.utils.translation import ugettext_lazy as _

from corehq.apps.consumer_user.const import (
CONSUMER_INVITATION_ACCEPTED,
CONSUMER_INVITATION_STATUS,
)
from corehq.apps.consumer_user.models import (
ConsumerUser,
ConsumerUserCaseRelationship,
)
from corehq.apps.hqcase.utils import update_case


class ConsumerUserSignUpForm(ModelForm):

def __init__(self, *args, **kwargs):
self.invitation = kwargs.pop('invitation', None)
super().__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = True

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

def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(username=email).exists():
raise ValidationError(_(u'Username "%s" is already in use.' % email))
return email

def save(self, commit=True):
user = super(ConsumerUserSignUpForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
user.username = self.cleaned_data['email']
if commit:
user.save()
consumer_user = ConsumerUser.objects.create(user=user)
if self.invitation:
self.invitation.accepted = True
self.invitation.save()
ConsumerUserCaseRelationship.objects.create(case_id=self.invitation.case_id,
domain=self.invitation.domain,
consumer_user=consumer_user)
update_case(self.invitation.domain,
self.invitation.case_id,
{CONSUMER_INVITATION_STATUS: CONSUMER_INVITATION_ACCEPTED})
return user
51 changes: 51 additions & 0 deletions corehq/apps/consumer_user/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 2.2.16 on 2021-02-23 06:52

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='ConsumerUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='ConsumerUserInvitation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('email', models.EmailField(max_length=254)),
('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)),
('invited_on', models.DateTimeField(auto_now=True)),
('active', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='ConsumerUserCaseRelationship',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('case_id', models.CharField(max_length=255)),
('domain', models.CharField(max_length=255)),
('consumer_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
to='consumer_user.ConsumerUser')),
],
options={
'unique_together': {('case_id', 'domain')},
},
),
]
Empty file.
55 changes: 55 additions & 0 deletions corehq/apps/consumer_user/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.contrib.auth.models import User
from django.db import models


class GetOrNoneManager(models.Manager):
"""
Adds get_or_none method to objects
"""

def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except self.model.DoesNotExist:
return None


class ConsumerUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
objects = GetOrNoneManager()


class ConsumerUserCaseRelationship(models.Model):
consumer_user = models.ForeignKey(ConsumerUser, on_delete=models.CASCADE)
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()
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)
invited_on = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)

def make_inactive(self):
self.active = False
self.save(update_fields=['active'])

def accept(self):
self.accepted = True
self.save(update_fields=['accepted'])

@classmethod
def create_invitation(cls, case_id, domain, opened_by, email):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: what's the purpose of this method? In the place you call this, you could just replace this call with ConsumerUserInviation.objects.create(...) right?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created this before when code was clumsy

instance = cls(case_id=case_id,
domain=domain,
invited_by=opened_by,
email=email)
instance.save()
return instance
45 changes: 45 additions & 0 deletions corehq/apps/consumer_user/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from corehq.apps.consumer_user.models import (
ConsumerUserCaseRelationship,
ConsumerUserInvitation,
)
from corehq.form_processor.models import CommCareCaseSQL
from corehq.form_processor.signals import sql_case_post_save

from .const import (
CONSUMER_INVITATION_ACCEPTED,
CONSUMER_INVITATION_CASE_TYPE,
CONSUMER_INVITATION_SENT,
CONSUMER_INVITATION_STATUS,
)
from .tasks import create_new_invitation


def send_email_case_changed_receiver(sender, case, **kwargs):
if case.type != CONSUMER_INVITATION_CASE_TYPE:
Copy link

@proteusvacuum proteusvacuum Mar 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to add an extra check here

case.get_case_property(CONSUMER_INVITATION_STATUS) == CONSUMER_INVITATION_SENT

Otherwise you'll end up with an infinite loop.

Once you fix that, you'll see there is still a failing test.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the change inside the method. If we keep it at top when the case is closed it wont update the corresponding invitation

return
email = case.get_case_property('email')
status = case.get_case_property(CONSUMER_INVITATION_STATUS)
invitation = ConsumerUserInvitation.objects.filter(case_id=case.case_id,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how I didn't catch this before, but this is the wrong case_id. From the spec, this should be the "uuid for the patient/demographic case."
It would be something like:

host_indices = [index for index in case.indices where index.relationship = 'extension']
try:
    person_case_id = host_indices[0].referenced_id
except IndexError:
    return    # the app is set up incorrectly.

Copy link
Owner Author

@challabeehyv challabeehyv Mar 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only save case_id, domain in both ConsumerUserInvitation and ConsumerUserCaseRelationship models as mentioned in the document. You want me to store uuid for the patient/demographic case in the case_id right. I tried implementing the above logic but getting host_indices as empty list when I call from tests using create_case. I tried looking at other usages but could n't find anything helpful. Can you share here how to use this correctly?

Also, Since we are now planning to use uuid for the patient/demographic case in the case_id, will update_case work with this reference_id? Should I add a new column in both ConsumerUserInvitation and ConsumerUserCaseRelationship models to store case_id too?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can create indexed cases like this:

https://github.com/challabeehyv/commcare-hq/blob/consumer_user_poc/corehq/ex-submodules/casexml/apps/case/tests/test_db_accessors.py#L178-L186

So you would need to make both a demographic, and an invitation case in your tests.

We want the CaseRelationship to link to the demographic case, and we would want to store that id on the invitation when it is created to stop a case getting reassigned between the invitation being created and being accepted.

I think if there can only be a single invitation case open for a particular demographic case, we should be able to always get the invitation back (by looking at the reverse indexed cases for one with the invitation type).

However, I agree that it might be better to store both invitation case_id and the demographic case_id on the ConsumerUserInvitation. I don't think you need to add this to the ConsumerUserCaseRelationship.

domain=case.domain,
active=True).last()
is_status_sent_or_accepted = status == CONSUMER_INVITATION_SENT or status == CONSUMER_INVITATION_ACCEPTED
if case.closed:
if invitation:
invitation.make_inactive()
return
elif invitation and email == invitation.email and is_status_sent_or_accepted:
return
elif invitation:
invitation.make_inactive()
if ConsumerUserCaseRelationship.objects.filter(case_id=case.case_id,
domain=case.domain).exists():
return
create_new_invitation.delay(case.case_id, case.domain, case.opened_by, email)


def connect_signals():
sql_case_post_save.connect(
send_email_case_changed_receiver,
CommCareCaseSQL,
dispatch_uid='send_email_case_changed_receiver'
)
40 changes: 40 additions & 0 deletions corehq/apps/consumer_user/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.conf import settings
from django.core.signing import TimestampSigner
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _

from celery.task import task

from dimagi.utils.web import get_url_base

from corehq.apps.consumer_user.models import ConsumerUserInvitation
from corehq.apps.hqcase.utils import update_case
from corehq.apps.hqwebapp.tasks import send_html_email_async

from .const import CONSUMER_INVITATION_SENT, CONSUMER_INVITATION_STATUS


@task
def create_new_invitation(case_id, domain, opened_by, email):
invitation = ConsumerUserInvitation.create_invitation(case_id, domain, opened_by, email)
url = '%s%s' % (get_url_base(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I get this error when running this in celery:

2021-03-02 21:23:54,886: INFO/MainProcess] Received task: corehq.apps.consumer_user.tasks.create_new_invitation[1d1e586c-7ef7-498d-acd6-61372c937621]  
[2021-03-02 21:23:54,920: ERROR/ForkPoolWorker-6] Task corehq.apps.consumer_user.tasks.create_new_invitation[1d1e586c-7ef7-498d-acd6-61372c937621] raised unexpected: NoReverseMatch("'consumer_user' is not a registered namespace")
Traceback (most recent call last):
  File "/home/frener/.virtualenvs/cchq/lib/python3.8/site-packages/django/urls/base.py", line 75, in reverse
    extra, resolver = resolver.namespace_dict[ns]
KeyError: 'consumer_user'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/frener/.virtualenvs/cchq/lib/python3.8/site-packages/celery/app/trace.py", line 375, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/frener/.virtualenvs/cchq/lib/python3.8/site-packages/celery/app/trace.py", line 632, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/frener/dev/dimagi/commcare-hq/corehq/apps/consumer_user/tasks.py", line 24, in create_new_invitation
    reverse('consumer_user:consumer_user_register',
  File "/home/frener/.virtualenvs/cchq/lib/python3.8/site-packages/django/urls/base.py", line 86, in reverse
    raise NoReverseMatch("%s is not a registered namespace" % key)
django.urls.exceptions.NoReverseMatch: 'consumer_user' is not a registered namespace

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its working in my local system when I trigger the call directly.

[2021-03-03 10:19:33,850: INFO/MainProcess] Received task: corehq.apps.consumer_user.tasks.create_new_invitation[1138ed38-8487-41f9-8df2-5ff10bdd453c]  
[2021-03-03 10:19:34,204: WARNING/ForkPoolWorker-6] http://localhost:8000/hq/consumer_user/signup/MjQ:1lHObN:-8hAS0-6c2CSKgckOVNlP60X5Z4/
[2021-03-03 10:19:34,248: INFO/ForkPoolWorker-6] Received Form a61e5f87f4a94f04ac0825ea3636fdae with 0 attachments
[2021-03-03 10:19:34,310: INFO/ForkPoolWorker-6] Finished normal processing for Form a61e5f87f4a94f04ac0825ea3636fdae
[2021-03-03 10:19:34,313: INFO/ForkPoolWorker-6] Task corehq.apps.consumer_user.tasks.create_new_invitation[1138ed38-8487-41f9-8df2-5ff10bdd453c] succeeded in 0.4627520860012737s: None
[2021-03-03 10:20:08,799: INFO/MainProcess] Received task: corehq.apps.consumer_user.tasks.create_new_invitation[e5fd1b81-a816-4b1f-96b0-13cd446b1678]  
[2021-03-03 10:20:09,169: WARNING/ForkPoolWorker-12] http://localhost:8000/hq/consumer_user/signup/MjU:1lHObw:voZOGBr9qQtJTYLfyIRFPf_DpUY/
[2021-03-03 10:20:09,203: INFO/ForkPoolWorker-12] Received Form eb1e4a8de3c54fbfb79780cc4bcaf3ae with 0 attachments
[2021-03-03 10:20:09,272: INFO/ForkPoolWorker-12] Finished normal processing for Form eb1e4a8de3c54fbfb79780cc4bcaf3ae
[2021-03-03 10:20:09,276: INFO/ForkPoolWorker-12] Task corehq.apps.consumer_user.tasks.create_new_invitation[e5fd1b81-a816-4b1f-96b0-13cd446b1678] succeeded in 0.4763715970002522s: None
[2021-03-03 10:20:15,488: INFO/MainProcess] Received task: corehq.apps.consumer_user.tasks.create_new_invitation[1edfe58b-76c2-431c-b6a8-22f52cbea709]  
[2021-03-03 10:20:15,863: WARNING/ForkPoolWorker-1] http://localhost:8000/hq/consumer_user/signup/MjY:1lHOc3:fodmjQtbPEgqF-8lyRJpa3NZ_04/
[2021-03-03 10:20:15,893: INFO/ForkPoolWorker-1] Received Form 5ebe229fde2e4ea68c22f4529541d82a with 0 attachments
[2021-03-03 10:20:15,951: INFO/ForkPoolWorker-1] Finished normal processing for Form 5ebe229fde2e4ea68c22f4529541d82a
[2021-03-03 10:20:15,955: INFO/ForkPoolWorker-1] Task corehq.apps.consumer_user.tasks.create_new_invitation[1edfe58b-76c2-431c-b6a8-22f52cbea709] succeeded in 0.466650219001167s: None
[2021-03-03 10:20:16,090: INFO/MainProcess] Received task: corehq.apps.consumer_user.tasks.create_new_invitation[33e3fcae-5e4a-4d3a-91b3-7a922718d73d]  
[2021-03-03 10:20:16,471: WARNING/ForkPoolWorker-2] http://localhost:8000/hq/consumer_user/signup/Mjc:1lHOc4:hVJ8QRhq3jWPmfuHlxua-1scLos/
[2021-03-03 10:20:16,504: INFO/ForkPoolWorker-2] Received Form cb44518343e446f39fcaa08b806da419 with 0 attachments
[2021-03-03 10:20:16,561: INFO/ForkPoolWorker-2] Finished normal processing for Form cb44518343e446f39fcaa08b806da419
[2021-03-03 10:20:16,565: INFO/ForkPoolWorker-2] Task corehq.apps.consumer_user.tasks.create_new_invitation[33e3fcae-5e4a-4d3a-91b3-7a922718d73d] succeeded in 0.4747796890005702s: None

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked if I missed anything while pushing. I pushed all the changes I made. Can you tell me how are you triggering this task? I will try to replicate in my system

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I was testing by creating a case through an app I built locally. I will try again and see if there is anything with my local setup that was causing this.

reverse('consumer_user:consumer_user_register',
kwargs={
'invitation': TimestampSigner().sign(urlsafe_base64_encode(
force_bytes(invitation.pk)
))
}))
email_context = {
'link': url,
}
print(url)
send_html_email_async.delay(
_('Beneficiary Registration'),
email,
render_to_string('email/registration_email.html', email_context),
text_content=render_to_string('email/registration_email.txt', email_context)
)
update_case(domain, case_id, {CONSUMER_INVITATION_STATUS: CONSUMER_INVITATION_SENT})
26 changes: 26 additions & 0 deletions corehq/apps/consumer_user/templates/change_contact_details.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% block content %}
<h2>Change Contact Details</h2>
{% if msg %}
<p style="font-weight:bold">{{ msg }}</p>
{% endif %}
{% if form.errors %}
<ul class="user-msg error">
{% for field in form %}
{% for error in field.errors %}
<li>
{% if field != '__all__' %}
<strong>{{ field.label }}:</strong>
{% endif %}
{{ error }}
</li>
{% endfor %}
{% endfor %}
</ul>
{% endif %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
<a href="{% url 'consumer_user:consumer_user_homepage' %}">HomePage</a>
{% endblock %}
Loading