Add replacement chain context to file request

refs MAT-804
flag=buttons_and_icons_root_account

Test Plan:
1. Checkout g/288281 in canvas-rce-api
2. Build canvas JS bundles and canvas-rce
4. Navigate to a Canvas course
5. Create an assignment: "Assignment A"
6. In Assignment A, embed an Icon Maker Icon
7. Create another assignment: "Assignment B"
8. Embed the same Icon Maker Icon in Assignment B
9. Navigatge to Assignment A and edit the Icon
   Maker Icon. Make some notable change, check the
   "Apply changes to all instances of this..." box,
   and save the change
10. Navigate to Assignment B
11. Verify the change made in step 9 is applied to
    the Icon Maker Icon in Assignment B
12. Verify you can now edit the Icon Maker Icon in
    Assignment B without issue

Change-Id: I5627f0ae158bd01313a185fd665d12880e3009b3
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/288280
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Gonzalo Penaranda <gonzalo.penaranda@instructure.com>
QA-Review: Gonzalo Penaranda <gonzalo.penaranda@instructure.com>
Product-Review: David Lyons <lyons@instructure.com>
This commit is contained in:
Weston Dransfield 2022-03-28 11:17:53 -06:00
parent 27448cb655
commit f2499b46ec
4 changed files with 70 additions and 6 deletions

View File

@ -295,7 +295,14 @@ describe('RCE "Buttons and Icons" Plugin > ButtonsTray', () => {
ed = new FakeEditor()
})
const subject = () => render(<ButtonsTray onClose={jest.fn()} editor={ed} />)
const subject = () =>
render(
<ButtonsTray
onClose={jest.fn()}
editor={ed}
rceConfig={{contextType: 'course', contextId: 2}}
/>
)
it('loads the standard SVG metadata', async () => {
const {getByLabelText, getAllByTestId} = subject()
@ -323,7 +330,15 @@ describe('RCE "Buttons and Icons" Plugin > ButtonsTray', () => {
ed.setSelectedNode(ed.dom.select('#test-image')[0])
})
const subject = () => render(<ButtonsTray onClose={jest.fn()} editing editor={ed} />)
const subject = () =>
render(
<ButtonsTray
onClose={jest.fn()}
editing
editor={ed}
rcsConfig={{contextType: 'course', contextId: 2}}
/>
)
beforeEach(() => {
fetchMock.mock('*', {

View File

@ -29,7 +29,11 @@ describe('useSvgSettings()', () => {
beforeEach(() => {
ed = new Editor()
rcs = {getFile: jest.fn(() => Promise.resolve({name: 'Test Button.svg'}))}
rcs = {
getFile: jest.fn(() => Promise.resolve({name: 'Test Button.svg'})),
contextType: 'course',
contextId: 1
}
RceApiSource.mockImplementation(() => rcs)
})
@ -251,6 +255,19 @@ describe('useSvgSettings()', () => {
})
})
it('uses replacement chain context info in request for file name', async () => {
const {result, waitForValueToChange} = renderHook(() => useSvgSettings(ed, editing, rcs))
await waitForValueToChange(() => {
return result.current[0]
})
expect(rcs.getFile).toHaveBeenCalledWith('1', {
replacement_chain_context_id: 1,
replacement_chain_context_type: 'course'
})
})
it('parses the SVG settings from the SVG metadata', async () => {
const {result, waitForValueToChange} = renderHook(() => useSvgSettings(ed, editing, rcs))

View File

@ -103,7 +103,10 @@ export function useSvgSettings(editor, editing, rcsConfig) {
const rcs = new RceApiSource(rcsConfig)
const fileData = await rcs.getFile(fileId)
const fileData = await rcs.getFile(fileId, {
replacement_chain_context_type: rcsConfig.contextType,
replacement_chain_context_id: rcsConfig.contextId
})
const fileName = fileData.name.replace(/\.[^\.]+$/, '')
const metadataJson = JSON.parse(metadata)

View File

@ -436,13 +436,42 @@ class RceApiSource {
return this.apiFetch(uri, headers, {skipParse: true})
}
getFile(id) {
getFile(id, options = {}) {
const headers = headerFor(this.jwt)
const base = this.baseUri('file')
const uri = `${base}/${id}`
// Valid query parameters for getFile
const {replacement_chain_context_type, replacement_chain_context_id} = options
const uri = this.addParamsIfPresent(`${base}/${id}`, {
replacement_chain_context_type,
replacement_chain_context_id
})
return this.apiFetch(uri, headers).then(normalizeFileData)
}
// @private
addParamsIfPresent(uri, params) {
let url
try {
url = new URL(uri)
} catch (e) {
// Just return the URI if it was invalid
return uri
}
// Add all truthy parameters to the URL
for (const [name, value] of Object.entries(params)) {
if (!value) continue
url.searchParams.append(name, value)
}
return url.toString()
}
// @private
async apiFetch(uri, headers, options) {
if (!this.hasSession) {