media security_type updates

This commit is contained in:
2023-09-29 07:19:33 +10:00
parent d9c0c8f1d8
commit 42f2baca5e
12 changed files with 219 additions and 96 deletions

View File

@@ -85,6 +85,7 @@ import { Media } from "../helpers/api.types";
import { onMounted, ref, watch } from "vue";
import { ImportMetaExtras } from "../../../import-meta";
import { strCaseCmp } from "../helpers/string";
import { mediaGetWebURL } from "../helpers/media";
const emits = defineEmits(["update:modelValue"]);
const props = defineProps({
@@ -157,24 +158,8 @@ const updateFileList = (newFileList: Array<Media>) => {
fileList.value = [];
for (const mediaItem of newFileList) {
const webUrl = (import.meta as ImportMetaExtras).env.APP_URL;
const apiUrl = (import.meta as ImportMetaExtras).env.APP_URL_API;
// Is the URL a API request?
if (mediaItem.url.startsWith(apiUrl)) {
const fileUrlPath = mediaItem.url.substring(apiUrl.length);
const fileUrlParts = fileUrlPath.split("/");
if (
fileUrlParts.length === 4 &&
fileUrlParts[0].length === 0 &&
strCaseCmp("media", fileUrlParts[1]) === true &&
strCaseCmp("download", fileUrlParts[3]) === true
) {
mediaItem.url = webUrl + "/file/" + fileUrlParts[2];
fileList.value.push(mediaItem);
}
} else {
mediaItem.url = mediaGetWebURL(mediaItem);
if (mediaItem.url != "") {
fileList.value.push(mediaItem);
}
}

View File

@@ -1,6 +1,6 @@
<template>
<SMForm :model-value="form" @submit="handleSubmit">
<SMFormCard :loading="dialogLoading">
<SMCard :loading="dialogLoading">
<template #header>
<h3>Change Password</h3>
<p>Enter your new password below</p>
@@ -16,7 +16,7 @@
<button type="button" @click="handleClickCancel">Cancel</button>
<input role="button" type="submit" value="Update" />
</template>
</SMFormCard>
</SMCard>
</SMForm>
</template>
@@ -31,11 +31,12 @@ import { useToastStore } from "../../store/ToastStore";
import { useUserStore } from "../../store/UserStore";
import SMForm from "../SMForm.vue";
import SMInput from "../SMInput.vue";
import SMCard from "../SMCard.vue";
const form: FormObject = reactive(
Form({
password: FormControl("", And([Required(), Password()])),
})
}),
);
const applicationStore = useApplicationStore();

View File

@@ -145,7 +145,8 @@
)}')`,
}">
<div
v-if="item.security_type != ''">
v-if="item.security_type != ''"
class="absolute right--1 top--1 h-4 w-4">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24">

View File

