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

ABDM changes for consuming APIs in the mobile app. #32194

Closed
wants to merge 188 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
188 commits
Select commit Hold shift + click to select a range
17cbc8f
Removed safe from accept_invite
mjriley Jan 17, 2022
0ef7fa6
Removed the safe filter from userreports templates
mjriley Feb 9, 2022
45bc345
remove careplan report templates
mjriley Feb 11, 2022
d5dc397
remove safe from conditional alerts
mjriley Jan 17, 2022
5816f0b
Removed safe from SMS
mjriley Jan 17, 2022
3a3d1d9
Removed safe usage from users
mjriley Jan 17, 2022
0096518
Removed safe usages from HQAdmin
mjriley Jan 17, 2022
707b685
remove safe from domain templates
mjriley Jan 18, 2022
d2c22e6
Remove safe filter from report templates
mjriley Feb 9, 2022
281abd1
Removed safe filter from feature flags
mjriley Feb 9, 2022
f0480d4
Removed safe filter from fixtures
mjriley Feb 10, 2022
e4f4cce
Removed safe filter from accounting
mjriley Feb 10, 2022
75cee53
Remove safe filter from custom data fields
mjriley Feb 10, 2022
a2bc2f4
remove safe filter from openmrs
mjriley Feb 11, 2022
8332e93
Remove safe filter from inddex
mjriley Feb 11, 2022
00c2bc0
removed safe filter from casexml
mjriley Feb 14, 2022
7ac580b
Removed safe filter from app manager templates
mjriley Feb 15, 2022
3dce722
Removed safe filter from crispy text field
mjriley Feb 23, 2022
a3b9108
removed safe filter from crispy templates
mjriley Feb 24, 2022
2a676da
Removed unnecessary import
mjriley May 4, 2022
a41d145
fixed a variable naming issue
mjriley May 4, 2022
126cea1
Merge branch 'master' into mjr/safe_hqwebapp
mjriley May 4, 2022
56fc7fc
Removed additional safe filters from templates
mjriley May 4, 2022
580e4ba
Updated invite template style
mjriley May 5, 2022
67f9165
Merge branch 'mjr/safe_hqadmin' into mjr/mark_safe_combined
mjriley May 9, 2022
4709df6
Merge branch 'mjr/safe_app_manager' into mjr/mark_safe_combined
mjriley May 9, 2022
cb1869c
Merge branch 'mjr/safe_custom_data_fields' into mjr/mark_safe_combined
mjriley May 9, 2022
3be941b
Merge branch 'mjr/safe_motech' into mjr/mark_safe_combined
mjriley May 9, 2022
e33ba12
Merge branch 'mjr/safe_reports' into mjr/mark_safe_combined
mjriley May 9, 2022
804bebe
Merge branch 'mjr/safe_users' into mjr/mark_safe_combined
mjriley May 9, 2022
2121e22
Merge branch 'mjr/safe_sms' into mjr/mark_safe_combined
mjriley May 9, 2022
fb51e67
Merge branch 'mjr/safe_casexml' into mjr/mark_safe_combined
mjriley May 9, 2022
d8bc231
Merge branch 'mjr/safe_accounting' into mjr/mark_safe_combined
mjriley May 9, 2022
b77ba0e
Merge branch 'mjr/safe_fixtures' into mjr/mark_safe_combined
mjriley May 9, 2022
2b43e71
Merge branch 'mjr/safe_toggleui' into mjr/mark_safe_combined
mjriley May 9, 2022
777e777
Merge branch 'mjr/safe_domain' into mjr/mark_safe_combined
mjriley May 9, 2022
ebd9fd5
Merge branch 'mjr/safe_messaging' into mjr/mark_safe_combined
mjriley May 9, 2022
587a622
Merge branch 'mjr/safe_hqwebapp' into mjr/mark_safe_combined
mjriley May 9, 2022
5ea0f1a
Merge branch 'mjr/safe_userreports' into mjr/mark_safe_combined
mjriley May 9, 2022
00e0ccd
Merge branch 'mjr/report_careplan' into mjr/mark_safe_combined
mjriley May 9, 2022
59a0658
Merge branch 'mjr/safe_accept_invite' into mjr/mark_safe_combined
mjriley May 9, 2022
8668562
Updated DataTables output to be HTML-safe
mjriley May 10, 2022
be165a7
Merge branch 'mjr/safe_inddex' into mjr/all_safe_fixes
mjriley May 11, 2022
299f292
Break out username for easier traceback handling in signup
mjriley May 12, 2022
5954509
Fixed an issue for new users attempting to accept an invite
mjriley May 12, 2022
f3f3c29
Fixed conditional alert HTML artifact
mjriley May 16, 2022
6be3231
Fixed an HTML artifact bug with custom reports
mjriley May 25, 2022
0c6ce4b
Merge branch 'master' into mjr/all_safe_fixes
millerdev Jun 20, 2022
6e0e44c
Merge branch 'master' into mjr/all_safe_fixes
orangejenny Jul 1, 2022
fd5307e
CommCare HQ
kaapstorm Sep 14, 2022
2b3b509
Postgresql 14
millerdev Sep 7, 2022
3b6327d
Log service version info in test output
millerdev Sep 20, 2022
ba82c67
ABDM api for mobile app consumption
Sep 22, 2022
23d321b
Add abdm api token to response of mobile restore
Sep 22, 2022
424af6d
Add auth settings + register in primary urls.py
Sep 22, 2022
f7e8afd
abdm migrations
Sep 22, 2022
09c8c5a
add abdm exclusion to domain migration tests
Sep 22, 2022
496bd0b
Merge remote-tracking branch 'origin/master' into akj/abdm-api-for-mo…
Sep 26, 2022
d8e49bf
Refactor based on review comments
Sep 26, 2022
b96be7f
remove CRUDPaginatedViewMixin from AutomaticUpdateRuleListView
gherceg Sep 27, 2022
f759674
fix stickler JS warnings
gherceg Sep 27, 2022
5a48dce
first batch of addressing feedback
gherceg Sep 27, 2022
d9cce87
second batch of addressing feedback
gherceg Sep 27, 2022
13240dc
ignore stickler syntax error
gherceg Sep 27, 2022
53c2a7b
unwrap id in delete rule modal
gherceg Sep 28, 2022
f7917ab
move header and help text outside of tabs
gherceg Sep 28, 2022
56b14a5
use page_context, not main_context
gherceg Sep 28, 2022
847ec50
rename list_automatic_update_rules.js to deduplication_rules.js
gherceg Sep 29, 2022
24a16d5
duplicate format_rule code into deduplication list view (the irony)
gherceg Sep 30, 2022
5a620bd
Change the way a "for export" adapter is acquired
joxl Sep 26, 2022
5423bc1
Change document adapter usage pattern
joxl Sep 27, 2022
04f7876
Move `index_name` and `type` class attributes to init args
joxl Sep 27, 2022
276fd41
Update the manager adapter pattern to match document adapters
joxl Sep 27, 2022
e1aeba7
Overhaul `ElasticDocumentAdapter.update()`
joxl Sep 28, 2022
c8e5f47
Refactor `ElasticDocumentAdapter` keyword arguments
joxl Sep 30, 2022
6a5a30a
use get_timezone_for_user directly
gherceg Oct 17, 2022
1e37222
missing time from page context
gherceg Oct 17, 2022
fbc3d87
Merge branch 'master' into gh/replace-base-crud-view
gherceg Oct 18, 2022
01bdea4
basic implementation of rule run history tab
gherceg Sep 29, 2022
19c30b9
add paginated for rule run history tab
gherceg Oct 17, 2022
b434fc6
add num of updates and closes to table
gherceg Oct 17, 2022
be99017
filter DomainCaseRuleRun by case update workflow
gherceg Oct 18, 2022
d3c670b
add status field to table
gherceg Oct 18, 2022
0f142f0
refactor to ensure 'update rule' is not used
gherceg Oct 18, 2022
1d35b7d
misc: remove older django version compatibility
AmitPhulera Oct 19, 2022
2f304e2
misc: more docstring in transient_util
AmitPhulera Oct 19, 2022
9c0e723
add: Tombstone class
AmitPhulera Oct 19, 2022
b0bdda5
tests: Tomobstone class
AmitPhulera Oct 19, 2022
95bb118
refactor:set default property to None
AmitPhulera Oct 19, 2022
a6a26a4
refactor: some refactors to support the multiplexer class coming up
AmitPhulera Oct 19, 2022
6c86188
add: ElasticMultiplexAdapter class
AmitPhulera Oct 19, 2022
e8a9846
refactor: create_document_adapter to return multiplexer class if seco…
AmitPhulera Oct 19, 2022
bb0fd46
refactor: split helper functions into a sepearate test helper class
AmitPhulera Oct 19, 2022
4b86cad
add: tests for the multiplexer adapter
AmitPhulera Oct 19, 2022
e51a2da
add allowed_actions to dedupe view
gherceg Oct 19, 2022
0bec349
Merge branch 'gh/replace-base-crud-view' into gh/add-history-tab
gherceg Oct 20, 2022
0eed91a
add docstrings for tombstones
AmitPhulera Oct 20, 2022
643b2bb
update readme as per the changes in the PR
AmitPhulera Oct 20, 2022
da0ba4e
rename reference to auto_update_rule_run_history.html
gherceg Oct 20, 2022
7119925
move index cleanup from teardown to self.addCleanup
AmitPhulera Oct 20, 2022
44755b4
Update corehq/apps/es/transient_util.py
AmitPhulera Oct 20, 2022
eba1c36
pass fn instead of result in addCleanup
AmitPhulera Oct 21, 2022
a4c9792
sort rule runs by descending started and finished dates
gherceg Oct 23, 2022
bd20ea8
Add checkbox case search option to app manager
nospame Oct 24, 2022
e4d47ce
document usage for tombstones in readme
AmitPhulera Oct 25, 2022
5328d10
Add checkbox to case search query view
nospame Oct 25, 2022
d6b199f
Add checkbox prompt to xml tests
nospame Oct 25, 2022
1d099f8
Merge branch 'master' of github.com:dimagi/commcare-hq into em/case-s…
nospame Oct 25, 2022
0bc1aad
add mgmnt command to get es version when index was created
AmitPhulera Oct 26, 2022
8628a7e
remove confusing para from readme
AmitPhulera Oct 26, 2022
94436e6
Refactor
nospame Oct 26, 2022
3761567
bump default items per page from 5 to 25
gherceg Oct 27, 2022
ee5a952
Nitpicking
minhaminha Oct 28, 2022
e604d66
Shadow module to get persistent and inline details from itself instea…
SmittieC Oct 28, 2022
4496d8c
Refactor a bit
SmittieC Oct 28, 2022
2055e5f
remove unused methods
AddisonDunn Oct 31, 2022
6b16f49
add TableauUser, TableauGroup models
AddisonDunn Oct 31, 2022
60d5df1
Merge remote-tracking branch 'origin/master' into akj/abdm-api-for-mo…
Nov 1, 2022
69b5818
add translations for tableau roles
AddisonDunn Nov 1, 2022
961def7
Revert "Refactor"
nospame Nov 1, 2022
75fbce7
refactor - look for self.app on the EntriesHelper instead of passing …
SmittieC Nov 2, 2022
f4e73e8
changed default pagination to 25 on wrong table
gherceg Nov 2, 2022
54bf4c0
Use lookup tables in checkbox case search property
nospame Nov 2, 2022
df54e23
Allow multiple checkboxes in case search UI
nospame Nov 2, 2022
63bd5db
Stickler
nospame Nov 2, 2022
716051d
initial command to backfill subevent date
snopoke Nov 3, 2022
93b588c
update from sms
snopoke Nov 3, 2022
29bb536
backfill from xformsession
snopoke Nov 3, 2022
04260fd
make chunksize configurable
snopoke Nov 3, 2022
dbd9660
add migration status to command
snopoke Nov 3, 2022
6172be0
test that rows with dates are not updated
snopoke Nov 3, 2022
05a506d
combine tests into a single class
snopoke Nov 3, 2022
8486963
increase max length for username field
AddisonDunn Nov 3, 2022
492daad
Merge remote-tracking branch 'origin/master' into akj/abdm-api-for-mo…
Nov 6, 2022
2ed59f4
Merge pull request #32151 from dimagi/nh/commcare_hq_rst
kaapstorm Nov 7, 2022
850019b
Merge pull request #32289 from dimagi/ap/es-index-version-created
AmitPhulera Nov 7, 2022
0821b24
add more options for testing
snopoke Nov 7, 2022
7e85b13
fix backfill tests
snopoke Nov 7, 2022
8d58e89
Revert "[SAAS-14102] addf field to messaging sub-event model to recor…
snopoke Nov 7, 2022
3547632
Merge pull request #32314 from dimagi/revert-32307-sk/subevent-date-l…
snopoke Nov 7, 2022
aed8e7e
Revert "Revert "[SAAS-14102] addf field to messaging sub-event model …
snopoke Nov 7, 2022
ebed0b8
set 'auto_now' in a separate migration to avoid table lock on the ini…
snopoke Nov 7, 2022
1943140
improve query performance
snopoke Nov 7, 2022
987ee41
add count query for better progress & refactor
snopoke Nov 7, 2022
4db0721
Merge pull request #32302 from dimagi/ad/create-other-tableau-syncing…
AddisonDunn Nov 7, 2022
b9047da
skip if no rows
snopoke Nov 7, 2022
a4eb5c9
lower defualt chunksize
snopoke Nov 7, 2022
6424929
Merge pull request #32315 from dimagi/revert-32314-revert-32307-sk/su…
snopoke Nov 7, 2022
b379963
Merge branch 'master' into sk/backfill-subevent-date
snopoke Nov 7, 2022
d4eb4b2
Optimize EnterpriseFormReport.total_for_domain()
millerdev Nov 7, 2022
7235e7f
Feature flag for restore content
Nov 8, 2022
6587471
Use extensions for fetching abdm token in restore
Nov 8, 2022
d9a2787
Merge pull request #32298 from dimagi/cs/sc-2369/shadow_module_fix
SmittieC Nov 8, 2022
a9671d9
Merge pull request #32311 from dimagi/sk/backfill-subevent-date
snopoke Nov 8, 2022
7883b48
update API to use new date field for sorting
snopoke Nov 8, 2022
07b6743
Merge pull request #32317 from dimagi/dm/optimize-enterprise-forms-re…
millerdev Nov 8, 2022
11d5047
Merge branch 'master' into dm/pg14
millerdev Nov 8, 2022
502d1e1
DRY postgres version and warn on outdated pin
millerdev Nov 8, 2022
0071f2f
Merge pull request #32120 from dimagi/dm/pg14
millerdev Nov 8, 2022
e78d971
Update staging.yml
minhaminha Nov 8, 2022
cdc21fd
Updated EOF nav config to use select2
orangejenny Nov 8, 2022
b157ed6
Merge pull request #32288 from dimagi/mjr/all_safe_fixes
minhaminha Nov 8, 2022
cab23cc
Fix html typo
nospame Nov 8, 2022
a238477
Show multiselect disabled + checked for checkbox property
nospame Nov 8, 2022
bdea408
updating files: scripts/staging.yml
nospame Nov 8, 2022
b66f25d
Merge pull request #32211 from dimagi/gh/replace-base-crud-view
gherceg Nov 8, 2022
d291ae3
Update staging.yml
gherceg Nov 8, 2022
32d2961
Update translations
dannyroberts Nov 9, 2022
3e5e07e
Merge pull request #32265 from dimagi/jm+ap/elastic-multiplexer
AmitPhulera Nov 9, 2022
9a7d94b
Merge pull request #32323 from dimagi/jls/eof-nav-select2s
orangejenny Nov 9, 2022
17c0050
only check for data registry if not remote link
gherceg Nov 9, 2022
88c05d5
add search box to rule run table
gherceg Nov 9, 2022
4830ebe
add brief description of rule run history table
gherceg Nov 9, 2022
f1ae3ec
Merge pull request #32290 from dimagi/em/case-search-checkbox
nospame Nov 9, 2022
6083729
use datasource var in data registry check
gherceg Nov 9, 2022
d234d42
datasource as optional param in is_data_registry_report
gherceg Nov 9, 2022
3f6b2fb
Update staging.yml
gherceg Nov 9, 2022
5edb2ac
update description for rule run history table
gherceg Nov 9, 2022
48e79ca
Merge pull request #32324 from dimagi/create-pull-request/update-tran…
joxl Nov 9, 2022
3d8615b
updating files: scripts/staging.yml
esoergel Nov 9, 2022
31a846a
Merge pull request #32326 from dimagi/gh/resolve-remote-link-issue
gherceg Nov 9, 2022
f518467
Update staging.yml
gherceg Nov 9, 2022
6b5d317
Merge pull request #32258 from dimagi/gh/add-history-tab
gherceg Nov 9, 2022
44b9aa2
Update staging.yml
gherceg Nov 9, 2022
1274cfd
update staging
snopoke Nov 10, 2022
8e7f4a2
Merge pull request #32322 from dimagi/sk/messaging-api-new-date-field
snopoke Nov 10, 2022
52bd4d1
Merge branch 'akj/abdm-api-for-mobile-app' of https://github.com/dima…
Nov 11, 2022
1094b43
remove drf default auth from settings.py
Nov 11, 2022
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: 2 additions & 0 deletions corehq/apps/domain/tests/test_deletion_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
'toggle_ui',
'sso',
'oauth_integrations',
'rest_framework',
}

