Skip to content
Closed
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
2 changes: 2 additions & 0 deletions src/common/authGroups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Exact group-name checks, kept free of UI imports so the Node unit tests can load them.
export const hasAuthGroup = (user, groupName) => Boolean(user?.auth_groups?.includes(groupName));
24 changes: 2 additions & 22 deletions src/common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import {
} from 'lodash';
import {
DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT, OCL_SERVERS_GROUP, OCL_FHIR_SERVERS_GROUP, HAPI_FHIR_SERVERS_GROUP,
OPENMRS_URL, DEFAULT_FHIR_SERVER_FOR_LOCAL_ID, OPERATIONS_PANEL_GROUP
OPENMRS_URL, DEFAULT_FHIR_SERVER_FOR_LOCAL_ID
} from './constants';
import APIService from '../services/APIService';
import GAService from '../services/GAService';
import { ensureIdToken } from './ssoSession';
export { hasAuthGroup } from './authGroups';
import { SERVER_CONFIGS } from './serverConfigs';
import { legacyHashRoute, isSameSitePath } from './history';

Expand Down Expand Up @@ -453,27 +454,6 @@ export const getFHIRServerConfigFromCurrentContext = () => {
return getLocalFHIRServerConfig() || getDefaultFHIRServerConfig();
}

export const canSwitchServer = () => {
const user = getCurrentUser();

return Boolean(
getSelectedServerConfig() ||
get(user, 'is_superuser') ||
hasAuthGroup(user, 'server')
);
}

export const hasAuthGroup = (user, groupName) => Boolean(find(user?.auth_groups, group => group.includes(groupName)))

export const canViewOperationsPanel = () => {
const user = getCurrentUser()

return Boolean(
get(user, 'is_staff') ||
hasAuthGroup(user, OPERATIONS_PANEL_GROUP)
)
}

export const isFHIRServer = () => get(getAppliedServerConfig(), 'type') === 'fhir';

export const isConcept = uri => Boolean(uri.match('/concepts/'));
Expand Down
3 changes: 2 additions & 1 deletion src/components/map-projects/MapProject.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ import { OperationsContext } from '../app/LayoutContext';
import APIService, { isTransientNetworkError, retryWithBackoff } from '../../services/APIService';
import { buildAttributionHeaders, buildConfigSnapshot, summarizeRunCompletion, matchesOnOCL } from '../../services/attribution'
import { CAPACITY_LIMIT, RATE_LIMIT, CAPACITY_WAIT_CAP_MS, HEAVY_REQUEST_TIMEOUT_MS, LIGHT_REQUEST_TIMEOUT_MS, createCapacityGate, createLimiter, isRetryableError, requestWithCapacityRetry, sleepUnlessCancelled, untilCancelled } from '../../services/capacity'
import { highlightTexts, dropVersion, getCurrentUser, hasAuthGroup, hasCapability, getMapperPreview, getNewProjectBlockReason, downloadObject, currentUserToken, refreshCurrentUserCapabilitiesCache } from '../../common/utils';
import { hasAuthGroup } from '../../common/authGroups';
import { highlightTexts, dropVersion, getCurrentUser, hasCapability, getMapperPreview, getNewProjectBlockReason, downloadObject, currentUserToken, refreshCurrentUserCapabilitiesCache } from '../../common/utils';
import { WHITE, SURFACE_COLORS, TEXT_GRAY } from '../../common/colors';

import { useDoubleClick } from '../common/useDoubleClick'
Expand Down
2 changes: 2 additions & 0 deletions src/components/map-projects/__tests__/aiVisibility.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ test('getAIAssistantChoices: non-staff core, early-access and unlimited-AI users
const localeOnly = { canSelectAIModel: false, canSetAIOutputLocale: true }
assert.deepEqual(getAIAssistantChoices({ is_staff: false, auth_groups: ['core_user'] }), localeOnly)
assert.deepEqual(getAIAssistantChoices({ auth_groups: ['early_access'] }), localeOnly)
assert.deepEqual(getAIAssistantChoices({ auth_groups: ['pro'] }), localeOnly)
assert.deepEqual(getAIAssistantChoices({ auth_groups: ['mapper-approved'] }), { canSelectAIModel: false, canSetAIOutputLocale: false })
assert.deepEqual(getAIAssistantChoices({ auth_groups: ['preview'] }, { unlimitedAICalls: true }), localeOnly)
})

