mirror of
https://github.com/bewcloud/bewcloud.git
synced 2026-03-11 08:54:49 +00:00
Misc fixes for file shares
Remove file share when deleting a file/directory (#121) Keep a consistent logged-out-view of file shares (#123) Simplify README, add FAQ with more info, including `.env`-based config (#90) Closes #121 Closes #123 Closes #90
This commit is contained in:
parent
cfa21e6089
commit
a68bdba4b5
13 changed files with 273 additions and 55 deletions
217
FAQ.md
Normal file
217
FAQ.md
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
# bewCloud - FAQ (Frequently Asked Questions)
|
||||
|
||||
## How does Contacts/CardDav and Calendar/CalDav work?
|
||||
|
||||
CalDav/CardDav is now available since [v2.3.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0), using [Radicale](https://radicale.org/v3.html) via Docker, which is already _very_ efficient (and battle-tested). The "Contacts" client for CardDav is available since [v2.4.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0) and the "Calendar" client for CalDav is available since [v2.5.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.5.0). [Check this tag/release for custom-made server code where it was all mostly working, except for many edge cases, if you're interested](https://github.com/bewcloud/bewcloud/releases/tag/v0.0.1-self-made-carddav-caldav).
|
||||
|
||||
In order to share a calendar, you can either have a shared user, or you can symlink the calendar to the user's own calendar (simply `ln -s /<absolute-path-to-data-radicale>/collections/collection-root/<owner-user-id>/<calendar-to-share> /<absolute-path-to-data-radicale>/collections/collection-root/<user-id-to-share-with>/`).
|
||||
|
||||
> [!NOTE]
|
||||
> If you're running radicale with docker, the symlink needs to point to the container's directory, usually starting with `/data` if you didn't change the `radicale-config/config`, otherwise the container will fail to load the linked directory.
|
||||
|
||||
## How does private file sharing work?
|
||||
|
||||
Public file sharing is now possible since [v2.2.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.2.0). [Check this PR for advanced sharing with internal and external users, with read and write access that was being done and almost working, if you're interested](https://github.com/bewcloud/bewcloud/pull/4). I ditched all that complexity for simply using [symlinks](https://en.wikipedia.org/wiki/Symbolic_link) for internal sharing, as it served my use case (I have multiple data backups and trust the people I provide accounts to, with the symlinks).
|
||||
|
||||
You can simply `ln -s /<absolute-path-to-data-files>/<owner-user-id>/<directory-to-share> /<absolute-path-to-data-files>/<user-id-to-share-with>/` to create a shared directory between two users, and the same directory can have different names, now.
|
||||
|
||||
> [!NOTE]
|
||||
> If you're running the app with docker, the symlink needs to point to the container's directory, usually starting with `/app` if you didn't change the `Dockerfile`, otherwise the container will fail to load the linked directory.
|
||||
|
||||
## How can I use .env for configuration?
|
||||
|
||||
During [v1](https://github.com/bewcloud/bewcloud/releases/tag/v1.0.0), bewCloud was entirely configured with a `.env` file, but since [v2](https://github.com/bewcloud/bewcloud/releases/tag/v2.0.0) it was swapped to being used exclusively for "secrets", and having a more robust `bewcloud.config.ts` file for configuration. While it's unlikely `.env`-only configuration will be supported again in the future, the advantage of a `bewcloud.config.ts` file is that it's more dynamic and powerful, which means you can "hack" your way into using a `.env` file for configuration, like how it was suggested [in this comment](https://github.com/bewcloud/bewcloud/issues/90#issuecomment-3450344972). It's copied below for reference, and it's a bit outdated, but should serve as a good starting point, and you can make a PR to update it:
|
||||
|
||||
> [!NOTE]
|
||||
> This is not recommended and should only be done if you know what you're doing.
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
bewcloud.config.ts
|
||||
</summary>
|
||||
|
||||
```ts
|
||||
import { Config, OptionalApp, PartialDeep } from './lib/types.ts';
|
||||
|
||||
// Check the Config type for all the possible options and instructions.
|
||||
function requireValue<T>(value: T | undefined, key: string): T {
|
||||
if (value === undefined || value === '') {
|
||||
throw new Error(`Environment variable ${key} is required but not set`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getEnvString(key: string, defaultValue: string): string {
|
||||
return Deno.env.get(key) ?? defaultValue;
|
||||
}
|
||||
|
||||
function getEnvBoolean(key: string, defaultValue: boolean): boolean {
|
||||
const value = Deno.env.get(key);
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value.toLowerCase() === 'true' || value === '1';
|
||||
}
|
||||
|
||||
function getEnvNumber(key: string, defaultValue: number): number {
|
||||
const value = Deno.env.get(key);
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
const parsed = parseInt(value, 10);
|
||||
return isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
|
||||
function getEnvStringArray(key: string, defaultValue: string[]): string[] {
|
||||
const value = Deno.env.get(key);
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter((item) => item.length > 0);
|
||||
}
|
||||
const config: PartialDeep<Config> = {
|
||||
auth: {
|
||||
baseUrl: getEnvString('BEWCLOUD_AUTH_BASE_URL', 'http://localhost:8000'),
|
||||
allowSignups: getEnvBoolean('BEWCLOUD_AUTH_ALLOW_SIGNUPS', false),
|
||||
enableEmailVerification: getEnvBoolean(
|
||||
'BEWCLOUD_AUTH_ENABLE_EMAIL_VERIFICATION',
|
||||
false,
|
||||
),
|
||||
enableForeverSignup: getEnvBoolean(
|
||||
'BEWCLOUD_AUTH_ENABLE_FOREVER_SIGNUP',
|
||||
true,
|
||||
),
|
||||
enableMultiFactor: getEnvBoolean(
|
||||
'BEWCLOUD_AUTH_ENABLE_MULTI_FACTOR',
|
||||
false,
|
||||
),
|
||||
allowedCookieDomains: getEnvStringArray(
|
||||
'BEWCLOUD_AUTH_ALLOWED_COOKIE_DOMAINS',
|
||||
[],
|
||||
),
|
||||
skipCookieDomainSecurity: getEnvBoolean(
|
||||
'BEWCLOUD_AUTH_SKIP_COOKIE_DOMAIN_SECURITY',
|
||||
false,
|
||||
),
|
||||
enableSingleSignOn: getEnvBoolean(
|
||||
'BEWCLOUD_AUTH_ENABLE_SINGLE_SIGN_ON',
|
||||
false,
|
||||
),
|
||||
singleSignOnUrl: getEnvString('BEWCLOUD_AUTH_SINGLE_SIGN_ON_URL', ''),
|
||||
singleSignOnEmailAttribute: getEnvString(
|
||||
'BEWCLOUD_AUTH_SINGLE_SIGN_ON_EMAIL_ATTRIBUTE',
|
||||
'email',
|
||||
),
|
||||
singleSignOnScopes: getEnvStringArray(
|
||||
'BEWCLOUD_AUTH_SINGLE_SIGN_ON_SCOPES',
|
||||
['openid', 'email'],
|
||||
),
|
||||
},
|
||||
files: {
|
||||
rootPath: getEnvString('BEWCLOUD_FILES_ROOT_PATH', 'data-files'),
|
||||
allowPublicSharing: getEnvBoolean(
|
||||
'BEWCLOUD_FILES_ALLOW_PUBLIC_SHARING',
|
||||
false,
|
||||
),
|
||||
},
|
||||
core: {
|
||||
enabledApps: getEnvStringArray('BEWCLOUD_CORE_ENABLED_APPS', [
|
||||
'dashboard',
|
||||
'files',
|
||||
'news',
|
||||
'notes',
|
||||
'photos',
|
||||
'expenses',
|
||||
]) as OptionalApp[],
|
||||
},
|
||||
visuals: {
|
||||
title: getEnvString('BEWCLOUD_VISUALS_TITLE', ''),
|
||||
description: getEnvString('BEWCLOUD_VISUALS_DESCRIPTION', ''),
|
||||
helpEmail: getEnvString('BEWCLOUD_VISUALS_HELP_EMAIL', 'help@bewcloud.com'),
|
||||
},
|
||||
email: {
|
||||
from: getEnvString('BEWCLOUD_EMAIL_FROM', 'help@bewcloud.com'),
|
||||
host: getEnvString('BEWCLOUD_EMAIL_HOST', 'localhost'),
|
||||
port: getEnvNumber('BEWCLOUD_EMAIL_PORT', 465),
|
||||
},
|
||||
contacts: {
|
||||
enableCardDavServer: getEnvBoolean(
|
||||
'BEWCLOUD_CONTACTS_ENABLE_CARDDAV_SERVER',
|
||||
true,
|
||||
),
|
||||
cardDavUrl: getEnvString(
|
||||
'BEWCLOUD_CONTACTS_CARDDAV_URL',
|
||||
'http://127.0.0.1:5232',
|
||||
),
|
||||
},
|
||||
calendar: {
|
||||
enableCalDavServer: getEnvBoolean(
|
||||
'BEWCLOUD_CALENDAR_ENABLE_CALDAV_SERVER',
|
||||
true,
|
||||
),
|
||||
calDavUrl: getEnvString(
|
||||
'BEWCLOUD_CALENDAR_CALDAV_URL',
|
||||
'http://127.0.0.1:5232',
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Append the following to your `.env` file
|
||||
|
||||
<details>
|
||||
<summary> .env </summary>
|
||||
|
||||
```env
|
||||
# Auth Configuration
|
||||
BEWCLOUD_AUTH_BASE_URL=http://localhost:8000
|
||||
BEWCLOUD_AUTH_ALLOW_SIGNUPS=false
|
||||
BEWCLOUD_AUTH_ENABLE_EMAIL_VERIFICATION=false
|
||||
BEWCLOUD_AUTH_ENABLE_FOREVER_SIGNUP=true
|
||||
BEWCLOUD_AUTH_ENABLE_MULTI_FACTOR=false
|
||||
# Comma-separated list of allowed cookie domains
|
||||
BEWCLOUD_AUTH_ALLOWED_COOKIE_DOMAINS=
|
||||
BEWCLOUD_AUTH_SKIP_COOKIE_DOMAIN_SECURITY=false
|
||||
|
||||
# Single Sign-On Configuration
|
||||
BEWCLOUD_AUTH_ENABLE_SINGLE_SIGN_ON=false
|
||||
BEWCLOUD_AUTH_SINGLE_SIGN_ON_URL=
|
||||
BEWCLOUD_AUTH_SINGLE_SIGN_ON_EMAIL_ATTRIBUTE=email
|
||||
# Comma-separated list of scopes
|
||||
BEWCLOUD_AUTH_SINGLE_SIGN_ON_SCOPES=openid,email
|
||||
|
||||
# Files Configuration
|
||||
BEWCLOUD_FILES_ROOT_PATH=data-files
|
||||
BEWCLOUD_FILES_ALLOW_PUBLIC_SHARING=false
|
||||
|
||||
# Core Configuration
|
||||
# Comma-separated list of enabled apps (dashboard and files cannot be disabled)
|
||||
BEWCLOUD_CORE_ENABLED_APPS=news,notes,photos,expenses,contacts,calendar
|
||||
|
||||
# Visuals Configuration
|
||||
BEWCLOUD_VISUALS_TITLE=
|
||||
BEWCLOUD_VISUALS_DESCRIPTION=
|
||||
BEWCLOUD_VISUALS_HELP_EMAIL=help@bewcloud.com
|
||||
|
||||
# Email/SMTP Configuration
|
||||
BEWCLOUD_EMAIL_FROM=help@bewcloud.com
|
||||
BEWCLOUD_EMAIL_HOST=localhost
|
||||
BEWCLOUD_EMAIL_PORT=465
|
||||
|
||||
# Contacts Configuration
|
||||
BEWCLOUD_CONTACTS_ENABLE_CARDDAV_SERVER=true
|
||||
BEWCLOUD_CONTACTS_CARDDAV_URL=http://127.0.0.1:5232
|
||||
|
||||
# Calendar Configuration
|
||||
BEWCLOUD_CALENDAR_ENABLE_CALDAV_SERVER=true
|
||||
BEWCLOUD_CALENDAR_CALDAV_URL=http://127.0.0.1:5232
|
||||
```
|
||||
|
||||
</details>
|
||||
38
README.md
38
README.md
|
|
@ -14,7 +14,7 @@ If you're looking for the mobile app, it's at [`bewcloud-mobile`](https://github
|
|||
|
||||
[-51a4fb?style=for-the-badge)](https://buy.stripe.com/fZu8wOb5RfIydj56FA1gs0J)
|
||||
|
||||
Or, to run on your own machine using Docker, start with these commands:
|
||||
Or, to run on your own machine, start with these commands:
|
||||
|
||||
```sh
|
||||
mkdir data-files data-radicale radicale-config # local directories for storing user-uploaded files, radicale data, and radicale config (these last two are necessary only if you're using CalDav/CardDav/Contacts)
|
||||
|
|
@ -39,9 +39,9 @@ docker compose run --rm website bash -c "cd /app && make migrate-db" # initializ
|
|||
>
|
||||
> `1993:1993` above comes from deno's [docker image](https://github.com/denoland/deno_docker/blob/2abfe921484bdc79d11c7187a9d7b59537457c31/ubuntu.dockerfile#L20-L22) where `1993` is the default user id in it. It might change in the future since I don't control it.
|
||||
|
||||
See the [Community Links](#community-links) section for alternative ways of running bewCloud yourself; please be aware these are not officially endorsed.
|
||||
If you're interested in building/contributing (or just running the app locally), check the [Development section below](#development).
|
||||
|
||||
If you're interested in building/contributing, check the [Development section below](#development).
|
||||
See the [Community Links](#community-links) section for alternative ways of running bewCloud yourself.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Even with signups disabled (`config.auth.allowSignups=false`), the first signup will work and become an admin.
|
||||
|
|
@ -73,18 +73,18 @@ These are the amazing entities or individuals who are sponsoring this project fo
|
|||
docker compose -f docker-compose.dev.yml up # (optional) runs docker with postgres, locally
|
||||
make migrate-db # runs any missing database migrations
|
||||
make start # runs the app
|
||||
make format # formats the code
|
||||
make test # runs tests
|
||||
make format # (optional) formats the code (if you're interested in contributing)
|
||||
make test # (optional) runs tests (if you're interested in contributing)
|
||||
```
|
||||
|
||||
### Other less-used commands
|
||||
### Other less-used commands (mostly for development)
|
||||
|
||||
```sh
|
||||
make exec-db # runs psql inside the postgres container, useful for running direct development queries like `DROP DATABASE "bewcloud"; CREATE DATABASE "bewcloud";`
|
||||
make build # generates all static files for production deploy
|
||||
```
|
||||
|
||||
## Structure
|
||||
## File/Directory Structure
|
||||
|
||||
- Routes are defined at `routes/`.
|
||||
- Static files are defined at `static/`.
|
||||
|
|
@ -98,23 +98,9 @@ make build # generates all static files for production deploy
|
|||
|
||||
Just push to the `main` branch.
|
||||
|
||||
## How does Contacts/CardDav and Calendar/CalDav work?
|
||||
## FAQ (Frequently Asked Questions)
|
||||
|
||||
CalDav/CardDav is now available since [v2.3.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0), using [Radicale](https://radicale.org/v3.html) via Docker, which is already _very_ efficient (and battle-tested). The "Contacts" client for CardDav is available since [v2.4.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0) and the "Calendar" client for CalDav is available since [v2.5.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.5.0). [Check this tag/release for custom-made server code where it was all mostly working, except for many edge cases, if you're interested](https://github.com/bewcloud/bewcloud/releases/tag/v0.0.1-self-made-carddav-caldav).
|
||||
|
||||
In order to share a calendar, you can either have a shared user, or you can symlink the calendar to the user's own calendar (simply `ln -s /<absolute-path-to-data-radicale>/collections/collection-root/<owner-user-id>/<calendar-to-share> /<absolute-path-to-data-radicale>/collections/collection-root/<user-id-to-share-with>/`).
|
||||
|
||||
> [!NOTE]
|
||||
> If you're running radicale with docker, the symlink needs to point to the container's directory, usually starting with `/data` if you didn't change the `radicale-config/config`, otherwise the container will fail to load the linked directory.
|
||||
|
||||
## How does private file sharing work?
|
||||
|
||||
Public file sharing is now possible since [v2.2.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.2.0). [Check this PR for advanced sharing with internal and external users, with read and write access that was being done and almost working, if you're interested](https://github.com/bewcloud/bewcloud/pull/4). I ditched all that complexity for simply using [symlinks](https://en.wikipedia.org/wiki/Symbolic_link) for internal sharing, as it served my use case (I have multiple data backups and trust the people I provide accounts to, with the symlinks).
|
||||
|
||||
You can simply `ln -s /<absolute-path-to-data-files>/<owner-user-id>/<directory-to-share> /<absolute-path-to-data-files>/<user-id-to-share-with>/` to create a shared directory between two users, and the same directory can have different names, now.
|
||||
|
||||
> [!NOTE]
|
||||
> If you're running the app with docker, the symlink needs to point to the container's directory, usually starting with `/app` if you didn't change the `Dockerfile`, otherwise the container will fail to load the linked directory.
|
||||
[Check the FAQ](/FAQ.md) for answers to common questions, like private calendar and file sharing, or `.env`-based configuration.
|
||||
|
||||
## How does it look?
|
||||
|
||||
|
|
@ -122,5 +108,7 @@ You can simply `ln -s /<absolute-path-to-data-files>/<owner-user-id>/<directory-
|
|||
|
||||
## Community Links
|
||||
|
||||
* [`bewcloud-nixos`](https://gitlab.com/ntninja/bewcloud-nixos/) by @ntninja exposes bewCloud as a NixOS integration as an alternative to using Docker or running the app locally.
|
||||
* For installation and known limitations, please see its [README](https://gitlab.com/ntninja/bewcloud-nixos/-/blob/main/README.md).
|
||||
These are not officially endorsed, but are alternative ways of running bewCloud.
|
||||
|
||||
- [`bewcloud-nixos`](https://gitlab.com/ntninja/bewcloud-nixos/) by [@ntninja](https://github.com/ntninja) exposes bewCloud as a NixOS integration as an alternative to using Docker or running the app locally.
|
||||
- For installation and known limitations, please see its [README](https://gitlab.com/ntninja/bewcloud-nixos/-/blob/main/README.md).
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default function Header({ route, user, enabledApps }: Data) {
|
|||
|
||||
const menuItems = potentialMenuItems.filter(Boolean) as MenuItem[];
|
||||
|
||||
if (user) {
|
||||
if (user && !route.startsWith('/file-share')) {
|
||||
const activeMenu = menuItems.find((menu) => route.startsWith(menu.url));
|
||||
|
||||
let pageLabel = activeMenu?.label || '404 - Page not found';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
website:
|
||||
image: ghcr.io/bewcloud/bewcloud:v3.0.1
|
||||
image: ghcr.io/bewcloud/bewcloud:v3.0.2
|
||||
restart: always
|
||||
ports:
|
||||
- 127.0.0.1:8000:8000
|
||||
|
|
|
|||
|
|
@ -701,6 +701,14 @@ async function deleteDirectoryOrFile(userId: string, path: string, name: string)
|
|||
|
||||
const rootPath = join(await AppConfig.getFilesRootPath(), userId, path);
|
||||
|
||||
const fileShares = (await AppConfig.isPublicFileSharingAllowed())
|
||||
? await FileShareModel.getByParentFilePath(userId, path)
|
||||
: [];
|
||||
|
||||
const fileSharesForPath = fileShares.filter((fileShare) =>
|
||||
fileShare.file_path === `${join(path, name)}/` || fileShare.file_path === join(path, name)
|
||||
);
|
||||
|
||||
try {
|
||||
if (path.startsWith(TRASH_PATH)) {
|
||||
await Deno.remove(join(rootPath, name), { recursive: true });
|
||||
|
|
@ -708,6 +716,11 @@ async function deleteDirectoryOrFile(userId: string, path: string, name: string)
|
|||
const trashPath = join(await AppConfig.getFilesRootPath(), userId, TRASH_PATH);
|
||||
await Deno.rename(join(rootPath, name), join(trashPath, name));
|
||||
}
|
||||
|
||||
// Delete all file shares for this path
|
||||
for (const fileShare of fileSharesForPath) {
|
||||
await FileShareModel.delete(fileShare.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const calendarEvent = await CalendarEventModel.get(context.state.user.id, calendarId, calendarEventId);
|
||||
|
||||
if (!calendarEvent) {
|
||||
return new Response('Not found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const calendars = await CalendarModel.list(context.state.user.id);
|
||||
|
|
@ -83,7 +83,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const calendarEvent = await CalendarEventModel.get(context.state.user.id, calendarId, calendarEventId);
|
||||
|
||||
if (!calendarEvent) {
|
||||
return new Response('Not found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const calendars = await CalendarModel.list(context.state.user.id);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const contact = await ContactModel.get(context.state.user.id, addressBookId, contactId);
|
||||
|
||||
if (!contact) {
|
||||
return new Response('Not found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
return await context.render({ contact, formData: {}, addressBookId });
|
||||
|
|
@ -64,7 +64,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const contact = await ContactModel.get(context.state.user.id, addressBookId, contactId);
|
||||
|
||||
if (!contact) {
|
||||
return new Response('Not found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
|
|
|
|||
|
|
@ -24,25 +24,25 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileShareId } = context.params;
|
||||
|
||||
if (!fileShareId) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const isPublicFileSharingAllowed = await AppConfig.isPublicFileSharingAllowed();
|
||||
|
||||
if (!isPublicFileSharingAllowed) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const baseUrl = (await AppConfig.getConfig()).auth.baseUrl;
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
|
|||
|
|
@ -12,23 +12,23 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileShareId, fileName } = context.params;
|
||||
|
||||
if (!fileShareId || !fileName) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const isPublicFileSharingAllowed = await AppConfig.isPublicFileSharingAllowed();
|
||||
|
||||
if (!isPublicFileSharingAllowed) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (fileShare.extra.hashed_password) {
|
||||
|
|
@ -71,7 +71,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const fileResult = await FileModel.get(fileShare.user_id, currentPath, decodeURIComponent(fileName));
|
||||
|
||||
if (!fileResult.success) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
return new Response(fileResult.contents! as BodyInit, {
|
||||
|
|
|
|||
|
|
@ -20,23 +20,23 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileShareId } = context.params;
|
||||
|
||||
if (!fileShareId) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const isPublicFileSharingAllowed = await AppConfig.isPublicFileSharingAllowed();
|
||||
|
||||
if (!isPublicFileSharingAllowed) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!fileShare.extra.hashed_password) {
|
||||
|
|
@ -49,23 +49,23 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileShareId } = context.params;
|
||||
|
||||
if (!fileShareId) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const isPublicFileSharingAllowed = await AppConfig.isPublicFileSharingAllowed();
|
||||
|
||||
if (!isPublicFileSharingAllowed) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!fileShare.extra.hashed_password) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileName } = context.params;
|
||||
|
||||
if (!fileName) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
|
|
@ -39,7 +39,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const fileResult = await FileModel.get(context.state.user.id, currentPath, decodeURIComponent(fileName));
|
||||
|
||||
if (!fileResult.success) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
return new Response(fileResult.contents! as BodyInit, {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileName } = context.params;
|
||||
|
||||
if (!fileName) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('notes'))) {
|
||||
|
|
@ -43,13 +43,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
|
||||
// Don't allow non-markdown files here
|
||||
if (!fileName.endsWith('.md')) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const fileResult = await FileModel.get(context.state.user.id, currentPath, decodeURIComponent(fileName));
|
||||
|
||||
if (!fileResult.success) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
return await context.render({ fileName, currentPath, contents: new TextDecoder().decode(fileResult.contents!) });
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const { fileName } = context.params;
|
||||
|
||||
if (!fileName) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('photos'))) {
|
||||
|
|
@ -45,7 +45,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
const fileResult = await FileModel.get(context.state.user.id, currentPath, decodeURIComponent(fileName));
|
||||
|
||||
if (!fileResult.success) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
return context.renderNotFound();
|
||||
}
|
||||
|
||||
const width = parseInt(searchParams.get('width') || '500', 10);
|
||||
|
|
|
|||
Loading…
Reference in a new issue