Repository: compiler-explorer/compiler-explorer
Pull request #7131 (2024-11-27 06:19:26)

Add controller for site templates
Equivalent of #7130 for site templates


Patch:
diff --git a/app.ts b/app.ts
index d466b6a17..d8923c376 100755
--- a/app.ts
+++ b/app.ts
@@ -57,6 +57,7 @@ import {startWineInit} from './lib/exec.js';
 import {RemoteExecutionQuery} from './lib/execution/execution-query.js';
 import {initHostSpecialties} from './lib/execution/execution-triple.js';
 import {startExecutionWorkerThread} from './lib/execution/sqs-execution-queue.js';
+import {SiteTemplateController} from './lib/handlers/api/site-template-controller.js';
 import {SourceController} from './lib/handlers/api/source-controller.js';
 import {CompileHandler} from './lib/handlers/compile.js';
 import * as healthCheck from './lib/handlers/health-check.js';
@@ -557,6 +558,8 @@ async function main() {
     const sourceHandler = new SourceController(sources);
     const compilerFinder = new CompilerFinder(compileHandler, compilerProps, awsProps, defArgs, clientOptionsHandler);
 
+    const siteTemplateController = new SiteTemplateController();
+
     logger.info('=======================================');
     if (gitReleaseName) logger.info(`  git release ${gitReleaseName}`);
     if (releaseBuildNumber) logger.info(`  release build ${releaseBuildNumber}`);
@@ -869,6 +872,7 @@ async function main() {
         .use(bodyParser.json({limit: ceProps('bodyParserLimit', maxUploadSize)}))
         .use('/source/:source/list', sourceHandler.listEntries.bind(sourceHandler))
         .use('/source/:source/load/:language/:filename', sourceHandler.loadEntry.bind(sourceHandler))
+        .get('/api/siteTemplates', siteTemplateController.getSiteTemplates.bind(siteTemplateController))
         .get('/g/:id', oldGoogleUrlHandler)
         // Deprecated old route for this -- TODO remove in late 2021
         .post('/shortener', routeApi.apiHandler.shortener.handle.bind(routeApi.apiHandler.shortener));
diff --git a/lib/handlers/api.ts b/lib/handlers/api.ts
index a90b3a228..735eefc55 100644
--- a/lib/handlers/api.ts
+++ b/lib/handlers/api.ts
@@ -44,7 +44,6 @@ import {StorageBase} from '../storage/index.js';
 import {withAssemblyDocumentationProviders} from './assembly-documentation.js';
 import {CompileHandler} from './compile.js';
 import {FormattingHandler} from './formatting.js';
-import {getSiteTemplates} from './site-templates.js';
 
 function methodNotAllowed(req: express.Request, res: express.Response) {
     res.send('Method Not Allowed');
@@ -139,13 +138,6 @@ export class ApiHandler {
                 res.send(all);
             })
             .all(methodNotAllowed);
-        this.handle
-            .route('/siteTemplates')
-            .get(async (req, res) => {
-                res.send(await getSiteTemplates());
-            })
-            .all(methodNotAllowed);
-
         this.handle.route('/shortlinkinfo/:id').get(this.shortlinkInfoHandler.bind(this)).all(methodNotAllowed);
 
         const shortenerType = getShortenerTypeByKey(urlShortenService);
diff --git a/lib/handlers/api/site-template-controller.ts b/lib/handlers/api/site-template-controller.ts
new file mode 100644
index 000000000..6f49a9732
--- /dev/null
+++ b/lib/handlers/api/site-template-controller.ts
@@ -0,0 +1,34 @@
+// Copyright (c) 2024, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import express from 'express';
+
+import {getSiteTemplates} from '../site-templates.js';
+
+export class SiteTemplateController {
+    public async getSiteTemplates(req: express.Request, res: express.Response) {
+        const templates = await getSiteTemplates();
+        res.send(templates);
+    }
+}


Test patch:
diff --git a/test/handlers/api-tests.ts b/test/handlers/api-tests.ts
index e809a25f6..92194b165 100644
--- a/test/handlers/api-tests.ts
+++ b/test/handlers/api-tests.ts
@@ -183,7 +183,4 @@ describe('API handling', () => {
             .expect(422, {exit: 3, answer: "Style 'bad-base' is not supported"})
             .expect('Content-Type', /json/);
     });
-    it('should respond to plain site template requests', async () => {
-        await request(app).get('/api/siteTemplates').expect(200).expect('Content-Type', /json/);
-    });
 });
diff --git a/test/handlers/site-templates-tests.ts b/test/handlers/site-templates-tests.ts
index e9d0fa112..aca4dc2ef 100644
--- a/test/handlers/site-templates-tests.ts
+++ b/test/handlers/site-templates-tests.ts
@@ -1,12 +1,26 @@
-import {describe, expect, it} from 'vitest';
+import express from 'express';
+import request from 'supertest';
+import {beforeAll, describe, expect, it} from 'vitest';
 
+import {SiteTemplateController} from '../../lib/handlers/api/site-template-controller.js';
 import {getSiteTemplates} from '../../lib/handlers/site-templates.js';
 
 describe('Site Templates Backend', () => {
+    let app: express.Express;
+    beforeAll(() => {
+        app = express();
+        const controller = new SiteTemplateController();
+        app.use('/api/siteTemplates', controller.getSiteTemplates.bind(controller));
+    });
+
     it('should load site templates properly', async () => {
         const templates = await getSiteTemplates();
         // not super comprehensive
         expect(templates.meta).toHaveProperty('meta.screenshot_dimensions');
         expect(Object.entries(templates.templates).length).toBeTruthy();
     });
+
+    it('should respond to plain site template requests', async () => {
+        await request(app).get('/api/siteTemplates').expect(200).expect('Content-Type', /json/);
+    });
 });