IGNORE_MODELS = {
Expand All @@ -65,6 +66,7 @@
'util.TransientBounceEmail',
'registration.AsyncSignupRequest',
'users.UserHistory',
'custom.abdm.models.ABDMUser',
}


Expand Down
1 change: 1 addition & 0 deletions corehq/apps/dump_reload/tests/test_dump_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"util.PermanentBounceMeta",
"util.TransientBounceEmail",
"users.Permission",
"abdm.ABDMUser",
}

# TODO: determine which of these should not be ignored
Expand Down
9 changes: 8 additions & 1 deletion corehq/ex-submodules/casexml/apps/phone/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import six

from casexml.apps.phone.exceptions import RestoreException
from custom.abdm.milestone_one.utils.user_util import get_abdm_api_token

USER_REGISTRATION_XMLNS_DEPRECATED = "http://openrosa.org/user-registration"
USER_REGISTRATION_XMLNS = "http://openrosa.org/user/registration"
Expand Down Expand Up @@ -129,10 +130,16 @@ def get_registration_element_data(restore_user):
"password": restore_user.password,
"uuid": restore_user.user_id,
"date": date_to_xml_string(restore_user.date_joined),
"user_data": restore_user.user_session_data
"user_data": get_session_data_with_abdm_token(restore_user)
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if this used a toggle so that it only added the ABDM data if necessary. Also, this seems like a good place to use an extension point:

