Changed config api. Split config controllers into separate files. Split bookmarks controllers into separate files
This commit is contained in:
parent
76e50624e7
commit
cfb471e578
23 changed files with 579 additions and 602 deletions
|
@ -1,6 +1,7 @@
|
||||||
### v1.7.1 (TBA)
|
### v1.7.1 (TBA)
|
||||||
- Fixed search action not being triggered by Numpad Enter
|
- Fixed search action not being triggered by Numpad Enter
|
||||||
- Fixed search bar not redirecting to valid URL if it starts with capital letter ([#118](https://github.com/pawelmalak/flame/issues/118))
|
- Fixed search bar not redirecting to valid URL if it starts with capital letter ([#118](https://github.com/pawelmalak/flame/issues/118))
|
||||||
|
- Performance improvements
|
||||||
|
|
||||||
### v1.7.0 (2021-10-11)
|
### v1.7.0 (2021-10-11)
|
||||||
- Search bar will now redirect if valid URL or IP is provided ([#67](https://github.com/pawelmalak/flame/issues/67))
|
- Search bar will now redirect if valid URL or IP is provided ([#67](https://github.com/pawelmalak/flame/issues/67))
|
||||||
|
|
|
@ -5,14 +5,17 @@ import { App, ApiResponse, NewApp, Config } from '../../interfaces';
|
||||||
import { CreateNotificationAction } from './notification';
|
import { CreateNotificationAction } from './notification';
|
||||||
|
|
||||||
export interface GetAppsAction<T> {
|
export interface GetAppsAction<T> {
|
||||||
type: ActionTypes.getApps | ActionTypes.getAppsSuccess | ActionTypes.getAppsError;
|
type:
|
||||||
|
| ActionTypes.getApps
|
||||||
|
| ActionTypes.getAppsSuccess
|
||||||
|
| ActionTypes.getAppsError;
|
||||||
payload: T;
|
payload: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getApps = () => async (dispatch: Dispatch) => {
|
export const getApps = () => async (dispatch: Dispatch) => {
|
||||||
dispatch<GetAppsAction<undefined>>({
|
dispatch<GetAppsAction<undefined>>({
|
||||||
type: ActionTypes.getApps,
|
type: ActionTypes.getApps,
|
||||||
payload: undefined
|
payload: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -20,12 +23,12 @@ export const getApps = () => async (dispatch: Dispatch) => {
|
||||||
|
|
||||||
dispatch<GetAppsAction<App[]>>({
|
dispatch<GetAppsAction<App[]>>({
|
||||||
type: ActionTypes.getAppsSuccess,
|
type: ActionTypes.getAppsSuccess,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface PinAppAction {
|
export interface PinAppAction {
|
||||||
type: ActionTypes.pinApp;
|
type: ActionTypes.pinApp;
|
||||||
|
@ -35,59 +38,64 @@ export interface PinAppAction {
|
||||||
export const pinApp = (app: App) => async (dispatch: Dispatch) => {
|
export const pinApp = (app: App) => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const { id, isPinned, name } = app;
|
const { id, isPinned, name } = app;
|
||||||
const res = await axios.put<ApiResponse<App>>(`/api/apps/${id}`, { isPinned: !isPinned });
|
const res = await axios.put<ApiResponse<App>>(`/api/apps/${id}`, {
|
||||||
|
isPinned: !isPinned,
|
||||||
|
});
|
||||||
|
|
||||||
const status = isPinned ? 'unpinned from Homescreen' : 'pinned to Homescreen';
|
const status = isPinned
|
||||||
|
? 'unpinned from Homescreen'
|
||||||
|
: 'pinned to Homescreen';
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `App ${name} ${status}`
|
message: `App ${name} ${status}`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<PinAppAction>({
|
dispatch<PinAppAction>({
|
||||||
type: ActionTypes.pinApp,
|
type: ActionTypes.pinApp,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface AddAppAction {
|
export interface AddAppAction {
|
||||||
type: ActionTypes.addAppSuccess;
|
type: ActionTypes.addAppSuccess;
|
||||||
payload: App;
|
payload: App;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addApp = (formData: NewApp | FormData) => async (dispatch: Dispatch) => {
|
export const addApp =
|
||||||
try {
|
(formData: NewApp | FormData) => async (dispatch: Dispatch) => {
|
||||||
const res = await axios.post<ApiResponse<App>>('/api/apps', formData);
|
try {
|
||||||
|
const res = await axios.post<ApiResponse<App>>('/api/apps', formData);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `App added`
|
message: `App added`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
await dispatch<AddAppAction>({
|
await dispatch<AddAppAction>({
|
||||||
type: ActionTypes.addAppSuccess,
|
type: ActionTypes.addAppSuccess,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
|
|
||||||
// Sort apps
|
// Sort apps
|
||||||
dispatch<any>(sortApps())
|
dispatch<any>(sortApps());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface DeleteAppAction {
|
export interface DeleteAppAction {
|
||||||
type: ActionTypes.deleteApp,
|
type: ActionTypes.deleteApp;
|
||||||
payload: number
|
payload: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deleteApp = (id: number) => async (dispatch: Dispatch) => {
|
export const deleteApp = (id: number) => async (dispatch: Dispatch) => {
|
||||||
|
@ -98,79 +106,85 @@ export const deleteApp = (id: number) => async (dispatch: Dispatch) => {
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'App deleted'
|
message: 'App deleted',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<DeleteAppAction>({
|
dispatch<DeleteAppAction>({
|
||||||
type: ActionTypes.deleteApp,
|
type: ActionTypes.deleteApp,
|
||||||
payload: id
|
payload: id,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface UpdateAppAction {
|
export interface UpdateAppAction {
|
||||||
type: ActionTypes.updateApp;
|
type: ActionTypes.updateApp;
|
||||||
payload: App;
|
payload: App;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateApp = (id: number, formData: NewApp | FormData) => async (dispatch: Dispatch) => {
|
export const updateApp =
|
||||||
try {
|
(id: number, formData: NewApp | FormData) => async (dispatch: Dispatch) => {
|
||||||
const res = await axios.put<ApiResponse<App>>(`/api/apps/${id}`, formData);
|
try {
|
||||||
|
const res = await axios.put<ApiResponse<App>>(
|
||||||
|
`/api/apps/${id}`,
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `App updated`
|
message: `App updated`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
await dispatch<UpdateAppAction>({
|
await dispatch<UpdateAppAction>({
|
||||||
type: ActionTypes.updateApp,
|
type: ActionTypes.updateApp,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
|
|
||||||
// Sort apps
|
// Sort apps
|
||||||
dispatch<any>(sortApps())
|
dispatch<any>(sortApps());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface ReorderAppsAction {
|
export interface ReorderAppsAction {
|
||||||
type: ActionTypes.reorderApps;
|
type: ActionTypes.reorderApps;
|
||||||
payload: App[]
|
payload: App[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReorderQuery {
|
interface ReorderQuery {
|
||||||
apps: {
|
apps: {
|
||||||
id: number;
|
id: number;
|
||||||
orderId: number;
|
orderId: number;
|
||||||
}[]
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reorderApps = (apps: App[]) => async (dispatch: Dispatch) => {
|
export const reorderApps = (apps: App[]) => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const updateQuery: ReorderQuery = { apps: [] }
|
const updateQuery: ReorderQuery = { apps: [] };
|
||||||
|
|
||||||
apps.forEach((app, index) => updateQuery.apps.push({
|
apps.forEach((app, index) =>
|
||||||
id: app.id,
|
updateQuery.apps.push({
|
||||||
orderId: index + 1
|
id: app.id,
|
||||||
}))
|
orderId: index + 1,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
await axios.put<ApiResponse<{}>>('/api/apps/0/reorder', updateQuery);
|
await axios.put<ApiResponse<{}>>('/api/apps/0/reorder', updateQuery);
|
||||||
|
|
||||||
dispatch<ReorderAppsAction>({
|
dispatch<ReorderAppsAction>({
|
||||||
type: ActionTypes.reorderApps,
|
type: ActionTypes.reorderApps,
|
||||||
payload: apps
|
payload: apps,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface SortAppsAction {
|
export interface SortAppsAction {
|
||||||
type: ActionTypes.sortApps;
|
type: ActionTypes.sortApps;
|
||||||
|
@ -179,13 +193,13 @@ export interface SortAppsAction {
|
||||||
|
|
||||||
export const sortApps = () => async (dispatch: Dispatch) => {
|
export const sortApps = () => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get<ApiResponse<Config>>('/api/config/useOrdering');
|
const res = await axios.get<ApiResponse<Config>>('/api/config');
|
||||||
|
|
||||||
dispatch<SortAppsAction>({
|
dispatch<SortAppsAction>({
|
||||||
type: ActionTypes.sortApps,
|
type: ActionTypes.sortApps,
|
||||||
payload: res.data.data.value
|
payload: res.data.data.useOrdering,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,133 +1,157 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { ActionTypes } from './actionTypes';
|
import { ActionTypes } from './actionTypes';
|
||||||
import { Category, ApiResponse, NewCategory, Bookmark, NewBookmark, Config } from '../../interfaces';
|
import {
|
||||||
|
Category,
|
||||||
|
ApiResponse,
|
||||||
|
NewCategory,
|
||||||
|
Bookmark,
|
||||||
|
NewBookmark,
|
||||||
|
Config,
|
||||||
|
} from '../../interfaces';
|
||||||
import { CreateNotificationAction } from './notification';
|
import { CreateNotificationAction } from './notification';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET CATEGORIES
|
* GET CATEGORIES
|
||||||
*/
|
*/
|
||||||
export interface GetCategoriesAction<T> {
|
export interface GetCategoriesAction<T> {
|
||||||
type: ActionTypes.getCategories | ActionTypes.getCategoriesSuccess | ActionTypes.getCategoriesError;
|
type:
|
||||||
|
| ActionTypes.getCategories
|
||||||
|
| ActionTypes.getCategoriesSuccess
|
||||||
|
| ActionTypes.getCategoriesError;
|
||||||
payload: T;
|
payload: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCategories = () => async (dispatch: Dispatch) => {
|
export const getCategories = () => async (dispatch: Dispatch) => {
|
||||||
dispatch<GetCategoriesAction<undefined>>({
|
dispatch<GetCategoriesAction<undefined>>({
|
||||||
type: ActionTypes.getCategories,
|
type: ActionTypes.getCategories,
|
||||||
payload: undefined
|
payload: undefined,
|
||||||
})
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.get<ApiResponse<Category[]>>('/api/categories');
|
const res = await axios.get<ApiResponse<Category[]>>('/api/categories');
|
||||||
|
|
||||||
dispatch<GetCategoriesAction<Category[]>>({
|
dispatch<GetCategoriesAction<Category[]>>({
|
||||||
type: ActionTypes.getCategoriesSuccess,
|
type: ActionTypes.getCategoriesSuccess,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ADD CATEGORY
|
* ADD CATEGORY
|
||||||
*/
|
*/
|
||||||
export interface AddCategoryAction {
|
export interface AddCategoryAction {
|
||||||
type: ActionTypes.addCategory,
|
type: ActionTypes.addCategory;
|
||||||
payload: Category
|
payload: Category;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addCategory = (formData: NewCategory) => async (dispatch: Dispatch) => {
|
export const addCategory =
|
||||||
try {
|
(formData: NewCategory) => async (dispatch: Dispatch) => {
|
||||||
const res = await axios.post<ApiResponse<Category>>('/api/categories', formData);
|
try {
|
||||||
|
const res = await axios.post<ApiResponse<Category>>(
|
||||||
|
'/api/categories',
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `Category ${formData.name} created`
|
message: `Category ${formData.name} created`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<AddCategoryAction>({
|
dispatch<AddCategoryAction>({
|
||||||
type: ActionTypes.addCategory,
|
type: ActionTypes.addCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<any>(sortCategories());
|
dispatch<any>(sortCategories());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ADD BOOKMARK
|
* ADD BOOKMARK
|
||||||
*/
|
*/
|
||||||
export interface AddBookmarkAction {
|
export interface AddBookmarkAction {
|
||||||
type: ActionTypes.addBookmark,
|
type: ActionTypes.addBookmark;
|
||||||
payload: Bookmark
|
payload: Bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addBookmark = (formData: NewBookmark | FormData) => async (dispatch: Dispatch) => {
|
export const addBookmark =
|
||||||
try {
|
(formData: NewBookmark | FormData) => async (dispatch: Dispatch) => {
|
||||||
const res = await axios.post<ApiResponse<Bookmark>>('/api/bookmarks', formData);
|
try {
|
||||||
|
const res = await axios.post<ApiResponse<Bookmark>>(
|
||||||
|
'/api/bookmarks',
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `Bookmark created`
|
message: `Bookmark created`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<AddBookmarkAction>({
|
dispatch<AddBookmarkAction>({
|
||||||
type: ActionTypes.addBookmark,
|
type: ActionTypes.addBookmark,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PIN CATEGORY
|
* PIN CATEGORY
|
||||||
*/
|
*/
|
||||||
export interface PinCategoryAction {
|
export interface PinCategoryAction {
|
||||||
type: ActionTypes.pinCategory,
|
type: ActionTypes.pinCategory;
|
||||||
payload: Category
|
payload: Category;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pinCategory = (category: Category) => async (dispatch: Dispatch) => {
|
export const pinCategory =
|
||||||
try {
|
(category: Category) => async (dispatch: Dispatch) => {
|
||||||
const { id, isPinned, name } = category;
|
try {
|
||||||
const res = await axios.put<ApiResponse<Category>>(`/api/categories/${id}`, { isPinned: !isPinned });
|
const { id, isPinned, name } = category;
|
||||||
|
const res = await axios.put<ApiResponse<Category>>(
|
||||||
|
`/api/categories/${id}`,
|
||||||
|
{ isPinned: !isPinned }
|
||||||
|
);
|
||||||
|
|
||||||
const status = isPinned ? 'unpinned from Homescreen' : 'pinned to Homescreen';
|
const status = isPinned
|
||||||
|
? 'unpinned from Homescreen'
|
||||||
|
: 'pinned to Homescreen';
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `Category ${name} ${status}`
|
message: `Category ${name} ${status}`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<PinCategoryAction>({
|
dispatch<PinCategoryAction>({
|
||||||
type: ActionTypes.pinCategory,
|
type: ActionTypes.pinCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DELETE CATEGORY
|
* DELETE CATEGORY
|
||||||
*/
|
*/
|
||||||
export interface DeleteCategoryAction {
|
export interface DeleteCategoryAction {
|
||||||
type: ActionTypes.deleteCategory,
|
type: ActionTypes.deleteCategory;
|
||||||
payload: number
|
payload: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deleteCategory = (id: number) => async (dispatch: Dispatch) => {
|
export const deleteCategory = (id: number) => async (dispatch: Dispatch) => {
|
||||||
|
@ -138,141 +162,151 @@ export const deleteCategory = (id: number) => async (dispatch: Dispatch) => {
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `Category deleted`
|
message: `Category deleted`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<DeleteCategoryAction>({
|
dispatch<DeleteCategoryAction>({
|
||||||
type: ActionTypes.deleteCategory,
|
type: ActionTypes.deleteCategory,
|
||||||
payload: id
|
payload: id,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UPDATE CATEGORY
|
* UPDATE CATEGORY
|
||||||
*/
|
*/
|
||||||
export interface UpdateCategoryAction {
|
export interface UpdateCategoryAction {
|
||||||
type: ActionTypes.updateCategory,
|
type: ActionTypes.updateCategory;
|
||||||
payload: Category
|
payload: Category;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateCategory = (id: number, formData: NewCategory) => async (dispatch: Dispatch) => {
|
export const updateCategory =
|
||||||
try {
|
(id: number, formData: NewCategory) => async (dispatch: Dispatch) => {
|
||||||
const res = await axios.put<ApiResponse<Category>>(`/api/categories/${id}`, formData);
|
try {
|
||||||
|
const res = await axios.put<ApiResponse<Category>>(
|
||||||
|
`/api/categories/${id}`,
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: `Category ${formData.name} updated`
|
message: `Category ${formData.name} updated`,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<UpdateCategoryAction>({
|
dispatch<UpdateCategoryAction>({
|
||||||
type: ActionTypes.updateCategory,
|
type: ActionTypes.updateCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data,
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<any>(sortCategories());
|
dispatch<any>(sortCategories());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DELETE BOOKMARK
|
* DELETE BOOKMARK
|
||||||
*/
|
*/
|
||||||
export interface DeleteBookmarkAction {
|
export interface DeleteBookmarkAction {
|
||||||
type: ActionTypes.deleteBookmark,
|
type: ActionTypes.deleteBookmark;
|
||||||
payload: {
|
payload: {
|
||||||
bookmarkId: number,
|
bookmarkId: number;
|
||||||
categoryId: number
|
categoryId: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deleteBookmark = (bookmarkId: number, categoryId: number) => async (dispatch: Dispatch) => {
|
export const deleteBookmark =
|
||||||
try {
|
(bookmarkId: number, categoryId: number) => async (dispatch: Dispatch) => {
|
||||||
await axios.delete<ApiResponse<{}>>(`/api/bookmarks/${bookmarkId}`);
|
try {
|
||||||
|
await axios.delete<ApiResponse<{}>>(`/api/bookmarks/${bookmarkId}`);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
payload: {
|
payload: {
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'Bookmark deleted'
|
message: 'Bookmark deleted',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
dispatch<DeleteBookmarkAction>({
|
dispatch<DeleteBookmarkAction>({
|
||||||
type: ActionTypes.deleteBookmark,
|
type: ActionTypes.deleteBookmark,
|
||||||
payload: {
|
payload: {
|
||||||
bookmarkId,
|
bookmarkId,
|
||||||
categoryId
|
categoryId,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UPDATE BOOKMARK
|
* UPDATE BOOKMARK
|
||||||
*/
|
*/
|
||||||
export interface UpdateBookmarkAction {
|
export interface UpdateBookmarkAction {
|
||||||
type: ActionTypes.updateBookmark,
|
type: ActionTypes.updateBookmark;
|
||||||
payload: Bookmark
|
payload: Bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateBookmark = (
|
export const updateBookmark =
|
||||||
bookmarkId: number,
|
(
|
||||||
formData: NewBookmark | FormData,
|
bookmarkId: number,
|
||||||
category: {
|
formData: NewBookmark | FormData,
|
||||||
prev: number,
|
category: {
|
||||||
curr: number
|
prev: number;
|
||||||
}
|
curr: number;
|
||||||
) => async (dispatch: Dispatch) => {
|
|
||||||
try {
|
|
||||||
const res = await axios.put<ApiResponse<Bookmark>>(`/api/bookmarks/${bookmarkId}`, formData);
|
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
|
||||||
type: ActionTypes.createNotification,
|
|
||||||
payload: {
|
|
||||||
title: 'Success',
|
|
||||||
message: `Bookmark updated`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check if category was changed
|
|
||||||
const categoryWasChanged = category.curr !== category.prev;
|
|
||||||
|
|
||||||
if (categoryWasChanged) {
|
|
||||||
// Delete bookmark from old category
|
|
||||||
dispatch<DeleteBookmarkAction>({
|
|
||||||
type: ActionTypes.deleteBookmark,
|
|
||||||
payload: {
|
|
||||||
bookmarkId,
|
|
||||||
categoryId: category.prev
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Add bookmark to the new category
|
|
||||||
dispatch<AddBookmarkAction>({
|
|
||||||
type: ActionTypes.addBookmark,
|
|
||||||
payload: res.data.data
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Else update only name/url/icon
|
|
||||||
dispatch<UpdateBookmarkAction>({
|
|
||||||
type: ActionTypes.updateBookmark,
|
|
||||||
payload: res.data.data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
) =>
|
||||||
console.log(err);
|
async (dispatch: Dispatch) => {
|
||||||
}
|
try {
|
||||||
}
|
const res = await axios.put<ApiResponse<Bookmark>>(
|
||||||
|
`/api/bookmarks/${bookmarkId}`,
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch<CreateNotificationAction>({
|
||||||
|
type: ActionTypes.createNotification,
|
||||||
|
payload: {
|
||||||
|
title: 'Success',
|
||||||
|
message: `Bookmark updated`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if category was changed
|
||||||
|
const categoryWasChanged = category.curr !== category.prev;
|
||||||
|
|
||||||
|
if (categoryWasChanged) {
|
||||||
|
// Delete bookmark from old category
|
||||||
|
dispatch<DeleteBookmarkAction>({
|
||||||
|
type: ActionTypes.deleteBookmark,
|
||||||
|
payload: {
|
||||||
|
bookmarkId,
|
||||||
|
categoryId: category.prev,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add bookmark to the new category
|
||||||
|
dispatch<AddBookmarkAction>({
|
||||||
|
type: ActionTypes.addBookmark,
|
||||||
|
payload: res.data.data,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Else update only name/url/icon
|
||||||
|
dispatch<UpdateBookmarkAction>({
|
||||||
|
type: ActionTypes.updateBookmark,
|
||||||
|
payload: res.data.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SORT CATEGORIES
|
* SORT CATEGORIES
|
||||||
|
@ -284,16 +318,16 @@ export interface SortCategoriesAction {
|
||||||
|
|
||||||
export const sortCategories = () => async (dispatch: Dispatch) => {
|
export const sortCategories = () => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get<ApiResponse<Config>>('/api/config/useOrdering');
|
const res = await axios.get<ApiResponse<Config>>('/api/config');
|
||||||
|
|
||||||
dispatch<SortCategoriesAction>({
|
dispatch<SortCategoriesAction>({
|
||||||
type: ActionTypes.sortCategories,
|
type: ActionTypes.sortCategories,
|
||||||
payload: res.data.data.value
|
payload: res.data.data.useOrdering,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* REORDER CATEGORIES
|
* REORDER CATEGORIES
|
||||||
|
@ -307,25 +341,31 @@ interface ReorderQuery {
|
||||||
categories: {
|
categories: {
|
||||||
id: number;
|
id: number;
|
||||||
orderId: number;
|
orderId: number;
|
||||||
}[]
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reorderCategories = (categories: Category[]) => async (dispatch: Dispatch) => {
|
export const reorderCategories =
|
||||||
try {
|
(categories: Category[]) => async (dispatch: Dispatch) => {
|
||||||
const updateQuery: ReorderQuery = { categories: [] }
|
try {
|
||||||
|
const updateQuery: ReorderQuery = { categories: [] };
|
||||||
|
|
||||||
categories.forEach((category, index) => updateQuery.categories.push({
|
categories.forEach((category, index) =>
|
||||||
id: category.id,
|
updateQuery.categories.push({
|
||||||
orderId: index + 1
|
id: category.id,
|
||||||
}))
|
orderId: index + 1,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
await axios.put<ApiResponse<{}>>('/api/categories/0/reorder', updateQuery);
|
await axios.put<ApiResponse<{}>>(
|
||||||
|
'/api/categories/0/reorder',
|
||||||
|
updateQuery
|
||||||
|
);
|
||||||
|
|
||||||
dispatch<ReorderCategoriesAction>({
|
dispatch<ReorderCategoriesAction>({
|
||||||
type: ActionTypes.reorderCategories,
|
type: ActionTypes.reorderCategories,
|
||||||
payload: categories
|
payload: categories,
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,16 +3,15 @@ import { Dispatch } from 'redux';
|
||||||
import { ActionTypes } from './actionTypes';
|
import { ActionTypes } from './actionTypes';
|
||||||
import { Config, ApiResponse, Query } from '../../interfaces';
|
import { Config, ApiResponse, Query } from '../../interfaces';
|
||||||
import { CreateNotificationAction } from './notification';
|
import { CreateNotificationAction } from './notification';
|
||||||
import { searchConfig } from '../../utility';
|
|
||||||
|
|
||||||
export interface GetConfigAction {
|
export interface GetConfigAction {
|
||||||
type: ActionTypes.getConfig;
|
type: ActionTypes.getConfig;
|
||||||
payload: Config[];
|
payload: Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getConfig = () => async (dispatch: Dispatch) => {
|
export const getConfig = () => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get<ApiResponse<Config[]>>('/api/config');
|
const res = await axios.get<ApiResponse<Config>>('/api/config');
|
||||||
|
|
||||||
dispatch<GetConfigAction>({
|
dispatch<GetConfigAction>({
|
||||||
type: ActionTypes.getConfig,
|
type: ActionTypes.getConfig,
|
||||||
|
@ -20,7 +19,7 @@ export const getConfig = () => async (dispatch: Dispatch) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set custom page title if set
|
// Set custom page title if set
|
||||||
document.title = searchConfig('customTitle', 'Flame');
|
document.title = res.data.data.customTitle;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -28,12 +27,12 @@ export const getConfig = () => async (dispatch: Dispatch) => {
|
||||||
|
|
||||||
export interface UpdateConfigAction {
|
export interface UpdateConfigAction {
|
||||||
type: ActionTypes.updateConfig;
|
type: ActionTypes.updateConfig;
|
||||||
payload: Config[];
|
payload: Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateConfig = (formData: any) => async (dispatch: Dispatch) => {
|
export const updateConfig = (formData: any) => async (dispatch: Dispatch) => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.put<ApiResponse<Config[]>>('/api/config', formData);
|
const res = await axios.put<ApiResponse<Config>>('/api/config', formData);
|
||||||
|
|
||||||
dispatch<CreateNotificationAction>({
|
dispatch<CreateNotificationAction>({
|
||||||
type: ActionTypes.createNotification,
|
type: ActionTypes.createNotification,
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { ActionTypes, Action } from '../actions';
|
import { ActionTypes, Action } from '../actions';
|
||||||
import { Config, Query } from '../../interfaces';
|
import { Config, Query } from '../../interfaces';
|
||||||
|
import { configTemplate } from '../../utility';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
config: Config[];
|
config: Config;
|
||||||
customQueries: Query[];
|
customQueries: Query[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: State = {
|
const initialState: State = {
|
||||||
loading: true,
|
loading: true,
|
||||||
config: [],
|
config: configTemplate,
|
||||||
customQueries: [],
|
customQueries: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const App = require('../../models/App');
|
const App = require('../../../models/App');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const Logger = require('../../utils/Logger');
|
const Logger = require('../../../utils/Logger');
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
const loadConfig = require('../../utils/loadConfig');
|
const loadConfig = require('../../../utils/loadConfig');
|
||||||
|
|
||||||
const useDocker = async (apps) => {
|
const useDocker = async (apps) => {
|
||||||
const {
|
const {
|
||||||
|
@ -50,7 +50,7 @@ const useDocker = async (apps) => {
|
||||||
for (const container of containers) {
|
for (const container of containers) {
|
||||||
let labels = container.Labels;
|
let labels = container.Labels;
|
||||||
|
|
||||||
// todo
|
// Traefik labels for URL configuration
|
||||||
if (!('flame.url' in labels)) {
|
if (!('flame.url' in labels)) {
|
||||||
for (const label of Object.keys(labels)) {
|
for (const label of Object.keys(labels)) {
|
||||||
if (/^traefik.*.frontend.rule/.test(label)) {
|
if (/^traefik.*.frontend.rule/.test(label)) {
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
const asyncWrapper = require('../middleware/asyncWrapper');
|
|
||||||
const ErrorResponse = require('../utils/ErrorResponse');
|
|
||||||
const Bookmark = require('../models/Bookmark');
|
|
||||||
const { Sequelize } = require('sequelize');
|
|
||||||
|
|
||||||
// @desc Create new bookmark
|
|
||||||
// @route POST /api/bookmarks
|
|
||||||
// @access Public
|
|
||||||
exports.createBookmark = asyncWrapper(async (req, res, next) => {
|
|
||||||
let bookmark;
|
|
||||||
|
|
||||||
let _body = {
|
|
||||||
...req.body,
|
|
||||||
categoryId: parseInt(req.body.categoryId),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (req.file) {
|
|
||||||
_body.icon = req.file.filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
bookmark = await Bookmark.create(_body);
|
|
||||||
|
|
||||||
res.status(201).json({
|
|
||||||
success: true,
|
|
||||||
data: bookmark,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Get all bookmarks
|
|
||||||
// @route GET /api/bookmarks
|
|
||||||
// @access Public
|
|
||||||
exports.getBookmarks = asyncWrapper(async (req, res, next) => {
|
|
||||||
const bookmarks = await Bookmark.findAll({
|
|
||||||
order: [[Sequelize.fn('lower', Sequelize.col('name')), 'ASC']],
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: bookmarks,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Get single bookmark
|
|
||||||
// @route GET /api/bookmarks/:id
|
|
||||||
// @access Public
|
|
||||||
exports.getBookmark = asyncWrapper(async (req, res, next) => {
|
|
||||||
const bookmark = await Bookmark.findOne({
|
|
||||||
where: { id: req.params.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!bookmark) {
|
|
||||||
return next(
|
|
||||||
new ErrorResponse(
|
|
||||||
`Bookmark with id of ${req.params.id} was not found`,
|
|
||||||
404
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: bookmark,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Update bookmark
|
|
||||||
// @route PUT /api/bookmarks/:id
|
|
||||||
// @access Public
|
|
||||||
exports.updateBookmark = asyncWrapper(async (req, res, next) => {
|
|
||||||
let bookmark = await Bookmark.findOne({
|
|
||||||
where: { id: req.params.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!bookmark) {
|
|
||||||
return next(
|
|
||||||
new ErrorResponse(
|
|
||||||
`Bookmark with id of ${req.params.id} was not found`,
|
|
||||||
404
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let _body = {
|
|
||||||
...req.body,
|
|
||||||
categoryId: parseInt(req.body.categoryId),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (req.file) {
|
|
||||||
_body.icon = req.file.filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
bookmark = await bookmark.update(_body);
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: bookmark,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Delete bookmark
|
|
||||||
// @route DELETE /api/bookmarks/:id
|
|
||||||
// @access Public
|
|
||||||
exports.deleteBookmark = asyncWrapper(async (req, res, next) => {
|
|
||||||
await Bookmark.destroy({
|
|
||||||
where: { id: req.params.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: {},
|
|
||||||
});
|
|
||||||
});
|
|
27
controllers/bookmarks/createBookmark.js
Normal file
27
controllers/bookmarks/createBookmark.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const Bookmark = require('../../models/Bookmark');
|
||||||
|
|
||||||
|
// @desc Create new bookmark
|
||||||
|
// @route POST /api/bookmarks
|
||||||
|
// @access Public
|
||||||
|
const createBookmark = asyncWrapper(async (req, res, next) => {
|
||||||
|
let bookmark;
|
||||||
|
|
||||||
|
let _body = {
|
||||||
|
...req.body,
|
||||||
|
categoryId: parseInt(req.body.categoryId),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
_body.icon = req.file.filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmark = await Bookmark.create(_body);
|
||||||
|
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
data: bookmark,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = createBookmark;
|
18
controllers/bookmarks/deleteBookmark.js
Normal file
18
controllers/bookmarks/deleteBookmark.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const Bookmark = require('../../models/Bookmark');
|
||||||
|
|
||||||
|
// @desc Delete bookmark
|
||||||
|
// @route DELETE /api/bookmarks/:id
|
||||||
|
// @access Public
|
||||||
|
const deleteBookmark = asyncWrapper(async (req, res, next) => {
|
||||||
|
await Bookmark.destroy({
|
||||||
|
where: { id: req.params.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = deleteBookmark;
|
19
controllers/bookmarks/getAllBookmarks.js
Normal file
19
controllers/bookmarks/getAllBookmarks.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const Bookmark = require('../../models/Bookmark');
|
||||||
|
const { Sequelize } = require('sequelize');
|
||||||
|
|
||||||
|
// @desc Get all bookmarks
|
||||||
|
// @route GET /api/bookmarks
|
||||||
|
// @access Public
|
||||||
|
const getAllBookmarks = asyncWrapper(async (req, res, next) => {
|
||||||
|
const bookmarks = await Bookmark.findAll({
|
||||||
|
order: [[Sequelize.fn('lower', Sequelize.col('name')), 'ASC']],
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: bookmarks,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = getAllBookmarks;
|
28
controllers/bookmarks/getSingleBookmark.js
Normal file
28
controllers/bookmarks/getSingleBookmark.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const ErrorResponse = require('../../utils/ErrorResponse');
|
||||||
|
const Bookmark = require('../../models/Bookmark');
|
||||||
|
|
||||||
|
// @desc Get single bookmark
|
||||||
|
// @route GET /api/bookmarks/:id
|
||||||
|
// @access Public
|
||||||
|
const getSingleBookmark = asyncWrapper(async (req, res, next) => {
|
||||||
|
const bookmark = await Bookmark.findOne({
|
||||||
|
where: { id: req.params.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!bookmark) {
|
||||||
|
return next(
|
||||||
|
new ErrorResponse(
|
||||||
|
`Bookmark with the id of ${req.params.id} was not found`,
|
||||||
|
404
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: bookmark,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = getSingleBookmark;
|
7
controllers/bookmarks/index.js
Normal file
7
controllers/bookmarks/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
createBookmark: require('./createBookmark'),
|
||||||
|
getAllBookmarks: require('./getAllBookmarks'),
|
||||||
|
getSingleBookmark: require('./getSingleBookmark'),
|
||||||
|
updateBookmark: require('./updateBookmark'),
|
||||||
|
deleteBookmark: require('./deleteBookmark'),
|
||||||
|
};
|
39
controllers/bookmarks/updateBookmark.js
Normal file
39
controllers/bookmarks/updateBookmark.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const ErrorResponse = require('../../utils/ErrorResponse');
|
||||||
|
const Bookmark = require('../../models/Bookmark');
|
||||||
|
|
||||||
|
// @desc Update bookmark
|
||||||
|
// @route PUT /api/bookmarks/:id
|
||||||
|
// @access Public
|
||||||
|
const updateBookmark = asyncWrapper(async (req, res, next) => {
|
||||||
|
let bookmark = await Bookmark.findOne({
|
||||||
|
where: { id: req.params.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!bookmark) {
|
||||||
|
return next(
|
||||||
|
new ErrorResponse(
|
||||||
|
`Bookmark with id of ${req.params.id} was not found`,
|
||||||
|
404
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _body = {
|
||||||
|
...req.body,
|
||||||
|
categoryId: parseInt(req.body.categoryId),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
_body.icon = req.file.filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmark = await bookmark.update(_body);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: bookmark,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = updateBookmark;
|
|
@ -4,15 +4,13 @@ const Category = require('../models/Category');
|
||||||
const Bookmark = require('../models/Bookmark');
|
const Bookmark = require('../models/Bookmark');
|
||||||
const Config = require('../models/Config');
|
const Config = require('../models/Config');
|
||||||
const { Sequelize } = require('sequelize');
|
const { Sequelize } = require('sequelize');
|
||||||
|
const loadConfig = require('../utils/loadConfig');
|
||||||
|
|
||||||
// @desc Create new category
|
// @desc Create new category
|
||||||
// @route POST /api/categories
|
// @route POST /api/categories
|
||||||
// @access Public
|
// @access Public
|
||||||
exports.createCategory = asyncWrapper(async (req, res, next) => {
|
exports.createCategory = asyncWrapper(async (req, res, next) => {
|
||||||
// Get config from database
|
const { pinCategoriesByDefault: pinCategories } = await loadConfig();
|
||||||
const pinCategories = await Config.findOne({
|
|
||||||
where: { key: 'pinCategoriesByDefault' },
|
|
||||||
});
|
|
||||||
|
|
||||||
let category;
|
let category;
|
||||||
|
|
||||||
|
@ -37,12 +35,8 @@ exports.createCategory = asyncWrapper(async (req, res, next) => {
|
||||||
// @route GET /api/categories
|
// @route GET /api/categories
|
||||||
// @access Public
|
// @access Public
|
||||||
exports.getCategories = asyncWrapper(async (req, res, next) => {
|
exports.getCategories = asyncWrapper(async (req, res, next) => {
|
||||||
// Get config from database
|
const { useOrdering: orderType } = await loadConfig();
|
||||||
const useOrdering = await Config.findOne({
|
|
||||||
where: { key: 'useOrdering' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const orderType = useOrdering ? useOrdering.value : 'createdAt';
|
|
||||||
let categories;
|
let categories;
|
||||||
|
|
||||||
if (orderType == 'name') {
|
if (orderType == 'name') {
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
const asyncWrapper = require('../middleware/asyncWrapper');
|
|
||||||
const ErrorResponse = require('../utils/ErrorResponse');
|
|
||||||
const Config = require('../models/Config');
|
|
||||||
const { Op } = require('sequelize');
|
|
||||||
const File = require('../utils/File');
|
|
||||||
const { join } = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
// @desc Insert new key:value pair
|
|
||||||
// @route POST /api/config
|
|
||||||
// @access Public
|
|
||||||
exports.createPair = asyncWrapper(async (req, res, next) => {
|
|
||||||
const pair = await Config.create(req.body);
|
|
||||||
|
|
||||||
res.status(201).json({
|
|
||||||
success: true,
|
|
||||||
data: pair,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Get all key:value pairs
|
|
||||||
// @route GET /api/config
|
|
||||||
// @route GET /api/config?keys=foo,bar,baz
|
|
||||||
// @access Public
|
|
||||||
exports.getAllPairs = asyncWrapper(async (req, res, next) => {
|
|
||||||
let pairs;
|
|
||||||
|
|
||||||
if (req.query.keys) {
|
|
||||||
// Check for specific keys to get in a single query
|
|
||||||
const keys = req.query.keys.split(',').map((key) => {
|
|
||||||
return { key };
|
|
||||||
});
|
|
||||||
|
|
||||||
pairs = await Config.findAll({
|
|
||||||
where: {
|
|
||||||
[Op.or]: keys,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Else get all
|
|
||||||
pairs = await Config.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: pairs,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Get single key:value pair
|
|
||||||
// @route GET /api/config/:key
|
|
||||||
// @access Public
|
|
||||||
exports.getSinglePair = asyncWrapper(async (req, res, next) => {
|
|
||||||
const pair = await Config.findOne({
|
|
||||||
where: { key: req.params.key },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!pair) {
|
|
||||||
return next(new ErrorResponse(`Key ${req.params.key} was not found`, 404));
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: pair,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Update value
|
|
||||||
// @route PUT /api/config/:key
|
|
||||||
// @access Public
|
|
||||||
exports.updateValue = asyncWrapper(async (req, res, next) => {
|
|
||||||
let pair = await Config.findOne({
|
|
||||||
where: { key: req.params.key },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!pair) {
|
|
||||||
return next(new ErrorResponse(`Key ${req.params.key} was not found`, 404));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pair.isLocked) {
|
|
||||||
return next(
|
|
||||||
new ErrorResponse(
|
|
||||||
`Value of key ${req.params.key} is locked and can not be changed`,
|
|
||||||
400
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pair = await pair.update({ ...req.body });
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: pair,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Update multiple values
|
|
||||||
// @route PUT /api/config/
|
|
||||||
// @access Public
|
|
||||||
exports.updateValues = asyncWrapper(async (req, res, next) => {
|
|
||||||
Object.entries(req.body).forEach(async ([key, value]) => {
|
|
||||||
await Config.update(
|
|
||||||
{ value },
|
|
||||||
{
|
|
||||||
where: { key },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const config = await Config.findAll();
|
|
||||||
|
|
||||||
res.status(200).send({
|
|
||||||
success: true,
|
|
||||||
data: config,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Delete key:value pair
|
|
||||||
// @route DELETE /api/config/:key
|
|
||||||
// @access Public
|
|
||||||
exports.deletePair = asyncWrapper(async (req, res, next) => {
|
|
||||||
const pair = await Config.findOne({
|
|
||||||
where: { key: req.params.key },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!pair) {
|
|
||||||
return next(new ErrorResponse(`Key ${req.params.key} was not found`, 404));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pair.isLocked) {
|
|
||||||
return next(
|
|
||||||
new ErrorResponse(
|
|
||||||
`Value of key ${req.params.key} is locked and can not be deleted`,
|
|
||||||
400
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await pair.destroy();
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: {},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Get custom CSS file
|
|
||||||
// @route GET /api/config/0/css
|
|
||||||
// @access Public
|
|
||||||
exports.getCss = asyncWrapper(async (req, res, next) => {
|
|
||||||
const file = new File(join(__dirname, '../public/flame.css'));
|
|
||||||
const content = file.read();
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: content,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @desc Update custom CSS file
|
|
||||||
// @route PUT /api/config/0/css
|
|
||||||
// @access Public
|
|
||||||
exports.updateCss = asyncWrapper(async (req, res, next) => {
|
|
||||||
const file = new File(join(__dirname, '../public/flame.css'));
|
|
||||||
file.write(req.body.styles, false);
|
|
||||||
|
|
||||||
// Copy file to docker volume
|
|
||||||
fs.copyFileSync(
|
|
||||||
join(__dirname, '../public/flame.css'),
|
|
||||||
join(__dirname, '../data/flame.css')
|
|
||||||
);
|
|
||||||
|
|
||||||
res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
data: {},
|
|
||||||
});
|
|
||||||
});
|
|
18
controllers/config/getCSS.js
Normal file
18
controllers/config/getCSS.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const File = require('../../utils/File');
|
||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
// @desc Get custom CSS file
|
||||||
|
// @route GET /api/config/0/css
|
||||||
|
// @access Public
|
||||||
|
const getCSS = asyncWrapper(async (req, res, next) => {
|
||||||
|
const file = new File(join(__dirname, '../../public/flame.css'));
|
||||||
|
const content = file.read();
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: content,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = getCSS;
|
16
controllers/config/getConfig.js
Normal file
16
controllers/config/getConfig.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const loadConfig = require('../../utils/loadConfig');
|
||||||
|
|
||||||
|
// @desc Get config
|
||||||
|
// @route GET /api/config
|
||||||
|
// @access Public
|
||||||
|
const getConfig = asyncWrapper(async (req, res, next) => {
|
||||||
|
const config = await loadConfig();
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: config,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = getConfig;
|
6
controllers/config/index.js
Normal file
6
controllers/config/index.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
getCSS: require('./getCSS'),
|
||||||
|
updateCSS: require('./updateCSS'),
|
||||||
|
getConfig: require('./getConfig'),
|
||||||
|
updateConfig: require('./updateConfig'),
|
||||||
|
};
|
24
controllers/config/updateCSS.js
Normal file
24
controllers/config/updateCSS.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const File = require('../../utils/File');
|
||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
// @desc Update custom CSS file
|
||||||
|
// @route PUT /api/config/0/css
|
||||||
|
// @access Public
|
||||||
|
const updateCSS = asyncWrapper(async (req, res, next) => {
|
||||||
|
const file = new File(join(__dirname, '../../public/flame.css'));
|
||||||
|
file.write(req.body.styles, false);
|
||||||
|
|
||||||
|
// Copy file to docker volume
|
||||||
|
fs.copyFileSync(
|
||||||
|
join(__dirname, '../../public/flame.css'),
|
||||||
|
join(__dirname, '../../data/flame.css')
|
||||||
|
);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = updateCSS;
|
24
controllers/config/updateConfig.js
Normal file
24
controllers/config/updateConfig.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const asyncWrapper = require('../../middleware/asyncWrapper');
|
||||||
|
const loadConfig = require('../../utils/loadConfig');
|
||||||
|
const { writeFile } = require('fs/promises');
|
||||||
|
|
||||||
|
// @desc Update config
|
||||||
|
// @route PUT /api/config/
|
||||||
|
// @access Public
|
||||||
|
const updateConfig = asyncWrapper(async (req, res, next) => {
|
||||||
|
const existingConfig = await loadConfig();
|
||||||
|
|
||||||
|
const newConfig = {
|
||||||
|
...existingConfig,
|
||||||
|
...req.body,
|
||||||
|
};
|
||||||
|
|
||||||
|
await writeFile('data/config.json', JSON.stringify(newConfig));
|
||||||
|
|
||||||
|
res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
data: newConfig,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = updateConfig;
|
|
@ -11,7 +11,7 @@ const storage = multer.diskStorage({
|
||||||
},
|
},
|
||||||
filename: (req, file, cb) => {
|
filename: (req, file, cb) => {
|
||||||
cb(null, Date.now() + '--' + file.originalname);
|
cb(null, Date.now() + '--' + file.originalname);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const supportedTypes = ['jpg', 'jpeg', 'png', 'svg', 'svg+xml'];
|
const supportedTypes = ['jpg', 'jpeg', 'png', 'svg', 'svg+xml'];
|
||||||
|
|
|
@ -4,21 +4,18 @@ const upload = require('../middleware/multer');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
createBookmark,
|
createBookmark,
|
||||||
getBookmarks,
|
getAllBookmarks,
|
||||||
getBookmark,
|
getSingleBookmark,
|
||||||
updateBookmark,
|
updateBookmark,
|
||||||
deleteBookmark
|
deleteBookmark,
|
||||||
} = require('../controllers/bookmark');
|
} = require('../controllers/bookmarks');
|
||||||
|
|
||||||
router
|
router.route('/').post(upload, createBookmark).get(getAllBookmarks);
|
||||||
.route('/')
|
|
||||||
.post(upload, createBookmark)
|
|
||||||
.get(getBookmarks);
|
|
||||||
|
|
||||||
router
|
router
|
||||||
.route('/:id')
|
.route('/:id')
|
||||||
.get(getBookmark)
|
.get(getSingleBookmark)
|
||||||
.put(upload, updateBookmark)
|
.put(upload, updateBookmark)
|
||||||
.delete(deleteBookmark);
|
.delete(deleteBookmark);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -2,20 +2,14 @@ const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
createPair,
|
getCSS,
|
||||||
getAllPairs,
|
updateCSS,
|
||||||
getSinglePair,
|
getConfig,
|
||||||
updateValue,
|
updateConfig,
|
||||||
updateValues,
|
|
||||||
deletePair,
|
|
||||||
updateCss,
|
|
||||||
getCss,
|
|
||||||
} = require('../controllers/config');
|
} = require('../controllers/config');
|
||||||
|
|
||||||
router.route('/').post(createPair).get(getAllPairs).put(updateValues);
|
router.route('/').get(getConfig).put(updateConfig);
|
||||||
|
|
||||||
router.route('/:key').get(getSinglePair).put(updateValue).delete(deletePair);
|
router.route('/0/css').get(getCSS).put(updateCSS);
|
||||||
|
|
||||||
router.route('/0/css').get(getCss).put(updateCss);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
Loading…
Reference in a new issue