diff --git a/corehq/apps/users/urls.py b/corehq/apps/users/urls.py
index c8335edfe2c1..03906828abec 100644
--- a/corehq/apps/users/urls.py
+++ b/corehq/apps/users/urls.py
@@ -60,9 +60,11 @@
UploadCommCareUsers,
UserUploadStatusView,
activate_commcare_user,
+ activate_connectid_link,
count_commcare_users,
count_web_users,
deactivate_commcare_user,
+ deactivate_connectid_link,
delete_commcare_user,
demo_restore_job_poll,
download_commcare_users,
@@ -161,6 +163,10 @@
url(r'^commcare/account/(?P[ \w-]+)/groups/$', update_user_groups, name='update_user_groups'),
url(r'^commcare/activate/(?P[ \w-]+)/$', activate_commcare_user, name='activate_commcare_user'),
url(r'^commcare/deactivate/(?P[ \w-]+)/$', deactivate_commcare_user, name='deactivate_commcare_user'),
+ url(r'^commcare/activate_connectid_link/(?P[ \w-]+)/$',
+ activate_connectid_link, name='activate_connectid_link'),
+ url(r'^commcare/deactivate_connectid_link/(?P[ \w-]+)/$',
+ deactivate_connectid_link, name='deactivate_connectid_link'),
url(
r'^commcare/send_confirmation_email/(?P[ \w-]+)/$',
send_confirmation_email,
diff --git a/corehq/apps/users/views/mobile/users.py b/corehq/apps/users/views/mobile/users.py
index 6d9b3f3c014e..dd1a4c18174e 100644
--- a/corehq/apps/users/views/mobile/users.py
+++ b/corehq/apps/users/views/mobile/users.py
@@ -6,6 +6,7 @@
from django.contrib import messages
from django.contrib.humanize.templatetags.humanize import naturaltime
from django.core.exceptions import ValidationError
+from django.db.models import F
from django.http import (
Http404,
HttpResponse,
@@ -925,6 +926,32 @@ def _modify_user_status(request, domain, user_id, is_active):
})
+@require_can_edit_commcare_users
+@require_POST
+@location_safe
+def activate_connectid_link(request, domain, user_id):
+ return _toggle_connectid_link(request, domain, user_id, True)
+
+
+@require_can_edit_commcare_users
+@require_POST
+@location_safe
+def deactivate_connectid_link(request, domain, user_id):
+ return _toggle_connectid_link(request, domain, user_id, False)
+
+
+def _toggle_connectid_link(request, domain, user_id, is_active):
+ if not toggles.COMMCARE_CONNECT.enabled(domain):
+ return HttpResponseBadRequest()
+ user = CommCareUser.get_by_user_id(user_id, domain)
+ connect_link = ConnectIDUserLink.objects.get(commcare_user=user.get_django_user())
+ connect_link.is_active = is_active
+ connect_link.save()
+ return JsonResponse({
+ 'success': True,
+ })
+
+
@require_can_edit_commcare_users
@require_POST
@location_safe
@@ -982,6 +1009,22 @@ def _status_string(user_data):
else:
return _('Pending Confirmation')
+ def get_connect_links_by_username(users):
+ if not toggles.COMMCARE_CONNECT.enabled(domain):
+ return {}
+ usernames = [
+ f"{u['base_username']}@{domain}.commcarehq.org"
+ for u in users
+ ]
+ links = ConnectIDUserLink.objects.filter(
+ commcare_user__username__in=usernames
+ ).annotate(commcare_username=F("commcare_user__username")).all()
+ return {
+ link.commcare_username.split("@")[0]: link
+ for link in links
+ }
+
+ connect_links = get_connect_links_by_username(users)
for user in users:
date_registered = user.pop('created_on', '')
if date_registered:
@@ -989,6 +1032,8 @@ def _status_string(user_data):
# make sure these are always set and default to true
user['is_active'] = user.get('is_active', True)
user['is_account_confirmed'] = user.get('is_account_confirmed', True)
+ connect_link = connect_links.get(user.get('base_username'))
+ user['is_connect_link_active'] = connect_link.is_active if connect_link else None
user.update({
'username': user.pop('base_username', ''),
'user_id': user.pop('_id'),
@@ -1705,7 +1750,6 @@ def send_connectid_invite(request, domain, user_id):
url: {url}
Make a POST call to above url with invite_code and your ConnectID token
"""
- print(text_content)
return send_sms(
domain=domain,
contact=None,
diff --git a/migrations.lock b/migrations.lock
index a6a74cdf3249..4d944033b36c 100644
--- a/migrations.lock
+++ b/migrations.lock
@@ -1249,6 +1249,7 @@ users
0069_alter_invitation_custom_user_data_and_more
0070_alter_invitation_tableau_role
0071_rm_user_data
+ 0072_connectiduserlink_is_active
util
0001_initial
0002_complaintbouncemeta_permanentbouncemeta_transientbounceemail
From 1f3e480db969836d7116795a811b74637975e6a7 Mon Sep 17 00:00:00 2001
From: Sravan Reddy
Date: Fri, 25 Oct 2024 14:20:12 +0530
Subject: [PATCH 03/10] format the deeplink
---
corehq/apps/users/views/mobile/users.py | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/corehq/apps/users/views/mobile/users.py b/corehq/apps/users/views/mobile/users.py
index dd1a4c18174e..7ee86fb4b91c 100644
--- a/corehq/apps/users/views/mobile/users.py
+++ b/corehq/apps/users/views/mobile/users.py
@@ -2,6 +2,7 @@
import json
import re
import time
+from urllib.parse import quote_plus, unquote_plus
from django.contrib import messages
from django.contrib.humanize.templatetags.humanize import naturaltime
@@ -33,7 +34,7 @@
from casexml.apps.phone.models import SyncLogSQL
from couchexport.models import Format
from couchexport.writers import Excel2007ExportWriter
-from dimagi.utils.web import json_response
+from dimagi.utils.web import json_response, get_site_domain
from dimagi.utils.logging import notify_exception
from soil import DownloadBase
from soil.exceptions import TaskFailedError
@@ -1741,14 +1742,10 @@ def send_connectid_invite(request, domain, user_id):
return HttpResponse(status=400)
invite_code = encrypt_account_confirmation_info(user)
- url = absolute_reverse("confirm_connectid_user", args=[user.domain])
+ deeplink = f"connect://hq_invite/{get_site_domain()}/a/{quote_plus(domain)}/{quote_plus(invite_code)}/{quote_plus(user.username)}/"
text_content = f"""
- Link your ConnectID account to CommCare
- username: {user.username}
- domain: {domain}
- invite_code: {invite_code}
- url: {url}
- Make a POST call to above url with invite_code and your ConnectID token
+ You are invited to join a CommCare project (domain)
+ Please click on {deeplink} to accept.
"""
return send_sms(
domain=domain,
@@ -1763,7 +1760,7 @@ def confirm_connectid_user(request, domain):
try:
token = request.POST["token"]
invite_code = request.POST["invite_code"]
- invite = json.loads(b64_aes_decrypt(invite_code))
+ invite = json.loads(b64_aes_decrypt(unquote_plus(invite_code)))
user_id = invite['user_id']
expiry_time = invite['time']
except ValueError:
From cf7b51fb3d0b933af93bd002f8d15f52352ec492 Mon Sep 17 00:00:00 2001
From: Sravan Reddy
Date: Fri, 25 Oct 2024 18:20:36 +0530
Subject: [PATCH 04/10] Fix connectid sms
---
corehq/apps/users/forms.py | 8 +--
.../users/static/users/js/mobile_workers.js | 4 +-
corehq/apps/users/views/mobile/users.py | 50 +++++++++++++++----
3 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/corehq/apps/users/forms.py b/corehq/apps/users/forms.py
index b5c79e69f45e..93965432141b 100644
--- a/corehq/apps/users/forms.py
+++ b/corehq/apps/users/forms.py
@@ -847,9 +847,10 @@ def __init__(self, project, request_user, *args, **kwargs):
provision_by_sms = TWO_STAGE_USER_PROVISIONING_BY_SMS.enabled(self.domain)
if provision_by_sms or provision_by_cid:
+ varname = 'account_invite_by_cid' if provision_by_cid else 'force_account_confirmation_by_sms'
confirm_account_by_sms_field = crispy.Field(
- 'force_account_confirmation_by_sms' if provision_by_sms else 'account_invite_by_cid',
- data_bind='checked: force_account_confirmation_by_sms || account_invite_by_cid',
+ varname,
+ data_bind=f'checked: {varname}',
)
phone_number_field = crispy.Div(
crispy.Field(
@@ -945,7 +946,8 @@ def __init__(self, project, request_user, *args, **kwargs):
{disabled_email}
+ && ($root.stagedUser().force_account_confirmation_by_sms()
+ || $root.stagedUser().account_invite_by_cid) -->
{disabled_phone}