Skip to content

Commit

Permalink
Add Delink/relink
Browse files Browse the repository at this point in the history
  • Loading branch information
sravfeyn committed Aug 12, 2024
1 parent 55c8233 commit 6c180df
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 5 deletions.
2 changes: 2 additions & 0 deletions corehq/apps/domain/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ def authenticate(self, request, username, password):
domain=couch_user.domain,
commcare_user__username=couch_user.username
)
if not link.is_active:
return None

return link.commcare_user

Expand Down
1 change: 1 addition & 0 deletions corehq/apps/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3282,6 +3282,7 @@ class ConnectIDUserLink(models.Model):
connectid_username = models.TextField()
commcare_user = models.ForeignKey(User, related_name='connectid_user', on_delete=models.CASCADE)
domain = models.TextField()
is_active = models.BooleanField(default=True)

class Meta:
unique_together = ('domain', 'commcare_user')
18 changes: 14 additions & 4 deletions corehq/apps/users/static/users/js/mobile_workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ hqDefine("users/js/mobile_workers",[
phone_number: '',
is_active: true,
is_account_confirmed: true,
is_connect_link_active: null,
deactivate_after_date: '',
});

Expand Down Expand Up @@ -108,10 +109,7 @@ hqDefine("users/js/mobile_workers",[
return initialPageData.reverse('edit_commcare_user', self.user_id());
});

