Skip to content
Open
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: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ SPONSOR_USERS_API_SCOPES="show-medata/read show-medata/write access-requests/rea
EMAIL_SCOPES="clients/read templates/read templates/write emails/read"
FILE_UPLOAD_SCOPES="files/upload"
SPONSOR_PAGES_API_URL=https://sponsor-pages-api.dev.fnopen.com
SPONSOR_PAGES_SCOPES="page-template/read page-template/write"
SPONSOR_PAGES_SCOPES="page-template/read page-template/write show-page/read show-page/write"
SCOPES="profile openid offline_access ${SPONSOR_USERS_API_SCOPES} ${PURCHASES_API_SCOPES} ${EMAIL_SCOPES} ${FILE_UPLOAD_SCOPES} ${SPONSOR_PAGES_SCOPES} ${SCOPES_BASE_REALM}/summits/delete-event ${SCOPES_BASE_REALM}/summits/write ${SCOPES_BASE_REALM}/summits/write-event ${SCOPES_BASE_REALM}/summits/read/all ${SCOPES_BASE_REALM}/summits/read ${SCOPES_BASE_REALM}/summits/publish-event ${SCOPES_BASE_REALM}/members/read ${SCOPES_BASE_REALM}/members/read/me ${SCOPES_BASE_REALM}/speakers/write ${SCOPES_BASE_REALM}/attendees/write ${SCOPES_BASE_REALM}/members/write ${SCOPES_BASE_REALM}/organizations/write ${SCOPES_BASE_REALM}/organizations/read ${SCOPES_BASE_REALM}/summits/write-presentation-materials ${SCOPES_BASE_REALM}/summits/registration-orders/update ${SCOPES_BASE_REALM}/summits/registration-orders/delete ${SCOPES_BASE_REALM}/summits/registration-orders/create/offline ${SCOPES_BASE_REALM}/summits/badge-scans/read entity-updates/publish ${SCOPES_BASE_REALM}/audit-logs/read"
GOOGLE_API_KEY=
ALLOWED_USER_GROUPS="super-admins administrators summit-front-end-administrators summit-room-administrators track-chairs-admins sponsors"
Expand Down
126 changes: 81 additions & 45 deletions src/actions/media-file-type-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
* */

import T from "i18n-react/dist/i18n-react";
import history from "../history";
import _ from "lodash";
import {
getRequest,
putRequest,
Expand All @@ -23,9 +24,18 @@ import {
showMessage,
showSuccessMessage,
authErrorHandler,
fetchResponseHandler,
fetchErrorHandler,
escapeFilterValue
} from "openstack-uicore-foundation/lib/utils/actions";
import URI from "urijs";
import history from "../history";
import { getAccessTokenSafely } from "../utils/methods";
import {
DEBOUNCE_WAIT,
DEFAULT_PER_PAGE,
FIVE_PER_PAGE
} from "../utils/constants";

export const REQUEST_MEDIA_FILE_TYPES = "REQUEST_MEDIA_FILE_TYPES";
export const RECEIVE_MEDIA_FILE_TYPES = "RECEIVE_MEDIA_FILE_TYPES";
Expand All @@ -39,15 +49,21 @@ export const MEDIA_FILE_TYPE_ADDED = "MEDIA_FILE_TYPE_ADDED";
export const MEDIA_FILE_TYPE_DELETED = "MEDIA_FILE_TYPE_DELETED";

export const getMediaFileTypes =
(term = null, page = 1, perPage = 10, order = "id", orderDir = 1) =>
async (dispatch, getState) => {
(
term = null,
page = 1,
perPage = DEFAULT_PER_PAGE,
order = "id",
orderDir = 1
) =>
async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const filter = [];

dispatch(startLoading());

const params = {
page: page,
page,
per_page: perPage,
access_token: accessToken
};
Expand All @@ -64,7 +80,7 @@ export const getMediaFileTypes =
// order
if (order != null && orderDir != null) {
const orderDirSign = orderDir === 1 ? "" : "-";
params["order"] = `${orderDirSign}${order}`;
params.order = `${orderDirSign}${order}`;
}

return getRequest(
Expand All @@ -78,7 +94,7 @@ export const getMediaFileTypes =
});
};

export const getAllMediaFileTypes = () => async (dispatch, getState) => {
export const getAllMediaFileTypes = () => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

dispatch(startLoading());
Expand All @@ -100,33 +116,32 @@ export const getAllMediaFileTypes = () => async (dispatch, getState) => {
});
};

