♻️ oo-connector: refactored router system to something more coherent (#525)
This commit is contained in:
@@ -5,24 +5,25 @@ import cors from 'cors';
|
|||||||
import { renderFile } from 'eta';
|
import { renderFile } from 'eta';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import errorMiddleware from './middlewares/error.middleware';
|
import errorMiddleware from './middlewares/error.middleware';
|
||||||
import { SERVER_PORT, SERVER_PREFIX } from '@config';
|
import { SERVER_PORT } from '@config';
|
||||||
import logger from './lib/logger';
|
import logger from './lib/logger';
|
||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
import apiService from './services/api.service';
|
import apiService from './services/api.service';
|
||||||
import onlyofficeService from './services/onlyoffice.service';
|
import onlyofficeService from './services/onlyoffice.service';
|
||||||
|
import { makeURLTo, mountRoutes } from './routes';
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
public app: express.Application;
|
public app: express.Application;
|
||||||
public env: string;
|
public env: string;
|
||||||
public port: string | number;
|
public port: string | number;
|
||||||
|
|
||||||
constructor(routes: Routes[]) {
|
constructor() {
|
||||||
this.app = express();
|
this.app = express();
|
||||||
this.env = NODE_ENV;
|
this.env = NODE_ENV;
|
||||||
|
|
||||||
this.initViews();
|
this.initViews();
|
||||||
this.initMiddlewares();
|
this.initMiddlewares();
|
||||||
this.initRoutes(routes);
|
this.initRoutes();
|
||||||
this.initErrorHandling();
|
this.initErrorHandling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,15 +35,13 @@ class App {
|
|||||||
|
|
||||||
public getServer = () => this.app;
|
public getServer = () => this.app;
|
||||||
|
|
||||||
private initRoutes = (routes: Routes[]) => {
|
private initRoutes = () => {
|
||||||
this.app.use((req, res, next) => {
|
this.app.use((req, res, next) => {
|
||||||
logger.info(`Received request: ${req.method} ${req.originalUrl} from ${req.header('user-agent')} (${req.ip})`);
|
logger.info(`Received request: ${req.method} ${req.originalUrl} from ${req.header('user-agent')} (${req.ip})`);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
routes.forEach(route => {
|
mountRoutes(this.app);
|
||||||
this.app.use(route.path ?? '/', route.router);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.get('/health', (_req, res) => {
|
this.app.get('/health', (_req, res) => {
|
||||||
Promise.all([onlyofficeService.getLatestLicence(), apiService.hasToken(), onlyofficeService.getForgottenList()]).then(
|
Promise.all([onlyofficeService.getLatestLicence(), apiService.hasToken(), onlyofficeService.getForgottenList()]).then(
|
||||||
@@ -58,7 +57,7 @@ class App {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.app.use(
|
this.app.use(
|
||||||
SERVER_PREFIX.replace(/\/$/, '') + '/assets',
|
makeURLTo.assets(),
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
|
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ export const {
|
|||||||
export const twakeDriveTokenRefrehPeriodMS = 10 * 60 * 1000;
|
export const twakeDriveTokenRefrehPeriodMS = 10 * 60 * 1000;
|
||||||
export const onlyOfficeForgottenFilesCheckPeriodMS = 10 * 60 * 1000;
|
export const onlyOfficeForgottenFilesCheckPeriodMS = 10 * 60 * 1000;
|
||||||
export const onlyOfficeConnectivityCheckPeriodMS = 10 * 60 * 1000;
|
export const onlyOfficeConnectivityCheckPeriodMS = 10 * 60 * 1000;
|
||||||
|
|
||||||
|
export const SERVER_TDRIVE_API_PREFIX = '/tdriveApi/1';
|
||||||
|
|||||||
+6
-7
@@ -1,13 +1,13 @@
|
|||||||
import editorService from '@/services/editor.service';
|
import editorService from '@/services/editor.service';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import { CREDENTIALS_SECRET, SERVER_ORIGIN, SERVER_PREFIX } from '@config';
|
import { CREDENTIALS_SECRET } from '@config';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import driveService from '@/services/drive.service';
|
import driveService from '@/services/drive.service';
|
||||||
import { DriveFileType } from '@/interfaces/drive.interface';
|
import { DriveFileType } from '@/interfaces/drive.interface';
|
||||||
import fileService from '@/services/file.service';
|
import fileService from '@/services/file.service';
|
||||||
import { OfficeToken } from '@/interfaces/routes.interface';
|
import { OfficeToken } from '@/interfaces/routes.interface';
|
||||||
import logger from '@/lib/logger';
|
import logger from '@/lib/logger';
|
||||||
import * as Utils from '@/utils';
|
import { makeURLTo } from '@/routes';
|
||||||
|
|
||||||
interface RequestQuery {
|
interface RequestQuery {
|
||||||
mode: string;
|
mode: string;
|
||||||
@@ -29,7 +29,7 @@ interface RequestEditorQuery {
|
|||||||
* The user is redirected from there to open directly the OnlyOffice edition server's web UI, with appropriate preview or not
|
* The user is redirected from there to open directly the OnlyOffice edition server's web UI, with appropriate preview or not
|
||||||
* and rights checks.
|
* and rights checks.
|
||||||
*/
|
*/
|
||||||
class IndexController {
|
class BrowserEditorController {
|
||||||
/**
|
/**
|
||||||
* Opened by the user's browser, proxied through the Twake Drive backend. Checks access to the
|
* Opened by the user's browser, proxied through the Twake Drive backend. Checks access to the
|
||||||
* file with the backend, then redirects the user to the `editor` method but directly on this
|
* file with the backend, then redirects the user to the `editor` method but directly on this
|
||||||
@@ -98,9 +98,8 @@ class IndexController {
|
|||||||
expiresIn: 60 * 60 * 24 * 30,
|
expiresIn: 60 * 60 * 24 * 30,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
res.redirect(
|
res.redirect(
|
||||||
Utils.joinURL([SERVER_ORIGIN ?? '', SERVER_PREFIX, 'editor'], {
|
makeURLTo.editorAbsolute({
|
||||||
token,
|
token,
|
||||||
file_id,
|
file_id,
|
||||||
editing_session_key: editingSessionKey,
|
editing_session_key: editingSessionKey,
|
||||||
@@ -145,7 +144,7 @@ class IndexController {
|
|||||||
res.render('index', {
|
res.render('index', {
|
||||||
...initResponse,
|
...initResponse,
|
||||||
docId: preview ? file_id : editing_session_key,
|
docId: preview ? file_id : editing_session_key,
|
||||||
server: Utils.joinURL([SERVER_ORIGIN, SERVER_PREFIX]),
|
server: makeURLTo.rootAbsolute(),
|
||||||
token: inPageToken,
|
token: inPageToken,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -155,4 +154,4 @@ class IndexController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IndexController;
|
export default BrowserEditorController;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import logger from '@/lib/logger';
|
import logger from '@/lib/logger';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import * as Utils from '@/utils';
|
import { makeURLTo } from '@/routes';
|
||||||
import { SERVER_ORIGIN, SERVER_PREFIX } from '@config';
|
|
||||||
|
|
||||||
export default (error: Error & { status?: number }, req: Request, res: Response, next: NextFunction): void => {
|
export default (error: Error & { status?: number }, req: Request, res: Response, next: NextFunction): void => {
|
||||||
try {
|
try {
|
||||||
@@ -12,7 +11,7 @@ export default (error: Error & { status?: number }, req: Request, res: Response,
|
|||||||
|
|
||||||
res.status(status);
|
res.status(status);
|
||||||
res.render('error', {
|
res.render('error', {
|
||||||
server: Utils.joinURL([SERVER_ORIGIN, SERVER_PREFIX]),
|
server: makeURLTo.rootAbsolute(),
|
||||||
errorMessage: message,
|
errorMessage: message,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import TwakeDriveBackendCallbackController from '@/controllers/backend-callbacks.controller';
|
import TwakeDriveBackendCallbackController from '@/controllers/backend-callbacks.controller';
|
||||||
import { Routes } from '@/interfaces/routes.interface';
|
|
||||||
import authMiddleware from '@/middlewares/auth.middleware';
|
import authMiddleware from '@/middlewares/auth.middleware';
|
||||||
import { Router } from 'express';
|
import type { Router } from 'express';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These routes are called by Twake Drive backend, for ex. before editing or retreiving a file,
|
* These routes are called by Twake Drive backend, for ex. before editing or retreiving a file,
|
||||||
* if it has an editing_session_key still, get the status of that and force a resolution.
|
* if it has an editing_session_key still, get the status of that and force a resolution.
|
||||||
*/
|
*/
|
||||||
export default class TwakeDriveBackendCallbackRoutes implements Routes {
|
export const TwakeDriveBackendCallbackRoutes = {
|
||||||
public readonly router = Router();
|
mount(router: Router) {
|
||||||
public readonly path = '/tdriveApi/1';
|
const controller = new TwakeDriveBackendCallbackController();
|
||||||
private readonly controller: TwakeDriveBackendCallbackController;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.controller = new TwakeDriveBackendCallbackController();
|
|
||||||
// Why post ? to garantee it is never cached and always ran
|
// Why post ? to garantee it is never cached and always ran
|
||||||
this.router.post('/session/:editing_session_key/check', authMiddleware, this.controller.checkSessionStatus);
|
router.post('/session/:editing_session_key/check', authMiddleware, controller.checkSessionStatus);
|
||||||
this.router.delete('/session/:editing_session_key', authMiddleware, this.controller.deleteSessionKey);
|
router.delete('/session/:editing_session_key', authMiddleware, controller.deleteSessionKey);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import BrowserEditorController from '@/controllers/browser-editor.controller';
|
||||||
|
import authMiddleware from '@/middlewares/auth.middleware';
|
||||||
|
import requirementsMiddleware from '@/middlewares/requirements.middleware';
|
||||||
|
import type { Router } from 'express';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the user previews or edits a file in Twake Drive, their browser is sent to these routes
|
||||||
|
* which return a webpage that instantiates the client side JS Only Office component.
|
||||||
|
*/
|
||||||
|
export const BrowserEditorRoutes = {
|
||||||
|
mount(router: Router) {
|
||||||
|
const controller = new BrowserEditorController();
|
||||||
|
router.get('/', requirementsMiddleware, authMiddleware, controller.index);
|
||||||
|
router.get('/editor', requirementsMiddleware, authMiddleware, controller.editor);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import IndexController from '@/controllers/index.controller';
|
|
||||||
import { Routes } from '@/interfaces/routes.interface';
|
|
||||||
import authMiddleware from '@/middlewares/auth.middleware';
|
|
||||||
import requirementsMiddleware from '@/middlewares/requirements.middleware';
|
|
||||||
import { Router } from 'express';
|
|
||||||
import { SERVER_PREFIX } from '@config';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the user previews or edits a file in Twake Drive, their browser is sent to these routes
|
|
||||||
* which return a webpage that instantiates the client side JS Only Office component.
|
|
||||||
*/
|
|
||||||
class IndexRoute implements Routes {
|
|
||||||
public path = SERVER_PREFIX;
|
|
||||||
public router = Router();
|
|
||||||
public indexController: IndexController;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.indexController = new IndexController();
|
|
||||||
this.initRoutes();
|
|
||||||
}
|
|
||||||
|
|
||||||
private initRoutes = () => {
|
|
||||||
this.router.get('/', requirementsMiddleware, authMiddleware, this.indexController.index);
|
|
||||||
this.router.get('/editor', requirementsMiddleware, authMiddleware, this.indexController.editor);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IndexRoute;
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Application, Router } from 'express';
|
||||||
|
|
||||||
|
import * as Utils from '@/utils';
|
||||||
|
|
||||||
|
import { TwakeDriveBackendCallbackRoutes } from './backend-callbacks.route';
|
||||||
|
import { BrowserEditorRoutes } from './browser-editor.route';
|
||||||
|
import { OnlyOfficeRoutes } from './onlyoffice.route';
|
||||||
|
|
||||||
|
import { SERVER_ORIGIN, SERVER_PREFIX, SERVER_TDRIVE_API_PREFIX } from '@config';
|
||||||
|
|
||||||
|
export function mountRoutes(app: Application) {
|
||||||
|
// These routes are forwarded through the Twake Drive front, back and here
|
||||||
|
const proxiedRouter = Router();
|
||||||
|
BrowserEditorRoutes.mount(proxiedRouter);
|
||||||
|
OnlyOfficeRoutes.mount(proxiedRouter);
|
||||||
|
console.log('Mounting at ' + SERVER_PREFIX);
|
||||||
|
app.use(SERVER_PREFIX, proxiedRouter);
|
||||||
|
|
||||||
|
// These endpoints should only be accessible to the Twake Drive backend
|
||||||
|
const apiRouter = Router();
|
||||||
|
console.log('Mounting at ' + SERVER_TDRIVE_API_PREFIX);
|
||||||
|
TwakeDriveBackendCallbackRoutes.mount(apiRouter);
|
||||||
|
app.use(SERVER_TDRIVE_API_PREFIX, apiRouter);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeURLTo = {
|
||||||
|
rootAbsolute: () => Utils.joinURL([SERVER_ORIGIN, SERVER_PREFIX]),
|
||||||
|
assets: () => Utils.joinURL([SERVER_PREFIX, 'assets']),
|
||||||
|
editorAbsolute(params: { token: string; file_id: string; editing_session_key: string; company_id: string; preview: string; office_token: string }) {
|
||||||
|
return Utils.joinURL([SERVER_ORIGIN ?? '', SERVER_PREFIX, 'editor'], params);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// export function makeURLToEditor2() {
|
||||||
|
// const initResponse = await editorService.init(company_id, file_name, file_id, user, preview, drive_file_id || file_id);
|
||||||
|
|
||||||
|
// res.render('index', {
|
||||||
|
// ...initResponse,
|
||||||
|
// docId: preview ? file_id : editing_session_key,
|
||||||
|
// server: Utils.joinURL([SERVER_ORIGIN, SERVER_PREFIX]),
|
||||||
|
// token: inPageToken,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
@@ -1,23 +1,15 @@
|
|||||||
import OnlyOfficeController from '@/controllers/onlyoffice.controller';
|
import OnlyOfficeController from '@/controllers/onlyoffice.controller';
|
||||||
import { Routes } from '@/interfaces/routes.interface';
|
|
||||||
import requirementsMiddleware from '@/middlewares/requirements.middleware';
|
import requirementsMiddleware from '@/middlewares/requirements.middleware';
|
||||||
import { Router } from 'express';
|
import type { Router } from 'express';
|
||||||
import { SERVER_PREFIX } from '@config';
|
|
||||||
|
|
||||||
class OnlyOfficeRoute implements Routes {
|
/**
|
||||||
public path = SERVER_PREFIX;
|
* These routes are called by the Only Office server
|
||||||
public router = Router();
|
* when reading a document or updating an editing session
|
||||||
public onlyOfficeController: OnlyOfficeController;
|
*/
|
||||||
|
export const OnlyOfficeRoutes = {
|
||||||
constructor() {
|
mount(router: Router) {
|
||||||
this.onlyOfficeController = new OnlyOfficeController();
|
const controller = new OnlyOfficeController();
|
||||||
this.initRoutes();
|
router.get(`/:mode/read`, requirementsMiddleware, controller.read);
|
||||||
}
|
router.post(`/:mode/callback`, requirementsMiddleware, controller.ooCallback);
|
||||||
|
},
|
||||||
private initRoutes = () => {
|
|
||||||
this.router.get(`:mode/read`, requirementsMiddleware, this.onlyOfficeController.read);
|
|
||||||
this.router.post(`:mode/callback`, requirementsMiddleware, this.onlyOfficeController.ooCallback);
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default OnlyOfficeRoute;
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import App from '@/app';
|
import App from '@/app';
|
||||||
import IndexRoute from './routes/index.route';
|
|
||||||
import OnlyOfficeRoute from './routes/onlyoffice.route';
|
|
||||||
import TwakeDriveBackendCallbacksRoutes from './routes/backend-callbacks.route';
|
|
||||||
|
|
||||||
const app = new App([new IndexRoute(), new OnlyOfficeRoute(), new TwakeDriveBackendCallbacksRoutes()]);
|
const app = new App();
|
||||||
|
|
||||||
app.listen();
|
app.listen();
|
||||||
|
|||||||
Reference in New Issue
Block a user