mirror of
https://github.com/bewcloud/bewcloud.git
synced 2026-03-11 08:54:49 +00:00
Merge branch 'main' into feature/directory-download-optimizations
This commit is contained in:
commit
47578b2fe7
78 changed files with 3493 additions and 68 deletions
2
.dvmrc
2
.dvmrc
|
|
@ -1 +1 @@
|
|||
2.5.3
|
||||
2.5.6
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM denoland/deno:ubuntu-2.5.3
|
||||
FROM denoland/deno:ubuntu-2.5.6
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const config: PartialDeep<Config> = {
|
|||
// allowDirectoryDownloads: false, // If true, directories can be downloaded as zip files
|
||||
// },
|
||||
// core: {
|
||||
// enabledApps: ['news', 'notes', 'photos', 'expenses', 'contacts', 'calendar'], // dashboard and files cannot be disabled
|
||||
// enabledApps: ['dashboard', 'files', 'news', 'notes', 'photos', 'expenses', 'contacts', 'calendar'], // The apps to show, in order of appearance in the header. The first app will be the default one shown after logging in. At least one is required.
|
||||
// },
|
||||
// visuals: {
|
||||
// title: 'My own cloud',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Head } from 'fresh/runtime.ts';
|
||||
|
||||
import { OptionalApp, User } from '/lib/types.ts';
|
||||
import { capitalizeWord } from '/lib/utils/misc.ts';
|
||||
|
||||
interface Data {
|
||||
route: string;
|
||||
|
|
@ -23,52 +24,10 @@ export default function Header({ route, user, enabledApps }: Data) {
|
|||
|
||||
const iconWidthAndHeightInPixels = 20;
|
||||
|
||||
const potentialMenuItems: (MenuItem | null)[] = [
|
||||
{
|
||||
url: '/dashboard',
|
||||
label: 'Dashboard',
|
||||
},
|
||||
enabledApps.includes('news')
|
||||
? {
|
||||
url: '/news',
|
||||
label: 'News',
|
||||
}
|
||||
: null,
|
||||
{
|
||||
url: '/files',
|
||||
label: 'Files',
|
||||
},
|
||||
enabledApps.includes('notes')
|
||||
? {
|
||||
url: '/notes',
|
||||
label: 'Notes',
|
||||
}
|
||||
: null,
|
||||
enabledApps.includes('photos')
|
||||
? {
|
||||
url: '/photos',
|
||||
label: 'Photos',
|
||||
}
|
||||
: null,
|
||||
enabledApps.includes('expenses')
|
||||
? {
|
||||
url: '/expenses',
|
||||
label: 'Expenses',
|
||||
}
|
||||
: null,
|
||||
enabledApps.includes('contacts')
|
||||
? {
|
||||
url: '/contacts',
|
||||
label: 'Contacts',
|
||||
}
|
||||
: null,
|
||||
enabledApps.includes('calendar')
|
||||
? {
|
||||
url: '/calendar',
|
||||
label: 'Calendar',
|
||||
}
|
||||
: null,
|
||||
];
|
||||
const potentialMenuItems: (MenuItem | null)[] = enabledApps.map((app) => ({
|
||||
url: `/${app}`,
|
||||
label: capitalizeWord(app),
|
||||
}));
|
||||
|
||||
const menuItems = potentialMenuItems.filter(Boolean) as MenuItem[];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"lock": false,
|
||||
"lock": true,
|
||||
"tasks": {
|
||||
"check": "deno fmt --check && deno lint && deno check .",
|
||||
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
"fresh/": "https://deno.land/x/fresh@1.7.3/",
|
||||
"$fresh/": "https://deno.land/x/fresh@1.7.3/",
|
||||
"@libs/xml": "https://deno.land/x/xml@2.1.3/mod.ts",
|
||||
|
||||
"postgres": "jsr:@db/postgres@0.19.5",
|
||||
"@b-fuze/deno-dom": "jsr:@b-fuze/deno-dom@0.1.56",
|
||||
|
|
@ -40,7 +41,6 @@
|
|||
"@hexagon/croner": "jsr:@hexagon/croner@9.1.0",
|
||||
"@mikaelporttila/rss": "jsr:@mikaelporttila/rss@1.1.3",
|
||||
"@libs/qrcode": "jsr:@libs/qrcode@3.0.0",
|
||||
"@libs/xml": "jsr:@libs/xml@7.0.2",
|
||||
"@simplewebauthn/server": "jsr:@simplewebauthn/server@13.2.1",
|
||||
"@simplewebauthn/browser": "jsr:@simplewebauthn/browser@13.2.0",
|
||||
"@std/assert": "jsr:@std/assert@1.0.14",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
services:
|
||||
postgresql:
|
||||
image: postgres:17
|
||||
image: postgres:18.1
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=fake
|
||||
- POSTGRES_DB=bewcloud
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- pgdata:/var/lib/postgresql/18/docker
|
||||
ports:
|
||||
- 5432:5432
|
||||
ulimits:
|
||||
|
|
@ -18,7 +18,7 @@ services:
|
|||
|
||||
# NOTE: If you don't want to use the CardDav/CalDav servers, you can comment/remove this service.
|
||||
radicale:
|
||||
image: tomsquest/docker-radicale:3.5.7.0
|
||||
image: tomsquest/docker-radicale:3.5.8.2
|
||||
ports:
|
||||
- 5232:5232
|
||||
init: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
website:
|
||||
image: ghcr.io/bewcloud/bewcloud:v2.7.0
|
||||
image: ghcr.io/bewcloud/bewcloud:v3.0.0
|
||||
restart: always
|
||||
ports:
|
||||
- 127.0.0.1:8000:8000
|
||||
|
|
@ -13,14 +13,14 @@ services:
|
|||
- ./bewcloud.config.ts:/app/bewcloud.config.ts
|
||||
|
||||
postgresql:
|
||||
image: postgres:17
|
||||
image: postgres:18.1
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=fake
|
||||
- POSTGRES_DB=bewcloud
|
||||
restart: always
|
||||
volumes:
|
||||
- bewcloud-db:/var/lib/postgresql/data
|
||||
- bewcloud-db:/var/lib/postgresql/18/docker
|
||||
# NOTE: uncomment below only if you need to connect to the database from outside the container
|
||||
# ports:
|
||||
# - 127.0.0.1:5432:5432
|
||||
|
|
@ -32,7 +32,7 @@ services:
|
|||
|
||||
# NOTE: If you don't want to use the CardDav/CalDav servers, you can comment/remove this service.
|
||||
radicale:
|
||||
image: tomsquest/docker-radicale:3.5.7.0
|
||||
image: tomsquest/docker-radicale:3.5.8.2
|
||||
# NOTE: uncomment below only if you need to connect to the CardDav/CalDav servers from outside the container
|
||||
# ports:
|
||||
# - 127.0.0.1:5232:5232
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class AppConfig {
|
|||
allowDirectoryDownloads: false,
|
||||
},
|
||||
core: {
|
||||
enabledApps: ['news', 'notes', 'photos', 'expenses', 'contacts', 'calendar'],
|
||||
enabledApps: ['dashboard', 'files', 'news', 'notes', 'photos', 'expenses', 'contacts', 'calendar'],
|
||||
},
|
||||
visuals: {
|
||||
title: '',
|
||||
|
|
@ -98,6 +98,10 @@ export class AppConfig {
|
|||
|
||||
console.info('\nConfig loaded from bewcloud.config.ts', JSON.stringify(this.config, null, 2), '\n');
|
||||
|
||||
if (this.config.core.enabledApps.length === 0) {
|
||||
throw new Error('At least one app must be enabled. Please check the config.core.enabledApps array.');
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error('Error loading config from bewcloud.config.ts. Using default config instead.', error);
|
||||
|
|
|
|||
|
|
@ -184,7 +184,9 @@ export class OidcModel {
|
|||
throw new Error('There was a problem signing up or logging in!');
|
||||
}
|
||||
|
||||
let urlToRedirectTo = '/dashboard';
|
||||
const firstEnabledApp = config.core.enabledApps[0];
|
||||
|
||||
let urlToRedirectTo = `/${firstEnabledApp}`;
|
||||
|
||||
if (urlSearchParams.has('state')) {
|
||||
const state = this.parseState(urlSearchParams.get('state')!);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ export const currencyMap = new Map<SupportedCurrencySymbol, SupportedCurrency>([
|
|||
|
||||
export type PartialDeep<T> = (T extends (infer U)[] ? PartialDeep<U>[] : { [P in keyof T]?: PartialDeep<T[P]> }) | T;
|
||||
|
||||
export type OptionalApp = 'news' | 'notes' | 'photos' | 'expenses' | 'contacts' | 'calendar';
|
||||
export type OptionalApp = 'dashboard' | 'files' | 'news' | 'notes' | 'photos' | 'expenses' | 'contacts' | 'calendar';
|
||||
|
||||
export interface Config {
|
||||
auth: {
|
||||
|
|
@ -188,7 +188,7 @@ export interface Config {
|
|||
allowDirectoryDownloads: boolean;
|
||||
};
|
||||
core: {
|
||||
/** dashboard and files cannot be disabled */
|
||||
/** The apps to show, in order of appearance in the header. The first app will be the default one shown after logging in. At least one is required. */
|
||||
enabledApps: OptionalApp[];
|
||||
};
|
||||
visuals: {
|
||||
|
|
|
|||
225
lib/utils/webdav_test.ts
Normal file
225
lib/utils/webdav_test.ts
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
import { assertEquals } from '@std/assert';
|
||||
import { parse, stringify } from '@libs/xml';
|
||||
|
||||
import { addDavPrefixToKeys, getProperDestinationPath, getPropertyNames } from './webdav.ts';
|
||||
|
||||
Deno.test('that getProperDestinationPath works', () => {
|
||||
const tests: { input: string; expected?: string }[] = [
|
||||
{
|
||||
input: `http://127.0.0.1/dav/12345-abcde-67890`,
|
||||
expected: 'dav/12345-abcde-67890',
|
||||
},
|
||||
{
|
||||
input: `http://127.0.0.1/dav/spaced-%20uid`,
|
||||
expected: 'dav/spaced- uid',
|
||||
},
|
||||
{
|
||||
input: `http://127.0.0.1/dav/something-deeper/spaced-%C3%A7uid`,
|
||||
expected: 'dav/something-deeper/spaced-çuid',
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = getProperDestinationPath(test.input);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that addDavPrefixToKeys works', () => {
|
||||
const tests: {
|
||||
input: { object: Record<string, any> | Record<string, any>[]; prefix?: string };
|
||||
expected: Record<string, any>;
|
||||
}[] = [
|
||||
{
|
||||
input: {
|
||||
object: {
|
||||
displayname: 'test',
|
||||
},
|
||||
},
|
||||
expected: {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: [
|
||||
{ displayname: 'test' },
|
||||
{ color: 'black' },
|
||||
],
|
||||
},
|
||||
expected: [
|
||||
{ 'D:displayname': 'test' },
|
||||
{ 'D:color': 'black' },
|
||||
],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: { '@version': '1.0', '@encoding': 'UTF-8', displayname: 'test', color: 'black' },
|
||||
},
|
||||
expected: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
'D:displayname': 'test',
|
||||
'D:color': 'black',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: { displayname: 'test', color: 'black' },
|
||||
prefix: 'S:',
|
||||
},
|
||||
expected: {
|
||||
'S:displayname': 'test',
|
||||
'S:color': 'black',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = addDavPrefixToKeys(test.input.object, test.input.prefix);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that getPropertyNames works', () => {
|
||||
const tests: {
|
||||
input: Record<string, any>;
|
||||
expected: string[];
|
||||
}[] = [
|
||||
{
|
||||
input: {
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: ['displayname'],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
'D:color': 'black',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: ['displayname', 'color'],
|
||||
},
|
||||
{
|
||||
input: {},
|
||||
expected: ['allprop'],
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = getPropertyNames(test.input);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that @libs/xml.parse works', () => {
|
||||
const tests: { input: string; expected: Record<string, any> }[] = [
|
||||
{
|
||||
input: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<propfind xmlns="DAV:">
|
||||
<prop>
|
||||
<displayname>test</displayname>
|
||||
</prop>
|
||||
</propfind>`,
|
||||
expected: {
|
||||
xml: {
|
||||
'@version': 1,
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
propfind: {
|
||||
'@xmlns': 'DAV:',
|
||||
prop: {
|
||||
displayname: 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
expected: {
|
||||
xml: {
|
||||
'@version': 1,
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
'D:propfind': {
|
||||
'@xmlns:D': 'DAV:',
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = parse(test.input);
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that @libs/xml.stringify works', () => {
|
||||
const tests: { input: Record<string, any>; expected: string }[] = [
|
||||
{
|
||||
input: {
|
||||
xml: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind>
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
},
|
||||
{
|
||||
input: {
|
||||
xml: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
'D:propfind': {
|
||||
'@xmlns:D': 'DAV:',
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = stringify(test.input);
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { CalendarEvent, CalendarEventModel, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { generateVCalendar, getDateRangeForCalendarView } from '/lib/utils/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -28,6 +29,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { Calendar, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { CALENDAR_COLOR_OPTIONS, getColorAsHex } from '/lib/utils/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.name) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { CalendarEvent, CalendarEventModel, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { getDateRangeForCalendarView } from '/lib/utils/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -25,6 +26,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { Calendar, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.calendarId) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { CalendarEvent, CalendarEventModel } from '/lib/models/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.calendarIds) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { FreshContextState } from '/lib/types.ts';
|
|||
import { CalendarEvent, CalendarEventModel, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { concurrentPromises } from '/lib/utils/misc.ts';
|
||||
import { getDateRangeForCalendarView, getIdFromVEvent, splitTextIntoVEvents } from '/lib/utils/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -26,6 +27,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { CalendarEvent, CalendarEventModel } from '/lib/models/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { FreshContextState } from '/lib/types.ts';
|
|||
import { Calendar, CalendarModel } from '/lib/models/calendar.ts';
|
||||
import { UserModel } from '/lib/models/user.ts';
|
||||
import { CALENDAR_COLOR_OPTIONS, getColorAsHex } from '/lib/utils/calendar.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -25,6 +26,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.id) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AddressBook, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.name) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { Contact, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { generateVCard } from '/lib/utils/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -23,6 +24,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.firstName || !requestBody.addressBookId) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AddressBook, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.addressBookId) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { Contact, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.contactId || !requestBody.addressBookId) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AddressBook, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -18,6 +19,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const addressBooks = await ContactModel.listAddressBooks(context.state.user.id);
|
||||
|
||||
const responseBody: ResponseBody = { success: true, addressBooks };
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { Contact, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.addressBookId) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { FreshContextState } from '/lib/types.ts';
|
|||
import { Contact, ContactModel } from '/lib/models/contacts.ts';
|
||||
import { concurrentPromises } from '/lib/utils/misc.ts';
|
||||
import { getIdFromVCard, splitTextIntoVCards } from '/lib/utils/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -23,6 +24,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.vCards || !requestBody.addressBookId) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Handlers } from 'fresh/server.ts';
|
||||
|
||||
import { DashboardLink, FreshContextState } from '/lib/types.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
import { DashboardModel } from '/lib/models/dashboard.ts';
|
||||
|
||||
interface Data {}
|
||||
|
|
@ -19,6 +20,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('dashboard'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const userDashboard = await DashboardModel.getByUserId(context.state.user.id);
|
||||
|
||||
if (!userDashboard) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Handlers } from 'fresh/server.ts';
|
||||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
import { DashboardModel } from '/lib/models/dashboard.ts';
|
||||
|
||||
interface Data {}
|
||||
|
|
@ -19,6 +20,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('dashboard'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const userDashboard = await DashboardModel.getByUserId(context.state.user.id);
|
||||
|
||||
if (!userDashboard) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -23,6 +24,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, Expense, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel, ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -26,6 +27,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.name || requestBody.name.length < 2) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, Expense, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel, ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, Expense, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel, ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const newExpenses = await ExpenseModel.getAllForExport(context.state.user.id);
|
||||
|
||||
const newBudgets = await BudgetModel.getAllForExport(context.state.user.id);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { Budget, Expense, FreshContextState } from '/lib/types.ts';
|
||||
import { concurrentPromises } from '/lib/utils/misc.ts';
|
||||
import { BudgetModel, deleteAllBudgetsAndExpenses, ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -25,6 +26,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -24,6 +25,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Budget, Expense, FreshContextState } from '/lib/types.ts';
|
||||
import { BudgetModel, ExpenseModel } from '/lib/models/expenses.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -27,6 +28,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const isPublicFileSharingAllowed = await AppConfig.isPublicFileSharingAllowed();
|
||||
|
||||
if (!isPublicFileSharingAllowed) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -58,6 +58,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Directory downloads are not enabled', { status: 403 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
const parentPath = searchParams.get('parentPath') || '/';
|
||||
const name = searchParams.get('name');
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.fileShareId) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { searchFilesAndDirectories } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (!requestBody.searchTerm?.trim()) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { Directory, DirectoryFile, FreshContextState } from '/lib/types.ts';
|
||||
import { DirectoryModel, FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -17,6 +18,13 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().formData();
|
||||
|
||||
const pathInView = requestBody.get('path_in_view') as string;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState, NewsFeed } from '/lib/types.ts';
|
||||
import { FeedModel } from '/lib/models/news.ts';
|
||||
import { fetchNewArticles } from '/crons/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.feedUrl) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState, NewsFeed } from '/lib/types.ts';
|
||||
import { FeedModel } from '/lib/models/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.feedId) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { FreshContextState, NewsFeed } from '/lib/types.ts';
|
|||
import { concurrentPromises } from '/lib/utils/misc.ts';
|
||||
import { FeedModel } from '/lib/models/news.ts';
|
||||
import { fetchNewArticles } from '/crons/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -22,6 +23,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.feedUrls) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { ArticleModel } from '/lib/models/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -19,6 +20,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (requestBody.articleId) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
import { FreshContextState, NewsFeedArticle } from '/lib/types.ts';
|
||||
import { ArticleModel, FeedModel } from '/lib/models/news.ts';
|
||||
import { fetchNewArticles } from '/crons/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -19,6 +20,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const newsFeeds = await FeedModel.list(context.state.user.id);
|
||||
|
||||
if (!newsFeeds.length) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('notes'))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
const requestBody = await request.clone().json() as RequestBody;
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
throw new Error('CalDAV server is not enabled');
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
throw new Error('Calendar app is not enabled');
|
||||
}
|
||||
|
||||
const userId = context.state.user.id;
|
||||
const timezoneId = context.state.user.extra.timezone?.id || 'UTC';
|
||||
const timezoneUtcOffset = context.state.user.extra.timezone?.utcOffset || 0;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
throw new Error('CalDAV server is not enabled');
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
throw new Error('Calendar app is not enabled');
|
||||
}
|
||||
|
||||
let { calendarEventId } = context.params;
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
@ -63,6 +67,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
throw new Error('CalDAV server is not enabled');
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
throw new Error('Calendar app is not enabled');
|
||||
}
|
||||
|
||||
const { calendarEventId } = context.params;
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
throw new Error('CalDAV server is not enabled');
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('calendar'))) {
|
||||
throw new Error('Calendar app is not enabled');
|
||||
}
|
||||
|
||||
const userCalendars = await CalendarModel.list(context.state.user.id);
|
||||
|
||||
return await context.render({ userCalendars });
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
throw new Error('CardDAV server is not enabled');
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
throw new Error('Contacts app is not enabled');
|
||||
}
|
||||
|
||||
const userId = context.state.user.id;
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Contact, ContactModel } from '/lib/models/contacts.ts';
|
|||
import { getFormDataField } from '/lib/form-utils.tsx';
|
||||
import ViewContact, { formFields } from '/islands/contacts/ViewContact.tsx';
|
||||
import { updateVCard } from '/lib/utils/contacts.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {
|
||||
contact: Contact;
|
||||
|
|
@ -21,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Redirect', { status: 303, headers: { 'Location': `/login` } });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
throw new Error('Contacts app is not enabled');
|
||||
}
|
||||
|
||||
const { contactId } = context.params;
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
@ -43,6 +48,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Redirect', { status: 303, headers: { 'Location': `/login` } });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('contacts'))) {
|
||||
throw new Error('Contacts app is not enabled');
|
||||
}
|
||||
|
||||
const { contactId } = context.params;
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers, PageProps } from 'fresh/server.ts';
|
|||
|
||||
import { Dashboard, FreshContextState } from '/lib/types.ts';
|
||||
import { DashboardModel } from '/lib/models/dashboard.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
import Notes from '/islands/dashboard/Notes.tsx';
|
||||
import Links from '/islands/dashboard/Links.tsx';
|
||||
|
||||
|
|
@ -15,6 +16,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Redirect', { status: 303, headers: { 'Location': `/login` } });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('dashboard'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
let userDashboard = await DashboardModel.getByUserId(context.state.user.id);
|
||||
|
||||
if (!userDashboard) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,13 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
|||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!(await AppConfig.isAppEnabled('files')) && !(await AppConfig.isAppEnabled('photos')) &&
|
||||
!(await AppConfig.isAppEnabled('notes'))
|
||||
) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
let { filePath } = context.params;
|
||||
|
||||
if (!filePath) {
|
||||
|
|
@ -218,10 +225,17 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
|||
const depthString = request.headers.get('depth');
|
||||
const depth = depthString ? parseInt(depthString, 10) : null;
|
||||
const xml = await request.clone().text();
|
||||
let properties: string[] = [];
|
||||
|
||||
const parsedXml = parse(xml);
|
||||
try {
|
||||
const parsedXml = parse(xml) as Record<string, any>;
|
||||
|
||||
const properties = getPropertyNames(parsedXml);
|
||||
properties = getPropertyNames(parsedXml);
|
||||
} catch (error) {
|
||||
console.error('Error parsing XML: ', error);
|
||||
|
||||
properties = ['allprop'];
|
||||
}
|
||||
|
||||
await ensureUserPathIsValidAndSecurelyAccessible(userId, filePath);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('expenses'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/files` } });
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
|
||||
const baseUrl = (await AppConfig.getConfig()).auth.baseUrl;
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
|
|
@ -54,6 +58,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const fileShare = await FileShareModel.getById(fileShareId);
|
||||
|
||||
if (!fileShare) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
|
||||
const baseUrl = (await AppConfig.getConfig()).auth.baseUrl;
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
||||
let currentPath = searchParams.get('path') || '/';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Handlers } from 'fresh/server.ts';
|
||||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
|
||||
interface Data {}
|
||||
|
|
@ -17,6 +18,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('files'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
||||
let currentPath = searchParams.get('path') || '/';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
import { Handlers } from 'fresh/server.ts';
|
||||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
export const handler: Handlers<Data, FreshContextState> = {
|
||||
GET(request, context) {
|
||||
async GET(request, context) {
|
||||
const config = await AppConfig.getConfig();
|
||||
|
||||
if (context.state.user) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/dashboard` } });
|
||||
const firstEnabledApp = config.core.enabledApps[0];
|
||||
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/${firstEnabledApp}` } });
|
||||
}
|
||||
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': '/login' } });
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/dashboard` } });
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
const userArticles = await ArticleModel.listUnread(context.state.user.id);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Handlers, PageProps } from 'fresh/server.ts';
|
|||
|
||||
import { FreshContextState, NewsFeed } from '/lib/types.ts';
|
||||
import { FeedModel } from '/lib/models/news.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
import Feeds from '/islands/news/Feeds.tsx';
|
||||
|
||||
interface Data {
|
||||
|
|
@ -14,6 +15,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Redirect', { status: 303, headers: { 'Location': `/login` } });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('news'))) {
|
||||
return new Response('Redirect', { status: 303, headers: { 'Location': `/` } });
|
||||
}
|
||||
|
||||
const userFeeds = await FeedModel.list(context.state.user.id);
|
||||
|
||||
return await context.render({ userFeeds });
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Handlers, PageProps } from 'fresh/server.ts';
|
|||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import Note from '/islands/notes/Note.tsx';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {
|
||||
fileName: string;
|
||||
|
|
@ -22,6 +23,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('notes'))) {
|
||||
throw new Error('Notes app is not enabled');
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
||||
let currentPath = searchParams.get('path') || '/';
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import sharp from 'sharp';
|
|||
|
||||
import { FreshContextState } from '/lib/types.ts';
|
||||
import { FileModel } from '/lib/models/files.ts';
|
||||
import { AppConfig } from '/lib/config.ts';
|
||||
|
||||
interface Data {}
|
||||
|
||||
|
|
@ -23,6 +24,10 @@ export const handler: Handlers<Data, FreshContextState> = {
|
|||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
if (!(await AppConfig.isAppEnabled('photos'))) {
|
||||
throw new Error('Photos app is not enabled');
|
||||
}
|
||||
|
||||
const searchParams = new URL(request.url).searchParams;
|
||||
|
||||
let currentPath = searchParams.get('path') || '/';
|
||||
|
|
|
|||
Loading…
Reference in a new issue