Skip to content

Commit

Permalink
Merge pull request #3634 from nulib/deploy/staging
Browse files Browse the repository at this point in the history
Deploy v9.0.4 to production
  • Loading branch information
mbklein authored Nov 16, 2023
2 parents 64effe6 + 15205be commit 0fd536d
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 59 deletions.
26 changes: 6 additions & 20 deletions app/assets/js/components/UI/IIIF/Viewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,23 @@ import { useWorkDispatch, useWorkState } from "@js/context/work-context";
import CloverViewer from "@samvera/clover-iiif/viewer";
import IIIFViewerPosterSelector from "@js/components/UI/IIIF/PosterSelector";
import PropTypes from "prop-types";
import { useQuery } from "@apollo/client";
import { GET_DC_API_TOKEN } from "@js/components/Work/work.gql";
import { getApiResponseHeaders } from "@js/services/get-api-response-headers";

const IIIFViewer = ({ fileSets, iiifContent, workTypeId }) => {
const workState = useWorkState();
const dispatch = useWorkDispatch();

const { activeMediaFileSet } = workState;
const { activeMediaFileSet, dcApiToken } = workState;
const [etag, setEtag] = useState();

/**
* Get the DC API super user token from the API every 5 minutes.
*/
const { data: dataDcApiToken, error: errorDcApiToken } = useQuery(
GET_DC_API_TOKEN,
{ pollInterval: 300000 }
);

const token = dataDcApiToken?.dcApiToken?.token;

if (errorDcApiToken) console.error(errorDcApiToken);

/**
* Get the etag from the API response headers every 10 seconds.
*/
useEffect(() => {
if (!token) return;
if (!dcApiToken) return;

const fetchEtag = async () => {
const response = await getApiResponseHeaders(iiifContent, token);
const response = await getApiResponseHeaders(iiifContent, dcApiToken);
const headers = new Headers(response);
const etag = headers.get("etag");
setEtag(etag);
Expand All @@ -47,7 +33,7 @@ const IIIFViewer = ({ fileSets, iiifContent, workTypeId }) => {
}, 10000);

return () => clearInterval(interval);
}, [token, iiifContent]);
}, [dcApiToken, iiifContent]);

