mirror of
https://github.com/bewcloud/bewcloud.git
synced 2026-03-11 08:54:49 +00:00
Improve App Selection
This allows not enabling Dashboard and Files. It also sorts the apps in the menu according to the order in the `config.core.enabledApps` array. Since this will require a major version upgrade (`v3.0.0`), I also took the opportunity to upgrade PostgreSQL. You can [follow this guide on how to upgrade PostgreSQL on Docker containers](https://news.onbrn.com/step-by-step-guide-upgrading-postgresql-docker-containers/). Finally, this has some minor security improvements (confirming API endpoints won't work if their app is disabled in the config). Closes #114 Closes #108
This commit is contained in:
parent
3fdda5b34e
commit
d86e65475c
73 changed files with 384 additions and 62 deletions
|
|
@ -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,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.8.1
|
||||
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
|
||||
|
|
|
|||
|
|
@ -25,7 +25,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: '',
|
||||
|
|
@ -96,6 +96,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: {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -20,6 +20,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) {
|
||||
|
|
|
|||
|
|
@ -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