diff --git a/client/src/App.tsx b/client/src/App.tsx
index 6a066b2..23acef2 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -2,19 +2,30 @@ import { Fragment, useContext, useEffect } from 'react';
import { Switch, Route } from 'react-router-dom';
import { Navbar } from './components/Navigation/Navbar';
import { Editor, Home, Snippet, Snippets, Auth, Profile } from './containers';
-import { ProtectedRoute } from './utils';
-import { AuthContext } from './store';
+import { decodeToken, ProtectedRoute } from './utils';
+import { AuthContext, SnippetsContext } from './store';
export const App = () => {
- const { autoLogin } = useContext(AuthContext);
+ const { autoLogin, logout } = useContext(AuthContext);
+ const { getSnippets, countTags } = useContext(SnippetsContext);
useEffect(() => {
- // autoLogin();
- // const checker = setInterval(() => {
- // autoLogin();
- // console.log('cake');
- // }, 1000);
- // return () => window.clearInterval(checker);
+ autoLogin();
+
+ getSnippets();
+ countTags();
+
+ const checkTokenValidity = setInterval(() => {
+ if (localStorage.token) {
+ const { exp: expiresAt } = decodeToken(localStorage.token);
+
+ if (Date.now() > expiresAt * 1000) {
+ logout();
+ }
+ }
+ }, 1000);
+
+ return () => window.clearInterval(checkTokenValidity);
}, []);
return (
diff --git a/client/src/containers/Auth.tsx b/client/src/containers/Auth.tsx
index 2a7a78a..d437994 100644
--- a/client/src/containers/Auth.tsx
+++ b/client/src/containers/Auth.tsx
@@ -1,5 +1,5 @@
import { useContext, useEffect } from 'react';
-import { useHistory } from 'react-router';
+import { useHistory, useLocation } from 'react-router';
import { AuthContext } from '../store';
import { AuthForm } from '../components/Auth';
import { Card, Layout } from '../components/UI';
@@ -8,9 +8,13 @@ export const Auth = (): JSX.Element => {
const { isAuthenticated } = useContext(AuthContext);
const history = useHistory();
+ // Get previous location
+ const location = useLocation<{ from: string }>();
+ const { from } = location.state || '/';
+
useEffect(() => {
if (isAuthenticated) {
- history.push('/');
+ history.push(from);
}
}, [isAuthenticated]);
diff --git a/client/src/utils/ProtectedRoute.tsx b/client/src/utils/ProtectedRoute.tsx
index 54a5d13..caaafd6 100644
--- a/client/src/utils/ProtectedRoute.tsx
+++ b/client/src/utils/ProtectedRoute.tsx
@@ -10,6 +10,13 @@ export const ProtectedRoute = ({ ...rest }: RouteProps) => {
if (isAuthenticated) {
return ;
} else {
- return ;
+ return (
+
+ );
}
};
diff --git a/client/src/utils/authErrorHandler.ts b/client/src/utils/authErrorHandler.ts
new file mode 100644
index 0000000..68fbfa6
--- /dev/null
+++ b/client/src/utils/authErrorHandler.ts
@@ -0,0 +1,20 @@
+import { errorHandler } from '.';
+import { UserWithRole } from '../typescript/interfaces';
+
+interface Params {
+ err: any;
+ setIsAuthenticated: (v: React.SetStateAction) => void;
+ setUser: (v: React.SetStateAction) => void;
+}
+
+export const authErrorHandler = (params: Params) => {
+ const { err, setUser, setIsAuthenticated } = params;
+
+ errorHandler(err);
+
+ localStorage.removeItem('token');
+
+ setUser(null);
+
+ setIsAuthenticated(false);
+};
diff --git a/client/src/utils/errorHandler.ts b/client/src/utils/errorHandler.ts
index 98a1159..f102fad 100644
--- a/client/src/utils/errorHandler.ts
+++ b/client/src/utils/errorHandler.ts
@@ -11,5 +11,7 @@ export const errorHandler = (err: any) => {
msg = 'Something went wrong';
}
+ // todo: emit notification
+ // redirect on error
console.log(msg);
};
diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts
index 9327a09..c64769d 100644
--- a/client/src/utils/index.ts
+++ b/client/src/utils/index.ts
@@ -3,4 +3,6 @@ export * from './badgeColor';
export * from './findLanguage';
export * from './searchParser';
export * from './ProtectedRoute';
+export * from './authErrorHandler';
export * from './errorHandler';
+export * from './decodeToken';
diff --git a/docker-compose.yml b/docker-compose.yml
index fd3c750..74d9e30 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,4 +7,6 @@ services:
- /path/to/host/data:/app/data
ports:
- 5000:5000
+ environment:
+ - NODE_ENV: production
restart: unless-stopped
diff --git a/list.md b/list.md
new file mode 100644
index 0000000..aeb01a9
--- /dev/null
+++ b/list.md
@@ -0,0 +1,13 @@
+**Implemented**
+
+- [x] Login / logout / register
+- [x] Auto login (token valid 14 days)
+- [x] Roles (admin, user)
+
+**Planned features**
+
+- [ ] Guest access (read and search access to snippets marked as public)
+- [ ] Generate token for raw snippet access
+- [ ] Admin panel (right now admin and users share the same view)
+
+By default, admin account is created with login `admin@local.com` and password `snippet-admin`. If there are any snippets in the database, they will be assigned to the admin as the owner.
diff --git a/src/middleware/errorHandler.ts b/src/middleware/errorHandler.ts
index bdc7591..4cfedfc 100644
--- a/src/middleware/errorHandler.ts
+++ b/src/middleware/errorHandler.ts
@@ -11,6 +11,20 @@ export const errorHandler = (
) => {
logger.log(err.message, 'ERROR');
+ if (process.env.NODE_ENV == 'development') {
+ console.log(err);
+ }
+
+ const error = {
+ ...err
+ };
+
+ if (err.message == 'Validation error') {
+ // @ts-ignore
+ error.message = err.errors[0].message;
+ error.statusCode = 400;
+ }
+
res.status(err.statusCode || 500).json({
error: err.message || 'Internal Server Error'
});
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 5a404b8..0d2cd26 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -7,3 +7,4 @@ export * from './createAdmin';
export * from './hashPassword';
export * from './signToken';
export * from './createAdmin';
+export * from './resourceExists';
diff --git a/src/utils/resourceExists.ts b/src/utils/resourceExists.ts
new file mode 100644
index 0000000..4bfaf6e
--- /dev/null
+++ b/src/utils/resourceExists.ts
@@ -0,0 +1,17 @@
+import { NextFunction } from 'express';
+import { ErrorResponse } from '.';
+
+export const resourceExists = (
+ resource: any,
+ name: string,
+ id: number,
+ next: NextFunction
+) => {
+ if (!resource) {
+ return next(
+ new ErrorResponse(404, `${name} with the id of ${id} was not found`)
+ );
+ }
+
+ return;
+};