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

Add ConnectID Invite/De-Link/Re-Link features #34967

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions corehq/apps/domain/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,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
32 changes: 28 additions & 4 deletions corehq/apps/users/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
from corehq.pillows.utils import MOBILE_USER_TYPE, WEB_USER_TYPE
from corehq.feature_previews import USE_LOCATION_DISPLAY_NAME
from corehq.toggles import (
COMMCARE_CONNECT,
TWO_STAGE_USER_PROVISIONING,
TWO_STAGE_USER_PROVISIONING_BY_SMS,
)
Expand Down Expand Up @@ -735,6 +736,13 @@ class NewMobileWorkerForm(forms.Form):
),
required=False,
)
account_invite_by_cid = forms.BooleanField(
label=gettext_noop("Invite using ConnectID phone number?"),
help_text=gettext_noop(
"If checked, the user will be sent an SMS to join the project using their ConnectID app."
),
required=False,
)
phone_number = forms.CharField(
required=False,
label=gettext_noop("Phone Number"),
Expand Down Expand Up @@ -833,10 +841,16 @@ def __init__(self, project, request_user, *args, **kwargs):
data_bind='value: send_account_confirmation_email',
)

if TWO_STAGE_USER_PROVISIONING_BY_SMS.enabled(self.domain):
# cid => connect-id
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: might be better to just have connect_id in the variable than use cid and add a comment to explain it

provision_by_cid = COMMCARE_CONNECT.enabled(self.domain)

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',
data_bind='checked: force_account_confirmation_by_sms',
varname,
data_bind=f'checked: {varname}',
)
phone_number_field = crispy.Div(
crispy.Field(
Expand Down Expand Up @@ -932,9 +946,14 @@ def __init__(self, project, request_user, *args, **kwargs):
<i class="fa fa-warning"></i> {disabled_email}
<!-- /ko -->
<!-- ko if: !($root.stagedUser().force_account_confirmation())
&& $root.stagedUser().force_account_confirmation_by_sms() -->
&& ($root.stagedUser().force_account_confirmation_by_sms()
|| $root.stagedUser().account_invite_by_cid) -->
<i class="fa fa-warning"></i> {disabled_phone}
<!-- /ko -->
<!-- ko if: !($root.stagedUser().force_account_confirmation())
&& $root.stagedUser().account_invite_by_cid() -->
<i class="fa fa-warning"></i> {disabled_cid}
<!-- /ko -->
<!-- /ko -->
</p>
'''.format(
Expand All @@ -957,6 +976,11 @@ def __init__(self, project, request_user, *args, **kwargs):
"will set their own password on confirming "
"their account phone number."
),
disabled_cid = _(
"Setting a password is disabled. The user "
"will be to access by logging into their "
"ConnectID app."
),
short=_("Password must have at least {password_length} characters."
).format(password_length=settings.MINIMUM_PASSWORD_LENGTH)
)),
Expand Down
18 changes: 18 additions & 0 deletions corehq/apps/users/migrations/0073_connectiduserlink_is_active.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.14 on 2024-08-12 09:56

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('users', '0072_remove_invitation_supply_point'),
]

operations = [
migrations.AddField(
model_name='connectiduserlink',
name='is_active',
field=models.BooleanField(default=True),
),
]
1 change: 1 addition & 0 deletions corehq/apps/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3289,6 +3289,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')
58 changes: 49 additions & 9 deletions corehq/apps/users/static/users/js/mobile_workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ hqDefine("users/js/mobile_workers",[
email: '',
send_account_confirmation_email: false,
force_account_confirmation_by_sms: false,
account_invite_by_cid: false,
phone_number: '',
is_active: true,
is_account_confirmed: true,
is_connect_link_active: null,
deactivate_after_date: '',
});

Expand All @@ -94,20 +96,19 @@ hqDefine("users/js/mobile_workers",[
self.sendConfirmationEmailEnabled = ko.observable(self.force_account_confirmation());

// used by two-stage sms provisioning
self.phoneRequired = ko.observable(self.force_account_confirmation_by_sms());
self.phoneRequired = ko.observable(self.force_account_confirmation_by_sms() || self.account_invite_by_cid());

self.passwordEnabled = ko.observable(!(self.force_account_confirmation_by_sms() || self.force_account_confirmation()));
self.passwordEnabled = ko.observable(!(
self.force_account_confirmation_by_sms() || self.force_account_confirmation() || self.account_invite_by_cid())
);

self.action_error = ko.observable(''); // error when activating/deactivating a user

self.edit_url = ko.computed(function () {
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) {
$modal.find(".btn").addSpinnerToButton();
$.ajax({
method: 'POST',
Expand All @@ -125,6 +126,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 Expand Up @@ -177,6 +190,31 @@ hqDefine("users/js/mobile_workers",[
});
};

self.sendConnectIDInvite = function () {
var urlName = 'send_connectid_invite';
var $modal = $('#confirm_' + self.user_id());

$modal.find(".btn").addSpinnerToButton();
$.ajax({
method: 'POST',
url: initialPageData.reverse(urlName, self.user_id()),
success: function (data) {
$modal.modal('hide');
if (data.success) {
self.action_error('');
} else {
self.action_error(data.error);
}

},
error: function () {
$modal.modal('hide');
$modal.find(".btn").removeSpinnerFromButton();
self.action_error(gettext("Issue communicating with server. Try again."));
},
});
};

return self;
};

Expand Down Expand Up @@ -291,7 +329,7 @@ hqDefine("users/js/mobile_workers",[
return self.STATUS.DISABLED;
}

if (self.stagedUser().force_account_confirmation_by_sms()) {
if (self.stagedUser().force_account_confirmation_by_sms() || self.stagedUser().account_invite_by_cid()) {
return self.STATUS.DISABLED;
}

Expand Down Expand Up @@ -508,7 +546,7 @@ hqDefine("users/js/mobile_workers",[
user.send_account_confirmation_email(false);
}
});
user.force_account_confirmation_by_sms.subscribe(function (enabled) {
var handlePhoneRequired = function (enabled) {
if (enabled) {
// make phone number required
user.phoneRequired(true);
Expand All @@ -522,7 +560,9 @@ hqDefine("users/js/mobile_workers",[
// enable password input
user.passwordEnabled(true);
}
});
};
user.force_account_confirmation_by_sms.subscribe(handlePhoneRequired);
user.account_invite_by_cid.subscribe(handlePhoneRequired);
});

self.initializeUser = function () {
Expand Down
Loading