@openstax/ts-utils 1.4.1 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/config/envConfig.js +12 -3
- package/dist/cjs/services/accountsGateway/index.d.ts +77 -0
- package/dist/cjs/services/accountsGateway/index.js +110 -0
- package/dist/cjs/services/apiGateway/index.d.ts +3 -0
- package/dist/cjs/services/authProvider/browser.d.ts +2 -2
- package/dist/cjs/services/authProvider/browser.js +2 -2
- package/dist/cjs/services/authProvider/subrequest.d.ts +2 -2
- package/dist/cjs/services/authProvider/subrequest.js +2 -2
- package/dist/cjs/services/lrsGateway/xapiUtils.d.ts +32 -0
- package/dist/cjs/services/lrsGateway/xapiUtils.js +61 -0
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/config/envConfig.js +12 -3
- package/dist/esm/services/accountsGateway/index.d.ts +77 -0
- package/dist/esm/services/accountsGateway/index.js +103 -0
- package/dist/esm/services/apiGateway/index.d.ts +3 -0
- package/dist/esm/services/authProvider/browser.d.ts +2 -2
- package/dist/esm/services/authProvider/browser.js +2 -2
- package/dist/esm/services/authProvider/subrequest.d.ts +2 -2
- package/dist/esm/services/authProvider/subrequest.js +2 -2
- package/dist/esm/services/lrsGateway/xapiUtils.d.ts +32 -0
- package/dist/esm/services/lrsGateway/xapiUtils.js +55 -0
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +2 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.envConfig = exports.ENV_BUILD_CONFIGS = void 0;
|
|
4
|
-
const
|
|
5
|
-
const guards_1 = require("../guards");
|
|
4
|
+
const _1 = require(".");
|
|
6
5
|
/**
|
|
7
6
|
* A list of environment variables that were requested at build time. Used by webpack to
|
|
8
7
|
* capture build-time environment variables values.
|
|
@@ -35,7 +34,17 @@ const envConfig = (name, type = 'build', defaultValue) => {
|
|
|
35
34
|
// - https://github.com/webpack/webpack/issues/14800
|
|
36
35
|
// - https://github.com/webpack/webpack/issues/5392
|
|
37
36
|
const envs = { ...process.env, ...(typeof __PROCESS_ENV !== 'undefined' ? __PROCESS_ENV : {}) };
|
|
38
|
-
|
|
37
|
+
if (envs[name] === undefined) {
|
|
38
|
+
if (defaultValue === undefined) {
|
|
39
|
+
throw new Error(`expected to find environment variable with name: ${name}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return (0, _1.resolveConfigValue)(defaultValue);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return envs[name];
|
|
47
|
+
}
|
|
39
48
|
};
|
|
40
49
|
};
|
|
41
50
|
exports.envConfig = envConfig;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { GenericFetch } from '../../fetch';
|
|
3
|
+
import { JsonCompatibleStruct } from '../../routing';
|
|
4
|
+
import { ApiUser } from '../authProvider';
|
|
5
|
+
import { Logger } from '../logger';
|
|
6
|
+
export declare type Config = {
|
|
7
|
+
accountsBase: string;
|
|
8
|
+
accountsAuthToken: string;
|
|
9
|
+
};
|
|
10
|
+
interface Initializer<C> {
|
|
11
|
+
configSpace?: C;
|
|
12
|
+
fetch: GenericFetch;
|
|
13
|
+
}
|
|
14
|
+
export declare type FindUserPayload = ({
|
|
15
|
+
external_id: string;
|
|
16
|
+
} | {
|
|
17
|
+
uuid: string;
|
|
18
|
+
}) & {
|
|
19
|
+
sso?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare type FindOrCreateUserPayload = {
|
|
22
|
+
external_id: string;
|
|
23
|
+
email?: string;
|
|
24
|
+
already_verified?: boolean;
|
|
25
|
+
first_name?: string;
|
|
26
|
+
last_name?: string;
|
|
27
|
+
full_name?: string;
|
|
28
|
+
salesforce_contact_id?: string;
|
|
29
|
+
faculty_status?: string;
|
|
30
|
+
role?: string;
|
|
31
|
+
school_type?: string;
|
|
32
|
+
is_test?: boolean;
|
|
33
|
+
sso?: string;
|
|
34
|
+
};
|
|
35
|
+
export declare type FindOrCreateUserResponse = {
|
|
36
|
+
id: number;
|
|
37
|
+
uuid: string;
|
|
38
|
+
external_ids: string[];
|
|
39
|
+
is_test: boolean;
|
|
40
|
+
sso: string;
|
|
41
|
+
};
|
|
42
|
+
export declare type FindUserResponse = (FindOrCreateUserResponse & {
|
|
43
|
+
external_ids: string[];
|
|
44
|
+
}) | undefined;
|
|
45
|
+
export declare type LinkUserPayload = {
|
|
46
|
+
userId: number;
|
|
47
|
+
externalId: string;
|
|
48
|
+
};
|
|
49
|
+
export declare type LinkUserResponse = {
|
|
50
|
+
user_id: number;
|
|
51
|
+
external_id: string;
|
|
52
|
+
};
|
|
53
|
+
export declare type SearchUsersPayload = {
|
|
54
|
+
q: string;
|
|
55
|
+
order_by?: string;
|
|
56
|
+
};
|
|
57
|
+
export declare type SearchUsersResponse = {
|
|
58
|
+
items: Array<ApiUser & {
|
|
59
|
+
external_ids: string[];
|
|
60
|
+
} & JsonCompatibleStruct>;
|
|
61
|
+
total_count: number;
|
|
62
|
+
};
|
|
63
|
+
export declare const accountsGateway: <C extends string = "accounts">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
64
|
+
accountsBase: import("../../config").ConfigValueProvider<string>;
|
|
65
|
+
accountsAuthToken: import("../../config").ConfigValueProvider<string>;
|
|
66
|
+
}; }) => {
|
|
67
|
+
findOrCreateUser: (body: FindOrCreateUserPayload) => Promise<FindOrCreateUserResponse>;
|
|
68
|
+
findUser: (body: FindUserPayload) => Promise<FindUserResponse>;
|
|
69
|
+
getUser: (token: string) => Promise<ApiUser & JsonCompatibleStruct>;
|
|
70
|
+
linkUser: (body: LinkUserPayload) => Promise<LinkUserResponse>;
|
|
71
|
+
mapUserUuids: <T>(userUuidsMap: {
|
|
72
|
+
[uuid: string]: T;
|
|
73
|
+
}, logger: Logger, platformId?: string | undefined) => Promise<[string, T][]>;
|
|
74
|
+
searchUsers: (payload: SearchUsersPayload) => Promise<SearchUsersResponse>;
|
|
75
|
+
};
|
|
76
|
+
export declare type AccountsGateway = ReturnType<ReturnType<typeof accountsGateway>>;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.accountsGateway = void 0;
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
8
|
+
const query_string_1 = __importDefault(require("query-string"));
|
|
9
|
+
const config_1 = require("../../config");
|
|
10
|
+
const guards_1 = require("../../guards");
|
|
11
|
+
const routing_1 = require("../../routing");
|
|
12
|
+
const logger_1 = require("../logger");
|
|
13
|
+
class ApiError extends Error {
|
|
14
|
+
constructor(message, status) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.status = status;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const accountsGateway = (initializer) => (configProvider) => {
|
|
20
|
+
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'accounts')];
|
|
21
|
+
const accountsBase = (0, config_1.resolveConfigValue)(config.accountsBase);
|
|
22
|
+
const accountsAuthToken = (0, config_1.resolveConfigValue)(config.accountsAuthToken);
|
|
23
|
+
const request = async (method, path, options, statuses = [200, 201]) => {
|
|
24
|
+
const host = (await accountsBase).replace(/\/+$/, '');
|
|
25
|
+
const url = `${host}/api/${path}`;
|
|
26
|
+
const config = {
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: `Bearer ${options.token || await accountsAuthToken}`,
|
|
29
|
+
},
|
|
30
|
+
method,
|
|
31
|
+
};
|
|
32
|
+
if (options.body) {
|
|
33
|
+
config.body = JSON.stringify(options.body);
|
|
34
|
+
}
|
|
35
|
+
const response = await initializer.fetch(url, config);
|
|
36
|
+
if (!statuses.includes(response.status)) {
|
|
37
|
+
throw new ApiError(`Received unexpected status code ${response.status} for Accounts API call: ${method} ${url}`, response.status);
|
|
38
|
+
}
|
|
39
|
+
return response.json();
|
|
40
|
+
};
|
|
41
|
+
const findOrCreateUser = async (body) => request(routing_1.METHOD.POST, 'user/find-or-create', { body });
|
|
42
|
+
const findUser = async (body) => {
|
|
43
|
+
try {
|
|
44
|
+
return await request(routing_1.METHOD.POST, 'user/find', { body });
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const getUser = async (token) => request(routing_1.METHOD.GET, 'user', { token });
|
|
56
|
+
const linkUser = async (body) => request(routing_1.METHOD.POST, 'user/external-ids', {
|
|
57
|
+
body: {
|
|
58
|
+
external_id: body.externalId,
|
|
59
|
+
user_id: body.userId,
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const searchUsers = async (payload) => request(routing_1.METHOD.GET, `users?${query_string_1.default.stringify(payload)}`, {});
|
|
63
|
+
const getPlatformUserId = (externalIds, platformId) => {
|
|
64
|
+
for (const externalId of externalIds) {
|
|
65
|
+
const [userPlatformId, userId] = externalId.split('/', 2);
|
|
66
|
+
if (userPlatformId === platformId) {
|
|
67
|
+
return userId;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
/*
|
|
72
|
+
* If a platformId is given, returns an array where
|
|
73
|
+
* the first element is the user id from the platform
|
|
74
|
+
* and the second is the value from the map
|
|
75
|
+
* Otherwise, returns an array where
|
|
76
|
+
* the first element is the user's full_name
|
|
77
|
+
* and the second is the value from the map
|
|
78
|
+
*/
|
|
79
|
+
const mapUserUuids = async (userUuidsMap, logger, platformId) => {
|
|
80
|
+
const results = [];
|
|
81
|
+
// Accounts will not return any results if this search returns more than 10 users
|
|
82
|
+
const chunkedUuids = (0, lodash_1.chunk)(Object.keys(userUuidsMap), 10);
|
|
83
|
+
await Promise.all(chunkedUuids.map(async (uuids) => {
|
|
84
|
+
const { items } = await searchUsers({ q: uuids.map((uuid) => `uuid:${uuid}`).join(' ') });
|
|
85
|
+
const accountsUuids = items.map((user) => user.uuid);
|
|
86
|
+
if (!(0, lodash_1.isEqual)(accountsUuids.sort(), uuids.sort())) {
|
|
87
|
+
logger.logEvent(logger_1.Level.Warn, {
|
|
88
|
+
message: 'Unexpected Accounts user search results',
|
|
89
|
+
uuids,
|
|
90
|
+
accountsUuids,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
items.forEach((user) => {
|
|
94
|
+
const userId = platformId ? getPlatformUserId(user.external_ids, platformId) : user.full_name;
|
|
95
|
+
if (!userId) {
|
|
96
|
+
const missing = platformId ? 'external_id matching the given platformId' : 'full_name';
|
|
97
|
+
logger.logEvent(logger_1.Level.Warn, {
|
|
98
|
+
message: `Accounts user has no ${missing}`,
|
|
99
|
+
accountsUuid: user.uuid,
|
|
100
|
+
platformId,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
results.push([userId || 'N/A', userUuidsMap[user.uuid]]);
|
|
104
|
+
});
|
|
105
|
+
}));
|
|
106
|
+
return results;
|
|
107
|
+
};
|
|
108
|
+
return { findOrCreateUser, findUser, getUser, linkUser, mapUserUuids, searchUsers };
|
|
109
|
+
};
|
|
110
|
+
exports.accountsGateway = accountsGateway;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Headers } from 'node-fetch';
|
|
1
2
|
import { ConfigProviderForConfig } from '../../config';
|
|
2
3
|
import { ConfigForFetch, GenericFetch, Response } from '../../fetch';
|
|
3
4
|
import { AnyRoute, ApiResponse, OutputForRoute, ParamsForRoute, PayloadForRoute, QueryParams } from '../../routing';
|
|
@@ -24,11 +25,13 @@ interface AcceptStatus<Ro> {
|
|
|
24
25
|
<S extends number[]>(...args: S): ApiClientResponse<any>;
|
|
25
26
|
}
|
|
26
27
|
declare type UnsafeApiClientResponse<Ro> = {
|
|
28
|
+
headers: Headers;
|
|
27
29
|
load: () => Promise<any>;
|
|
28
30
|
status: number;
|
|
29
31
|
acceptStatus: AcceptStatus<Ro>;
|
|
30
32
|
};
|
|
31
33
|
declare type ApiClientResponse<Ro> = Ro extends any ? {
|
|
34
|
+
headers: Headers;
|
|
32
35
|
status: TResponseStatus<Ro>;
|
|
33
36
|
load: () => Promise<TResponsePayload<Ro>>;
|
|
34
37
|
} : never;
|
|
@@ -2,7 +2,7 @@ import { ConfigProviderForConfig } from '../../config';
|
|
|
2
2
|
import { FetchConfig, GenericFetch } from '../../fetch';
|
|
3
3
|
import { User } from '.';
|
|
4
4
|
declare type Config = {
|
|
5
|
-
|
|
5
|
+
accountsBase: string;
|
|
6
6
|
};
|
|
7
7
|
interface Initializer<C> {
|
|
8
8
|
configSpace?: C;
|
|
@@ -28,7 +28,7 @@ export interface Window {
|
|
|
28
28
|
removeEventListener: (event: 'message', callback: EventHandler) => void;
|
|
29
29
|
}
|
|
30
30
|
export declare const browserAuthProvider: <C extends string = "auth">({ window, configSpace }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
31
|
-
|
|
31
|
+
accountsBase: import("../../config").ConfigValueProvider<string>;
|
|
32
32
|
}; }) => {
|
|
33
33
|
/**
|
|
34
34
|
* adds auth parameters to the url. this is only safe to use when using javascript to navigate
|
|
@@ -7,7 +7,7 @@ const guards_1 = require("../../guards");
|
|
|
7
7
|
const embeddedAuthProvider_1 = require("./utils/embeddedAuthProvider");
|
|
8
8
|
const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
9
9
|
const config = configProvider[(0, guards_1.ifDefined)(configSpace, 'auth')];
|
|
10
|
-
const
|
|
10
|
+
const accountsBase = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.accountsBase));
|
|
11
11
|
const queryString = window.location.search;
|
|
12
12
|
const queryKey = 'auth';
|
|
13
13
|
const authQuery = new URLSearchParams(queryString).get(queryKey);
|
|
@@ -71,7 +71,7 @@ const browserAuthProvider = ({ window, configSpace }) => (configProvider) => {
|
|
|
71
71
|
* requests user identity from accounts api using given token or cookie
|
|
72
72
|
*/
|
|
73
73
|
const getFetchUser = async () => {
|
|
74
|
-
const response = await window.fetch((await
|
|
74
|
+
const response = await window.fetch((await accountsBase()).replace(/\/+$/, '') + '/api/user', getAuthorizedFetchConfigFromData(userData));
|
|
75
75
|
if (response.status === 200) {
|
|
76
76
|
return { ...userData, user: await response.json() };
|
|
77
77
|
}
|
|
@@ -3,7 +3,7 @@ import { GenericFetch } from '../../fetch';
|
|
|
3
3
|
import { CookieAuthProvider } from '.';
|
|
4
4
|
declare type Config = {
|
|
5
5
|
cookieName: string;
|
|
6
|
-
|
|
6
|
+
accountsBase: string;
|
|
7
7
|
};
|
|
8
8
|
interface Initializer<C> {
|
|
9
9
|
configSpace?: C;
|
|
@@ -11,6 +11,6 @@ interface Initializer<C> {
|
|
|
11
11
|
}
|
|
12
12
|
export declare const subrequestAuthProvider: <C extends string = "subrequest">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
13
|
cookieName: import("../../config").ConfigValueProvider<string>;
|
|
14
|
-
|
|
14
|
+
accountsBase: import("../../config").ConfigValueProvider<string>;
|
|
15
15
|
}; }) => CookieAuthProvider;
|
|
16
16
|
export {};
|
|
@@ -8,7 +8,7 @@ const _1 = require(".");
|
|
|
8
8
|
const subrequestAuthProvider = (initializer) => (configProvider) => {
|
|
9
9
|
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'subrequest')];
|
|
10
10
|
const cookieName = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.cookieName));
|
|
11
|
-
const
|
|
11
|
+
const accountsBase = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.accountsBase));
|
|
12
12
|
return ({ request, profile }) => {
|
|
13
13
|
let user;
|
|
14
14
|
const getAuthorizedFetchConfig = profile.track('getAuthorizedFetchConfig', () => async () => {
|
|
@@ -23,7 +23,7 @@ const subrequestAuthProvider = (initializer) => (configProvider) => {
|
|
|
23
23
|
if (!token) {
|
|
24
24
|
return undefined;
|
|
25
25
|
}
|
|
26
|
-
return p.trackFetch(initializer.fetch)(await
|
|
26
|
+
return p.trackFetch(initializer.fetch)((await accountsBase()).replace(/\/+$/, '') + '/api/user', { headers })
|
|
27
27
|
.then(response => response.json());
|
|
28
28
|
});
|
|
29
29
|
return {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AccountsGateway } from '../accountsGateway';
|
|
2
|
+
import { AuthProvider } from '../authProvider';
|
|
3
|
+
import { Logger } from '../logger';
|
|
4
|
+
import { LrsGateway } from '.';
|
|
5
|
+
export interface Grade {
|
|
6
|
+
scoreGiven: number;
|
|
7
|
+
scoreMaximum: number;
|
|
8
|
+
comment?: string;
|
|
9
|
+
activityProgress: 'Initialized' | 'Started' | 'inProgress' | 'Submitted' | 'Completed';
|
|
10
|
+
gradingProgress: 'FullyGraded' | 'Pending' | 'PendingManual' | 'Failed' | 'NotReady';
|
|
11
|
+
userId: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const getRegistrationAttemptInfo: (lrs: LrsGateway, registration: string, options?: {
|
|
14
|
+
anyUser?: boolean | undefined;
|
|
15
|
+
} | undefined) => Promise<{
|
|
16
|
+
[key: string]: import("./attempt-utils").ActivityState;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const getCurrentGrade: (services: {
|
|
19
|
+
lrs: LrsGateway;
|
|
20
|
+
ltiAuthProvider: AuthProvider;
|
|
21
|
+
}, registration: string, options?: {
|
|
22
|
+
scoreMaximum?: number | undefined;
|
|
23
|
+
userId?: string | undefined;
|
|
24
|
+
} | undefined) => Promise<Grade | null>;
|
|
25
|
+
export declare const getAllGradesForAssignment: (services: {
|
|
26
|
+
accountsGateway: AccountsGateway;
|
|
27
|
+
lrs: LrsGateway;
|
|
28
|
+
logger: Logger;
|
|
29
|
+
}, registration: string, options?: {
|
|
30
|
+
platformId?: string | undefined;
|
|
31
|
+
scoreMaximum?: number | undefined;
|
|
32
|
+
} | undefined) => Promise<Grade[]>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAllGradesForAssignment = exports.getCurrentGrade = exports.getRegistrationAttemptInfo = void 0;
|
|
4
|
+
const __1 = require("../..");
|
|
5
|
+
const attempt_utils_1 = require("./attempt-utils");
|
|
6
|
+
const getRegistrationAttemptInfo = async (lrs, registration, options) => {
|
|
7
|
+
const allStatements = await lrs.getAllXapiStatements({ ...options, registration, ensureSync: true });
|
|
8
|
+
// Partition statements for each user
|
|
9
|
+
const statementsPerUser = {};
|
|
10
|
+
allStatements.forEach((statement) => {
|
|
11
|
+
var _a;
|
|
12
|
+
// If we ever support accounts from different statement.actor.account.homePage, this method may need changes
|
|
13
|
+
// (unless we can guarantee the statement.actor.account.name are unique)
|
|
14
|
+
statementsPerUser[_a = statement.actor.account.name] || (statementsPerUser[_a] = []);
|
|
15
|
+
statementsPerUser[statement.actor.account.name].push(statement);
|
|
16
|
+
});
|
|
17
|
+
const result = {};
|
|
18
|
+
for (const [userUuid, userStatements] of Object.entries(statementsPerUser)) {
|
|
19
|
+
result[userUuid] = (0, attempt_utils_1.resolveAttemptInfo)(userStatements);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
exports.getRegistrationAttemptInfo = getRegistrationAttemptInfo;
|
|
24
|
+
// generates a payload that can be sent to the LMS, documentation here:
|
|
25
|
+
// lti: http://www.imsglobal.org/spec/lti-ags/v2p0#score-publish-service
|
|
26
|
+
// ltijs: https://cvmcosta.me/ltijs/#/grading
|
|
27
|
+
const getInfoGrade = (info, userId, maxScore) => {
|
|
28
|
+
var _a;
|
|
29
|
+
const completed = info.currentAttemptCompleted;
|
|
30
|
+
const { raw, scaled, max } = ((_a = completed === null || completed === void 0 ? void 0 : completed.result) === null || _a === void 0 ? void 0 : _a.score) || {};
|
|
31
|
+
const scoreMaximum = maxScore !== null && maxScore !== void 0 ? maxScore : 100;
|
|
32
|
+
const scoreGiven = raw && max
|
|
33
|
+
? scoreMaximum / max * raw
|
|
34
|
+
: scaled
|
|
35
|
+
? scaled * scoreMaximum
|
|
36
|
+
: 0;
|
|
37
|
+
return {
|
|
38
|
+
userId,
|
|
39
|
+
activityProgress: completed ? 'Completed' : 'Started',
|
|
40
|
+
gradingProgress: completed ? 'FullyGraded' : 'NotReady',
|
|
41
|
+
scoreMaximum,
|
|
42
|
+
scoreGiven: (0, __1.roundToPrecision)(scoreGiven, -2),
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const getCurrentGrade = async (services, registration, options) => {
|
|
46
|
+
var _a;
|
|
47
|
+
const user = await services.ltiAuthProvider.getUser();
|
|
48
|
+
if (!user) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const infoPerUser = await (0, exports.getRegistrationAttemptInfo)(services.lrs, registration);
|
|
52
|
+
const userInfo = infoPerUser[user.uuid];
|
|
53
|
+
return getInfoGrade(userInfo !== null && userInfo !== void 0 ? userInfo : (0, attempt_utils_1.resolveAttemptInfo)([]), (_a = options === null || options === void 0 ? void 0 : options.userId) !== null && _a !== void 0 ? _a : user.uuid, options === null || options === void 0 ? void 0 : options.scoreMaximum);
|
|
54
|
+
};
|
|
55
|
+
exports.getCurrentGrade = getCurrentGrade;
|
|
56
|
+
const getAllGradesForAssignment = async (services, registration, options) => {
|
|
57
|
+
const infoPerUserUuid = await (0, exports.getRegistrationAttemptInfo)(services.lrs, registration, { anyUser: true });
|
|
58
|
+
const mappedResults = await services.accountsGateway.mapUserUuids(infoPerUserUuid, services.logger, options === null || options === void 0 ? void 0 : options.platformId);
|
|
59
|
+
return mappedResults.map(([userId, userInfo]) => getInfoGrade(userInfo, userId, options === null || options === void 0 ? void 0 : options.scoreMaximum));
|
|
60
|
+
};
|
|
61
|
+
exports.getAllGradesForAssignment = getAllGradesForAssignment;
|