studiokit-scaffolding-js 5.2.0-next.2.7 → 5.2.0-next.2.8
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
|
|
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;
|
|
@@ -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:
|
|
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
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
});
|
package/lib/utils/quill.js
CHANGED
|
@@ -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) {
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
noStoreSaga_1.noStoreHooks.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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.
|
|
3
|
+
"version": "5.2.0-next.2.8",
|
|
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",
|