add file service.

This commit is contained in:
Simon Larsen
2022-09-06 21:07:02 +01:00
parent 19d9bcf069
commit 927860e71d
7 changed files with 153 additions and 7 deletions

View File

@@ -1,11 +1,13 @@
import { Column } from 'typeorm';
import ColumnLength from '../Types/Database/ColumnLength';
import ColumnType from '../Types/Database/ColumnType';
import SlugifyColumn from '../Types/Database/SlugifyColumn';
import TableColumn from '../Types/Database/TableColumn';
import TableColumnType from '../Types/Database/TableColumnType';
import ObjectID from '../Types/ObjectID';
import BaseModel from './BaseModel';
@SlugifyColumn('name', 'slug')
export default class FileModel extends BaseModel {
public constructor(id?: ObjectID) {
super(id);
@@ -37,4 +39,12 @@ export default class FileModel extends BaseModel {
length: ColumnLength.ShortText,
})
public type?: string = undefined;
@TableColumn({ required: true, unique: true, type: TableColumnType.Slug })
@Column({
nullable: false,
type: ColumnType.Slug,
length: ColumnLength.Slug,
})
public slug?: string = undefined;
}

View File

@@ -0,0 +1,10 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import File from 'Model/Models/File';
import DatabaseService from './DatabaseService';
export class Service extends DatabaseService<File> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(File, postgresDatabase);
}
}
export default new Service();

View File

@@ -0,0 +1,79 @@
import React, {
FunctionComponent,
ReactElement,
useEffect,
useState,
} from 'react';
import { useDropzone } from 'react-dropzone';
export interface ComponentProps {
initialValue?: undefined | string;
onClick?: undefined | (() => void);
placeholder?: undefined | string;
className?: undefined | string;
onChange?: undefined | ((value: string) => void);
value?: string | undefined;
readOnly?: boolean | undefined;
type?: 'text' | 'number' | 'date';
onFocus?: (() => void) | undefined;
onBlur?: (() => void) | undefined;
dataTestId?: string;
}
const FilePicker: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
const [files, setFiles] = useState<Array<File>>([]);
const [fileObjectURLs, setFileObjectURLs] = useState<Array<string>>([]);
const { getRootProps, getInputProps } = useDropzone({
accept: {
'image/*': []
},
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}
});
const thumbs = files.map((file) => {
const url: string = URL.createObjectURL(file);
const urlArr = [...fileObjectURLs]
urlArr.push(url);
setFileObjectURLs(urlArr);
return (<div className='file-picker-thumb' key={file.name}>
<div className='file-picker-thumb-inner'>
<img
src={url}
className='file-picker-img'
// Revoke data uri after image is loaded
onLoad={() => { URL.revokeObjectURL(url) }}
/>
</div>
</div>)
});
useEffect(() => {
// Make sure to revoke the data uris to avoid memory leaks, will run on unmount
return () => fileObjectURLs.forEach(fileURL => URL.revokeObjectURL(fileURL));
}, []);
return (
<section className="container">
<div {...getRootProps({ className: 'dropzone' })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<aside className='file-picker-thumb-container'>
{thumbs}
</aside>
</section>
);
};
export default FilePicker;

View File

@@ -289,4 +289,39 @@
border-style: dashed;
border-radius: 500px;
width: 300px;
}
}
// File Picker.
.file-picker-thumbs-container {
display: 'flex';
flex-direction: 'row';
flex-wrap: 'wrap';
margin-top: "16px"
}
.file-picker-thumb {
display: 'inline-flex';
border-radius: "2px";
border: '1px solid #eaeaea';
margin-bottom: 8;
margin-right: 8;
width: 100;
height: 100,;
padding: 4;
box-sizing: 'border-box'
};
.file-picker-thumb-inner {
display: 'flex';
min-width: 0;
overflow: 'hidden'
};
.file-picker-img {
display: 'block';
width: 'auto';
height: '100%'
};

View File

@@ -3,13 +3,22 @@ import { PostgresAppInstance } from 'CommonServer/Infrastructure/PostgresDatabas
import Express, { ExpressApplication } from 'CommonServer/Utils/Express';
import logger from 'CommonServer/Utils/Logger';
import App from 'CommonServer/Utils/StartServer';
import AuthenticationAPI from './API/AuthenticationAPI';
import File from 'Model/Models/File';
import FileService, {
Service as FileServiceType,
} from 'CommonServer/Services/FileService';
import BaseAPI from 'CommonServer/API/BaseAPI';
const app: ExpressApplication = Express.getExpressApp();
const APP_NAME: string = 'File';
app.use([`/${APP_NAME}`, '/'], AuthenticationAPI);
app.use(
new BaseAPI<File, FileServiceType>(
File,
FileService
).getRouter()
);
const init: Function = async (): Promise<void> => {
try {

View File

@@ -1,11 +1,11 @@
{
"name": "File",
"name": "file",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "File",
"name": "file",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
@@ -42,7 +42,7 @@
},
"devDependencies": {
"@faker-js/faker": "^6.3.1",
"@types/jest": "^27.4.1",
"@types/jest": "^27.5.2",
"@types/node": "^17.0.22",
"jest": "^27.5.1",
"ts-jest": "^27.1.4"
@@ -5119,7 +5119,7 @@
"requires": {
"@faker-js/faker": "^6.3.1",
"@types/crypto-js": "^4.1.1",
"@types/jest": "^27.4.1",
"@types/jest": "^27.5.2",
"@types/nanoid-dictionary": "^4.2.0",
"@types/node": "^17.0.22",
"@types/uuid": "^8.3.4",

View File

@@ -1,11 +1,14 @@
import { Entity } from 'typeorm';
import FileModel from 'Common/Models/FileModel';
import SingularPluralName from 'Common/Types/Database/SingularPluralName';
import Route from 'Common/Types/API/Route';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
@SingularPluralName('File', 'Files')
@Entity({
name: 'File',
})
@CrudApiEndpoint(new Route('/file'))
export default class Label extends FileModel {
}