Skip to content

Enable proxy access management extension #797

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

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
26 changes: 20 additions & 6 deletions client/api/asset.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import request from './request';

const urls = {
base: repositoryId => `/repositories/${repositoryId}/assets`
base: 'assets',
repository: repositoryId => `repositories/${repositoryId}/assets`
};

function getUrl(repositoryId, key) {
function getUrl(key) {
const params = { key };
return request.get(urls.base(repositoryId), { params }).then(res => res.data.url);
return request.get(urls.base, { params }).then(res => res.data.url);
}

function upload(repositoryId, data) {
return request.post(urls.base(repositoryId), data).then(res => res.data);
function upload(data) {
return request.post(urls.base, data).then(res => res.data);
}

function getRepositoryAssetUrl(repositoryId, key) {
const params = { key };
return request.get(urls.repository(repositoryId), { params })
.then(res => res.data.url);
}

function uploadRepositoryAsset(repositoryId, data) {
return request.post(urls.repository(repositoryId), data)
.then(res => res.data);
}

export default {
getUrl,
upload
upload,
getRepositoryAssetUrl,
uploadRepositoryAsset
};
79 changes: 41 additions & 38 deletions client/components/common/FileInput.vue
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
<template>
<form @submit.prevent>
<v-file-input
v-if="!fileKey"
:ref="id"
@change.native="upload"
@click:append="$refs[id].$el.querySelector('input').click()"
:accept="acceptedFileTypes"
:label="label"
:placeholder="placeholder"
:outlined="outlined"
:dense="dense"
:clearable="false"
:append-icon="uploading ? 'mdi-loading mdi-spin' : 'mdi-upload'"
prepend-icon="" />
<div v-else class="mb-5 px-1 grey--text text--darken-3">
<div>{{ label }}</div>
<v-btn
@click="downloadFile(fileKey, fileName)"
text
class="grey--text text--darken-4 text-none px-0">
{{ fileName | truncate(35) }}
</v-btn>
<v-btn
@click="deleteFile({ id, fileName })"
color="grey darken-4"
icon x-small
class="ml-1">
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</form>
<upload-provider
v-slot="{ uploading, uploadFile, downloadFile, deleteFile }"
@upload="$emit('upload', $event)"
@uploading="$emit('update:uploading', $event)"
@delete="$emit('delete', $event)"
:repository-id="repositoryId">
<form @submit.prevent>
<v-file-input
v-if="!fileKey"
:ref="id"
@change.native="uploadFile"
@click:append="$refs[id].$el.querySelector('input').click()"
:accept="acceptedFileTypes"
:label="label"
:placeholder="placeholder"
:outlined="outlined"
:dense="dense"
:clearable="false"
:append-icon="uploading ? 'mdi-loading mdi-spin' : 'mdi-upload'"
prepend-icon="" />
<div v-else class="mb-5 px-1 grey--text text--darken-3">
<div>{{ label }}</div>
<v-btn
@click="downloadFile(fileKey, fileName)"
text
class="grey--text text--darken-4 text-none px-0">
{{ fileName | truncate(35) }}
</v-btn>
<v-btn
@click="deleteFile({ id, fileName })"
color="grey darken-4"
icon x-small
class="ml-1">
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</form>
</upload-provider>
</template>

<script>
import get from 'lodash/get';
import uniqueId from 'lodash/uniqueId';
import uploadMixin from '@/components/common/mixins/upload';
import UploadProvider from '@/components/common/UploadProvider';

export default {
name: 'file-input',
mixins: [uploadMixin],
props: {
id: { type: String, default: () => uniqueId('file_') },
fileKey: { type: String, default: '' },
fileName: { type: String, default: '' },
repositoryId: { type: Number, default: null },
validate: { type: Object, default: () => ({ ext: [] }) },
label: { type: String, default: 'File upload' },
placeholder: { type: String, default: 'Choose a file' },
Expand All @@ -56,10 +63,6 @@ export default {
return ext.length ? `.${ext.join(',.')}` : '';
}
},
watch: {
uploading(val) {
this.$emit('update:uploading', val);
}
}
components: { UploadProvider }
};
</script>
2 changes: 2 additions & 0 deletions client/components/common/InputAsset.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
:uploading.sync="uploading"
:validate="{ ext: extensions }"
:confirm-deletion="false"
:repository-id="repositoryId"
:label="uploadLabel"
class="upload-btn" />
<template v-if="file">
Expand Down Expand Up @@ -93,6 +94,7 @@ function isUploaded(url) {
export default {
name: 'input-asset',
props: {
repositoryId: { type: Number, default: null },
url: { type: String, default: null },
publicUrl: { type: String, default: null },
extensions: { type: Array, required: true },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
<template>
<div>
<slot v-bind="{ uploading, uploadFile, downloadFile, deleteFile }"></slot>
</div>
</template>

<script>
import downloadMixin from 'utils/downloadMixin';
import loader from '@/components/common/loader';
import { mapGetters } from 'vuex';
import { mapRequests } from '@/plugins/radio';

export default {
inject: ['$storageService'],
mixins: [downloadMixin],
props: {
repositoryId: { type: Number, default: null }
},
data: () => ({ uploading: false }),
computed: mapGetters('repository', { repositoryId: 'id' }),
methods: {
...mapRequests('app', ['showConfirmationModal']),
createFileForm(e) {
Expand All @@ -16,9 +24,13 @@ export default {
if (!file) return;
this.form.append('file', file, file.name);
},
upload: loader(function (e) {
upload(data) {
if (!this.repositoryId) return this.storageService.upload(data);
return this.$storageService.uploadRepositoryAsset(this.repositoryId, data);
},
uploadFile: loader(function (e) {
this.createFileForm(e);
return this.$storageService.upload(this.repositoryId, this.form)
return this.upload(this.form)
.then(data => {
const { name } = this.form.get('file');
this.$emit('upload', { ...data, name });
Expand All @@ -27,7 +39,9 @@ export default {
});
}, 'uploading'),
async downloadFile(key, name) {
const url = await this.$storageService.getUrl(this.repositoryId, key);
const url = this.repositoryId
? await this.$storageService.getRepositoryAssetUrl(this.repositoryId, key)
: await this.$storageService.getUrl(key);
return this.download(url, name);
},
deleteFile(item) {
Expand All @@ -37,5 +51,11 @@ export default {
action: () => this.$emit('delete', item.id, null)
});
}
},
watch: {
uploading(val) {
this.$emit('uploading', val);
}
}
};
</script>;
23 changes: 13 additions & 10 deletions client/components/common/tce-core/UploadBtn.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<template>
<div class="file-upload">
<upload-provider
v-slot="{ uploading, downloadFile, deleteFile }"
ref="provider"
@upload="$emit('upload', $event)"
@uploading="$emit('update:uploading', $event)"
@delete="$emit('delete', $event)"
:repository-id="repositoryId"
class="file-upload">
<form @submit.prevent class="upload-form">
<validation-provider ref="validator" :rules="validate">
<input
Expand Down Expand Up @@ -32,35 +39,31 @@
<v-icon>mdi-delete</v-icon>
</v-btn>
</form>
</div>
</upload-provider>
</template>

<script>
import uniqueId from 'lodash/uniqueId';
import uploadMixin from '@/components/common/mixins/upload';
import UploadProvider from '@/components/common/UploadProvider';

export default {
name: 'upload-btn',
mixins: [uploadMixin],
props: {
id: { type: String, default: () => uniqueId('file_') },
fileName: { type: String, default: '' },
fileKey: { type: String, default: '' },
repositoryId: { type: Number, default: null },
validate: { type: Object, default: () => ({ ext: [] }) },
label: { type: String, default: 'Choose a file' },
sm: { type: Boolean, default: false }
},
methods: {
async validateAndUpload(e) {
const { valid } = await this.$refs.validator.validate(e);
if (valid) this.upload(e);
if (valid) this.$refs.provider.uploadFile(e);
}
},
watch: {
uploading(val) {
this.$emit('update:uploading', val);
}
}
components: { UploadProvider }
};
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<v-toolbar-title class="pl-1">Audio Component</v-toolbar-title>
<input-asset
@input="save"
:repository-id="element.repositoryId"
:url="url"
:public-url="publicUrl"
:extensions="[
Expand Down
13 changes: 8 additions & 5 deletions client/components/content-elements/tce-image/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const mime = require('mime-types');

const DEFAULT_IMAGE_EXTENSION = 'png';

function processImage(asset, { storage }) {
function processImage(asset, { getRepositoryStorage }) {
const image = asset.data.url;
const base64Pattern = /^data:image\/(\w+);base64,/;

Expand All @@ -22,21 +22,24 @@ function processImage(asset, { storage }) {
return Promise.resolve(asset);
}

const storage = getRepositoryStorage(asset.repositoryId);
const file = Buffer.from(image.replace(base64Pattern, ''), 'base64');
const extension = image.match(base64Pattern)[1] || DEFAULT_IMAGE_EXTENSION;
const hashString = `${asset.id}${file}`;
const hash = crypto.createHash('md5').update(hashString).digest('hex');
const storagePath = storage.getPath(asset.repositoryId);
const key = `${storagePath}/${asset.id}/${hash}.${extension}`;
const key = `${asset.id}/${hash}.${extension}`;
asset.data.url = key;
return saveFile(key, file, storage).then(() => asset);
}

function resolveImage(asset, { storage, storageProxy }) {
function resolveImage(asset, { getRepositoryStorage, storageProxy }) {
if (!asset.data || !asset.data.url) return Promise.resolve(asset);

const storage = getRepositoryStorage(asset.repositoryId);

function getUrl(key) {
asset.data.url = storageProxy.getFileUrl(key);
const fullKey = storage.getFullKey(key);
asset.data.url = storageProxy.getFileUrl(fullKey);
return asset;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<v-toolbar-title>PDF Component</v-toolbar-title>
<input-asset
@input="save"
:repository-id="element.repositoryId"
:url="url"
:public-url="publicUrl"
:extensions="['.pdf']"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<v-toolbar-title class="pl-1">Video component</v-toolbar-title>
<input-asset
@input="save"
:repository-id="element.repositoryId"
:url="url"
:public-url="publicUrl"
:extensions="['.mp4']"
Expand Down
4 changes: 0 additions & 4 deletions config/server/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

module.exports = {
provider: process.env.STORAGE_PROVIDER,
// The path where assets will be stored inside repository/${repositoryId} folder.
// For example, if path is equal to assets,
// assets will be stored inside repository/${repositoryId}/assets folder
path: 'assets',
protocol: 'storage://',
amazon: {
key: process.env.STORAGE_KEY,
Expand Down
12 changes: 8 additions & 4 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ const express = require('express');
const helmet = require('helmet');
const origin = require('./shared/origin');
const path = require('path');
const storage = require('./repository/storage');
const storageProxy = require('./repository/proxy');
const serviceProvider = require('./shared/serviceProvider');
// eslint-disable-next-line require-sort/require-sort
require('express-async-errors');

/* eslint-disable require-sort/require-sort */
const auth = require('./shared/auth');
const config = require('../config/server');
const logger = require('./shared/logger')();
const storage = require('./shared/storage')(config.storage);
serviceProvider.set('storage', storage);
const storageProxy = require('./shared/storage/proxy')(config.storage.proxy);
serviceProvider.set('storageProxy', storageProxy);
const router = require('./router');
/* eslint-enable */

storageProxy.addStorage('repository', storage);
const { STORAGE_PATH } = process.env;

const app = express();
Expand All @@ -41,8 +45,8 @@ app.use(origin());
app.use(express.static(path.join(__dirname, '../dist/')));
if (STORAGE_PATH) app.use(express.static(STORAGE_PATH));
if (storageProxy.isSelfHosted) {
const { proxy: middleware } = require('./shared/storage/proxy/mw')(storage, storageProxy);
app.use(storageProxy.path, middleware);
const { getFile } = require('./shared/storage/proxy/mw');
app.use(storageProxy.path, getFile(storageProxy));
}

// Mount main router.
Expand Down
Loading