In corehq/ex-submodules/casexml/apps/phone/xml.py

from corehq import extensions

def get_user_data_for_restore(restore_user):
    user_data = {}
    for custom_user_data in get_custom_user_data_for_restore(restore_user):
        user_data.update(custom_user_data)
    user_data.update(restore_user.user_session_data)
    return user_data

@extensions.extension_point
def get_custom_user_data_for_restore(restore_user):
    '''Get additional user data for restore

    :returns: Dict of user data
    '''
    pass

in custom/abdm

@get_custom_user_data_for_restore.extend()
def get_abdm_user_data(restore_user):
    if ABDM.enabled(restore_user.domain):
        return {"abdm_api_token": get_abdm_api_token(restore_user.username)}

You can read more about them here: https://commcare-hq.readthedocs.io/extensions.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it possible to check for a particular application, rather than a domain? For example, if some property is set within an application, then only the key will be returned.

Will check the extensions part.

Copy link
Contributor

@snopoke snopoke Sep 27, 2022

Choose a reason for hiding this comment

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

Is it possible to check for a particular application, rather than a domain? For example, if some property is set within an application, then only the key will be returned.

That could be possible. You would need to change the get_registration_element to accept more arguments (potentially just pass in the whole RestoreState class). The app would be restore_state.params.app (which could be None if it is not an app specific restore)

}