export const getMediaFileType =
(mediaFileTypeId) => async (dispatch, getState) => {
const accessToken = await getAccessTokenSafely();

dispatch(startLoading());
export const getMediaFileType = (mediaFileTypeId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

const params = {
access_token: accessToken
};
dispatch(startLoading());

return getRequest(
null,
createAction(RECEIVE_MEDIA_FILE_TYPE),
`${window.API_BASE_URL}/api/v1/summit-media-file-types/${mediaFileTypeId}`,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
const params = {
access_token: accessToken
};

export const resetMediaFileTypeForm = () => (dispatch, getState) => {
return getRequest(
null,
createAction(RECEIVE_MEDIA_FILE_TYPE),
`${window.API_BASE_URL}/api/v1/summit-media-file-types/${mediaFileTypeId}`,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
};

export const resetMediaFileTypeForm = () => (dispatch) => {
dispatch(createAction(RESET_MEDIA_FILE_TYPE_FORM)({}));
};

export const saveMediaFileType =
(entity, noAlert = false) =>
async (dispatch, getState) => {
async (dispatch) => {
const accessToken = await getAccessTokenSafely();

dispatch(startLoading());
Expand All @@ -142,7 +157,7 @@ export const saveMediaFileType =
normalizedEntity,
authErrorHandler,
entity
)(params)(dispatch).then((payload) => {
)(params)(dispatch).then(() => {
if (!noAlert)
dispatch(showSuccessMessage(T.translate("media_file_type.saved")));
else dispatch(stopLoading());
Expand Down Expand Up @@ -171,33 +186,54 @@ export const saveMediaFileType =
}
};

export const deleteMediaFileType =
(mediaFileTypeId) => async (dispatch, getState) => {
const accessToken = await getAccessTokenSafely();

const params = {
access_token: accessToken
};
export const deleteMediaFileType = (mediaFileTypeId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

return deleteRequest(
null,
createAction(MEDIA_FILE_TYPE_DELETED)({ mediaFileTypeId }),
`${window.API_BASE_URL}/api/v1/summit-media-file-types/${mediaFileTypeId}`,
null,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
const params = {
access_token: accessToken
};

return deleteRequest(
null,
createAction(MEDIA_FILE_TYPE_DELETED)({ mediaFileTypeId }),
`${window.API_BASE_URL}/api/v1/summit-media-file-types/${mediaFileTypeId}`,
null,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
};

const normalizeEntity = (entity) => {
const normalizedEntity = { ...entity };

delete normalizedEntity["id"];
delete normalizedEntity["created"];
delete normalizedEntity["modified"];
delete normalizedEntity.id;
delete normalizedEntity.created;
delete normalizedEntity.modified;

normalizedEntity.allowed_extensions = entity.allowed_extensions.split(",");

return normalizedEntity;
};

export const queryMediaFileTypes = _.debounce(async (input, callback) => {
const accessToken = await getAccessTokenSafely();
const apiUrl = URI(`${window.API_BASE_URL}/api/v1/summit-media-file-types`);

apiUrl.addQuery("access_token", accessToken);
apiUrl.addQuery("order", "name");
apiUrl.addQuery("per_page", FIVE_PER_PAGE);

if (input) {
input = escapeFilterValue(input);
apiUrl.addQuery("filter[]", `name=@${input}`);
}

fetch(apiUrl.toString())
.then(fetchResponseHandler)
.then((json) => {
const options = [...json.data];
callback(options);
})
.catch(fetchErrorHandler);
}, DEBOUNCE_WAIT);
Comment on lines +219 to +239
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing lodash import causes runtime error.

_.debounce is used on line 218, but lodash is not imported in this file. This will throw a ReferenceError: _ is not defined at runtime.

Additionally, when fetch fails, fetchErrorHandler is called but the callback is never invoked, which will leave the async autocomplete component in a loading state indefinitely.

🐛 Proposed fix

Add the lodash import at the top of the file with other imports:

 import T from "i18n-react/dist/i18n-react";
+import debounce from "lodash/debounce";
 import {
   getRequest,

Then update the function to use the named import and handle errors properly:

-export const queryMediaFileTypes = _.debounce(async (input, callback) => {
+export const queryMediaFileTypes = debounce(async (input, callback) => {
   const accessToken = await getAccessTokenSafely();
   const apiUrl = URI(`${window.API_BASE_URL}/api/v1/summit-media-file-types`);
 
   apiUrl.addQuery("access_token", accessToken);
   apiUrl.addQuery("order", "name");
   apiUrl.addQuery("per_page", FIVE_PER_PAGE);
 
   if (input) {
     input = escapeFilterValue(input);
     apiUrl.addQuery("filter[]", `name=@${input}`);
   }
 
   fetch(apiUrl.toString())
     .then(fetchResponseHandler)
     .then((json) => {
       const options = [...json.data];
       callback(options);
     })
-    .catch(fetchErrorHandler);
+    .catch((err) => {
+      fetchErrorHandler(err);
+      callback([]);
+    });
 }, DEBOUNCE_WAIT);
🤖 Prompt for AI Agents
In `@src/actions/media-file-type-actions.js` around lines 218 - 238, The file uses
_.debounce in queryMediaFileTypes but lodash isn't imported and fetch errors
never call the autocomplete callback; add an import for debounce (or lodash) at
the top (e.g., import { debounce } from 'lodash' or import _ from 'lodash') and
change queryMediaFileTypes to use the imported debounce (or _) instead of the
undefined _; also update the fetch .catch handler (associated with
fetchErrorHandler) to ensure callback is invoked on error (e.g., call
callback([]) or callback(null) after calling fetchErrorHandler) so the async
autocomplete is not left loading.

27 changes: 25 additions & 2 deletions src/actions/page-template-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* */

import T from "i18n-react/dist/i18n-react";
import moment from "moment-timezone";
import {
getRequest,
putRequest,
Expand All @@ -27,7 +28,8 @@ import { getAccessTokenSafely } from "../utils/methods";
import {
DEFAULT_CURRENT_PAGE,
DEFAULT_ORDER_DIR,
DEFAULT_PER_PAGE
DEFAULT_PER_PAGE,
PAGES_MODULE_KINDS
} from "../utils/constants";
import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions";

Expand Down Expand Up @@ -143,7 +145,28 @@ export const resetPageTemplateForm = () => (dispatch) => {
const normalizeEntity = (entity) => {
const normalizedEntity = { ...entity };

normalizedEntity.modules = [];
normalizedEntity.modules = entity.modules.map((module) => {
const normalizedModule = { ...module };

if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) {
normalizedModule.upload_deadline = moment
.utc(module.upload_deadline)
.unix();
}

if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.file_type_id) {
normalizedModule.file_type_id =
module.file_type_id?.value || module.file_type_id;
}

if (module.kind === PAGES_MODULE_KINDS.DOCUMENT && module.file) {
normalizedModule.file = module.file[0] || null;
}

delete normalizedModule._tempId;

return normalizedModule;
});
Comment on lines 145 to +169
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against missing modules during normalization.
If entity.modules is null/undefined (e.g., legacy templates or partial payloads), .map will throw and block save. Add a defensive fallback to keep saves resilient.

Proposed fix
-  normalizedEntity.modules = entity.modules.map((module) => {
+  const modules = Array.isArray(entity.modules) ? entity.modules : [];
+  normalizedEntity.modules = modules.map((module) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizeEntity = (entity) => {
const normalizedEntity = { ...entity };
normalizedEntity.modules = [];
normalizedEntity.modules = entity.modules.map((module) => {
const normalizedModule = { ...module };
if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) {
normalizedModule.upload_deadline = moment
.utc(module.upload_deadline)
.unix();
}
if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.file_type_id) {
normalizedModule.file_type_id =
module.file_type_id?.value || module.file_type_id;
}
if (module.kind === PAGES_MODULE_KINDS.DOCUMENT && module.file) {
normalizedModule.file = module.file[0] || null;
}
delete normalizedModule._tempId;
return normalizedModule;
});
const normalizeEntity = (entity) => {
const normalizedEntity = { ...entity };
const modules = Array.isArray(entity.modules) ? entity.modules : [];
normalizedEntity.modules = modules.map((module) => {
const normalizedModule = { ...module };
if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) {
normalizedModule.upload_deadline = moment
.utc(module.upload_deadline)
.unix();
}
if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.file_type_id) {
normalizedModule.file_type_id =
module.file_type_id?.value || module.file_type_id;
}
if (module.kind === PAGES_MODULE_KINDS.DOCUMENT && module.file) {
normalizedModule.file = module.file[0] || null;
}
delete normalizedModule._tempId;
return normalizedModule;
});
🤖 Prompt for AI Agents
In `@src/actions/page-template-actions.js` around lines 145 - 169, normalizeEntity
currently assumes entity.modules is always an array and calls .map, which throws
if modules is null/undefined; modify normalizeEntity to defensively handle
missing modules by using a fallback array (e.g., const modules = entity.modules
|| [] or entity.modules ?? []) or optional chaining before mapping so
normalization proceeds without error, then assign normalizedEntity.modules =
modules.map(...) as before (keeping the same per-module handling like
upload_deadline, file_type_id, file and deleting _tempId).


return normalizedEntity;
};
Expand Down
Loading