self.is_active.subscribe(function (newValue) {
var urlName = newValue ? 'activate_commcare_user' : 'deactivate_commcare_user',
$modal = $('#' + (newValue ? 'activate_' : 'deactivate_') + self.user_id());

var toggle_active = function($modal, urlName) {

Check failure on line 112 in corehq/apps/users/static/users/js/mobile_workers.js

View workflow job for this annotation

GitHub Actions / Lint Javascript

Identifier 'toggle_active' is not in camel case

Check failure on line 112 in corehq/apps/users/static/users/js/mobile_workers.js

View workflow job for this annotation

GitHub Actions / Lint Javascript

Missing space before function parentheses
$modal.find(".btn").addSpinnerToButton();
$.ajax({
method: 'POST',
Expand All @@ -129,6 +127,18 @@ hqDefine("users/js/mobile_workers",[
self.action_error(gettext("Issue communicating with server. Try again."));
},
});
};

self.is_active.subscribe(function (newValue) {
var urlName = newValue ? 'activate_commcare_user' : 'deactivate_commcare_user',
$modal = $('#' + (newValue ? 'activate_' : 'deactivate_') + self.user_id());
toggle_active($modal, urlName);
});

self.is_connect_link_active.subscribe(function (newValue) {
var urlName = newValue ? 'activate_connectid_link' : 'deactivate_connectid_link',
$modal = $('#' + (newValue ? 'activate_connect_link_' : 'deactivate_connect_link_') + self.user_id());
toggle_active($modal, urlName);
});

self.sendConfirmationEmail = function () {
Expand Down
102 changes: 102 additions & 0 deletions corehq/apps/users/templates/users/mobile_workers.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
{% registerurl 'paginate_mobile_workers' domain %}
{% registerurl 'activate_commcare_user' domain '---' %}
{% registerurl 'deactivate_commcare_user' domain '---' %}
{% registerurl 'activate_connectid_link' domain '---' %}
{% registerurl 'deactivate_connectid_link' domain '---' %}
{% registerurl 'send_confirmation_email' domain '---' %}
{% registerurl 'send_confirmation_sms' domain '---' %}
{% registerurl 'send_connectid_invite' domain '---' %}
Expand Down Expand Up @@ -198,6 +200,7 @@ <h3 class="panel-title">
<a data-bind="attr: {href: edit_url}, visible: user_id">
<i class="fa fa-user"></i> <strong data-bind="text: username"></strong>
</a>
<span data-bind="visible: is_connect_link_active() !== null" class="btn btn-info">ConnectID</span>
</td>
<td data-bind="attr: {class: creation_status}, text: first_name"></td>
<td data-bind="attr: {class: creation_status}, text: last_name"></td>
Expand Down Expand Up @@ -295,6 +298,7 @@ <h3 class="panel-title">{% trans 'Mobile Workers' %}</h3>
<i class="fa fa-user"></i>
<strong data-bind="text: username"></strong>
</a>
<span data-bind="visible: is_connect_link_active() !== null" class="btn btn-sm btn-info">ConnectID</span>
</td>
<td data-bind="text: first_name"></td>
<td data-bind="text: last_name"></td>
Expand Down Expand Up @@ -446,6 +450,104 @@ <h4 class="modal-title">{% trans "Deactivate Mobile Worker" %}</h4>
</div>
</div>
</div>
{% if request|toggle_enabled:"COMMCARE_CONNECT" %}
<div data-bind="visible: is_connect_link_active() === false">
<button type="button" class="btn btn-default" data-toggle="modal"
data-bind="attr: {'data-target': '#activate_connect_link_' + user_id()}">
{% trans "Reactivate Connect Lik" %}
</button>
<p data-bind="visible: action_error">
<i class="fa-solid fa-triangle-exclamation"></i>
<span data-bind="text: action_error"></span>
</p>
</div>
<div class="modal fade" data-bind="attr: {id: 'activate_connect_link_' + user_id()}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">{% trans "Close" %}</span>
</button>
<h4 class="modal-title">{% trans "Re-activate ConnectID Link" %}</h4>
</div>
<div class="modal-body">
<p class="lead">
{% blocktrans %}
Are you sure you want to <strong>reactivate</strong> Connect Link for this mobile worker?
{% endblocktrans %}
</p>
<p class="lead">
<i class="fa fa-user"></i>
<strong data-bind="text: username"></strong>
</p>
<p>
{% blocktrans %}
Deactivating disables users from logging in using their ConnectID account
{% endblocktrans %}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
{% trans "Cancel" %}
</button>
<button type="button" class="btn btn-primary"
data-bind="click: function(user) { user.is_connect_link_active(true); }">
{% trans 'Reactivate' %}
</button>
</div>
</div>
</div>
</div>
<div data-bind="visible: is_connect_link_active()">
<button type="button" class="btn btn-default" data-toggle="modal"
data-bind="attr: {'data-target': '#deactivate_connect_link_' + user_id()}">
{% trans "Deactivate Connect Link" %}
</button>
<p data-bind="visible: action_error">
<i class="fa-solid fa-triangle-exclamation"></i>
<span data-bind="text: action_error"></span>
</p>
</div>
<div class="modal fade" data-bind="attr: {id: 'deactivate_connect_link_' + user_id()}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">{% trans "Close" %}</span>
</button>
<h4 class="modal-title">{% trans "De-link ConnectID" %}</h4>
</div>
<div class="modal-body">
<p class="lead">
{% blocktrans %}
Are you sure you want to <strong>deactivate</strong> ConnectID link for this mobile worker?
{% endblocktrans %}
</p>
<p class="lead">
<i class="fa fa-user"></i>
<strong data-bind="text: username"></strong>
</p>
<p>
{% blocktrans %}
De-linked ConnectID users can no longer access this project
{% endblocktrans %}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
{% trans "Cancel" %}
</button>
<button type="button" class="btn btn-danger"
data-bind="click: function(user) { user.is_connect_link_active(false); }">
{% trans 'Deactivate' %}
</button>
</div>
</div>
</div>
</div>
{% endif %}
{% if two_stage_user_confirmation %}
<div class="modal fade" data-bind="attr: {id: 'confirm_' + user_id()}">
<div class="modal-dialog">
Expand Down
6 changes: 6 additions & 0 deletions corehq/apps/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -161,6 +163,10 @@
url(r'^commcare/account/(?P<couch_user_id>[ \w-]+)/groups/$', update_user_groups, name='update_user_groups'),
url(r'^commcare/activate/(?P<user_id>[ \w-]+)/$', activate_commcare_user, name='activate_commcare_user'),
url(r'^commcare/deactivate/(?P<user_id>[ \w-]+)/$', deactivate_commcare_user, name='deactivate_commcare_user'),
url(r'^commcare/activate_connectid_link/(?P<user_id>[ \w-]+)/$',
activate_connectid_link, name='activate_connectid_link'),
url(r'^commcare/deactivate_connectid_link/(?P<user_id>[ \w-]+)/$',
deactivate_connectid_link, name='deactivate_connectid_link'),
url(
r'^commcare/send_confirmation_email/(?P<user_id>[ \w-]+)/$',
send_confirmation_email,
Expand Down
46 changes: 45 additions & 1 deletion corehq/apps/users/views/mobile/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -982,13 +1009,31 @@ 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:
date_registered = iso_string_to_datetime(date_registered).strftime(USER_DATE_FORMAT)
# 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'),
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions migrations.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 6c180df

Please sign in to comment.