@@ -1,5 +1,6 @@
import { ImportMetaExtras } from "../../../import-meta";
import { Media, MediaJob } from "./api.types";
import { toTitleCase } from "./string";
import { strCaseCmp, toTitleCase } from "./string";
export const mediaGetVariantUrl = (
media: Media,
@@ -25,6 +26,30 @@ export const mediaGetVariantUrl = (
: media.url;
};
export const mediaGetWebURL = (media: Media): string => {
const webUrl = (import.meta as ImportMetaExtras).env.APP_URL;
const apiUrl = (import.meta as ImportMetaExtras).env.APP_URL_API;
let url = media.url;
// Is the URL a API request?
if (media.url.startsWith(apiUrl)) {
const fileUrlPath = media.url.substring(apiUrl.length);
const fileUrlParts = fileUrlPath.split("/");
if (
fileUrlParts.length >= 4 &&
fileUrlParts[0].length === 0 &&
strCaseCmp("media", fileUrlParts[1]) === true &&
strCaseCmp("download", fileUrlParts[3]) === true
) {
url = webUrl + "/file/" + fileUrlParts[2];
}
}
return url;
};
/**
* Check if a mime matches.
* @param {string} mimeExpected The mime expected.

View File

@@ -121,5 +121,9 @@ export const toPrice = (numOrString: number | string): string => {
* @returns {boolean} If the strings match.
*/
export const strCaseCmp = (string1: string, string2: string): boolean => {
return string1.toLowerCase() === string2.toLowerCase();
if (string1 !== undefined && string2 !== undefined) {
return string1.toLowerCase() === string2.toLowerCase();
}
return false;
};

View File

@@ -126,3 +126,22 @@ export const extractFileNameFromUrl = (url: string): string => {
const fileName = matches[1];
return fileName;
};
export const addQueryParam = (
url: string,
name: string,
value: string,
): string => {
const urlObject = new URL(url);
const queryParams = new URLSearchParams(urlObject.search);
if (queryParams.has(name)) {
queryParams.set(name, value);
} else {
// Add the new query parameter
queryParams.append(name, value);
}
urlObject.search = queryParams.toString();
return urlObject.toString();
};

View File

@@ -4,25 +4,49 @@
:status="pageStatus" />
<SMLoading v-else-if="pageLoading == true"></SMLoading>
<SMForm
v-else-if="showPasswordForm == true"
v-else-if="showForm == 'password'"
:model-value="form"
@submit="handleSubmit">
<SMFormCard>
<template #header>
<h3>Password Required</h3>
<p>This file requires a password before it can be viewed</p>
</template>
<template #body>
<SMInput
control="password"
type="password"
label="File Password"
autofocus />
</template>
<template #footer-space-between>
<input role="button" type="submit" value="OK" />
</template>
</SMFormCard>
<div
class="max-w-2xl mx-auto border-1 bg-white rounded-xl mt-7xl text-gray-5 px-12 py-8">
<h3 class="mb-4">Password Required</h3>
<p class="mb-2">
This file requires a password before it can be viewed
</p>
<SMInput
class="mb-4"
control="password"
type="password"
label="File Password"
autofocus />
<div class="flex flex-justify-end">
<input
type="submit"
class="font-medium px-6 py-3.1 rounded-2 hover:shadow-md text-lg transition bg-sky-600 hover:bg-sky-500 text-white cursor-pointer"
value="Submit" />
</div>
</div>
</SMForm>
<SMForm
v-else-if="showForm == 'complete'"
:model-value="form"
@submit="handleSubmit">
<div
class="max-w-2xl mx-auto border-1 bg-white rounded-xl mt-7xl text-gray-5 px-12 py-8">
<h3 class="mb-4">Download Complete</h3>
<p class="mb-2">
If you have permission to view this document, your download
should now begin.
</p>
<div class="flex flex-justify-end">
<button
role="button"
class="font-medium px-6 py-3.1 rounded-2 hover:shadow-md text-lg transition bg-sky-600 hover:bg-sky-500 text-white cursor-pointer"
@click="handleClose()">
Close
</button>
</div>
</div>
</SMForm>
</template>
@@ -30,8 +54,11 @@
import { reactive, ref } from "vue";
import { api } from "../helpers/api";
import { useRoute } from "vue-router";
import { Media } from "../helpers/api.types";
import { Media, MediaResponse } from "../helpers/api.types";
import SMForm from "../components/SMForm.vue";
import SMInput from "../components/SMInput.vue";
import SMLoading from "../components/SMLoading.vue";
import SMPageStatus from "../components/SMPageStatus.vue";
import { strCaseCmp } from "../helpers/string";
import { useUserStore } from "../store/UserStore";
import { Form, FormControl, FormObject } from "../helpers/form";
@@ -39,7 +66,7 @@ import { Required } from "../helpers/validate";
const pageStatus = ref(200);
const pageLoading = ref(true);
const showPasswordForm = ref(false);
const showForm = ref("");
const fileUrl = ref("");
const userStore = useUserStore();
@@ -71,6 +98,9 @@ const downloadFile = (params = {}) => {
}
window.location.href = url;
window.setTimeout(() => {
showForm.value = "complete";
}, 1500);
};
/*
@@ -84,6 +114,10 @@ const handleSubmit = () => {
downloadFile(params);
};
const handleClose = () => {
window.close();
};
/**
* Handle page loading
*/
@@ -96,34 +130,45 @@ const handleLoad = async () => {
id: route.params.id,
};
let result = await api.get({
url: "/media/:id",
params: params,
});
try {
let result = await api.get({
url: "/media/{id}",
params: params,
});
if (result.status === 200) {
const medium = result.data as Media;
fileUrl.value = medium.url;
if (result.status === 200) {
const data = result.data as MediaResponse;
const medium = data.medium as Media;
fileUrl.value = medium.url;
if (medium.security_type === "") {
downloadFile();
} else if (
strCaseCmp("permission", medium.security_type) === true &&
userStore.id
) {
const params = {
token: userStore.token,
};
if (medium.security_type === "") {
downloadFile();
} else if (
strCaseCmp("permission", medium.security_type) === true &&
userStore.id
) {
const params = {
token: userStore.token,
};
downloadFile(params);
} else if (strCaseCmp("password", medium.security_type) === true) {
showPasswordForm.value = true;
downloadFile(params);
} else if (
strCaseCmp("password", medium.security_type) === true
) {
showForm.value = "password";
} else {
/* unknown security type */
pageStatus.value = 403;
}
pageLoading.value = false;
} else {
/* unknown security type */
pageStatus.value = 403;
pageStatus.value = result.status;
pageLoading.value = false;
}
} else {
pageStatus.value = result.status;
} catch (error) {
pageStatus.value = error.status;
pageLoading.value = false;
}
}
};