def get_session_data_with_abdm_token(restore_user):
user_data = {"abdm_api_token": get_abdm_api_token(restore_user.username)}
user_data.update(restore_user.user_session_data)
return user_data


# Case registration blocks do not have a password
def get_registration_element_for_case(case):
root = safe_element("Registration")
Expand Down
Empty file added custom/abdm/__init__.py
Empty file.
19 changes: 19 additions & 0 deletions custom/abdm/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from rest_framework.authentication import TokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from custom.abdm.models import ABDMUser


class ABDMUserAuthentication(TokenAuthentication):

def authenticate(self, request):
access_token = request.META.get('HTTP_AUTHORIZATION', "")
token = access_token.split(" ")[-1]
if not token:
return None
try:
user = ABDMUser.objects.get(access_token=token)
Copy link
Contributor

Choose a reason for hiding this comment

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

If you make this model comply with the rest framework key structure then you could just do this:

class ABDMUserAuthentication(TokenAuthentication):
    model = ABDMUser

A rest framework token has a 'key' and 'user' fields (user is a FK to the Django user).

I'm also unclear why you need a custom model for the token and can't either use the existing HQApiKey or else the DRF Token model.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Intention is to restrict token's access to ABDM API only as it is accessed by a separate app. Will it possible to implement this limitation without a custom auth logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I remember that if those entries related to DRF's token were not added in the settings.py file, it resulted in the authentication system not getting triggered.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

