• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ubccpsc / classy / c3613766-7c49-4a6d-8ad5-a549be905ad5

04 Apr 2025 02:16PM UTC coverage: 87.191% (+0.09%) from 87.102%
c3613766-7c49-4a6d-8ad5-a549be905ad5

push

circleci

web-flow
Merge pull request #478 from ubccpsc310/main

Contribute 310's 24w2 changes upstream

1101 of 1340 branches covered (82.16%)

Branch coverage included in aggregate %.

3950 of 4453 relevant lines covered (88.7%)

35.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
packages/portal/backend/src/server/BackendServer.ts
1
/**
2
 * Created by rtholmes on 2018-02-23.
3
 */
4
import * as fs from "fs";
1✔
5
import * as restify from "restify";
1✔
6

7
import Config, { ConfigKey } from "@common/Config";
1✔
8
import Log from "@common/Log";
1✔
9

10
import { Factory } from "../Factory";
1✔
11
import AdminRoutes from "./common/AdminRoutes";
1✔
12
import { AuthRoutes } from "./common/AuthRoutes";
1✔
13
import { AutoTestRoutes } from "./common/AutoTestRoutes";
1✔
14
import GeneralRoutes from "./common/GeneralRoutes";
1✔
15
import { GitHubController } from "@backend/controllers/GitHubController";
1✔
16
import { GitHubActions } from "@backend/controllers/GitHubActions";
1✔
17

18
/**
19
 * This configures the REST endpoints for the server.
20
 */
