|
| 1 | +--- |
| 2 | +description: '@adminjs/upload' |
| 3 | +--- |
| 4 | + |
| 5 | +# Upload |
| 6 | + |
| 7 | +The upload feature helps organize your files and keep information about them in database. |
| 8 | + |
| 9 | +There is possibility to use different storage for files:  |
| 10 | + |
| 11 | +* local filesystem |
| 12 | +* AWS S3 |
| 13 | +* Google Cloud Storage |
| 14 | + |
| 15 | +To install the upload feature run: |
| 16 | + |
| 17 | +<pre class="language-shell"><code class="lang-shell"><strong>$ yarn add @adminjs/upload</strong></code></pre> |
| 18 | + |
| 19 | +The main concept of the upload feature is that it sends uploaded files to an external source. The database keeps the information about path and folder name where the file was stored. |
| 20 | + |
| 21 | +The feature uses following terms |
| 22 | + |
| 23 | +* `key` is the path of the stored file |
| 24 | +* `bucket` is the name of the container |
| 25 | + |
| 26 | +First we have to create in our database table where we store information about our files. |
| 27 | + |
| 28 | +Below is written interface for entity. Feel free to add your own fields to store other data connected with file. |
| 29 | + |
| 30 | +```typescript |
| 31 | +interface IFile { |
| 32 | + id: number; |
| 33 | + s3Key: string; |
| 34 | + bucket: string; |
| 35 | + mime: string; |
| 36 | + comment: string | null; |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +Next, you should decide, where your files will be stored and prepare resource entry for AdminJS |
| 41 | + |
| 42 | +{% tabs %} |
| 43 | +{% tab title="Local Filesystem" %} |
| 44 | +In this example your local server should have established `bucket` folder and it should be accessible by web browser (via `baseUrl` path) |
| 45 | + |
| 46 | +```javascript |
| 47 | +app.use(express.static(path.join(__dirname, '../public'))); |
| 48 | +``` |
| 49 | + |
| 50 | + |
| 51 | + |
| 52 | +```typescript |
| 53 | +import uploadFeature from '@adminjs/upload'; |
| 54 | +import { File } from './models/file'; |
| 55 | + |
| 56 | +const localProvider = { |
| 57 | + bucket: 'public/files', |
| 58 | + opts: { |
| 59 | + baseUrl: '/files', |
| 60 | + }, |
| 61 | +}; |
| 62 | + |
| 63 | +export const files = { |
| 64 | + resource: File, |
| 65 | + options: { |
| 66 | + properties: { |
| 67 | + s3Key: { |
| 68 | + type: 'string', |
| 69 | + }, |
| 70 | + bucket: { |
| 71 | + type: 'string', |
| 72 | + }, |
| 73 | + mime: { |
| 74 | + type: 'string', |
| 75 | + }, |
| 76 | + comment: { |
| 77 | + type: 'textarea', |
| 78 | + isSortable: false, |
| 79 | + }, |
| 80 | + }, |
| 81 | + }, |
| 82 | + features: [ |
| 83 | + uploadFeature({ |
| 84 | + provider: { local: localProvider }, |
| 85 | + validation: { mimeTypes: ['image/png', 'application/pdf', 'audio/mpeg'] }, |
| 86 | + }), |
| 87 | + ], |
| 88 | +}; |
| 89 | +``` |
| 90 | +{% endtab %} |
| 91 | + |
| 92 | +{% tab title="AWS S3" %} |
| 93 | +```typescript |
| 94 | +import uploadFeature from '@adminjs/upload'; |
| 95 | +import { File } from './models/file'; |
| 96 | + |
| 97 | +const AWScredentials = { |
| 98 | + accessKeyId: 'AWS_ACCESS_KEY_ID', |
| 99 | + secretAccessKey: 'AWS_SECRET_ACCESS_KEY', |
| 100 | + region: 'AWS_REGION', |
| 101 | + bucket: 'AWS_BUCKET', |
| 102 | +}; |
| 103 | + |
| 104 | +export const files = { |
| 105 | + resource: File, |
| 106 | + options: { |
| 107 | + properties: { |
| 108 | + s3Key: { |
| 109 | + type: 'string', |
| 110 | + }, |
| 111 | + bucket: { |
| 112 | + type: 'string', |
| 113 | + }, |
| 114 | + mime: { |
| 115 | + type: 'string', |
| 116 | + }, |
| 117 | + comment: { |
| 118 | + type: 'textarea', |
| 119 | + isSortable: false, |
| 120 | + }, |
| 121 | + }, |
| 122 | + }, |
| 123 | + features: [ |
| 124 | + uploadFeature({ |
| 125 | + provider: { aws: AWScredentials }, |
| 126 | + validation: { mimeTypes: ['application/pdf'] }, |
| 127 | + }), |
| 128 | + ], |
| 129 | +}; |
| 130 | +``` |
| 131 | +{% endtab %} |
| 132 | + |
| 133 | +{% tab title="Google Cloud Storage" %} |
| 134 | +<pre class="language-typescript"><code class="lang-typescript">import uploadFeature from '@adminjs/upload'; |
| 135 | +import { File } from './models/file'; |
| 136 | + |
| 137 | +<strong>const GCScredentials = { |
| 138 | +</strong> serviceAccount: 'SERVICE_ACCOUNT', |
| 139 | + bucket: 'GCP_STORAGE_BUCKET', |
| 140 | + expires: 0, |
| 141 | +}; |
| 142 | + |
| 143 | +export const files = { |
| 144 | + resource: File, |
| 145 | + options: { |
| 146 | + properties: { |
| 147 | + s3Key: { |
| 148 | + type: 'string', |
| 149 | + }, |
| 150 | + bucket: { |
| 151 | + type: 'string', |
| 152 | + }, |
| 153 | + mime: { |
| 154 | + type: 'string', |
| 155 | + }, |
| 156 | + comment: { |
| 157 | + type: 'textarea', |
| 158 | + isSortable: false, |
| 159 | + }, |
| 160 | + }, |
| 161 | + }, |
| 162 | + features: [ |
| 163 | + uploadFeature({ |
| 164 | + provider: { gpc: GCScredentials }, |
| 165 | + validation: { mimeTypes: ['image/png'] }, |
| 166 | + }), |
| 167 | + ], |
| 168 | +};</code></pre> |
| 169 | +{% endtab %} |
| 170 | +{% endtabs %} |
| 171 | + |
| 172 | +After that add files resource to AdminJS options config |
| 173 | + |
| 174 | +```typescript |
| 175 | +import { files } from './resources/files'; |
| 176 | + |
| 177 | +const adminJsOptions = { |
| 178 | + resources: [ |
| 179 | + //... |
| 180 | + files |
| 181 | + ], |
| 182 | + //... |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +If you would like to deal with multiple files with single database entry it will be necessary to modify config files |
| 187 | + |
| 188 | +{% tabs %} |
| 189 | +{% tab title="Entity" %} |
| 190 | +```typescript |
| 191 | +import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; |
| 192 | + |
| 193 | +@Entity({ name: 'files' }) |
| 194 | +export class File extends BaseEntity { |
| 195 | + @PrimaryGeneratedColumn() |
| 196 | + public id: number; |
| 197 | + |
| 198 | + @Column({ name: 's3_key', nullable: true, type: 'jsonb' }) |
| 199 | + public s3Key: string; |
| 200 | + |
| 201 | + @Column({ nullable: true, type: 'jsonb' }) |
| 202 | + public bucket: string; |
| 203 | + |
| 204 | + @Column({ nullable: true, type: 'jsonb' }) |
| 205 | + public mime: string; |
| 206 | + |
| 207 | + @Column({ nullable: true, type: 'text' }) |
| 208 | + public comment: string; |
| 209 | + |
| 210 | + @CreateDateColumn({ name: 'created_at' }) |
| 211 | + public createdAt: Date; |
| 212 | + |
| 213 | + @UpdateDateColumn({ name: 'updated_at' }) |
| 214 | + public updatedAt: Date; |
| 215 | +} |
| 216 | + |
| 217 | +``` |
| 218 | +{% endtab %} |
| 219 | + |
| 220 | +{% tab title="Resource" %} |
| 221 | +```typescript |
| 222 | +import uploadFeature from '@adminjs/upload'; |
| 223 | +import { File } from './models/file'; |
| 224 | + |
| 225 | +const localProvider = { |
| 226 | + bucket: 'public/files', |
| 227 | + baseUrl: '/files', |
| 228 | +}; |
| 229 | + |
| 230 | +export const files = { |
| 231 | + resource: File, |
| 232 | + options: { |
| 233 | + properties: { |
| 234 | + s3Key: { |
| 235 | + type: 'string', |
| 236 | + isArray: true, |
| 237 | + }, |
| 238 | + bucket: { |
| 239 | + type: 'string', |
| 240 | + isArray: true, |
| 241 | + }, |
| 242 | + mime: { |
| 243 | + type: 'string', |
| 244 | + isArray: true, |
| 245 | + }, |
| 246 | + comment: { |
| 247 | + type: 'textarea', |
| 248 | + isSortable: false, |
| 249 | + }, |
| 250 | + }, |
| 251 | + }, |
| 252 | + features: [ |
| 253 | + uploadFeature({ |
| 254 | + provider: { local: localProvider }, |
| 255 | + multiple: true, |
| 256 | + validation: { mimeTypes: ['image/png', 'application/pdf', 'audio/mpeg'] }, |
| 257 | + }), |
| 258 | + ], |
| 259 | +}; |
| 260 | +``` |
| 261 | +{% endtab %} |
| 262 | +{% endtabs %} |
| 263 | + |
0 commit comments