except ABDMUser.DoesNotExist:
raise AuthenticationFailed('Unauthorized')
if not user.is_token_valid:
raise AuthenticationFailed('Invalid Token')
return (user, None)
23 changes: 23 additions & 0 deletions custom/abdm/migrations/0001_squashed_0002_auto_20220926_0547.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.15 on 2022-09-26 05:56

from django.db import migrations, models


class Migration(migrations.Migration):

replaces = [('abdm', '0001_initial'), ('abdm', '0002_auto_20220926_0547')]

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='ABDMUser',
fields=[
('username', models.CharField(max_length=100, primary_key=True, serialize=False)),
('access_token', models.CharField(blank=True, max_length=2000, null=True)),
],
),
]
Empty file.
Empty file.
Empty file.
44 changes: 44 additions & 0 deletions custom/abdm/milestone_one/utils/abha_creation_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import logging

from custom.abdm.milestone_one.utils.request_util import get_response_http_post

logger = logging.getLogger(__name__)


def generate_aadhar_otp(aadhaar_number):
generate_aadhar_otp_url = "v1/registration/aadhaar/generateOtp"
payload = {"aadhaar": str(aadhaar_number)}
return get_response_http_post(generate_aadhar_otp_url, payload)


def generate_mobile_otp(mobile_number, txnid):
generate_mobile_otp_url = "v1/registration/aadhaar/generateMobileOTP"
payload = {"mobile": str(mobile_number), "txnId": txnid}
return get_response_http_post(generate_mobile_otp_url, payload)