/**
* When the Canvas changed in Clover, update the active media file set in Context.
Expand Down Expand Up @@ -85,12 +71,12 @@ const IIIFViewer = ({ fileSets, iiifContent, workTypeId }) => {
},
requestHeaders: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
Authorization: `Bearer ${dcApiToken}`,
},
showIIIFBadge: false,
};

if (!token) return <></>;
if (!dcApiToken) return <></>;

return (
<div className="container iiif-viewer" data-testid="iiif-viewer">
Expand Down
12 changes: 7 additions & 5 deletions app/assets/js/components/UI/IIIF/Viewer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@ const initialState = {
webVttString: "",
},
workType: "VIDEO",
dcApiToken: "asd8967asd89asc78234891289nkldsnn89123",
};

const mocks = [dcApiTokenMock];

jest.mock("@js/services/get-api-response-headers");

jest.mock("@samvera/clover-iiif/viewer", () => {
return {
__esModule: true,
default: (props) => {
// Call the canvasCallback with a string when the component is rendered
if (props.canvasCallback) {
props.canvasCallback(
"https://mat.dev.rdc.library.northwestern.edu:3002/works/a1239c42-6e26-4a95-8cde-0fa4dbf0af6a?as=iiif/canvas/access/0"
"https://mat.dev.rdc.library.northwestern.edu:3002/works/a1239c42-6e26-4a95-8cde-0fa4dbf0af6a?as=iiif/canvas/access/0",
);
}
return <div></div>;
Expand All @@ -54,7 +56,7 @@ describe("IIIFViewer component", () => {
workTypeId="IMAGE"
/>
</WorkProvider>,
{ mocks }
{ mocks },
);
expect(await screen.findByTestId("iiif-viewer"));
});
Expand All @@ -69,7 +71,7 @@ describe("IIIFViewer component", () => {
workTypeId="VIDEO"
/>
</WorkProvider>,
{ mocks }
{ mocks },
);
expect(await screen.findByTestId("set-poster-image-button"));
});
Expand All @@ -83,11 +85,11 @@ describe("IIIFViewer component", () => {
iiifContent="ABC123"
workTypeId="AUDIO"
/>
</WorkProvider>
</WorkProvider>,
);
await waitFor(() => {
expect(
screen.queryByTestId("set-poster-image-button")
screen.queryByTestId("set-poster-image-button"),
).not.toBeInTheDocument();
});
});
Expand Down
8 changes: 8 additions & 0 deletions app/assets/js/components/UI/ui.gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ export const DIGITAL_COLLECTIONS_URL = gql`
}
}
`;

export const GET_DCAPI_ENDPOINT = gql`
query {
dcapiEndpoint {
url
}
}
`;
17 changes: 16 additions & 1 deletion app/assets/js/components/UI/ui.gql.mock.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DIGITAL_COLLECTIONS_URL } from "./ui.gql";
import { GET_DCAPI_ENDPOINT, DIGITAL_COLLECTIONS_URL } from "./ui.gql";

export const mockDCUrl = "https://imamockurl.io/";
export const dcapiEndpointUrl =
"https://prefix.dev.rdc.library.northwestern.edu/";

export const digitalCollectionsUrlMock = {
request: {
Expand All @@ -14,3 +16,16 @@ export const digitalCollectionsUrlMock = {
},
},
};

export const dcApiEndpointMock = {
request: {
query: GET_DCAPI_ENDPOINT,
},
result: {
data: {
dcapiEndpoint: {
url: dcapiEndpointUrl,
},
},
},
};
52 changes: 37 additions & 15 deletions app/assets/js/components/Work/Fileset/ActionButtons/Access.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,41 @@ import PropTypes from "prop-types";
import { toastWrapper } from "@js/services/helpers";
import useFileSet from "@js/hooks/useFileSet";
import useIsAuthorized from "@js/hooks/useIsAuthorized";
import { useWorkDispatch } from "@js/context/work-context";
import { useWorkDispatch, useWorkState } from "@js/context/work-context";
import { getApiResponse } from "@js/services/get-api-response";
import { useQuery } from "@apollo/client";
import { AuthContext } from "@js/components/Auth/Auth";
import { GET_DCAPI_ENDPOINT } from "@js/components/UI/ui.gql";

export function MediaButtons({ fileSet }) {
const { getWebVttString } = useFileSet();
const { isAuthorized } = useIsAuthorized();
const dispatch = useWorkDispatch();
const [downloadStarted, setDownloadStarted] = React.useState(false);

const handleDownloadMedia = () => {
console.log("handleDownloadMedia", handleDownloadMedia);
// TODO: Call the download media endpoint here
const dispatch = useWorkDispatch();
const { dcApiToken } = useWorkState();
const currentUser = useContext(AuthContext);

toastWrapper(
"is-success",
`Your media download is being prepared. You will receive an email when it is ready.`
);
const { getWebVttString } = useFileSet();
const { isAuthorized } = useIsAuthorized();
const { data: dataDcApiEndpoint } = useQuery(GET_DCAPI_ENDPOINT);

const handleDownloadMedia = async () => {
setDownloadStarted(true);

const dcApiFileSet = `${dataDcApiEndpoint?.dcapiEndpoint?.url}/file-sets/${fileSet.id}`;
const uri = `${dcApiFileSet}/download?email=${currentUser?.email}`;

try {
const response = await getApiResponse(uri, dcApiToken);
if (response?.status !== 200) throw Error(response);

toastWrapper(
"is-success",
`Your media for <em>${fileSet.coreMetadata.label}</em> is being prepared for download. You will receive an email at <strong>${currentUser?.email}</strong> when it is ready.`,
);
} catch (error) {
console.error(error);
toastWrapper("is-danger", `The download request failed.`);
}
};

if (!fileSet) return null;
Expand All @@ -35,6 +52,7 @@ export function MediaButtons({ fileSet }) {
<div className="buttons is-grouped is-right">
{isAuthorized() && (
<Button
data-testid="edit-structure-button"
onClick={() =>
dispatch({
type: "toggleWebVttModal",
Expand All @@ -46,11 +64,14 @@ export function MediaButtons({ fileSet }) {
Edit structure (vtt)
</Button>
)}
{/* //TODO: Re-enable once backend is ready to support the link *}
{/* <Button onClick={handleDownloadMedia} disabled={downloadStarted}>
<Button
data-testid="download-fileset-button"
onClick={handleDownloadMedia}
disabled={downloadStarted}
>
<IconDownload />
Download
</Button> */}
</Button>
</div>
);
}
Expand Down Expand Up @@ -87,11 +108,12 @@ const WorkFilesetActionButtonsAccess = ({ fileSet }) => {
const iiifServerUrl = useContext(IIIFContext);
const { coreMetadata } = fileSet;
const isImageType = coreMetadata.mimeType?.includes("image");
const isVideoType = coreMetadata.mimeType?.includes("video");

if (isImageType) {
return <ImageButtons iiifServerUrl={iiifServerUrl} fileSet={fileSet} />;
}
if (!isImageType) {
if (isVideoType) {
return <MediaButtons fileSet={fileSet} />;
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { render, screen } from "@testing-library/react";
import { screen } from "@testing-library/react";

import { MediaButtons } from "./Access";
import React from "react";
import { WorkProvider } from "@js/context/work-context";
import { mockUser } from "@js/components/Auth/auth.gql.mock";
import useIsAuthorized from "@js/hooks/useIsAuthorized";
import { dcApiEndpointMock } from "@js/components/UI/ui.gql.mock";
import { renderWithRouterApollo } from "@js/services/testing-helpers";

const mocks = [dcApiEndpointMock];

jest.mock("@js/hooks/useIsAuthorized");
useIsAuthorized.mockReturnValue({
Expand Down Expand Up @@ -56,17 +60,18 @@ const initialState = {
webVttString: "",
},
workType: "VIDEO",
dcApiToken: "abcZ4323823092mccas999",
};

describe("MediaButtons", () => {
it("renders the Edit VTT button and Download Video button for a video mime/type Fileset", () => {
render(
renderWithRouterApollo(
<WorkProvider initialState={initialState}>
<MediaButtons fileSet={mockFileSet} />
</WorkProvider>
</WorkProvider>,
{ mocks },
);

expect(screen.getByText("Edit structure (vtt)")).toBeInTheDocument();
//expect(screen.getByText("Download")).toBeInTheDocument();
expect(screen.getByTestId("edit-structure-button")).toBeInTheDocument();
expect(screen.getByTestId("download-fileset-button")).toBeInTheDocument();
});
});
6 changes: 3 additions & 3 deletions app/assets/js/components/Work/Tabs/Tabs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,19 @@ xdescribe("Tabs component", () => {
fireEvent.click(queryByTestId("tab-administrative"));

expect(queryByTestId("tab-administrative-content")).not.toHaveClass(
"is-hidden"
"is-hidden",
);
expect(queryByTestId("tab-about-content")).toHaveClass("is-hidden");

fireEvent.click(queryByTestId("tab-preservation"));

expect(queryByTestId("tab-about-content")).toHaveClass("is-hidden");
expect(queryByTestId("tab-administrative-content")).toHaveClass(
"is-hidden"
"is-hidden",
);
expect(queryByTestId("tab-structure-content")).toHaveClass("is-hidden");
expect(queryByTestId("tab-preservation-content")).not.toHaveClass(
"is-hidden"
"is-hidden",
);
});
});
Expand Down
8 changes: 6 additions & 2 deletions app/assets/js/components/Work/Work.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
workArchiverEndpointMock,
dcApiTokenMock,
} from "./work.gql.mock";
import { dcApiEndpointMock } from "@js/components/UI/ui.gql.mock";
import { iiifServerUrlMock } from "@js/components/IIIF/iiif.gql.mock";
import { screen } from "@testing-library/react";
import { allCodeListMocks } from "@js/components/Work/controlledVocabulary.gql.mock";
Expand All @@ -17,6 +18,8 @@ import {
} from "@js/components/Collection/collection.gql.mock";
import { WorkProvider } from "@js/context/work-context";

jest.mock("@js/services/get-api-response-headers");

jest.mock("@js/hooks/useIsAuthorized");
useIsAuthorized.mockReturnValue({
user: mockUser,
Expand All @@ -25,6 +28,7 @@ useIsAuthorized.mockReturnValue({

const mocks = [
dcApiTokenMock,
dcApiEndpointMock,
iiifServerUrlMock,
getCollectionMock,
getCollectionsMock,
Expand All @@ -39,7 +43,7 @@ jest.mock("@samvera/clover-iiif/viewer", () => {
// Call the canvasCallback with a string when the component is rendered
if (props.canvasCallback) {
props.canvasCallback(
"https://mat.dev.rdc.library.northwestern.edu:3002/works/a1239c42-6e26-4a95-8cde-0fa4dbf0af6a?as=iiif/canvas/access/0"
"https://mat.dev.rdc.library.northwestern.edu:3002/works/a1239c42-6e26-4a95-8cde-0fa4dbf0af6a?as=iiif/canvas/access/0",
);
}
return <div></div>;
Expand All @@ -53,7 +57,7 @@ describe("Work component", () => {
<WorkProvider>
<Work work={mockWork} />
</WorkProvider>,
{ mocks }
{ mocks },
);
});

Expand Down
Loading

0 comments on commit 0fd536d

Please sign in to comment.