Skip to content

Commit

Permalink
Merge branch 'enhancements-6'
Browse files Browse the repository at this point in the history
  • Loading branch information
t7tran committed Oct 6, 2024
2 parents 1b1ab77 + e7a7c1b commit 7248f10
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 46 deletions.
9 changes: 0 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ on:

env:
GHCR_IMAGE: ghcr.io/${{ github.repository }}
DOCKERHUB_IMAGE: ${{ github.repository }}

jobs:
check-version:
Expand Down Expand Up @@ -92,21 +91,13 @@ jobs:
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_IMAGE }}
${{ env.GHCR_IMAGE }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=canary,enable=${{ needs.check-version.outputs.prerelease }}
- name: Login to Docker Hub
uses: docker/login-action@v3
if: env.DOCKERHUB_IMAGE
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Login to GHCR
uses: docker/login-action@v3
if: env.GHCR_IMAGE
Expand Down
24 changes: 0 additions & 24 deletions .github/workflows/sync-dockerhub-readme.yml

This file was deleted.

36 changes: 36 additions & 0 deletions api/src/controllers/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { respond } from '../middleware/respond.js';
import useCollection from '../middleware/use-collection.js';
import { validateBatch } from '../middleware/validate-batch.js';
import { FilesService } from '../services/files.js';
import { FoldersService } from '../services/folders.js';
import { MetaService } from '../services/meta.js';
import asyncHandler from '../utils/async-handler.js';
import { sanitizeQuery } from '../utils/sanitize-query.js';
Expand Down Expand Up @@ -96,6 +97,41 @@ export const multipartHandler: RequestHandler = (req, res, next) => {

payload.filename_download = filename;

payload.folder = payload.folder || req.query['folder'];

if (payload.folder && !/^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(payload.folder)) {
const foldersService = new FoldersService({ accountability: req.accountability, schema: req.schema });
const path: string = payload.folder;
const parts = path.split('/').filter((f) => !!f);

if (parts.length === 0) {
return busboy.emit('error', new InvalidPayloadError({ reason: `Invalid folder ${path}` }));
}

let folderId: string | undefined;
let parentFilter: any = { parent: { _null: true } };

for (const part of parts) {
folderId = (
await foldersService.readByQuery({
fields: ['id'],
filter: {
_and: [{ name: { _eq: part } }, parentFilter],
},
limit: 1,
})
)[0]?.['id'];

if (!folderId) {
return busboy.emit('error', new InvalidPayloadError({ reason: `Invalid folder ${path}` }));
}

parentFilter = { parent: { _eq: folderId } };
}

payload.folder = folderId;
}

const payloadWithRequiredFields = {
...payload,
type: mimeType,
Expand Down
46 changes: 35 additions & 11 deletions api/src/services/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ export class FilesService extends ItemsService<File> {

// Is this file a replacement? if the file data already exists and we have a primary key
const isReplacement = existingFile !== null && primaryKey !== undefined;
const emitFilterOpts: MutationOptions & Record<string, any> = { emitEvents: false, emitFilters: true };

// If this is a new file upload, we need to generate a new primary key and DB record
if (isReplacement === false || primaryKey === undefined) {
primaryKey = await this.createOne(payload, { emitEvents: false });
primaryKey = await this.createOne(payload, emitFilterOpts);
}

const fileExtension =
Expand Down Expand Up @@ -109,25 +110,48 @@ export class FilesService extends ItemsService<File> {
await disk.delete(payload.filename_disk!);
}
} catch (err: any) {
if (isReplacement === true) {
logger.warn(`Couldn't delete temp file ${tempFilenameDisk}`);
} else {
logger.warn(`Couldn't delete file ${payload.filename_disk}`);
if (!err.message?.includes("ENOENT")) {
if (isReplacement === true) {
logger.warn(`Couldn't delete temp file ${tempFilenameDisk}`);
} else {
logger.warn(`Couldn't delete file ${payload.filename_disk}`);
}

logger.warn(err);
}

logger.warn(err);
}
};

try {
const { stream: streamAfterHooks, reason, cleanup } = await emitter.emitFilter(
'files.upload',
{ stream, reason: "", cleanup: () => 0 },
{
payload,
collection: this.collection,
},
{
database: this.knex,
schema: this.schema,
accountability: this.accountability,
},
);

if (!streamAfterHooks) {
if (typeof cleanup === "function") cleanup();
throw new InvalidPayloadError({ reason: reason || 'Invalid payload' });
}

// If this is a replacement, we'll write the file to a temp location first to ensure we don't overwrite the existing file if something goes wrong
if (isReplacement === true) {
await disk.write(tempFilenameDisk, stream, payload.type);
await disk.write(tempFilenameDisk, streamAfterHooks, payload.type);
} else {
// If this is a new file upload, we'll write the file to the final location
await disk.write(payload.filename_disk, stream, payload.type);
await disk.write(payload.filename_disk, streamAfterHooks, payload.type);
}

if (typeof cleanup === "function") cleanup();

// Check if the file was truncated (if the stream ended early) and throw limit error if it was
if ('truncated' in stream && stream.truncated === true) {
throw new ContentTooLargeError();
Expand All @@ -138,7 +162,7 @@ export class FilesService extends ItemsService<File> {

await cleanUp();

if (err instanceof ContentTooLargeError) {
if (err instanceof ContentTooLargeError || err instanceof InvalidPayloadError) {
throw err;
} else {
throw new ServiceUnavailableError({ service: 'files', reason: `Couldn't save file ${payload.filename_disk}` });
Expand Down Expand Up @@ -172,7 +196,7 @@ export class FilesService extends ItemsService<File> {
schema: this.schema,
});

await sudoService.updateOne(primaryKey, { ...payload, ...metadata }, { emitEvents: false });
await sudoService.updateOne(primaryKey, { ...payload, ...metadata }, emitFilterOpts);

if (opts?.emitEvents !== false) {
emitter.emitAction(
Expand Down
4 changes: 2 additions & 2 deletions api/src/services/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export class ItemsService<Item extends AnyItem = AnyItem, Collection extends str
// Run all hooks that are attached to this event so the end user has the chance to augment the
// item that is about to be saved
const payloadAfterHooks =
opts.emitEvents !== false
(opts.emitEvents !== false || (opts as any).emitFilters !== false)
? await emitter.emitFilter(
this.eventScope === 'items'
? ['items.create', `${this.collection}.items.create`]
Expand Down Expand Up @@ -699,7 +699,7 @@ export class ItemsService<Item extends AnyItem = AnyItem, Collection extends str
// Run all hooks that are attached to this event so the end user has the chance to augment the
// item that is about to be saved
const payloadAfterHooks =
opts.emitEvents !== false
(opts.emitEvents !== false || (opts as any).emitFilters !== false)
? await emitter.emitFilter(
this.eventScope === 'items'
? ['items.update', `${this.collection}.items.update`]
Expand Down
1 change: 1 addition & 0 deletions app/src/routes/login/login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ useHead({
<v-icon name="lock" left />
{{ t('not_authenticated') }}
</template>
<component is="interface-presentation-custom-login-notice" :authenticated="authenticated" />
</template>
</public-view>
</template>
Expand Down
9 changes: 9 additions & 0 deletions packages/utils/shared/generate-joi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,15 @@ export function generateJoi(filter: FieldFilter | null, options?: JoiOptions): A
schema[key] = getAnySchema().invalid(null);
}

if (operator === '_exist') {
schema[key] = getAnySchema().exist();
}

if (operator === '_nexist') {
options.requireAll = false;
schema[key] = getAnySchema().forbidden();
}

if (operator === '_empty') {
schema[key] = getAnySchema().valid('');
}
Expand Down

0 comments on commit 7248f10

Please sign in to comment.