studiokit-scaffolding-js 5.2.0-next.2.7 → 5.2.0-next.2.9

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.
@@ -96,7 +96,7 @@ export declare class UserRoles extends Component<UserRolesProps, UserRolesState>
96
96
  textForRole: (role: string, lowercase?: boolean) => string;
97
97
  singularArticleForRole: (role: string) => string;
98
98
  addUserRoles: (identifiers: string[], role: string) => void;
99
- didAdd: (data?: FetchErrorData | AddBusinessModel | undefined) => void;
99
+ didAdd: (data: AddBusinessModel | FetchErrorData | null) => void;
100
100
  updateUserRole: (userRoleToUpdate: UserRole, newRole: string) => void;
101
101
  didUpdate: (isSuccess: boolean) => void;
102
102
  alertRemoveUserRole: (userRoleToRemove: UserRole) => void;
@@ -2,7 +2,6 @@ import { Action } from 'redux';
2
2
  import { CasV1LoginRequestBody, IdentityProvider } from '../../types';
3
3
  import { LocalLoginRequestBody } from '../../types/auth/LocalLoginRequestBody';
4
4
  import { OAuthToken, OAuthTokenOrNull } from '../../types/net';
5
- import { BaseModelFetchRequestAction } from './ModelAction';
6
5
  export declare enum AUTH_ACTION_TYPE {
7
6
  CAS_LOGIN_REQUESTED = "auth/CAS_LOGIN_REQUESTED",
8
7
  LOGIN_REQUESTED = "auth/LOGIN_REQUESTED",
@@ -43,12 +42,12 @@ export interface AuthIdentityProviderRequestAction extends Action<AUTH_IDENTITY_
43
42
  export declare enum AUTH_CAS_V1_LOGIN_REQUEST_ACTION_TYPE {
44
43
  CAS_V1_LOGIN_REQUEST = "auth/CAS_V1_LOGIN_REQUEST"
45
44
  }
46
- export interface AuthCasV1LoginRequestAction extends Omit<BaseModelFetchRequestAction<AUTH_CAS_V1_LOGIN_REQUEST_ACTION_TYPE>, 'modelName' | 'pathParams'> {
45
+ export interface AuthCasV1LoginRequestAction extends Action<AUTH_CAS_V1_LOGIN_REQUEST_ACTION_TYPE> {
47
46
  body: CasV1LoginRequestBody;
48
47
  }
49
48
  export declare enum AUTH_LOCAL_LOGIN_REQUEST_ACTION_TYPE {
50
49
  LOCAL_LOGIN_REQUEST = "auth/LOCAL_LOGIN_REQUEST"
51
50
  }
52
- export interface AuthLocalLoginRequestAction extends Omit<BaseModelFetchRequestAction<AUTH_LOCAL_LOGIN_REQUEST_ACTION_TYPE>, 'modelName' | 'pathParams'> {
51
+ export interface AuthLocalLoginRequestAction extends Action<AUTH_LOCAL_LOGIN_REQUEST_ACTION_TYPE> {
53
52
  body: LocalLoginRequestBody;
54
53
  }
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
2
  var __generator = (this && this.__generator) || function (thisArg, body) {
14
3
  var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
15
4
  return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
@@ -236,9 +225,16 @@ function credentialsLoginFlow(action, modelName) {
236
225
  return __generator(this, function (_a) {
237
226
  switch (_a.label) {
238
227
  case 0:
239
- modelFetchRequestAction = __assign(__assign({}, action), {
240
- // set required overrides
241
- type: actions_1.MODEL_FETCH_REQUEST_ACTION_TYPE.FETCH_REQUEST, modelName: modelName, noStore: true });
228
+ modelFetchRequestAction = {
229
+ // set required defaults
230
+ type: actions_1.MODEL_FETCH_REQUEST_ACTION_TYPE.FETCH_REQUEST,
231
+ modelName: modelName,
232
+ noStore: true,
233
+ // force no retry
234
+ noRetry: true,
235
+ // pass thru body
236
+ body: action.body
237
+ };
242
238
  return [4 /*yield*/, effects_1.call(loginFlow, modelFetchRequestAction)];
243
239
  case 1: return [2 /*return*/, _a.sent()];
244
240
  }
@@ -323,7 +319,7 @@ var getOAuthToken = function (modelName) {
323
319
  };
324
320
  exports.getOAuthToken = getOAuthToken;
325
321
  function authSaga(clientCredentialsParam, tokenPersistenceServiceParam, ticketProviderService, codeProviderService) {
326
- var casTicket, service, code, _a, casV1Action, localAction;
322
+ var casTicket, service, code, _a, casV1Action, localLoginAction;
327
323
  if (tokenPersistenceServiceParam === void 0) { tokenPersistenceServiceParam = tokenPersistenceService_1.tokenPersistenceService; }
328
324
  if (ticketProviderService === void 0) { ticketProviderService = ticketProviderService_1.ticketProviderService; }
329
325
  if (codeProviderService === void 0) { codeProviderService = codeProviderService_1.codeProviderService; }
@@ -381,10 +377,10 @@ function authSaga(clientCredentialsParam, tokenPersistenceServiceParam, ticketPr
381
377
  if (!!oauthToken) return [3 /*break*/, 16];
382
378
  return [4 /*yield*/, effects_1.race({
383
379
  casV1Action: effects_1.take(actions_1.AUTH_CAS_V1_LOGIN_REQUEST_ACTION_TYPE.CAS_V1_LOGIN_REQUEST),
384
- localAction: effects_1.take(actions_1.AUTH_LOCAL_LOGIN_REQUEST_ACTION_TYPE.LOCAL_LOGIN_REQUEST)
380
+ localLoginAction: effects_1.take(actions_1.AUTH_LOCAL_LOGIN_REQUEST_ACTION_TYPE.LOCAL_LOGIN_REQUEST)
385
381
  })];
386
382
  case 11:
387
- _a = _b.sent(), casV1Action = _a.casV1Action, localAction = _a.localAction;
383
+ _a = _b.sent(), casV1Action = _a.casV1Action, localLoginAction = _a.localLoginAction;
388
384
  return [4 /*yield*/, effects_1.put({ type: actions_1.AUTH_ACTION_TYPE.LOGIN_REQUESTED })];
389
385
  case 12:
390
386
  _b.sent();
@@ -394,8 +390,8 @@ function authSaga(clientCredentialsParam, tokenPersistenceServiceParam, ticketPr
394
390
  oauthToken = _b.sent();
395
391
  return [3 /*break*/, 16];
396
392
  case 14:
397
- if (!localAction) return [3 /*break*/, 16];
398
- return [4 /*yield*/, effects_1.call(localLoginFlow, localAction)];
393
+ if (!localLoginAction) return [3 /*break*/, 16];
394
+ return [4 /*yield*/, effects_1.call(localLoginFlow, localLoginAction)];
399
395
  case 15:
400
396
  oauthToken = _b.sent();
401
397
  _b.label = 16;
@@ -308,7 +308,7 @@ function modelFetch(modelFetchRequestAction) {
308
308
  // log to the console
309
309
  logger.error(error);
310
310
  didFail = true;
311
- // Do not continue to retry if the response is between 400-500 (except 408: request timeout)
311
+ // Do not retry if the response is between 400-500 (except 408: request timeout)
312
312
  if (errorData.status >= types_1.HTTP_STATUS_CODE.BAD_REQUEST &&
313
313
  errorData.status < types_1.HTTP_STATUS_CODE.INTERNAL_SERVER_ERROR &&
314
314
  errorData.status !== types_1.HTTP_STATUS_CODE.REQUEST_TIMEOUT) {
@@ -1,18 +1,18 @@
1
1
  import { SagaIterator } from '@redux-saga/core';
2
2
  import { AnyAction } from 'redux';
3
+ import { FetchErrorData } from '../../types';
3
4
  import { ModelFetchRequestAction } from '../actions';
4
- declare type HookFunction = (input: any) => void;
5
+ export declare type HookFunction<T = any> = (input: T | FetchErrorData | null) => void;
5
6
  export declare const matchesNoStoreAction: (incomingAction: AnyAction) => incomingAction is ModelFetchRequestAction;
6
7
  export declare const matchesFailedNoStoreHookAction: (incomingAction: AnyAction, noStoreAction: ModelFetchRequestAction) => boolean;
7
8
  export declare const takeMatchesFailedNoStoreHookAction: (noStoreAction: ModelFetchRequestAction) => (incomingAction: AnyAction) => boolean;
8
9
  export declare const matchesReceivedNoStoreHookAction: (incomingAction: AnyAction, noStoreAction: ModelFetchRequestAction) => boolean;
9
10
  export declare const takeMatchesReceivedNoStoreHookAction: (noStoreAction: ModelFetchRequestAction) => (incomingAction: AnyAction) => boolean;
10
- export declare const registerNoStoreActionHook: (key: string, hook: HookFunction) => void;
11
+ export declare const registerNoStoreActionHook: <T>(key: string, hook: HookFunction<T>) => void;
11
12
  export declare const unregisterNoStoreActionHook: (key: string) => void;
12
13
  export declare const noStoreHooks: {
13
- registerNoStoreActionHook: (key: string, hook: HookFunction) => void;
14
+ registerNoStoreActionHook: <T>(key: string, hook: HookFunction<T>) => void;
14
15
  unregisterNoStoreActionHook: (key: string) => void;
15
16
  };
16
17
  export declare function handleAction(noStoreAction: ModelFetchRequestAction): SagaIterator;
17
18
  export default function noStoreSaga(): SagaIterator;
18
- export {};
@@ -89,15 +89,15 @@ function handleAction(noStoreAction) {
89
89
  if (lodash_1.isNil(hook)) {
90
90
  return [2 /*return*/];
91
91
  }
92
- if (errorAction === null || errorAction === void 0 ? void 0 : errorAction.errorData) {
92
+ // return `errorData` on failure. modelFetchSaga will ALWAYS create `errorData`
93
+ if (errorAction) {
93
94
  hook(errorAction.errorData);
94
95
  return [2 /*return*/];
95
96
  }
96
- if (!(resultAction === null || resultAction === void 0 ? void 0 : resultAction.data)) {
97
- hook(null);
98
- return [2 /*return*/];
99
- }
100
- hook(resultAction.data);
97
+ // return `data` or `null` on a successful fetch result
98
+ // `data` can technically be `undefined`, e.g. if the server response is a NoContent (204),
99
+ // so the caller will need to determine if `null` is treated as an error or success
100
+ hook((resultAction === null || resultAction === void 0 ? void 0 : resultAction.data) || null);
101
101
  return [2 /*return*/];
102
102
  }
103
103
  });
@@ -19,6 +19,7 @@ var quill_1 = __importDefault(require("quill"));
19
19
  var uuid_1 = require("uuid");
20
20
  var actionCreator_1 = require("../redux/actionCreator");
21
21
  var noStoreSaga_1 = require("../redux/sagas/noStoreSaga");
22
+ var types_1 = require("../types");
22
23
  var Delta = quill_1.default.import('delta');
23
24
  /**
24
25
  * Check for non-public in the provided quill contents. Update the ImageValue of an op if an image is found to be
@@ -31,40 +32,53 @@ var checkForNonPublicImages = function (quill, checkedImages) {
31
32
  var _a, _b;
32
33
  (_b = (_a = quill
33
34
  .getContents()) === null || _a === void 0 ? void 0 : _a.ops // Is the op an image and have we not seen it before?
34
- ) === null || _b === void 0 ? void 0 : _b.filter(function (op) { var _a; return ((_a = op.insert) === null || _a === void 0 ? void 0 : _a.image) && !checkedImages.find(function (image) { return image.src === op.insert.image.src; }); }).forEach(function (op) {
35
+ ) === null || _b === void 0 ? void 0 : _b.filter(function (op) {
36
+ return op.insert.image &&
37
+ !checkedImages.find(function (image) { return image.src === op.insert.image.src; }) &&
38
+ op.insert.image.src.startsWith('http');
39
+ }).forEach(function (op) {
35
40
  // Check if the image is public. Do not check data:image urls
36
- if (op.insert.image.src && op.insert.image.src.startsWith('http')) {
37
- // Use the backend to check if the image is public
38
- // Due to CSP and other security measures, we can't check this in the frontend
39
- // uuidv5 is a deterministic uuid generator based on a namespace and a name
40
- // uuidv5.URL is the namespace for urls
41
- var hookId_1 = uuid_1.v5(op.insert.image.src, uuid_1.v5.URL);
42
- noStoreSaga_1.noStoreHooks.registerNoStoreActionHook(hookId_1, function (data) {
43
- noStoreSaga_1.noStoreHooks.unregisterNoStoreActionHook(hookId_1);
44
- // Backend fetches the URL. If there is no data returned or if the data returned has headers
45
- // but those headers are not of image type (i.e. it was a 302 that, when followed returned HTML
46
- // (I'm looking at you, Brightspace), then we update the image insert op to be nonPublic
47
- if (!data || (data['Content-Type'] && !data['Content-Type'][0].startsWith('image'))) {
48
- var contents = quill.getContents();
49
- var ops = contents.map(function (o) {
50
- var _a, _b;
51
- return ((_a = o.insert.image) === null || _a === void 0 ? void 0 : _a.src) && ((_b = op.insert.image) === null || _b === void 0 ? void 0 : _b.src) && o.insert.image.src === op.insert.image.src
52
- ? __assign(__assign({}, o), { insert: __assign(__assign({}, o.insert), { image: __assign(__assign({}, o.insert.image), { nonPublic: true }) }) }) : o;
53
- });
54
- var updatedContents = contents.diff(new Delta(ops));
55
- quill.updateContents(updatedContents);
56
- }
57
- });
58
- // This endpoint returns headers for a url. If the url is nonexistent, it will return null
59
- actionCreator_1.dispatchModelFetchRequest({
60
- modelName: 'urlChecker',
61
- guid: hookId_1,
62
- noStore: true,
63
- queryParams: {
64
- url: op.insert.image.src
65
- }
66
- });
67
- }
41
+ // Use the backend to check if the image is public
42
+ // Due to CSP and other security measures, we can't check this in the frontend
43
+ // uuidv5 is a deterministic uuid generator based on a namespace and a name
44
+ // uuidv5.URL is the namespace for urls
45
+ var hookId = uuid_1.v5(op.insert.image.src, uuid_1.v5.URL);
46
+ noStoreSaga_1.noStoreHooks.registerNoStoreActionHook(hookId, function (data) {
47
+ noStoreSaga_1.noStoreHooks.unregisterNoStoreActionHook(hookId);
48
+ var contentTypeKey;
49
+ /**
50
+ * API fetches the URL, and `noStoreSaga` returns either the result or error
51
+ * * `data` is `null` when the API could not fetch the URL with a successful status code, and returns `null` => `nonPublic`
52
+ * * `data` is `FetchErrorData` if the API request itself failed, e.g. from some unknown error, we don't know if the image is public => do not update
53
+ * * `data` is a dictionary of headers when the API does fetch the URL
54
+ * * if there is no `Content-Type` header, we don't know if the image is public => do not update
55
+ * * if there is a `Content-Type` header, but is NOT an image type (i.e. it was a 302 that, when followed returned HTML)
56
+ * (I'm looking at you, Brightspace) => `nonPublic`
57
+ * * if there is a `Content-Type` header, and it is an image type, then the image is public => do not update
58
+ */
59
+ if (!data ||
60
+ (!types_1.isFetchErrorData(data) &&
61
+ (contentTypeKey = Object.keys(data).find(function (k) { return k.toLowerCase() === 'content-type'; })) &&
62
+ !data[contentTypeKey][0].startsWith('image'))) {
63
+ var contents = quill.getContents();
64
+ var ops = contents.map(function (o) {
65
+ var _a;
66
+ return ((_a = o.insert.image) === null || _a === void 0 ? void 0 : _a.src) && op.insert.image.src && o.insert.image.src === op.insert.image.src
67
+ ? __assign(__assign({}, o), { insert: __assign(__assign({}, o.insert), { image: __assign(__assign({}, o.insert.image), { nonPublic: true }) }) }) : o;
68
+ });
69
+ var updatedContents = contents.diff(new Delta(ops));
70
+ quill.updateContents(updatedContents);
71
+ }
72
+ });
73
+ // This endpoint returns headers for a url. If the url is nonexistent, it will return null
74
+ actionCreator_1.dispatchModelFetchRequest({
75
+ modelName: 'urlChecker',
76
+ guid: hookId,
77
+ noStore: true,
78
+ queryParams: {
79
+ url: op.insert.image.src
80
+ }
81
+ });
68
82
  });
69
83
  };
70
84
  exports.checkForNonPublicImages = checkForNonPublicImages;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "studiokit-scaffolding-js",
3
- "version": "5.2.0-next.2.7",
3
+ "version": "5.2.0-next.2.9",
4
4
  "description": "Common scaffolding for Studio apps at Purdue",
5
5
  "repository": "https://gitlab.com/purdue-informatics/studiokit/studiokit-scaffolding-js",
6
6
  "license": "MIT",