Skip to content

Commit

Permalink
feat: analysis-bucket implementation (#433)
Browse files Browse the repository at this point in the history
* feat: create initial interface + entity for analysis-bucket

* feat: implemented tear down & spin-up command

* feat: implemented analysis-bucket api client

* feat: enhance implementation of bucket creation/deletion in analysis-manager

* fix: adjust analysis-entity structure to analysis interface

* feat: adjusted ui & component library

* fix: simplified auth middleware + updated queuing library

* fix: ui preview mode

* feat: create crud handlers for analysis-bucket

* feat: adjust analysis-bucket handling across services

* fix: test suite & linting issues
  • Loading branch information
tada5hi authored Jun 11, 2024
1 parent b44e278 commit 15329f4
Show file tree
Hide file tree
Showing 98 changed files with 1,542 additions and 546 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 33 additions & 33 deletions packages/client-ui/middleware/auth.global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,53 @@
*/

import { useStore } from '@authup/client-web-kit';
import { hasOwnProperty } from '@privateaim/kit';
import { storeToRefs } from 'pinia';
import type { RouteLocationNormalized } from 'vue-router';
import {
navigateTo,
} from '#app';
import { LayoutKey } from '../config/layout';

function checkAbilityOrPermission(route: RouteLocationNormalized, has: (name: string) => boolean) {
const layoutKeys : string[] = [
LayoutKey.REQUIRED_PERMISSIONS,
];

function checkPermission(route: RouteLocationNormalized, has: (name: string) => boolean) {
let isAllowed : undefined | boolean;

for (let i = 0; i < layoutKeys.length; i++) {
const layoutKey = layoutKeys[i];
const layoutKey = LayoutKey.REQUIRED_PERMISSIONS;

for (let j = 0; j < route.matched.length; j++) {
const matchedRecord = route.matched[j];
for (let j = 0; j < route.matched.length; j++) {
const matchedRecord = route.matched[j];

if (!Object.prototype.hasOwnProperty.call(matchedRecord.meta, layoutKey)) {
continue;
}
if (!hasOwnProperty(matchedRecord.meta, layoutKey)) {
continue;
}

const value = matchedRecord.meta[layoutKey];
if (Array.isArray(value)) {
isAllowed = value.some((val) => has(val));
}
const value = matchedRecord.meta[layoutKey];
if (Array.isArray(value)) {
isAllowed = value.some((val) => has(val));
}

if (isAllowed) {
return true;
}
if (isAllowed) {
return true;
}
}

if (typeof isAllowed === 'undefined') {
return true;
}

if (!isAllowed) {
const parts = route.path.split('/');
parts.pop();
throw new Error(parts.join('/'));
}

return true;
return isAllowed;
}

export default defineNuxtRouteMiddleware(async (to, from) => {
const store = useStore();
const { loggedIn } = storeToRefs(store);

let redirectPath = '/';
let redirectPath = '/login';

if (typeof from !== 'undefined') {
if (
typeof from !== 'undefined' &&
from.fullPath !== to.fullPath
) {
redirectPath = from.fullPath;
}

Expand All @@ -69,7 +61,10 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
} catch (e) {
store.logout();

if (!to.fullPath.startsWith('/logout') && !to.fullPath.startsWith('/login')) {
if (
!to.fullPath.startsWith('/logout') &&
!to.fullPath.startsWith('/login')
) {
return navigateTo({
path: '/logout',
query: {
Expand Down Expand Up @@ -99,15 +94,20 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
query,
});
}
}

try {
checkAbilityOrPermission(to, (name) => store.abilities.has(name));
} catch (e) {
if (
to.matched.some((matched) => !!matched.meta[LayoutKey.REQUIRED_PERMISSIONS])
) {
const permitted = checkPermission(to, (name) => store.abilities.has(name));
if (!permitted) {
return navigateTo({
path: redirectPath,
});
}
} else if (
}

if (
!to.fullPath.startsWith('/logout') &&
to.matched.some((matched) => matched.meta[LayoutKey.REQUIRED_LOGGED_OUT])
) {
Expand Down
41 changes: 25 additions & 16 deletions packages/client-ui/pages/analyses/[id]/results.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
- view the LICENSE file that was distributed with this source code.
-->
<script lang="ts">
import { FAnalysisBucket, FAnalysisBucketFileDownload, FAnalysisBucketFiles } from '@privateaim/client-vue';
import { computed } from 'vue';
import type { BuildInput } from 'rapiq';
import type { PropType } from 'vue';
import { type Analysis, type AnalysisFile, AnalysisFileType } from '@privateaim/core';
import { FAnalysisFileDownload, FAnalysisFiles } from '@privateaim/client-vue';
import { type Analysis, type AnalysisBucket, AnalysisBucketType } from '@privateaim/core';
import { defineNuxtComponent } from '#app';

export default defineNuxtComponent({
components: { FAnalysisFiles, FAnalysisFileDownload },
components: { FAnalysisBucket, FAnalysisBucketFiles, FAnalysisFileDownload: FAnalysisBucketFileDownload },
props: {
entity: {
type: Object as PropType<Analysis>,
Expand All @@ -22,12 +22,12 @@ export default defineNuxtComponent({
},
emits: ['updated', 'failed'],
setup(props) {
const query = computed<BuildInput<AnalysisFile>>(() => ({
const query = computed<BuildInput<AnalysisBucket>>(() => ({
filter: {
type: AnalysisFileType.RESULT,
type: AnalysisBucketType.RESULT,
analysis_id: props.entity.id,
},
} satisfies BuildInput<AnalysisFile>));
} satisfies BuildInput<AnalysisBucket>));

return {
query,
Expand All @@ -37,16 +37,25 @@ export default defineNuxtComponent({
</script>
<template>
<div class="panel-box">
<FAnalysisFiles
v-if="entity"
:query="query"
>
<template #itemActions="{ data }">
<FAnalysisFileDownload
:entity="data"
:with-icon="true"
/>
<FAnalysisBucket :query="query">
<template #default="{ data: bucket }">
<FAnalysisBucketFiles
v-if="entity"
:query="{ filters: { bucket_id: bucket.id } }"
>
<template #itemActions="{ data }">
<FAnalysisFileDownload
:entity="data"
:with-icon="true"
/>
</template>
</FAnalysisBucketFiles>
</template>
</FAnalysisFiles>
<template #error>
<div class="alert alert-sm alert-warning">
The result bucket does not exist. Therefore, no files can be downloaded.
</div>
</template>
</FAnalysisBucket>
</div>
</template>
2 changes: 2 additions & 0 deletions packages/client-ui/plugins/01.auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { install } from '@authup/client-web-kit';
import type { Pinia } from 'pinia';
import { useCookie } from '#imports';

export default defineNuxtPlugin({
Expand All @@ -14,6 +15,7 @@ export default defineNuxtPlugin({
const { authupUrl: baseURL } = runtimeConfig.public;

ctx.vueApp.use(install, {
pinia: ctx.$pinia as Pinia,
baseURL,
cookieSet: (key, value) => {
const cookie = useCookie(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
DomainType,
} from '@privateaim/core';
import type {
AnalysisFile,
AnalysisBucketFile,
} from '@privateaim/core';
import type { PropType } from 'vue';
import {
Expand All @@ -20,7 +20,7 @@ import { createEntityManager, defineEntityManagerEvents } from '../../core';
export default defineComponent({
props: {
entity: {
type: Object as PropType<AnalysisFile>,
type: Object as PropType<AnalysisBucketFile>,
required: true,
},
filesSelected: {
Expand All @@ -32,11 +32,11 @@ export default defineComponent({
},
},
emits: {
...defineEntityManagerEvents<AnalysisFile>(),
...defineEntityManagerEvents<AnalysisBucketFile>(),
// eslint-disable-next-line @typescript-eslint/no-unused-vars
toggle: (_entity?: AnalysisFile) => true,
toggle: (_entity?: AnalysisBucketFile) => true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
check: (_entity?: AnalysisFile) => true,
check: (_entity?: AnalysisBucketFile) => true,
},
setup(props, setup) {
const manager = createEntityManager({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* view the LICENSE file that was distributed with this source code.
*/

import type { AnalysisFile } from '@privateaim/core';
import type { AnalysisBucketFile } from '@privateaim/core';
import type { PropType } from 'vue';
import { defineComponent } from 'vue';
import { ActionCommandElementType, injectStorageHTTPClient, renderActionCommand } from '../../core';

const FAnalysisFileDownload = defineComponent({
const FAnalysisBucketFileDownload = defineComponent({
props: {
entity: {
type: Object as PropType<AnalysisFile>,
type: Object as PropType<AnalysisBucketFile>,
required: true,
},
elementType: {
Expand All @@ -33,7 +33,7 @@ const FAnalysisFileDownload = defineComponent({
const storageClient = injectStorageHTTPClient();

const execute = async () => {
const url = storageClient.bucketFile.getStreamURL(props.entity.bucket_file_id);
const url = storageClient.bucketFile.getStreamURL(props.entity.external_id);

window.open(
url,
Expand All @@ -57,5 +57,5 @@ const FAnalysisFileDownload = defineComponent({
});

export {
FAnalysisFileDownload,
FAnalysisBucketFileDownload,
};
Loading

0 comments on commit 15329f4

Please sign in to comment.