Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions app/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ REACT_APP_OPENSRP_API_V2_BASE_URL=https://reveal-stage.smartregister.org/opensrp
REACT_APP_OPENSRP_USER_URL=https://reveal-stage.smartregister.org/opensrp/user-details
REACT_APP_DISABLE_LOGIN_PROTECTION=false
REACT_APP_ENABLE_FHIR_USER_MANAGEMENT=false
REACT_APP_ENABLE_USERS=false
REACT_APP_ENABLE_USER_GROUPS=false
REACT_APP_ENABLE_USER_ROLES=false
REACT_APP_ENABLE_USER_SYNC=false
REACT_APP_FHIR_API_BASE_URL=https://fhir.labs.smartregister.org/fhir
REACT_APP_OPENSRP_OAUTH_SCOPES=profile
REACT_APP_ENABLE_FHIR_HEALTHCARE_SERVICES=false
Expand Down
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@opensrp/fhir-quest-form": "^0.0.0",
"@opensrp/fhir-team-management": "^0.0.5",
"@opensrp/fhir-user-management": "^0.0.1",
"@opensrp/fhir-user-sync": "workspace:^",
"@opensrp/fhir-views": "^0.0.0",
"@opensrp/i18n": "^0.0.1",
"@opensrp/keycloak-service": "^0.0.17",
Expand Down
12 changes: 12 additions & 0 deletions app/src/App/fhir-apps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
URL_USER_ROLES,
URL_FHIR_CARE_TEAM,
URL_TEAM_ASSIGNMENT,
URL_USER_SYNC,
} from '../constants';
import { providers } from '../configs/settings';
import CustomConnectedAPICallBack from '../components/page/CustomCallback';
Expand Down Expand Up @@ -101,6 +102,7 @@ import {
fhirCreateEditUserProps,
commmodityProps,
fhirCreateEditLocationProps,
userSyncProps,
} from './utils';
import './App.css';
import {
Expand Down Expand Up @@ -134,6 +136,7 @@ import {
DataImportList,
StartDataImport,
} from '@opensrp/fhir-import';
import { UserSync } from '@opensrp/fhir-user-sync';

/** Util function that renders Oauth2 callback components
*
Expand Down Expand Up @@ -289,6 +292,15 @@ const FHIRApps = () => {
permissions={['iam_user.read']}
component={FhirUserList}
/>
<PrivateComponent
redirectPath={APP_CALLBACK_URL}
disableLoginProtection={DISABLE_LOGIN_PROTECTION}
exact
path={URL_USER_SYNC}
{...userSyncProps}
permissions={['iam_user.read', 'Practitioner.create']}
component={UserSync}
/>
<PrivateComponent
redirectPath={APP_CALLBACK_URL}
disableLoginProtection={DISABLE_LOGIN_PROTECTION}
Expand Down
6 changes: 6 additions & 0 deletions app/src/App/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
DISABLE_TEAM_MEMBER_REASSIGNMENT,
FHIR_API_BASE_URL,
KEYCLOAK_USERS_PAGE_SIZE,
KEYCLOAK_API_BASE_URL,
} from '../configs/env';

export const BaseProps = {
Expand Down Expand Up @@ -115,3 +116,8 @@ export const fhirCreateEditLocationProps = {
...BaseProps,
commodityListId: COMMODITIES_LIST_RESOURCE_ID,
};

export const userSyncProps = {
fhirBaseURL: FHIR_API_BASE_URL,
keycloakBaseURL: KEYCLOAK_API_BASE_URL,
};
8 changes: 8 additions & 0 deletions app/src/configs/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ export const ENABLE_FHIR_LOCATIONS = setEnv('REACT_APP_ENABLE_FHIR_LOCATIONS', '
export const ENABLE_FHIR_USER_MANAGEMENT =
setEnv('REACT_APP_ENABLE_FHIR_USER_MANAGEMENT', 'false') === 'true';

export const ENABLE_USERS = setEnv('REACT_APP_ENABLE_USERS', 'false') === 'true';

export const ENABLE_USER_GROUPS = setEnv('REACT_APP_ENABLE_USER_GROUPS', 'false') === 'true';

export const ENABLE_USER_ROLES = setEnv('REACT_APP_ENABLE_USER_ROLES', 'false') === 'true';

export const ENABLE_USER_SYNC = setEnv('REACT_APP_ENABLE_USER_SYNC', 'false') === 'true';

export const FHIR_API_BASE_URL = setEnv(
'REACT_APP_FHIR_API_BASE_URL',
'https://fhir-auth.labs.smartregister.org/fhir'
Expand Down
1 change: 1 addition & 0 deletions app/src/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const URL_LOGOUT = '/logout';
export const URL_HOME = '/';

export const URL_USER = `${URL_ADMIN}/users`;
export const URL_USER_SYNC = `${URL_ADMIN}/users/sync`;
export const URL_ORG_AFFILIATION = `${URL_ADMIN}/OrgAffiliation`;
export const URL_USER_GROUPS = `${URL_USER}/groups`;
export const URL_USER_ROLES = `${URL_USER}/roles`;
Expand Down
22 changes: 21 additions & 1 deletion app/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ import {
ENABLE_QUEST,
ENABLE_TEAMS_ASSIGNMENT_MODULE,
ENABLE_FHIR_COMMODITY,
ENABLE_USERS,
ENABLE_USER_GROUPS,
ENABLE_USER_ROLES,
ENABLE_USER_SYNC,
} from '../configs/env';
import {
URL_USER,
URL_USER_SYNC,
URL_LOCATION_UNIT,
URL_TEAMS,
URL_TEAM_ASSIGNMENT,
Expand Down Expand Up @@ -74,18 +79,33 @@ export function getRoutes(roles: string[], t: TFunction, userRole: UserRole): Ro
permissions: ['iam_user.read'],
enabled: COMPOSITE_ENABLE_USER_MANAGEMENT,
children: [
{ title: t('Users'), key: 'users', url: URL_USER, permissions: ['iam_user.read'] },
{
title: t('Users'),
key: 'users',
url: URL_USER,
permissions: ['iam_user.read'],
enabled: ENABLE_USERS,
},
{
title: t('User Groups'),
key: 'user-groups',
url: URL_USER_GROUPS,
permissions: ['iam_group.read'],
enabled: ENABLE_USER_GROUPS,
},
{
title: t('User Roles'),
key: 'user-roles',
url: URL_USER_ROLES,
permissions: ['iam_role.read'],
enabled: ENABLE_USER_ROLES,
},
{
title: t('User Sync'),
key: 'user-sync',
url: URL_USER_SYNC,
permissions: ['iam_user.read', 'Practitioner.create'],
enabled: ENABLE_USER_SYNC,
},
],
},
Expand Down
28 changes: 28 additions & 0 deletions docs/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,34 @@ Below is a list of currently supported environment variables:
- **Optional**(`boolean`)
- default: `"false"`

- **REACT_APP_ENABLE_USERS**

- Enable the Users submenu under User Management
- **Optional**(`boolean`)
- default: `"false"`
- Note: Requires `REACT_APP_ENABLE_FHIR_USER_MANAGEMENT` to be enabled

- **REACT_APP_ENABLE_USER_GROUPS**

- Enable the User Groups submenu under User Management
- **Optional**(`boolean`)
- default: `"false"`
- Note: Requires `REACT_APP_ENABLE_FHIR_USER_MANAGEMENT` to be enabled

- **REACT_APP_ENABLE_USER_ROLES**

- Enable the User Roles submenu under User Management
- **Optional**(`boolean`)
- default: `"false"`
- Note: Requires `REACT_APP_ENABLE_FHIR_USER_MANAGEMENT` to be enabled

- **REACT_APP_ENABLE_USER_SYNC**

- Enable the User Sync submenu under User Management
- **Optional**(`boolean`)
- default: `"false"`
- Note: Requires `REACT_APP_ENABLE_FHIR_USER_MANAGEMENT` to be enabled

- **REACT_APP_OPENSRP_OAUTH_SCOPES**

- Sets the oauth app permission scopes.
Expand Down
58 changes: 58 additions & 0 deletions packages/fhir-user-sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# FHIR User Sync

Synchronization tool for ensuring all Keycloak users have the required FHIR resources.

## Features

- Scans all Keycloak users
- Checks for missing FHIR resources:
- Practitioner
- Group
- PractitionerRole
- Automatically creates missing resources
- Real-time progress tracking
- Detailed reporting

## Usage

The User Sync page is available in the sidebar under **Administration > User Management > User Sync**.

### Prerequisites

Users must have the following permissions:
- `iam_user.read` - To read Keycloak users
- `Practitioner.create` - To create FHIR resources

### How it works

1. Click "Start Synchronization" button
2. The tool scans all Keycloak users
3. For each user, it checks if they have:
- A Practitioner resource
- A Group resource
- A PractitionerRole resource
4. Missing resources are automatically created
5. Progress is displayed in real-time
6. A summary is shown when complete

## Component Props

```typescript
interface UserSyncProps {
fhirBaseURL: string; // FHIR server base URL
keycloakBaseURL: string; // Keycloak API base URL
}
```

## Development

```bash
# Build the package
yarn build

# Run tests
yarn test

# Lint
yarn lint
```
54 changes: 54 additions & 0 deletions packages/fhir-user-sync/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "@opensrp/fhir-user-sync",
"version": "0.0.1",
"description": "Keycloak user to FHIR resources synchronization",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": "https://github.com/OpenSRP/web/",
"scripts": {
"test": "run -T test $INIT_CWD --verbose",
"tsc": "run -T tsc",
"lint": "run -T eslint ./**/*.{js,jsx,ts,tsx}",
"copy": "run -T copyfiles -u 1 \"./src/**/*.{css,html}\" \"./dist/\"",
"build": "run tsc && run transpile && run copy",
"transpile": "run -T babel src -d dist --root-mode upward --extensions .ts,.tsx --ignore '**/*.test.ts,**/*.test.tsx,**/tests,**/__tests__'"
},
"jest": {
"automock": false,
"setupFiles": [
"../../setupTests"
]
},
"bugs": {
"url": "https://github.com/OpenSRP/web/issues"
},
"author": "OpenSRP Engineering",
"license": "Apache-2.0",
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@opensrp/fhir-helpers": "workspace:^",
"@opensrp/keycloak-service": "^0.0.17",
"@opensrp/notifications": "^0.0.5",
"@opensrp/pkg-config": "^0.0.9",
"@opensrp/rbac": "workspace:^",
"@opensrp/react-utils": "^0.0.12",
"@opensrp/user-management": "^0.1.19",
"uuid": "^8.3.1"
},
"devDependencies": {
"@smile-cdr/fhirts": "^1.2.5",
"@types/uuid": "8.3.0"
},
"peerDependencies": {
"@opensrp/i18n": "^0.0.1",
"antd": "^5.5.2",
"react": "17.0.0",
"react-helmet": "^6.1.0"
}
}
Loading
Loading