Expand Down
9 changes: 9 additions & 0 deletions src/components/map-projects/__tests__/requestLimits.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ test('getRequestLimits: early access, 10 rows × 5 requests', () => {
assert.deepEqual(EARLY_ACCESS, { batchSize: 10, concurrentRequests: 5, capped: true })
})

test('getRequestLimits: pro gets early access limits (ocl_online#517)', () => {
assert.deepEqual(getRequestLimits({ auth_groups: ['pro'] }), EARLY_ACCESS)
assert.equal(hasFullRequestLimits({ auth_groups: ['pro'] }), false)
})

test('getRequestLimits: group names match exactly, so mapper-approved is not pro', () => {
assert.deepEqual(getRequestLimits({ auth_groups: ['mapper-approved'] }), PREVIEW)
})

test('getRequestLimits: preview, 10 rows × 2 requests', () => {
assert.deepEqual(PREVIEW, { batchSize: 10, concurrentRequests: 2, capped: true })
})
Expand Down
9 changes: 5 additions & 4 deletions src/components/map-projects/aiVisibility.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { hasAuthGroup } from '../../common/authGroups.js'
import { isEarlyAccessUser } from './requestLimits.js'

// An AI recommendation's internals are staff-only (ocl_online#254): the model,
// the prompt template and its URI, and the raw JSON that carries them. Core,
// early-access and preview users see the assessment and the candidates only.
export const canSeeAIInternals = user => Boolean(user?.is_staff || user?.is_superuser)

const inAuthGroup = (user, group) => Boolean(user?.auth_groups?.some(name => name.includes(group)))

// What a user can choose for the OCL AI Assistant (ocl_online#259):
// - the model and the prompt template: staff only, like seeing them. The AI
// Assistant honours a model override from staff only, so everyone else runs
// the project's template on that template's default model.
// - the output language: staff, core, early-access and unlimited-AI users.
// - the output language: staff, core, early-access (and pro, ocl_online#517) and unlimited-AI users.
export const getAIAssistantChoices = (user, { unlimitedAICalls = false } = {}) => ({
canSelectAIModel: canSeeAIInternals(user),
canSetAIOutputLocale: Boolean(
canSeeAIInternals(user) || unlimitedAICalls ||
inAuthGroup(user, 'core_user') || inAuthGroup(user, 'early_access')
hasAuthGroup(user, 'core_user') || isEarlyAccessUser(user)
),
})

Expand Down
9 changes: 6 additions & 3 deletions src/components/map-projects/requestLimits.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { hasAuthGroup } from '../../common/authGroups.js'

/**
* How many rows go in one matching request, and how many requests an
* algorithm keeps in flight, during Auto Match (ocl_online#274).
Expand All @@ -19,17 +21,18 @@ const FULL_LIMITS = { batchSize: 1000, concurrentRequests: 50, capped: false }
const EARLY_ACCESS_LIMITS = { batchSize: 10, concurrentRequests: 5, capped: true }
const PREVIEW_LIMITS = { batchSize: 10, concurrentRequests: 2, capped: true }

const inAuthGroup = (user, group) => Boolean(user?.auth_groups?.some(name => name.includes(group)))
// Pro gets early access's limits and choices (ocl_online#517).
export const isEarlyAccessUser = user => hasAuthGroup(user, 'early_access') || hasAuthGroup(user, 'pro')

export const hasFullRequestLimits = user => Boolean(user?.is_staff || user?.is_superuser || inAuthGroup(user, 'core_user'))
export const hasFullRequestLimits = user => Boolean(user?.is_staff || user?.is_superuser || hasAuthGroup(user, 'core_user'))

// The most rows per request, and requests in flight, a user may type in the
// form, by their highest tier. capped: false for core users and staff, whose
// saved settings run as they are.
export const getRequestLimits = user => {
if(hasFullRequestLimits(user))
return FULL_LIMITS
if(inAuthGroup(user, 'early_access'))
if(isEarlyAccessUser(user))
return EARLY_ACCESS_LIMITS
return PREVIEW_LIMITS
}
Expand Down
Loading