View File

@@ -74,12 +74,24 @@
<template #item-title="item">
<div class="flex gap-2">
<div
class="w-100 h-100 max-h-15 max-w-20 mr-2 bg-contain bg-no-repeat bg-center"
class="w-100 h-100 max-h-15 max-w-20 mr-2 bg-contain bg-no-repeat bg-center relative"
:style="{
backgroundImage: `url('${mediaGetThumbnail(
item,
)}')`,
}"></div>
}">
<div
v-if="item.security_type != ''"
class="absolute right--1 top--1 h-4 w-4">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24">
<title>locked</title>
<path
d="M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z" />
</svg>
</div>
</div>
<div class="flex flex-col flex-justify-center">
<span>{{ item.title }}</span>
<span class="small">({{ item.name }})</span>
@@ -101,11 +113,11 @@
fill="currentColor" />
</svg>
</button>
<button
type="button"
<a
:href="mediaGetWebURL(item)"
class="bg-transparent cursor-pointer hover:text-sky-5"
title="Download"
@click="handleDownload(item)">
target="_blank">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
@@ -114,7 +126,7 @@
d="M220-160q-24 0-42-18t-18-42v-143h60v143h520v-143h60v143q0 24-18 42t-42 18H220Zm260-153L287-506l43-43 120 120v-371h60v371l120-120 43 43-193 193Z"
fill="currrentColor" />
</svg>
</button>
</a>
<button
type="button"
class="bg-transparent cursor-pointer hover:text-red-7"
@@ -170,11 +182,11 @@ import SMMastHead from "../../components/SMMastHead.vue";
import SMTable from "../../components/SMTable.vue";
import SMPagination from "../../components/SMPagination.vue";
import SMLoading from "../../components/SMLoading.vue";
import { updateRouterParams } from "../../helpers/url";
import { addQueryParam, updateRouterParams } from "../../helpers/url";
import { userHasPermission } from "../../helpers/utils";
import SMPageStatus from "../../components/SMPageStatus.vue";
import SMCheckbox from "../../components/SMCheckbox.vue";
import { mediaGetThumbnail } from "../../helpers/media";
import { mediaGetThumbnail, mediaGetWebURL } from "../../helpers/media";
const route = useRoute();
const router = useRouter();
@@ -448,7 +460,9 @@ const handleEditSelected = async () => {
* @param {Media} item The media item.
*/
const handleDownload = (item: Media) => {
window.open(`${item.url}?download=1`, "_blank");
// window.open(`${item.url}?download=1`, "_blank");
// window.open(addQueryParam(mediaGetWebURL(item), "download", "1"), "_blank");
window.open(mediaGetWebURL(item), "_blank");
};
const computedSelectedCount = computed(() => {