Skip to content

Commit

Permalink
(feat) Unify session handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ibacher committed Apr 8, 2022
1 parent 6a05cf5 commit 012fdee
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 401 deletions.
22 changes: 1 addition & 21 deletions packages/apps/esm-login-app/src/CurrentUserContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useContext, useState, useMemo, useEffect } from "react";
import { getCurrentUser } from "@openmrs/esm-framework";
import { getCurrentUser, LoggedInUser } from "@openmrs/esm-framework";

const CurrentUser = React.createContext<User>({
current: undefined,
Expand All @@ -16,26 +16,6 @@ export interface User {
setCurrent(user: LoggedInUser): void;
}

export interface ResourceRef {
uuid: string;
display: string;
links: Array<any>;
}

export interface LoggedInUser {
uuid: string;
display: string;
username: string;
systemId: string;
userProperties: any;
person: ResourceRef;
privileges: Array<ResourceRef>;
roles: Array<ResourceRef>;
retired: boolean;
locale: string;
allowedLocales: Array<string>;
}

export function useCurrentUser() {
const value = useContext(CurrentUser);
return value.current;
Expand Down
8 changes: 3 additions & 5 deletions packages/apps/esm-offline-tools-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"offlineActionsTableAction": "Action",
"offlineActionsTableCreatedOn": "Date & Time",
"offlineActionsTableDeleteAction": "Delete action",
"offlineActionsTableDeleteActions": "Delete {count} actions",
"offlineActionsTableDeleteActions_plural": "Delete {count} actions",
"offlineActionsTableDeleteActions_one": "Delete {count} actions",
"offlineActionsTableDeleteActions_other": "Delete {count} actions",
"offlineActionsTableError": "Error",
"offlineActionsTablePatient": "Patient",
"offlineActionsUpdateOfflinePatients": "Update offline patients",
Expand All @@ -32,7 +32,5 @@
"offlinePatientSyncDetailsFallbackErrorMessage": "Unknown error.",
"offlinePatientSyncDetailsHeader": "Offline patient details",
"offlineReady": "Offline Ready",
"offlineToolsAppMenuLink": "Offline tools",
"offlineActionsTableDeleteActions_one": "Delete {count} actions",
"offlineActionsTableDeleteActions_other": "Delete {count} actions"
"offlineToolsAppMenuLink": "Offline tools"
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ export interface RootProps {}
const Root: React.FC<RootProps> = () => {
const [user, setUser] = useState<LoggedInUser | null | false>(null);
const [userSession, setUserSession] = useState<UserSession>(null);
const [allowedLocales, setAllowedLocales] = useState();
const [allowedLocales, setAllowedLocales] = useState<Array<string> | null>();
const logout = useCallback(() => setUser(false), []);
const openmrsSpaBase = window["getOpenmrsSpaBase"]();

useEffect(() => {
const currentUserSub = getSynchronizedCurrentUser({
includeAuthStatus: true,
}).subscribe((response) => {
setAllowedLocales(response["allowedLocales"]);
setAllowedLocales(response.allowedLocales);

if (response.authenticated) {
setUser(response.user);
} else {
Expand Down
48 changes: 27 additions & 21 deletions packages/framework/esm-api/src/shared-api-objects/current-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
import { Observable, ReplaySubject } from "rxjs";
import { filter, map, tap, mergeAll } from "rxjs/operators";
import { openmrsFetch, sessionEndpoint } from "../openmrs-fetch";
import {
LoggedInUserData,
import type {
LoggedInUser,
CurrentUserWithResponseOption,
UnauthenticatedUser,
CurrentUserWithoutResponseOption,
CurrentUserOptions,
SessionLocation,
Privilege,
Role,
Session,
} from "../types";

const userSubject = new ReplaySubject<Promise<LoggedInUserData>>(1);
const userSubject = new ReplaySubject<Promise<Session>>(1);
let lastFetchTimeMillis = 0;

/**
Expand Down Expand Up @@ -56,13 +57,13 @@ let lastFetchTimeMillis = 0;
function getCurrentUser(): Observable<LoggedInUser>;
function getCurrentUser(
opts: CurrentUserWithResponseOption
): Observable<UnauthenticatedUser>;
): Observable<Session>;
function getCurrentUser(
opts: CurrentUserWithoutResponseOption
): Observable<LoggedInUser>;
function getCurrentUser(
opts: CurrentUserOptions = { includeAuthStatus: false }
): Observable<LoggedInUser | UnauthenticatedUser> {
): Observable<LoggedInUser | Session> {
if (lastFetchTimeMillis < Date.now() - 1000 * 60) {
refetchCurrentUser();
}
Expand All @@ -72,31 +73,32 @@ function getCurrentUser(
tap(setUserLanguage),
map((r) => (opts.includeAuthStatus ? r : r.user)),
filter(Boolean)
) as Observable<LoggedInUser | UnauthenticatedUser>;
) as Observable<LoggedInUser | Session>;
}

function setUserLanguage(data: LoggedInUserData) {
if (data?.user?.userProperties?.defaultLocale) {
const locale = data.user.userProperties.defaultLocale;
const htmlLang = document.documentElement.getAttribute("lang");
export { getCurrentUser };

function setUserLanguage(data: Session) {
const locale = data?.user?.userProperties?.defaultLocale ?? data.locale;
const htmlLang = document.documentElement.getAttribute("lang");

if (locale !== htmlLang) {
document.documentElement.setAttribute("lang", locale);
}
if (locale !== htmlLang) {
document.documentElement.setAttribute("lang", locale);
}
}

function userHasPrivilege(requiredPrivilege: string, user: LoggedInUser) {
function userHasPrivilege(
requiredPrivilege: string,
user: { privileges: Array<Privilege> }
) {
return user.privileges.find((p) => requiredPrivilege === p.display);
}

function isSuperUser(user: LoggedInUser) {
function isSuperUser(user: { roles: Array<Role> }) {
const superUserRole = "System Developer";
return user.roles.find((role) => role.display === superUserRole);
}

export { getCurrentUser };

/**
* The `refetchCurrentUser` function causes a network request to redownload
* the user. All subscribers to the current user will be notified of the
Expand Down Expand Up @@ -124,7 +126,10 @@ export function refetchCurrentUser() {
);
}

export function userHasAccess(requiredPrivilege: string, user: LoggedInUser) {
export function userHasAccess(
requiredPrivilege: string,
user: { privileges: Array<Privilege>; roles: Array<Role> }
) {
return userHasPrivilege(requiredPrivilege, user) || isSuperUser(user);
}

Expand All @@ -140,8 +145,8 @@ export function getLoggedInUser() {
export function getSessionLocation() {
return new Promise<SessionLocation | undefined>((res, rej) => {
const sub = getCurrentUser({ includeAuthStatus: true }).subscribe(
(user) => {
res(user.sessionLocation);
(session) => {
res(session.sessionLocation);
sub.unsubscribe();
},
rej
Expand All @@ -161,5 +166,6 @@ export async function setSessionLocation(
},
signal: abortController.signal,
});

refetchCurrentUser();
}
8 changes: 2 additions & 6 deletions packages/framework/esm-api/src/types/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { LoggedInUser, UnauthenticatedUser } from "./user-resource";
import { Session } from "./user-resource";

export interface FetchResponse<T = any> extends Response {
data: T;
}

export type LoggedInUserData = UnauthenticatedUser & {
user?: LoggedInUser;
};

export interface LoggedInUserFetchResponse extends FetchResponse {
data: LoggedInUserData;
data: Session;
}
22 changes: 0 additions & 22 deletions packages/framework/esm-api/src/types/openmrs-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,3 @@ export interface OpenmrsResource {
display?: string;
[anythingElse: string]: any;
}

export interface SessionUser {
allowedLocales: Array<string>;
authenticated: boolean;
locale: string;
sessionId: string;
user: User;
currentProvider: { uuid: string; identifier: string };
sessionLocation: any | null;
}

export interface User {
display: string;
link: Array<string>;
person: any;
priviliges: any;
resourceVersion: any;
roles: Array<any>;
userProperties: any;
username: string;
uuid: string;
}
21 changes: 12 additions & 9 deletions packages/framework/esm-api/src/types/user-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ export interface CurrentUserWithoutResponseOption extends CurrentUserOptions {
includeAuthStatus: false;
}

export interface Session {
allowedLocales?: Array<string>;
authenticated: boolean;
locale?: string;
sessionId: string;
user?: LoggedInUser;
currentProvider?: { uuid: string; identifier: string };
sessionLocation?: SessionLocation;
}

export interface LoggedInUser {
uuid: string;
display: string;
username: string;
systemId: string;
userProperties: any;
userProperties: { [key: string]: any } | null;
person: Person;
privileges: Array<Privilege>;
roles: Array<Role>;
Expand All @@ -25,13 +35,6 @@ export interface LoggedInUser {
[anythingElse: string]: any;
}

export interface UnauthenticatedUser {
sessionId: string;
authenticated: boolean;
user?: LoggedInUser;
sessionLocation?: SessionLocation;
}

export interface SessionLocation {
uuid: string;
display: string;
Expand All @@ -47,7 +50,7 @@ export interface Person {
export interface Privilege {
uuid: string;
display: string;
links: Array<any>;
links?: Array<any>;
}

export interface Role {
Expand Down
Loading

0 comments on commit 012fdee

Please sign in to comment.