def verify_aadhar_otp(otp, txnid):
verify_aadhaar_otp_url = "v1/registration/aadhaar/verifyOTP"
payload = {"otp": str(otp), "txnId": txnid}
return get_response_http_post(verify_aadhaar_otp_url, payload)


def verify_mobile_otp(otp, txnid):
verify_mobile_otp_url = "v1/registration/aadhaar/verifyMobileOTP"
payload = {"otp": str(otp), "txnId": txnid}
return get_response_http_post(verify_mobile_otp_url, payload)


def create_health_id(txnid):
create_health_id_url = "v1/registration/aadhaar/createHealthIdWithPreVerified"
payload = {
"email": "",
"firstName": "",
"healthId": "",
"lastName": "",
"middleName": "",
"password": "",
"profilePhoto": "",
"txnId": txnid
}
return get_response_http_post(create_health_id_url, payload)
36 changes: 36 additions & 0 deletions custom/abdm/milestone_one/utils/abha_verification_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import requests

from custom.abdm.milestone_one.utils.request_util import get_access_token, get_response_http_post, base_url


def generate_auth_otp(health_id, auth_method):
auth_otp_url = "v2/auth/init"
payload = {"authMethod": auth_method, "healthid": health_id}
return get_response_http_post(auth_otp_url, payload)


