Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add image upload button to object page #529

Merged
merged 8 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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 packages/solid-crs-client/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { login, handleIncomingRedirect, logout, fetch, getDefaultSession } from '@inrupt/solid-client-authn-browser';
export { getSolidDataset, getThing, getStringNoLocale, getStringNoLocaleAll, getUrl, getStringByLocaleAll, getStringWithLocale, getStringWithLocaleAll, getThingAll, getUrlAll, removeAll, removeThing, saveSolidDatasetAt, setThing, removeUrl, Thing, addStringWithLocale, addStringNoLocale, addUrl, addDatetime, getDatetime, createThing, asUrl, overwriteFile, deleteFile, ThingPersisted, getInteger, addInteger, access, addDecimal, getDecimal, SolidDataset, createSolidDataset } from '@inrupt/solid-client';
export { getSolidDataset, getThing, getStringNoLocale, getStringNoLocaleAll, getUrl, getStringByLocaleAll, getStringWithLocale, getStringWithLocaleAll, getThingAll, getUrlAll, removeAll, removeThing, saveSolidDatasetAt, setThing, removeUrl, Thing, addStringWithLocale, addStringNoLocale, addUrl, addDatetime, getDatetime, createThing, asUrl, overwriteFile, deleteFile, ThingPersisted, getInteger, addInteger, access, addDecimal, getDecimal, SolidDataset, createSolidDataset, saveFileInContainer, WithResourceInfo } from '@inrupt/solid-client';
5 changes: 5 additions & 0 deletions packages/solid-crs-core/lib/collections/collection-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ export interface CollectionObject extends Resource {
*/
image: string;

/**
* The image file to be uploaded to the pod
*/
imageFile?: File;

/**
* A link to the digital representation of this object.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as client from '@netwerk-digitaal-erfgoed/solid-crs-client';
import { getStringNoLocale, getStringWithLocale, getUrl } from '@netwerk-digitaal-erfgoed/solid-crs-client';
import { getStringNoLocale, getStringWithLocale, getUrl, WithResourceInfo } from '@netwerk-digitaal-erfgoed/solid-crs-client';
import { Collection } from '../collections/collection';
import { CollectionObject } from '../collections/collection-object';
import { CollectionObjectSolidStore } from './collection-object-solid-store';
Expand Down Expand Up @@ -53,6 +53,8 @@ describe('CollectionObjectSolidStore', () => {
event: [ { name: 'event', uri: 'https://uri/' } ],
};

(service.uploadImage as any) = jest.fn(async () => 'http://test.image');

});

it('should instantiate', () => {
Expand Down Expand Up @@ -425,8 +427,7 @@ describe('CollectionObjectSolidStore', () => {
event: undefined,
};

const result = await service.save(objectWithoutSubject)
;
const result = await service.save(objectWithoutSubject);

expect(result).toEqual(expect.objectContaining({
description: objectWithoutSubject.description,
Expand All @@ -442,6 +443,32 @@ describe('CollectionObjectSolidStore', () => {

});

it('should call uploadImage when imageFile is set', async () => {

(client.getSolidDataset as any) = jest.fn(async () => 'test-dataset');
(client.getThing as any) = jest.fn(() => client.createThing());
(client.getUrl as any) = jest.fn(() => 'http://test-uri/');
(client.getUrlAll as any) = jest.fn(() => [ 'http://test-uri/' ]);
(client.setThing as any) = jest.fn(() => 'test-thing');
(client.removeThing as any) = jest.fn(() => 'test-thing');
(client.saveSolidDatasetAt as any) = jest.fn(async () => 'test-dataset');
(client.addUrl as any) = jest.fn(() => 'test-url');
(client.addStringNoLocale as any) = jest.fn(() => 'test-url');
(client.addStringWithLocale as any) = jest.fn(() => 'test-url');
(client.addInteger as any) = jest.fn(() => 'test-url');
(client.addDecimal as any) = jest.fn(() => 'test-url');

const objectWithImageFile = {
...mockObject,
imageFile: new File([ 'test-image' ], 'test-image.jpg'),
};

await service.save(objectWithImageFile);

expect(service.uploadImage).toHaveBeenCalledTimes(1);

});

});

describe('toThing()', () => {
Expand Down Expand Up @@ -799,4 +826,54 @@ describe('CollectionObjectSolidStore', () => {

});

describe('uploadImage()', () => {

const imageUri = 'https://image.uri/image.png';
const objectUri = 'https://object.uri/objects/object-1';
const imageFile = new File([ 'test' ], 'image.png', { type: 'image/png' });

beforeEach(() => {

// reset mocked uploadImage
service = new CollectionObjectSolidStore();

(client.saveFileInContainer as any) = jest.fn(async (): Promise<WithResourceInfo> => ({
internal_resourceInfo: {
sourceIri: imageUri,
isRawData: true,
contentType: 'image/png',
},
}));

});

it.each([ null, undefined ])('should error when objectUri is %s', async (value) => {

await expect(() => service.uploadImage(imageFile, value)).rejects.toThrow('Argument objectUri should be set');

});

it.each([ null, undefined ])('should error when imageFile is %s', async (value) => {

await expect(() => service.uploadImage(value, objectUri)).rejects.toThrow('Argument imageFile should be set');

});

it('should return image Uri when successful', async () => {

const result = await service.uploadImage(imageFile, objectUri);

expect(result).toEqual(imageUri);
expect(client.saveFileInContainer).toHaveBeenCalledTimes(1);

expect(client.saveFileInContainer).toHaveBeenCalledWith(
`https://object.uri/objects/`,
imageFile,
expect.objectContaining({ slug: 'image.png', contentType: 'image/png' }),
);

});

});

});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getUrl, getSolidDataset, getThing, getStringWithLocale, getThingAll, asUrl, ThingPersisted, fetch, createThing, addStringNoLocale, addUrl, addStringWithLocale, getStringNoLocale, saveSolidDatasetAt, setThing, removeThing, getDecimal, addDecimal, SolidDataset, getUrlAll, Thing } from '@netwerk-digitaal-erfgoed/solid-crs-client';
import { getUrl, getSolidDataset, getThing, getStringWithLocale, getThingAll, asUrl, ThingPersisted, fetch, createThing, addStringNoLocale, addUrl, addStringWithLocale, getStringNoLocale, saveSolidDatasetAt, setThing, removeThing, getDecimal, addDecimal, SolidDataset, getUrlAll, saveFileInContainer } from '@netwerk-digitaal-erfgoed/solid-crs-client';
import { v4, v5 } from 'uuid';
import { Collection } from '../collections/collection';
import { CollectionObject } from '../collections/collection-object';
Expand Down Expand Up @@ -315,6 +315,13 @@ export class CollectionObjectSolidStore implements CollectionObjectStore {

});

// upload the image if a file is set and update image URI
if (object.imageFile) {

object.image = await this.uploadImage(object.imageFile, object.image);

}

const {
object: objectThing,
digitalObject: digitalObjectThing,
Expand Down Expand Up @@ -684,6 +691,38 @@ export class CollectionObjectSolidStore implements CollectionObjectStore {

}

/**
* Uploads an image file to an 'images' directory next to the collection object.
*
* @param imageFile The image file to upload.
* @param objectUri The URI of the related object.
*
* @returns The URI of the uploaded image.
*/
async uploadImage(imageFile: File, objectUri: string): Promise<string> {

if (!imageFile) {

throw new ArgumentError('Argument imageFile should be set.', imageFile);

}

if (!objectUri) {

throw new ArgumentError('Argument objectUri should be set.', objectUri);

}

const savedFile = await saveFileInContainer(
`${new URL(objectUri).origin}${new URL(objectUri).pathname.split('/').slice(0, -1).join('/')}/`,
imageFile,
{ slug: imageFile.name, contentType: imageFile.type, fetch }
);

return savedFile.internal_resourceInfo.sourceIri;

}

/**
* Retrieves the URI of the digital object for a given CollectionObject
*
Expand Down
Loading