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: 2 additions & 0 deletions src/handlers/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { postVersionSource } from '../routes/version.js';
import copyHandler from '../routes/copy.js';
import logout from '../routes/logout.js';
import moveRoute from '../routes/move.js';
import postMedia from '../routes/media.js';

export default async function postHandler({ req, env, daCtx }) {
const { path } = daCtx;
Expand All @@ -25,6 +26,7 @@ export default async function postHandler({ req, env, daCtx }) {
if (path.startsWith('/copy')) return copyHandler({ req, env, daCtx });
if (path.startsWith('/move')) return moveRoute({ req, env, daCtx });
if (path.startsWith('/logout')) return logout({ env, daCtx });
if (path.startsWith('/media')) return postMedia({ req, env, daCtx });

return undefined;
}
12 changes: 11 additions & 1 deletion src/helpers/source.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function formPutHandler(req) {
return formData ? getFormEntries(formData) : null;
}

export default async function putHelper(req, env, daCtx) {
export async function putHelper(req, env, daCtx) {
const contentType = req.headers.get('content-type')?.split(';')[0];

if (!contentType) return null;
Expand All @@ -68,3 +68,13 @@ export default async function putHelper(req, env, daCtx) {

return undefined;
}

export async function getFileBody(data) {
await data.text();
return { body: data, type: data.type };
}

export function getObjectBody(data) {
// TODO: This will not correctly handle HTML as data
return { body: JSON.stringify(data), type: 'application/json' };
}
40 changes: 40 additions & 0 deletions src/routes/media.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2025 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import { hasPermission } from '../utils/auth.js';
import { MEDIA_TYPES } from '../utils/constants.js';
import { getFileBody, putHelper } from '../helpers/source.js';

export default async function postMedia({ req, env, daCtx }) {
if (!hasPermission(daCtx, daCtx.key, 'write')) return { status: 403 };

const obj = await putHelper(req, env, daCtx);
const { body, type: contentType } = await getFileBody(obj.data);

if (!MEDIA_TYPES.includes(contentType)) return { status: 400 };

const adminMediaAPI = env.AEM_ADMIN_MEDIA_API;
const url = `${adminMediaAPI}/${daCtx.fullKey}/main`;

const resp = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': contentType,
Authorization: `token ${env.AEM_ADMIN_MEDIA_API_KEY}`,
},
body,
});

if (!resp.ok) return { status: resp.status };
const data = await resp.json();
return { status: 200, body: JSON.stringify(data), contentType: 'application/json' };
}
2 changes: 1 addition & 1 deletion src/routes/source.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import putObject from '../storage/object/put.js';
import deleteObjects from '../storage/object/delete.js';
import { invalidateCollab } from '../storage/utils/object.js';

import putHelper from '../helpers/source.js';
import { putHelper } from '../helpers/source.js';
import deleteHelper from '../helpers/delete.js';
import { hasPermission } from '../utils/auth.js';

Expand Down
13 changes: 2 additions & 11 deletions src/storage/object/put.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,9 @@ import {
} from '@aws-sdk/client-s3';

import getS3Config from '../utils/config.js';
import { sourceRespObject } from '../../helpers/source.js';
import { putObjectWithVersion } from '../version/put.js';

async function getFileBody(data) {
await data.text();
return { body: data, type: data.type };
}
import { sourceRespObject, getFileBody, getObjectBody } from '../../helpers/source.js';

function getObjectBody(data) {
// TODO: This will not correctly handle HTML as data
return { body: JSON.stringify(data), type: 'application/json' };
}
import { putObjectWithVersion } from '../version/put.js';

function buildInput({
bucket, org, key, body, type,
Expand Down
10 changes: 10 additions & 0 deletions src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ export const SUPPORTED_TYPES = [
'image/gif',
'image/png',
'image/svg+xml',
'image/webp',
'video/mp4',
];

export const MEDIA_TYPES = [
'image/jpeg',
'image/gif',
'image/png',
'image/svg+xml',
'image/webp',
'video/mp4',
];

Expand Down
43 changes: 43 additions & 0 deletions test/handlers/post.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* governing permissions and limitations under the License.
*/
import assert from 'assert';
import esmock from 'esmock';

import postHandler from '../../src/handlers/post.js';

Expand All @@ -31,4 +32,46 @@ describe('Post Route', () => {
assert(deleteCalled.includes('foo@bar.org'));
assert(deleteCalled.includes('blah@blah.org'));
});

it('Test media route', async () => {
const mediaCalled = [];
const mockPostMedia = async ({ req, env, daCtx }) => {
mediaCalled.push({ req, env, daCtx });
return { status: 200, body: JSON.stringify({ id: 'media-123' }) };
};

const postHandlerWithMock = await esmock('../../src/handlers/post.js', {
'../../src/routes/media.js': {
default: mockPostMedia,
},
});

const req = { method: 'POST' };
const env = { AEM_ADMIN_MEDIA_API: 'https://api.example.com' };
const daCtx = {
path: '/media/image.jpg',
key: 'test/image.jpg',
};

const resp = await postHandlerWithMock.default({ req, env, daCtx });

assert.strictEqual(resp.status, 200);
assert.strictEqual(mediaCalled.length, 1);
assert.strictEqual(mediaCalled[0].req, req);
assert.strictEqual(mediaCalled[0].env, env);
assert.strictEqual(mediaCalled[0].daCtx, daCtx);
});

it('Test unknown route returns undefined', async () => {
const req = { method: 'POST' };
const env = {};
const daCtx = {
path: '/unknown/route',
key: 'test/unknown',
};

const resp = await postHandler({ req, env, daCtx });

assert.strictEqual(resp, undefined);
});
});
2 changes: 1 addition & 1 deletion test/helpers/source.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from 'assert';
import putHelper from '../../src/helpers/source.js';
import { putHelper } from '../../src/helpers/source.js';

import env from '../utils/mocks/env.js';
const daCtx = { org: 'cq', key: 'geometrixx/hello.html', propsKey: 'geometrixx/hello.html.props' };
Expand Down
Loading