def confirm_with_mobile_otp(otp, txn_id):
confirm_with_mobile_otp_url = "v1/auth/confirmWithMobileOTP"
payload = {"otp": otp, "txnId": txn_id}
return get_response_http_post(confirm_with_mobile_otp_url, payload)


def confirm_with_aadhaar_otp(otp, txn_id):
confirm_with_aadhaar_otp_url = "v1/auth/confirmWithAadhaarOtp"
payload = {"otp": otp, "txnId": txn_id}
return get_response_http_post(confirm_with_aadhaar_otp_url, payload)


def get_account_information(x_token):
account_information_url = "v1/account/profile"
headers = {"Content-Type": "application/json; charset=UTF-8"}
token = get_access_token()
headers.update({"Authorization": "Bearer {}".format(token), "X-Token": f"Bearer {x_token}"})
resp = requests.get(url=base_url + account_information_url, headers=headers)
return resp.json()


def search_by_health_id(health_id):
search_by_health_id_url = "v1/search/searchByHealthId"
payload = {"healthId": health_id}
return get_response_http_post(search_by_health_id_url, payload)
37 changes: 37 additions & 0 deletions custom/abdm/milestone_one/utils/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import logging

from functools import wraps
from typing import List

from custom.abdm.milestone_one.utils.response_handler import generate_invalid_req_response

logger = logging.getLogger(__name__)


def required_request_params(params):
"""
Checks if the parameters provided in the decorator(a list of strings) are present in the DRF request.
If not, raises 400 Bad Request error.
"""

def decorate(fn):
if not (params and isinstance(params, List)):
error_msg = "Request could not be validated as a valid input not provided. \
Required: List of parameters."
logger.warning(error_msg)
return generate_invalid_req_response(error_msg)

@wraps(fn)
def wrapped(request, *args, **kwargs):
invalid_params = []
for param in params:
if not request.data.get(param):
snopoke marked this conversation as resolved.
Show resolved Hide resolved
invalid_params.append(param)
if invalid_params:
error_msg = f"Missing required parameter(s) in the request: {','.join(invalid_params)}"
return generate_invalid_req_response(error_msg)
return fn(request, *args, **kwargs)

return wrapped

return decorate
28 changes: 28 additions & 0 deletions custom/abdm/milestone_one/utils/request_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import json
from typing import Any, Dict
import requests

from django.conf import settings

base_url = "https://healthidsbx.abdm.gov.in/api/"
gateway_url = "https://dev.abdm.gov.in/gateway/v0.5/sessions"


def get_access_token():
payload = {"clientId": settings.ABDM_CLIENT_ID, "clientSecret": settings.ABDM_CLIENT_SECRET}
headers = {"Content-Type": "application/json; charset=UTF-8"}
resp = requests.post(url=gateway_url, data=json.dumps(payload), headers=headers)
if resp.status_code == 200:
return resp.json().get("accessToken")