21
export default class BackendServer {
1✔
22
        private rest: restify.Server;
23
        private config: Config = null;
4✔
24
        private useHttps = false;
4✔
25

26
        constructor(useHttps = true) {
×
27
                Log.info("BackendServer::<init> - start");
4✔
28
                this.config = Config.getInstance();
4✔
29
                this.useHttps = useHttps;
4✔
30
        }
31

32
        /**
33
         * Used in tests.
34
         *
35
         * @returns {Server}
36
         */
37
        public getServer(): restify.Server {
38
                Log.trace("BackendServer::getServer()");
4✔
39
                return this.rest;
4✔
40
        }
41

42
        /**
43
         * Stops the server. Returns a promise so that we know when the connections
44
         * have actually been fully closed and the port has been released.
45
         *
46
         * @returns {Promise<boolean>}
47
         */
48
        public stop(): Promise<boolean> {
49
                Log.info("BackendServer::stop() - start");
4✔
50
                const that = this;
4✔
51
                return new Promise(function (fulfill) {
4✔
52
                        that.rest.close(function () {
4✔
53
                                Log.info("BackendServer::stop() - done");
4✔
54
                                fulfill(true);
4✔
55
                        });
56
                });
57
        }
58

59
        /**
60
         * Starts the server. Returns a promise with a boolean value. Promises are used
61
         * here because starting the server takes some time, and we want to know when it
62
         * is done (and if it worked).
63
         *
64
         * @returns {Promise<boolean>}
65
         */
66
        public start(): Promise<boolean> {
67
                Log.info("BackendServer::start() - start");
4✔
68

69
                const that = this;
4✔
70
                return new Promise(function (fulfill, reject) {
4✔
71
                        // noinspection TsLint
72
                        const httpsOptions: any = {
4✔
73
                                name: "backend",
74
                        };
75

76
                        /* istanbul ignore else */
77
                        if (that.useHttps === false) {
4✔
78
                                // test only
79
                                Log.warn("BackendServer::start() - disabling HTTPS; should only be used in testing!");
4✔
80
                        } else {
81
                                // prod only
82
                                httpsOptions["key"] = fs.readFileSync(that.config.getProp(ConfigKey.sslKeyPath));
83
                                httpsOptions["certificate"] = fs.readFileSync(that.config.getProp(ConfigKey.sslCertPath));
84
                        }
85

86
                        that.rest = restify.createServer(httpsOptions);
4✔
87
                        that.rest.use(restify.plugins.queryParser());
4✔
88
                        that.rest.use(restify.plugins.bodyParser({ mapParams: true }));
4✔
89

90
                        that.rest.use(function crossOrigin(req, res, next) {
4✔
91
                                res.header("Access-Control-Allow-Origin", "*");
133✔
92
                                res.header("Access-Control-Allow-Headers", "X-Requested-With Content-Type token user org");
133✔
93
                                return next();
133✔
94
                        });
95

96
                        // prevent caching, overrides cache headers in html files
97
                        that.rest.use(function (req, res, next) {
4✔
98
                                res.header("Last-Modified", new Date());
133✔
99
                                res.header("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0");
133✔
100
                                return next();
133✔
101
                        });
102

103
                        // Register handlers common between all classy instances
104
                        Log.info("BackendServer::start() - Registering common handlers");
4✔
105

106
                        // authentication
107
                        new AuthRoutes().registerRoutes(that.rest);
4✔
108

109
                        // autotest
110
                        new AutoTestRoutes().registerRoutes(that.rest);
4✔
111

112
                        // general
113
                        new GeneralRoutes().registerRoutes(that.rest);
4✔
114

115
                        // admin
116
                        new AdminRoutes().registerRoutes(that.rest);
4✔
117

118
                        Log.info("BackendServer::start() - Registering common handlers; done");
4✔
119

120
                        // Register custom route handler for specific classy instance
121
                        Log.info("BackendServer::start() - Registering custom handlers");
4✔
122

123
                        Log.info("BackendServer::start() - Loading custom course controller");
4✔
124
                        // We do not need a Custom Course Controller here, but this is a good place
125
                        // to make sure that the CustomCourseController loads up as expected
126
                        // alongside the CustomRouteHandler.
127
                        Factory.getCourseController(new GitHubController(GitHubActions.getInstance()))
4✔
128
                                .then(function (cc) {
129
                                        Log.info("BackendServer::start() - CustomCourseController loaded");
4✔
130
                                })
131
                                .catch(function (err) {
132
                                        Log.error("BackendServer::start() - Unable to load CustomCourseController: " + err);
×
133
                                });
134

135
                        Log.info("BackendServer::start() - Loading custom route handler");
4✔
136
                        Factory.getCustomRouteHandler()
4✔
137
                                .then(function (handler) {
138
                                        Log.info("BackendServer::start() - CustomRouteHandler loaded");
4✔
139
                                        handler.registerRoutes(that.rest);
4✔
140
                                        Log.info("BackendServer::start() - CustomRouteHandler registered");
4✔
141

142
                                        // serve up the static frontend resources
143
                                        const frontendHTML = __dirname + "/../../../frontend/html";
4✔
144
                                        Log.info("BackendServer::start() - Serving static from: " + frontendHTML);
4✔
145
                                        that.rest.get(
4✔
146
                                                "/*",
147
                                                restify.plugins.serveStatic({
148
                                                        directory: frontendHTML,
149
                                                        default: "index.html",
150
                                                })
151
                                        );
152

153
                                        const port = that.config.getProp(ConfigKey.backendPort);
4✔
154
                                        that.rest.listen(port, function () {
4✔
155
                                                Log.info("BackendServer::start() - restify listening: " + that.rest.url + "; on port: " + port);
4✔
156

157
                                                // after the Classy backend is up, check AutoTest
158
                                                // (Docker should load AutoTest first, but the delay should not hurt)
159
                                                setTimeout(() => {
4✔
160
                                                        AutoTestRoutes.checkATStatus()
3✔
161
                                                                .then(function (_result) {
162
                                                                        Log.trace("BackendServer::start() - AT status: success");
×
163
                                                                })
164
                                                                .catch(function (err) {
165
                                                                        Log.trace("BackendServer::start() - AT status: failure; ERROR: " + err.message);
3✔
166
                                                                });
167
                                                }, 500);
168

169
                                                fulfill(true);
4✔
170
                                        });
171

172
                                        /* istanbul ignore next */
173
                                        that.rest.on("error", function (err: string) {
174
                                                // catches errors in restify start; unusual syntax due to internal node not using normal exceptions here
175
                                                Log.error("BackendServer::start() - restify ERROR: " + err);
176
                                                reject(err);
177
                                        });
178
                                })
179
                                .catch(function (err) {
180
                                        Log.error("BackendServer::start() - Registering custom ERROR: " + err);
×
181
                                });
182
                });
183
        }
184
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc