feat: Optimize shared file viewing experience
- Add and update APIs for thumbnail display and file sorting. - Refresh frontend views and components to enhance shared file presentation.
This commit is contained in:
parent
ae0af1f996
commit
8b6b6b622e
@ -1,11 +1,12 @@
|
|||||||
import { fetchURL, removePrefix, createURL } from "./utils";
|
import { fetchURL, removePrefix, createURL } from "./utils";
|
||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
export async function fetch(url: string, password: string = "") {
|
export async function fetch(url: string, password: string = "") {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
const res = await fetchURL(
|
const res = await fetchURL(
|
||||||
`/api/public/share${url}`,
|
`/api/public/share${url}?s=${authStore.shareConfig.sortBy}&a=${Number(authStore.shareConfig.asc)}`,
|
||||||
{
|
{
|
||||||
headers: { "X-SHARE-PASSWORD": encodeURIComponent(password) },
|
headers: { "X-SHARE-PASSWORD": encodeURIComponent(password) },
|
||||||
},
|
},
|
||||||
@ -73,3 +74,14 @@ export function getDownloadURL(res: Resource, inline = false) {
|
|||||||
|
|
||||||
return createURL("api/public/dl/" + res.hash + res.path, params, false);
|
return createURL("api/public/dl/" + res.hash + res.path, params, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPreviewURL(file: ResourceItem, size: string) {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const params = {
|
||||||
|
inline: "true",
|
||||||
|
token: authStore.guestJwt,
|
||||||
|
key: Date.parse(file.modified),
|
||||||
|
};
|
||||||
|
|
||||||
|
return createURL("api/public/preview/" + size + file.path, params, false);
|
||||||
|
}
|
||||||
|
|||||||
@ -14,10 +14,7 @@
|
|||||||
:aria-selected="isSelected"
|
:aria-selected="isSelected"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img v-if="type === 'image' && isThumbsEnabled" v-lazy="thumbnailUrl" />
|
||||||
v-if="!readOnly && type === 'image' && isThumbsEnabled"
|
|
||||||
v-lazy="thumbnailUrl"
|
|
||||||
/>
|
|
||||||
<i v-else class="material-icons"></i>
|
<i v-else class="material-icons"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -42,15 +39,16 @@ import { useLayoutStore } from "@/stores/layout";
|
|||||||
import { enableThumbs } from "@/utils/constants";
|
import { enableThumbs } from "@/utils/constants";
|
||||||
import { filesize } from "@/utils";
|
import { filesize } from "@/utils";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { files as api } from "@/api";
|
import { files as api, pub as pub_api } from "@/api";
|
||||||
import * as upload from "@/utils/upload";
|
import * as upload from "@/utils/upload";
|
||||||
import { computed, inject, ref } from "vue";
|
import { computed, inject, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter, useRoute } from "vue-router";
|
||||||
|
|
||||||
const touches = ref<number>(0);
|
const touches = ref<number>(0);
|
||||||
|
|
||||||
const $showError = inject<IToastError>("$showError")!;
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string;
|
name: string;
|
||||||
@ -95,8 +93,13 @@ const thumbnailUrl = computed(() => {
|
|||||||
path: props.path,
|
path: props.path,
|
||||||
modified: props.modified,
|
modified: props.modified,
|
||||||
};
|
};
|
||||||
|
if (route.name === "Share") {
|
||||||
return api.getPreviewURL(file as Resource, "thumb");
|
const hash = props.url.split("/")[2];
|
||||||
|
file.path = `/${hash}${props.path}`;
|
||||||
|
return pub_api.getPreviewURL(file as Resource, "thumb");
|
||||||
|
} else {
|
||||||
|
return api.getPreviewURL(file as Resource, "thumb");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isThumbsEnabled = computed(() => {
|
const isThumbsEnabled = computed(() => {
|
||||||
|
|||||||
@ -1,41 +1,70 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { detectLocale, setLocale } from "@/i18n";
|
import { detectLocale, setLocale } from "@/i18n";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
|
import { useStorage } from "@vueuse/core";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
export const useAuthStore = defineStore("auth", {
|
export const useAuthStore = defineStore("auth", () => {
|
||||||
// convert to a function
|
const registeredUser = ref<IUser | null>(null);
|
||||||
state: (): {
|
const jwt = ref("");
|
||||||
user: IUser | null;
|
|
||||||
jwt: string;
|
const guestJwt = ref("");
|
||||||
} => ({
|
const guestUser = useStorage("guest", {
|
||||||
user: null,
|
locale: "zh-cn",
|
||||||
jwt: "",
|
viewMode: "list",
|
||||||
}),
|
singleClick: false,
|
||||||
getters: {
|
perm: { create: false },
|
||||||
// user and jwt getter removed, no longer needed
|
});
|
||||||
isLoggedIn: (state) => state.user !== null,
|
|
||||||
},
|
const shareConfig = ref({ sortBy: "name", asc: false });
|
||||||
actions: {
|
const isLoggedIn = computed(() => registeredUser.value !== null);
|
||||||
// no context as first argument, use `this` instead
|
const user = computed({
|
||||||
setUser(user: IUser) {
|
get: () =>
|
||||||
if (user === null) {
|
isLoggedIn.value ? registeredUser.value : (guestUser.value as IUser),
|
||||||
this.user = null;
|
set: (val) => {
|
||||||
return;
|
if (isLoggedIn.value) {
|
||||||
|
registeredUser.value = val;
|
||||||
|
} else {
|
||||||
|
guestUser.value = val;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setLocale(user.locale || detectLocale());
|
function setUser(_user: IUser) {
|
||||||
this.user = user;
|
if (_user === null) {
|
||||||
},
|
registeredUser.value = null;
|
||||||
updateUser(user: Partial<IUser>) {
|
return;
|
||||||
if (user.locale) {
|
}
|
||||||
setLocale(user.locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.user = { ...this.user, ...cloneDeep(user) } as IUser;
|
setLocale(_user.locale || detectLocale());
|
||||||
},
|
registeredUser.value = _user;
|
||||||
// easily reset state using `$reset`
|
}
|
||||||
clearUser() {
|
|
||||||
this.$reset();
|
function updateUser(_user: Partial<IUser>) {
|
||||||
},
|
if (_user.locale) {
|
||||||
},
|
setLocale(_user.locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
user.value = {
|
||||||
|
...user.value,
|
||||||
|
...cloneDeep(_user),
|
||||||
|
} as IUser;
|
||||||
|
}
|
||||||
|
// easily reset state using `$reset`
|
||||||
|
function clearUser() {
|
||||||
|
registeredUser.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
jwt,
|
||||||
|
guestJwt,
|
||||||
|
shareConfig,
|
||||||
|
|
||||||
|
isLoggedIn,
|
||||||
|
user,
|
||||||
|
|
||||||
|
setUser,
|
||||||
|
updateUser,
|
||||||
|
clearUser,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -95,7 +95,8 @@
|
|||||||
v-if="!req.isDir"
|
v-if="!req.isDir"
|
||||||
class="share__box__element share__box__center share__box__icon"
|
class="share__box__element share__box__center share__box__icon"
|
||||||
>
|
>
|
||||||
<i class="material-icons">{{ icon }}</i>
|
<img v-if="req.type === 'image'" :src="raw" />
|
||||||
|
<i v-else class="material-icons">{{ icon }}</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element" style="height: 3em">
|
<div class="share__box__element" style="height: 3em">
|
||||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||||
@ -236,51 +237,9 @@
|
|||||||
id="shareList"
|
id="shareList"
|
||||||
v-if="req.isDir && req.items.length > 0"
|
v-if="req.isDir && req.items.length > 0"
|
||||||
class="share__box share__box__items"
|
class="share__box share__box__items"
|
||||||
|
style="background-color: transparent"
|
||||||
>
|
>
|
||||||
<div class="share__box__header" v-if="req.isDir">
|
<FileListing />
|
||||||
{{ t("files.files") }}
|
|
||||||
</div>
|
|
||||||
<div id="listing" class="list file-icons">
|
|
||||||
<item
|
|
||||||
v-for="item in req.items.slice(0, showLimit)"
|
|
||||||
:key="base64(item.name)"
|
|
||||||
v-bind:index="item.index"
|
|
||||||
v-bind:name="item.name"
|
|
||||||
v-bind:isDir="item.isDir"
|
|
||||||
v-bind:url="item.url"
|
|
||||||
v-bind:modified="item.modified"
|
|
||||||
v-bind:type="item.type"
|
|
||||||
v-bind:size="item.size"
|
|
||||||
readOnly
|
|
||||||
>
|
|
||||||
</item>
|
|
||||||
<div
|
|
||||||
v-if="req.items.length > showLimit"
|
|
||||||
class="item"
|
|
||||||
@click="showLimit += 100"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
:class="{ active: fileStore.multiple }"
|
|
||||||
id="multiple-selection"
|
|
||||||
>
|
|
||||||
<p>{{ t("files.multipleSelectionEnabled") }}</p>
|
|
||||||
<div
|
|
||||||
@click="() => (fileStore.multiple = false)"
|
|
||||||
tabindex="0"
|
|
||||||
role="button"
|
|
||||||
:data-title="t('buttons.clear')"
|
|
||||||
:aria-label="t('buttons.clear')"
|
|
||||||
class="action"
|
|
||||||
>
|
|
||||||
<i class="material-icons">clear</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="req.isDir && req.items.length === 0"
|
v-else-if="req.isDir && req.items.length === 0"
|
||||||
@ -300,21 +259,24 @@
|
|||||||
import { pub as api } from "@/api";
|
import { pub as api } from "@/api";
|
||||||
import { filesize } from "@/utils";
|
import { filesize } from "@/utils";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { Base64 } from "js-base64";
|
|
||||||
|
|
||||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||||
import Action from "@/components/header/Action.vue";
|
import Action from "@/components/header/Action.vue";
|
||||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||||
import Errors from "@/views/Errors.vue";
|
import Errors from "@/views/Errors.vue";
|
||||||
import QrcodeVue from "qrcode.vue";
|
import QrcodeVue from "qrcode.vue";
|
||||||
import Item from "@/components/files/ListingItem.vue";
|
import FileListing from "@/views/files/FileListing.vue";
|
||||||
|
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
|
|
||||||
import { computed, inject, onMounted, onBeforeUnmount, ref, watch } from "vue";
|
import { computed, inject, onMounted, onBeforeUnmount, ref, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { StatusError } from "@/api/utils";
|
import { StatusError } from "@/api/utils";
|
||||||
import { copy } from "@/utils/clipboard";
|
import { copy } from "@/utils/clipboard";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
|
||||||
const error = ref<StatusError | null>(null);
|
const error = ref<StatusError | null>(null);
|
||||||
const showLimit = ref<number>(100);
|
const showLimit = ref<number>(100);
|
||||||
@ -331,7 +293,9 @@ const { t } = useI18n({});
|
|||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const fileStore = useFileStore();
|
const fileStore = useFileStore();
|
||||||
|
const { reload } = storeToRefs(fileStore);
|
||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
showLimit.value = 100;
|
showLimit.value = 100;
|
||||||
@ -352,16 +316,27 @@ const icon = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const link = computed(() => (req.value ? api.getDownloadURL(req.value) : ""));
|
const link = computed(() => (req.value ? api.getDownloadURL(req.value) : ""));
|
||||||
|
|
||||||
|
// 用于转换 URL 的辅助函数
|
||||||
|
function transformUrl(url: string) {
|
||||||
|
return url.replace(/share/, "api/public/dl") + "?token=" + token.value;
|
||||||
|
}
|
||||||
const raw = computed(() => {
|
const raw = computed(() => {
|
||||||
return req.value
|
// 如果 req.value 不存在,则直接返回空字符串
|
||||||
? req.value.items[fileStore.selected[0]].url.replace(
|
if (!req.value) {
|
||||||
/share/,
|
return "";
|
||||||
"api/public/dl"
|
}
|
||||||
) +
|
|
||||||
"?token=" +
|
// 如果 req.value 是目录
|
||||||
token.value
|
if (req.value.isDir) {
|
||||||
: "";
|
const selectedItemUrl = req.value.items[fileStore.selected[0]].url;
|
||||||
|
return transformUrl(selectedItemUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 req.value 不是目录
|
||||||
|
return transformUrl(req.value.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
const inlineLink = computed(() =>
|
const inlineLink = computed(() =>
|
||||||
req.value ? api.getDownloadURL(req.value, true) : ""
|
req.value ? api.getDownloadURL(req.value, true) : ""
|
||||||
);
|
);
|
||||||
@ -382,7 +357,6 @@ const modTime = computed(() =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
const base64 = (name: any) => Base64.encodeURI(name);
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
if (tag.value) {
|
if (tag.value) {
|
||||||
audio.value?.pause();
|
audio.value?.pause();
|
||||||
@ -392,6 +366,10 @@ const play = () => {
|
|||||||
tag.value = true;
|
tag.value = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(reload, (newValue) => {
|
||||||
|
newValue && fetchData();
|
||||||
|
});
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
fileStore.reload = false;
|
fileStore.reload = false;
|
||||||
fileStore.selected = [];
|
fileStore.selected = [];
|
||||||
@ -408,12 +386,12 @@ const fetchData = async () => {
|
|||||||
let url = route.path;
|
let url = route.path;
|
||||||
if (url === "") url = "/";
|
if (url === "") url = "/";
|
||||||
if (url[0] !== "/") url = "/" + url;
|
if (url[0] !== "/") url = "/" + url;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const file = await api.fetch(url, password.value);
|
const file = await api.fetch(url, password.value);
|
||||||
file.hash = hash.value;
|
file.hash = hash.value;
|
||||||
|
|
||||||
token.value = file.token || "";
|
token.value = file.token || "";
|
||||||
|
authStore.guestJwt = token.value;
|
||||||
|
|
||||||
fileStore.updateRequest(file);
|
fileStore.updateRequest(file);
|
||||||
document.title = `${file.name} - ${document.title}`;
|
document.title = `${file.name} - ${document.title}`;
|
||||||
@ -504,6 +482,7 @@ onMounted(async () => {
|
|||||||
hash.value = route.params.path[0];
|
hash.value = route.params.path[0];
|
||||||
window.addEventListener("keydown", keyEvent);
|
window.addEventListener("keydown", keyEvent);
|
||||||
await fetchData();
|
await fetchData();
|
||||||
|
fileStore.selected[0] = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|||||||
@ -74,6 +74,7 @@
|
|||||||
/>
|
/>
|
||||||
<action icon="info" :label="t('buttons.info')" show="info" />
|
<action icon="info" :label="t('buttons.info')" show="info" />
|
||||||
<action
|
<action
|
||||||
|
v-if="authStore.isLoggedIn"
|
||||||
icon="check_circle"
|
icon="check_circle"
|
||||||
:label="t('buttons.selectMultiple')"
|
:label="t('buttons.selectMultiple')"
|
||||||
@action="toggleMultipleSelection"
|
@action="toggleMultipleSelection"
|
||||||
@ -829,6 +830,8 @@ const sort = async (by: string) => {
|
|||||||
"sorting",
|
"sorting",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
authStore.shareConfig.sortBy = by;
|
||||||
|
authStore.shareConfig.asc = asc;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
$showError(e);
|
$showError(e);
|
||||||
}
|
}
|
||||||
@ -904,8 +907,10 @@ const switchView = async () => {
|
|||||||
viewMode: modes[authStore.user?.viewMode ?? "list"] || "list",
|
viewMode: modes[authStore.user?.viewMode ?? "list"] || "list",
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
if (authStore.isLoggedIn) {
|
||||||
users.update(data, ["viewMode"]).catch($showError);
|
// @ts-ignore
|
||||||
|
users.update(data, ["viewMode"]).catch($showError);
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
authStore.updateUser(data);
|
authStore.updateUser(data);
|
||||||
|
|||||||
@ -90,6 +90,8 @@ func NewHandler(
|
|||||||
public := api.PathPrefix("/public").Subrouter()
|
public := api.PathPrefix("/public").Subrouter()
|
||||||
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
|
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
|
||||||
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
|
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
|
||||||
|
public.PathPrefix("/preview/{size}/{path:.*}").
|
||||||
|
Handler(monkey(publicPreviewHandler(imgSvc, fileCache, server.EnableThumbnails, server.ResizePreview), "/api/public/preview")).Methods("GET")
|
||||||
|
|
||||||
return stripPrefix(server.BaseURL, r), nil
|
return stripPrefix(server.BaseURL, r), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,8 @@ func handleImagePreview(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createPreview(imgSvc ImgService, fileCache FileCache,
|
func createPreview(imgSvc ImgService, fileCache FileCache,
|
||||||
file *files.FileInfo, previewSize PreviewSize) ([]byte, error) {
|
file *files.FileInfo, previewSize PreviewSize,
|
||||||
|
) ([]byte, error) {
|
||||||
fd, err := file.Fs.Open(file.Path)
|
fd, err := file.Fs.Open(file.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -2,12 +2,14 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
@ -98,7 +100,16 @@ var publicShareHandler = withHashFile(func(w http.ResponseWriter, r *http.Reques
|
|||||||
file := d.raw.(*files.FileInfo)
|
file := d.raw.(*files.FileInfo)
|
||||||
|
|
||||||
if file.IsDir {
|
if file.IsDir {
|
||||||
file.Listing.Sorting = files.Sorting{By: "name", Asc: false}
|
sortBy := r.URL.Query().Get("s")
|
||||||
|
ascStr := r.URL.Query().Get("a")
|
||||||
|
asc := false
|
||||||
|
if sortBy == "" {
|
||||||
|
sortBy = "name"
|
||||||
|
}
|
||||||
|
if ascStr == "1" {
|
||||||
|
asc = true
|
||||||
|
}
|
||||||
|
file.Listing.Sorting = files.Sorting{By: sortBy, Asc: asc}
|
||||||
file.Listing.ApplySort()
|
file.Listing.ApplySort()
|
||||||
return renderJSON(w, r, file)
|
return renderJSON(w, r, file)
|
||||||
}
|
}
|
||||||
@ -115,6 +126,28 @@ var publicDlHandler = withHashFile(func(w http.ResponseWriter, r *http.Request,
|
|||||||
return rawDirHandler(w, r, d, file)
|
return rawDirHandler(w, r, d, file)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func publicPreviewHandler(imgSvc ImgService, fileCache FileCache, enableThumbnails, resizePreview bool) handleFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
previewSize, err := ParsePreviewSize(vars["size"])
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusBadRequest, err
|
||||||
|
}
|
||||||
|
r.URL.Path = vars["path"]
|
||||||
|
return withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||||
|
file := d.raw.(*files.FileInfo)
|
||||||
|
setContentDisposition(w, r, file)
|
||||||
|
|
||||||
|
switch file.Type {
|
||||||
|
case "image":
|
||||||
|
return handleImagePreview(w, r, imgSvc, fileCache, file, previewSize, enableThumbnails, resizePreview)
|
||||||
|
default:
|
||||||
|
return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", file.Type)
|
||||||
|
}
|
||||||
|
})(w, r, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func authenticateShareRequest(r *http.Request, l *share.Link) (int, error) {
|
func authenticateShareRequest(r *http.Request, l *share.Link) (int, error) {
|
||||||
if l.PasswordHash == "" {
|
if l.PasswordHash == "" {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user