def get_response_http_post(api_url, payload, additional_headers):
req_url = base_url + api_url
headers = {"Content-Type": "application/json"}
token = get_access_token()
headers.update({"Authorization": "Bearer {}".format(token)})
if additional_headers:
headers.update(additional_headers)
resp = requests.post(url=req_url, data=json.dumps(payload), headers=headers)
resp.raise_for_status()
return resp.json()
snopoke marked this conversation as resolved.
Show resolved Hide resolved
40 changes: 40 additions & 0 deletions custom/abdm/milestone_one/utils/response_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from rest_framework.response import Response

from rest_framework.status import HTTP_200_OK, HTTP_500_INTERNAL_SERVER_ERROR, HTTP_400_BAD_REQUEST

success_response_keys = ["txnId", "healthIdNumber", "auth_methods", "token"]


def get_response(response_data):
if not response_data:
return Response({"error": "No valid response found"}, status=HTTP_500_INTERNAL_SERVER_ERROR)
if any([key in response_data for key in success_response_keys]):
return _get_success_abdm_response(response_data)
return _get_error_abdm_response(response_data)


def generate_invalid_req_response(message):
resp = {
"code": "400",
"message": "Unable to process the current request due to incorrect data entered.",
"details": [{
"message": message,
"attribute": None
}]
}
return Response(resp, status=HTTP_400_BAD_REQUEST)


def _get_success_abdm_response(response_data):
return Response(response_data, status=HTTP_200_OK)


def _get_error_abdm_response(response_data):
if "code" in response_data:
return _parse_response(response_data)
return generate_invalid_req_response(response_data)


def _parse_response(response_data):
status_code = int(response_data.get("code").split("-")[-1])
return Response(response_data, status=status_code)
12 changes: 12 additions & 0 deletions custom/abdm/milestone_one/utils/user_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import logging

from custom.abdm.models import ABDMUser

logger = logging.getLogger(__name__)


def get_abdm_api_token(username):
user, _ = ABDMUser.objects.get_or_create(username=username)
if not user.access_token:
user.generate_token()
return user.access_token
Empty file.
54 changes: 54 additions & 0 deletions custom/abdm/milestone_one/views/abha_creation_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from custom.abdm.auth import ABDMUserAuthentication

from custom.abdm.milestone_one.utils import abha_creation_util as abdm_util
from custom.abdm.milestone_one.utils.decorators import required_request_params
from custom.abdm.milestone_one.utils.response_handler import get_response


@api_view(["POST"])
@permission_classes((IsAuthenticated,))
@authentication_classes((ABDMUserAuthentication,))
@required_request_params(["aadhaar"])
def generate_aadhaar_otp(request):
aadhaar_number = request.data.get("aadhaar")
resp = abdm_util.generate_aadhar_otp(aadhaar_number)
return get_response(resp)


@api_view(["POST"])
@permission_classes((IsAuthenticated,))
@authentication_classes((ABDMUserAuthentication,))
@required_request_params(["txn_id", "mobile_number"])
def generate_mobile_otp(request):
txn_id = request.data.get("txn_id")
mobile_number = request.data.get("mobile_number")
resp = abdm_util.generate_mobile_otp(mobile_number, txn_id)
return get_response(resp)


@api_view(["POST"])
@permission_classes((IsAuthenticated,))
@authentication_classes((ABDMUserAuthentication,))
@required_request_params(["txn_id", "otp"])
def verify_aadhaar_otp(request):
txn_id = request.data.get("txn_id")
otp = request.data.get("otp")
resp = abdm_util.verify_aadhar_otp(otp, txn_id)
return get_response(resp)


@api_view(["POST"])
@permission_classes((IsAuthenticated,))
@authentication_classes((ABDMUserAuthentication,))
@required_request_params(["txn_id", "otp"])
def verify_mobile_otp(request):
txn_id = request.data.get("txn_id")
otp = request.data.get("otp")
resp = abdm_util.verify_mobile_otp(otp, txn_id)
if resp and "txnId" in resp:
resp = abdm_util.create_health_id(txn_id)
resp.pop("token")
resp.pop("refreshToken")
return get_response(resp)
Loading