diff --git a/.gitignore b/.gitignore
index c0feab5..0ec7d59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -133,4 +133,5 @@ dist/
.yarn/install-state.gz
.pnp.*
-.DS_Store
\ No newline at end of file
+.DS_Store
+/generated/prisma
diff --git a/Aragon-Kanban-API.postman_collection.json b/Aragon-Kanban-API.postman_collection.json
new file mode 100644
index 0000000..4dbd899
--- /dev/null
+++ b/Aragon-Kanban-API.postman_collection.json
@@ -0,0 +1,142 @@
+{
+ "info": {
+ "name": "Aragon Kanban API",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "description": "Postman collection for Users, Boards, and Tasks API"
+ },
+ "item": [
+ {
+ "name": "Users",
+ "item": [
+ {
+ "name": "Get All Users",
+ "request": {
+ "method": "GET",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] }
+ }
+ },
+ {
+ "name": "Add User",
+ "request": {
+ "method": "POST",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"user\": {\n \"id\": 1,\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n}" },
+ "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] }
+ }
+ },
+ {
+ "name": "Update User",
+ "request": {
+ "method": "PUT",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"user\": {\n \"id\": 1,\n \"name\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n }\n}" },
+ "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] }
+ }
+ },
+ {
+ "name": "Delete User",
+ "request": {
+ "method": "DELETE",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/users/1", "host": ["{{baseUrl}}"], "path": ["users", "1"] }
+ }
+ }
+ ]
+ },
+ {
+ "name": "Boards",
+ "item": [
+ {
+ "name": "Get All Boards for User",
+ "request": {
+ "method": "GET",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/boards/user/1", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1"] }
+ }
+ },
+ {
+ "name": "Get Board by ID",
+ "request": {
+ "method": "GET",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] }
+ }
+ },
+ {
+ "name": "Add Board",
+ "request": {
+ "method": "POST",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"name\": \"Project Board\"\n}" },
+ "url": { "raw": "{{baseUrl}}/boards/user/1", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1"] }
+ }
+ },
+ {
+ "name": "Update Board",
+ "request": {
+ "method": "PUT",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"name\": \"Updated Board Name\"\n}" },
+ "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] }
+ }
+ },
+ {
+ "name": "Delete Board",
+ "request": {
+ "method": "DELETE",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] }
+ }
+ }
+ ]
+ },
+ {
+ "name": "Tasks",
+ "item": [
+ {
+ "name": "Get All Tasks for Board",
+ "request": {
+ "method": "GET",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/tasks/board/123", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123"] }
+ }
+ },
+ {
+ "name": "Get Task by ID",
+ "request": {
+ "method": "GET",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] }
+ }
+ },
+ {
+ "name": "Add Task",
+ "request": {
+ "method": "POST",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"title\": \"New Task\",\n \"description\": \"Task details\",\n \"status\": \"todo\"\n}" },
+ "url": { "raw": "{{baseUrl}}/tasks/board/123", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123"] }
+ }
+ },
+ {
+ "name": "Update Task",
+ "request": {
+ "method": "PUT",
+ "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}],
+ "body": { "mode": "raw", "raw": "{\n \"title\": \"Updated Task\",\n \"description\": \"Updated details\",\n \"status\": \"done\"\n}" },
+ "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] }
+ }
+ },
+ {
+ "name": "Delete Task",
+ "request": {
+ "method": "DELETE",
+ "header": [{"key": "Authorization", "value": "Bearer testtoken"}],
+ "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/lib/constants/EnvVars.js b/lib/constants/EnvVars.js
new file mode 100644
index 0000000..cbaa257
--- /dev/null
+++ b/lib/constants/EnvVars.js
@@ -0,0 +1,29 @@
+"use strict";
+/**
+ * Environments variables declared here.
+ */
+var _a, _b, _c, _d, _e, _f, _g;
+Object.defineProperty(exports, "__esModule", { value: true });
+/* eslint-disable node/no-process-env */
+exports.default = {
+ NodeEnv: ((_a = process.env.NODE_ENV) !== null && _a !== void 0 ? _a : ''),
+ Port: ((_b = process.env.PORT) !== null && _b !== void 0 ? _b : 0),
+ CookieProps: {
+ Key: 'ExpressGeneratorTs',
+ Secret: ((_c = process.env.COOKIE_SECRET) !== null && _c !== void 0 ? _c : ''),
+ // Casing to match express cookie options
+ Options: {
+ httpOnly: true,
+ signed: true,
+ path: ((_d = process.env.COOKIE_PATH) !== null && _d !== void 0 ? _d : ''),
+ maxAge: Number((_e = process.env.COOKIE_EXP) !== null && _e !== void 0 ? _e : 0),
+ domain: ((_f = process.env.COOKIE_DOMAIN) !== null && _f !== void 0 ? _f : ''),
+ secure: (process.env.SECURE_COOKIE === 'true'),
+ },
+ },
+ Jwt: {
+ Secret: ((_g = process.env.JWT_SECRET) !== null && _g !== void 0 ? _g : ''),
+ Exp: (process.env.COOKIE_EXP && process.env.COOKIE_EXP !== '' ? process.env.COOKIE_EXP : '1h'), // exp at the same time as the cookie
+ },
+};
+//# sourceMappingURL=EnvVars.js.map
\ No newline at end of file
diff --git a/lib/constants/EnvVars.js.map b/lib/constants/EnvVars.js.map
new file mode 100644
index 0000000..1a2395d
--- /dev/null
+++ b/lib/constants/EnvVars.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"EnvVars.js","sourceRoot":"","sources":["../../src/constants/EnvVars.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,wCAAwC;AAGxC,kBAAe;IACb,OAAO,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,QAAQ,mCAAI,EAAE,CAAC;IACrC,IAAI,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,IAAI,mCAAI,CAAC,CAAC;IAC7B,WAAW,EAAE;QACX,GAAG,EAAE,oBAAoB;QACzB,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,aAAa,mCAAI,EAAE,CAAC;QACzC,yCAAyC;QACzC,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,WAAW,mCAAI,EAAE,CAAC;YACrC,MAAM,EAAE,MAAM,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,UAAU,mCAAI,CAAC,CAAC;YAC3C,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,aAAa,mCAAI,EAAE,CAAC;YACzC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,MAAM,CAAC;SAC/C;KACF;IACD,GAAG,EAAE;QACH,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,UAAU,mCAAK,EAAE,CAAC;QACvC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,qCAAqC;KACtI;CACO,CAAC"}
\ No newline at end of file
diff --git a/lib/constants/HttpStatusCodes.js b/lib/constants/HttpStatusCodes.js
new file mode 100644
index 0000000..96b253b
--- /dev/null
+++ b/lib/constants/HttpStatusCodes.js
@@ -0,0 +1,327 @@
+"use strict";
+/* eslint-disable max-len */
+/**
+ * This file was copied from here: https://gist.github.com/scokmen/f813c904ef79022e84ab2409574d1b45
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * Hypertext Transfer Protocol (HTTP) response status codes.
+ * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}
+ */
+var HttpStatusCodes;
+(function (HttpStatusCodes) {
+ /**
+ * The server has received the request headers and the client should proceed to send the request body
+ * (in the case of a request for which a body needs to be sent; for example, a POST request).
+ * Sending a large request body to a server after a request has been rejected for inappropriate headers would be inefficient.
+ * To have a server check the request's headers, a client must send Expect: 100-continue as a header in its initial request
+ * and receive a 100 Continue status code in response before sending the body. The response 417 Expectation Failed indicates the request should not be continued.
+ */
+ HttpStatusCodes[HttpStatusCodes["CONTINUE"] = 100] = "CONTINUE";
+ /**
+ * The requester has asked the server to switch protocols and the server has agreed to do so.
+ */
+ HttpStatusCodes[HttpStatusCodes["SWITCHING_PROTOCOLS"] = 101] = "SWITCHING_PROTOCOLS";
+ /**
+ * A WebDAV request may contain many sub-requests involving file operations, requiring a long time to complete the request.
+ * This code indicates that the server has received and is processing the request, but no response is available yet.
+ * This prevents the client from timing out and assuming the request was lost.
+ */
+ HttpStatusCodes[HttpStatusCodes["PROCESSING"] = 102] = "PROCESSING";
+ /**
+ * Standard response for successful HTTP requests.
+ * The actual response will depend on the request method used.
+ * In a GET request, the response will contain an entity corresponding to the requested resource.
+ * In a POST request, the response will contain an entity describing or containing the result of the action.
+ */
+ HttpStatusCodes[HttpStatusCodes["OK"] = 200] = "OK";
+ /**
+ * The request has been fulfilled, resulting in the creation of a new resource.
+ */
+ HttpStatusCodes[HttpStatusCodes["CREATED"] = 201] = "CREATED";
+ /**
+ * The request has been accepted for processing, but the processing has not been completed.
+ * The request might or might not be eventually acted upon, and may be disallowed when processing occurs.
+ */
+ HttpStatusCodes[HttpStatusCodes["ACCEPTED"] = 202] = "ACCEPTED";
+ /**
+ * SINCE HTTP/1.1
+ * The server is a transforming proxy that received a 200 OK from its origin,
+ * but is returning a modified version of the origin's response.
+ */
+ HttpStatusCodes[HttpStatusCodes["NON_AUTHORITATIVE_INFORMATION"] = 203] = "NON_AUTHORITATIVE_INFORMATION";
+ /**
+ * The server successfully processed the request and is not returning any content.
+ */
+ HttpStatusCodes[HttpStatusCodes["NO_CONTENT"] = 204] = "NO_CONTENT";
+ /**
+ * The server successfully processed the request, but is not returning any content.
+ * Unlike a 204 response, this response requires that the requester reset the document view.
+ */
+ HttpStatusCodes[HttpStatusCodes["RESET_CONTENT"] = 205] = "RESET_CONTENT";
+ /**
+ * The server is delivering only part of the resource (byte serving) due to a range header sent by the client.
+ * The range header is used by HTTP clients to enable resuming of interrupted downloads,
+ * or split a download into multiple simultaneous streams.
+ */
+ HttpStatusCodes[HttpStatusCodes["PARTIAL_CONTENT"] = 206] = "PARTIAL_CONTENT";
+ /**
+ * The message body that follows is an XML message and can contain a number of separate response codes,
+ * depending on how many sub-requests were made.
+ */
+ HttpStatusCodes[HttpStatusCodes["MULTI_STATUS"] = 207] = "MULTI_STATUS";
+ /**
+ * The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response,
+ * and are not being included again.
+ */
+ HttpStatusCodes[HttpStatusCodes["ALREADY_REPORTED"] = 208] = "ALREADY_REPORTED";
+ /**
+ * The server has fulfilled a request for the resource,
+ * and the response is a representation of the result of one or more instance-manipulations applied to the current instance.
+ */
+ HttpStatusCodes[HttpStatusCodes["IM_USED"] = 226] = "IM_USED";
+ /**
+ * Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation).
+ * For example, this code could be used to present multiple video format options,
+ * to list files with different filename extensions, or to suggest word-sense disambiguation.
+ */
+ HttpStatusCodes[HttpStatusCodes["MULTIPLE_CHOICES"] = 300] = "MULTIPLE_CHOICES";
+ /**
+ * This and all future requests should be directed to the given URI.
+ */
+ HttpStatusCodes[HttpStatusCodes["MOVED_PERMANENTLY"] = 301] = "MOVED_PERMANENTLY";
+ /**
+ * This is an example of industry practice contradicting the standard.
+ * The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect
+ * (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302
+ * with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307
+ * to distinguish between the two behaviours. However, some Web applications and frameworks
+ * use the 302 status code as if it were the 303.
+ */
+ HttpStatusCodes[HttpStatusCodes["FOUND"] = 302] = "FOUND";
+ /**
+ * SINCE HTTP/1.1
+ * The response to the request can be found under another URI using a GET method.
+ * When received in response to a POST (or PUT/DELETE), the client should presume that
+ * the server has received the data and should issue a redirect with a separate GET message.
+ */
+ HttpStatusCodes[HttpStatusCodes["SEE_OTHER"] = 303] = "SEE_OTHER";
+ /**
+ * Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match.
+ * In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy.
+ */
+ HttpStatusCodes[HttpStatusCodes["NOT_MODIFIED"] = 304] = "NOT_MODIFIED";
+ /**
+ * SINCE HTTP/1.1
+ * The requested resource is available only through a proxy, the address for which is provided in the response.
+ * Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons.
+ */
+ HttpStatusCodes[HttpStatusCodes["USE_PROXY"] = 305] = "USE_PROXY";
+ /**
+ * No longer used. Originally meant "Subsequent requests should use the specified proxy."
+ */
+ HttpStatusCodes[HttpStatusCodes["SWITCH_PROXY"] = 306] = "SWITCH_PROXY";
+ /**
+ * SINCE HTTP/1.1
+ * In this case, the request should be repeated with another URI; however, future requests should still use the original URI.
+ * In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request.
+ * For example, a POST request should be repeated using another POST request.
+ */
+ HttpStatusCodes[HttpStatusCodes["TEMPORARY_REDIRECT"] = 307] = "TEMPORARY_REDIRECT";
+ /**
+ * The request and all future requests should be repeated using another URI.
+ * 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change.
+ * So, for example, submitting a form to a permanently redirected resource may continue smoothly.
+ */
+ HttpStatusCodes[HttpStatusCodes["PERMANENT_REDIRECT"] = 308] = "PERMANENT_REDIRECT";
+ /**
+ * The server cannot or will not process the request due to an apparent client error
+ * (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing).
+ */
+ HttpStatusCodes[HttpStatusCodes["BAD_REQUEST"] = 400] = "BAD_REQUEST";
+ /**
+ * Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet
+ * been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the
+ * requested resource. See Basic access authentication and Digest access authentication. 401 semantically means
+ * "unauthenticated",i.e. the user does not have the necessary credentials.
+ */
+ HttpStatusCodes[HttpStatusCodes["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
+ /**
+ * Reserved for future use. The original intention was that this code might be used as part of some form of digital
+ * cash or micro payment scheme, but that has not happened, and this code is not usually used.
+ * Google Developers API uses this status if a particular developer has exceeded the daily limit on requests.
+ */
+ HttpStatusCodes[HttpStatusCodes["PAYMENT_REQUIRED"] = 402] = "PAYMENT_REQUIRED";
+ /**
+ * The request was valid, but the server is refusing action.
+ * The user might not have the necessary permissions for a resource.
+ */
+ HttpStatusCodes[HttpStatusCodes["FORBIDDEN"] = 403] = "FORBIDDEN";
+ /**
+ * The requested resource could not be found but may be available in the future.
+ * Subsequent requests by the client are permissible.
+ */
+ HttpStatusCodes[HttpStatusCodes["NOT_FOUND"] = 404] = "NOT_FOUND";
+ /**
+ * A request method is not supported for the requested resource;
+ * for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource.
+ */
+ HttpStatusCodes[HttpStatusCodes["METHOD_NOT_ALLOWED"] = 405] = "METHOD_NOT_ALLOWED";
+ /**
+ * The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request.
+ */
+ HttpStatusCodes[HttpStatusCodes["NOT_ACCEPTABLE"] = 406] = "NOT_ACCEPTABLE";
+ /**
+ * The client must first authenticate itself with the proxy.
+ */
+ HttpStatusCodes[HttpStatusCodes["PROXY_AUTHENTICATION_REQUIRED"] = 407] = "PROXY_AUTHENTICATION_REQUIRED";
+ /**
+ * The server timed out waiting for the request.
+ * According to HTTP specifications:
+ * "The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time."
+ */
+ HttpStatusCodes[HttpStatusCodes["REQUEST_TIMEOUT"] = 408] = "REQUEST_TIMEOUT";
+ /**
+ * Indicates that the request could not be processed because of conflict in the request,
+ * such as an edit conflict between multiple simultaneous updates.
+ */
+ HttpStatusCodes[HttpStatusCodes["CONFLICT"] = 409] = "CONFLICT";
+ /**
+ * Indicates that the resource requested is no longer available and will not be available again.
+ * This should be used when a resource has been intentionally removed and the resource should be purged.
+ * Upon receiving a 410 status code, the client should not request the resource in the future.
+ * Clients such as search engines should remove the resource from their indices.
+ * Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead.
+ */
+ HttpStatusCodes[HttpStatusCodes["GONE"] = 410] = "GONE";
+ /**
+ * The request did not specify the length of its content, which is required by the requested resource.
+ */
+ HttpStatusCodes[HttpStatusCodes["LENGTH_REQUIRED"] = 411] = "LENGTH_REQUIRED";
+ /**
+ * The server does not meet one of the preconditions that the requester put on the request.
+ */
+ HttpStatusCodes[HttpStatusCodes["PRECONDITION_FAILED"] = 412] = "PRECONDITION_FAILED";
+ /**
+ * The request is larger than the server is willing or able to process. Previously called "Request Entity Too Large".
+ */
+ HttpStatusCodes[HttpStatusCodes["PAYLOAD_TOO_LARGE"] = 413] = "PAYLOAD_TOO_LARGE";
+ /**
+ * The URI provided was too long for the server to process. Often the result of too much data being encoded as a query-string of a GET request,
+ * in which case it should be converted to a POST request.
+ * Called "Request-URI Too Long" previously.
+ */
+ HttpStatusCodes[HttpStatusCodes["URI_TOO_LONG"] = 414] = "URI_TOO_LONG";
+ /**
+ * The request entity has a media type which the server or resource does not support.
+ * For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format.
+ */
+ HttpStatusCodes[HttpStatusCodes["UNSUPPORTED_MEDIA_TYPE"] = 415] = "UNSUPPORTED_MEDIA_TYPE";
+ /**
+ * The client has asked for a portion of the file (byte serving), but the server cannot supply that portion.
+ * For example, if the client asked for a part of the file that lies beyond the end of the file.
+ * Called "Requested Range Not Satisfiable" previously.
+ */
+ HttpStatusCodes[HttpStatusCodes["RANGE_NOT_SATISFIABLE"] = 416] = "RANGE_NOT_SATISFIABLE";
+ /**
+ * The server cannot meet the requirements of the Expect request-header field.
+ */
+ HttpStatusCodes[HttpStatusCodes["EXPECTATION_FAILED"] = 417] = "EXPECTATION_FAILED";
+ /**
+ * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol,
+ * and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by
+ * teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including Google.com.
+ */
+ HttpStatusCodes[HttpStatusCodes["I_AM_A_TEAPOT"] = 418] = "I_AM_A_TEAPOT";
+ /**
+ * The request was directed at a server that is not able to produce a response (for example because a connection reuse).
+ */
+ HttpStatusCodes[HttpStatusCodes["MISDIRECTED_REQUEST"] = 421] = "MISDIRECTED_REQUEST";
+ /**
+ * The request was well-formed but was unable to be followed due to semantic errors.
+ */
+ HttpStatusCodes[HttpStatusCodes["UNPROCESSABLE_ENTITY"] = 422] = "UNPROCESSABLE_ENTITY";
+ /**
+ * The resource that is being accessed is locked.
+ */
+ HttpStatusCodes[HttpStatusCodes["LOCKED"] = 423] = "LOCKED";
+ /**
+ * The request failed due to failure of a previous request (e.g., a PROPPATCH).
+ */
+ HttpStatusCodes[HttpStatusCodes["FAILED_DEPENDENCY"] = 424] = "FAILED_DEPENDENCY";
+ /**
+ * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field.
+ */
+ HttpStatusCodes[HttpStatusCodes["UPGRADE_REQUIRED"] = 426] = "UPGRADE_REQUIRED";
+ /**
+ * The origin server requires the request to be conditional.
+ * Intended to prevent "the 'lost update' problem, where a client
+ * GETs a resource's state, modifies it, and PUTs it back to the server,
+ * when meanwhile a third party has modified the state on the server, leading to a conflict."
+ */
+ HttpStatusCodes[HttpStatusCodes["PRECONDITION_REQUIRED"] = 428] = "PRECONDITION_REQUIRED";
+ /**
+ * The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes.
+ */
+ HttpStatusCodes[HttpStatusCodes["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS";
+ /**
+ * The server is unwilling to process the request because either an individual header field,
+ * or all the header fields collectively, are too large.
+ */
+ HttpStatusCodes[HttpStatusCodes["REQUEST_HEADER_FIELDS_TOO_LARGE"] = 431] = "REQUEST_HEADER_FIELDS_TOO_LARGE";
+ /**
+ * A server operator has received a legal demand to deny access to a resource or to a set of resources
+ * that includes the requested resource. The code 451 was chosen as a reference to the novel Fahrenheit 451.
+ */
+ HttpStatusCodes[HttpStatusCodes["UNAVAILABLE_FOR_LEGAL_REASONS"] = 451] = "UNAVAILABLE_FOR_LEGAL_REASONS";
+ /**
+ * A generic error message, given when an unexpected condition was encountered and no more specific message is suitable.
+ */
+ HttpStatusCodes[HttpStatusCodes["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
+ /**
+ * The server either does not recognize the request method, or it lacks the ability to fulfill the request.
+ * Usually this implies future availability (e.g., a new feature of a web-service API).
+ */
+ HttpStatusCodes[HttpStatusCodes["NOT_IMPLEMENTED"] = 501] = "NOT_IMPLEMENTED";
+ /**
+ * The server was acting as a gateway or proxy and received an invalid response from the upstream server.
+ */
+ HttpStatusCodes[HttpStatusCodes["BAD_GATEWAY"] = 502] = "BAD_GATEWAY";
+ /**
+ * The server is currently unavailable (because it is overloaded or down for maintenance).
+ * Generally, this is a temporary state.
+ */
+ HttpStatusCodes[HttpStatusCodes["SERVICE_UNAVAILABLE"] = 503] = "SERVICE_UNAVAILABLE";
+ /**
+ * The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.
+ */
+ HttpStatusCodes[HttpStatusCodes["GATEWAY_TIMEOUT"] = 504] = "GATEWAY_TIMEOUT";
+ /**
+ * The server does not support the HTTP protocol version used in the request
+ */
+ HttpStatusCodes[HttpStatusCodes["HTTP_VERSION_NOT_SUPPORTED"] = 505] = "HTTP_VERSION_NOT_SUPPORTED";
+ /**
+ * Transparent content negotiation for the request results in a circular reference.
+ */
+ HttpStatusCodes[HttpStatusCodes["VARIANT_ALSO_NEGOTIATES"] = 506] = "VARIANT_ALSO_NEGOTIATES";
+ /**
+ * The server is unable to store the representation needed to complete the request.
+ */
+ HttpStatusCodes[HttpStatusCodes["INSUFFICIENT_STORAGE"] = 507] = "INSUFFICIENT_STORAGE";
+ /**
+ * The server detected an infinite loop while processing the request.
+ */
+ HttpStatusCodes[HttpStatusCodes["LOOP_DETECTED"] = 508] = "LOOP_DETECTED";
+ /**
+ * Further extensions to the request are required for the server to fulfill it.
+ */
+ HttpStatusCodes[HttpStatusCodes["NOT_EXTENDED"] = 510] = "NOT_EXTENDED";
+ /**
+ * The client needs to authenticate to gain network access.
+ * Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used
+ * to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot).
+ */
+ HttpStatusCodes[HttpStatusCodes["NETWORK_AUTHENTICATION_REQUIRED"] = 511] = "NETWORK_AUTHENTICATION_REQUIRED";
+})(HttpStatusCodes || (HttpStatusCodes = {}));
+exports.default = HttpStatusCodes;
+//# sourceMappingURL=HttpStatusCodes.js.map
\ No newline at end of file
diff --git a/lib/constants/HttpStatusCodes.js.map b/lib/constants/HttpStatusCodes.js.map
new file mode 100644
index 0000000..9901b6f
--- /dev/null
+++ b/lib/constants/HttpStatusCodes.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"HttpStatusCodes.js","sourceRoot":"","sources":["../../src/constants/HttpStatusCodes.ts"],"names":[],"mappings":";AAAA,4BAA4B;AAC5B;;GAEG;;AAEH;;;GAGG;AACH,IAAK,eAsXJ;AAtXD,WAAK,eAAe;IAEhB;;;;;;OAMG;IACH,+DAAc,CAAA;IAEd;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;;;OAIG;IACH,mEAAgB,CAAA;IAEhB;;;;;OAKG;IACH,mDAAQ,CAAA;IAER;;OAEG;IACH,6DAAa,CAAA;IAEb;;;OAGG;IACH,+DAAc,CAAA;IAEd;;;;OAIG;IACH,yGAAmC,CAAA;IAEnC;;OAEG;IACH,mEAAgB,CAAA;IAEhB;;;OAGG;IACH,yEAAmB,CAAA;IAEnB;;;;OAIG;IACH,6EAAqB,CAAA;IAErB;;;OAGG;IACH,uEAAkB,CAAA;IAElB;;;OAGG;IACH,+EAAsB,CAAA;IAEtB;;;OAGG;IACH,6DAAa,CAAA;IAEb;;;;OAIG;IACH,+EAAsB,CAAA;IAEtB;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;;;;;OAOG;IACH,yDAAW,CAAA;IAEX;;;;;OAKG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,iEAAe,CAAA;IAEf;;OAEG;IACH,uEAAkB,CAAA;IAElB;;;;;OAKG;IACH,mFAAwB,CAAA;IAExB;;;;OAIG;IACH,mFAAwB,CAAA;IAExB;;;OAGG;IACH,qEAAiB,CAAA;IAEjB;;;;;OAKG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,+EAAsB,CAAA;IAEtB;;;OAGG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,mFAAwB,CAAA;IAExB;;OAEG;IACH,2EAAoB,CAAA;IAEpB;;OAEG;IACH,yGAAmC,CAAA;IAEnC;;;;OAIG;IACH,6EAAqB,CAAA;IAErB;;;OAGG;IACH,+DAAc,CAAA;IAEd;;;;;;OAMG;IACH,uDAAU,CAAA;IAEV;;OAEG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;;OAIG;IACH,uEAAkB,CAAA;IAElB;;;OAGG;IACH,2FAA4B,CAAA;IAE5B;;;;OAIG;IACH,yFAA2B,CAAA;IAE3B;;OAEG;IACH,mFAAwB,CAAA;IAExB;;;;OAIG;IACH,yEAAmB,CAAA;IAEnB;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,uFAA0B,CAAA;IAE1B;;OAEG;IACH,2DAAY,CAAA;IAEZ;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;OAEG;IACH,+EAAsB,CAAA;IAEtB;;;;;OAKG;IACH,yFAA2B,CAAA;IAE3B;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;OAGG;IACH,6GAAqC,CAAA;IAErC;;;OAGG;IACH,yGAAmC,CAAA;IAEnC;;OAEG;IACH,yFAA2B,CAAA;IAE3B;;;OAGG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,qEAAiB,CAAA;IAEjB;;;OAGG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,mGAAgC,CAAA;IAEhC;;OAEG;IACH,6FAA6B,CAAA;IAE7B;;OAEG;IACH,uFAA0B,CAAA;IAE1B;;OAEG;IACH,yEAAmB,CAAA;IAEnB;;OAEG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,6GAAqC,CAAA;AACzC,CAAC,EAtXI,eAAe,KAAf,eAAe,QAsXnB;AAED,kBAAe,eAAe,CAAC"}
\ No newline at end of file
diff --git a/lib/constants/misc.js b/lib/constants/misc.js
new file mode 100644
index 0000000..6f6641d
--- /dev/null
+++ b/lib/constants/misc.js
@@ -0,0 +1,10 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.NodeEnvs = void 0;
+var NodeEnvs;
+(function (NodeEnvs) {
+ NodeEnvs["Dev"] = "development";
+ NodeEnvs["Test"] = "test";
+ NodeEnvs["Production"] = "production";
+})(NodeEnvs || (exports.NodeEnvs = NodeEnvs = {}));
+//# sourceMappingURL=misc.js.map
\ No newline at end of file
diff --git a/lib/constants/misc.js.map b/lib/constants/misc.js.map
new file mode 100644
index 0000000..5e06715
--- /dev/null
+++ b/lib/constants/misc.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../src/constants/misc.ts"],"names":[],"mappings":";;;AAAA,IAAY,QAIX;AAJD,WAAY,QAAQ;IAClB,+BAAmB,CAAA;IACnB,yBAAa,CAAA;IACb,qCAAyB,CAAA;AAC3B,CAAC,EAJW,QAAQ,wBAAR,QAAQ,QAInB"}
\ No newline at end of file
diff --git a/lib/controllers/board.controller.js b/lib/controllers/board.controller.js
new file mode 100644
index 0000000..1919d4c
--- /dev/null
+++ b/lib/controllers/board.controller.js
@@ -0,0 +1,62 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const board_repo_1 = __importDefault(require("@src/repos/board.repo"));
+class BoardController {
+ constructor() {
+ // Get all boards for a user
+ this.getBoardsByUserId = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const userId = +req.params.userId;
+ const boards = await board_repo_1.default.getBoardsByUserId(userId);
+ return res.json({ boards });
+ };
+ // Get single board by userId and boardId
+ this.getBoardByUserId = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const userId = +req.params.userId;
+ const boardId = +req.params.boardId;
+ const board = await board_repo_1.default.getBoardByUserId(userId, boardId);
+ return res.json({ board });
+ };
+ // Create board for a user
+ this.createBoard = async (req, res) => {
+ if (!req.body.name) {
+ return res.status(400).json({ error: 'Board name required' });
+ }
+ const userId = +req.params.userId;
+ const boardData = req.body;
+ const board = await board_repo_1.default.createBoard(userId, boardData);
+ return res.status(201).json({ board });
+ };
+ // Update board for a user
+ this.updateBoard = async (req, res) => {
+ if (!req.body.name) {
+ return res.status(400).json({ error: 'Board name required' });
+ }
+ const userId = +req.params.userId;
+ const boardId = +req.params.boardId;
+ const boardData = req.body;
+ const board = await board_repo_1.default.updateBoard(userId, boardId, boardData);
+ return res.json({ board });
+ };
+ // Delete board for a user
+ this.deleteBoard = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const userId = +req.params.userId;
+ const boardId = +req.params.boardId;
+ await board_repo_1.default.deleteBoard(userId, boardId);
+ return res.status(204).end();
+ };
+ }
+}
+exports.default = new BoardController();
+//# sourceMappingURL=board.controller.js.map
\ No newline at end of file
diff --git a/lib/controllers/board.controller.js.map b/lib/controllers/board.controller.js.map
new file mode 100644
index 0000000..7a6c90f
--- /dev/null
+++ b/lib/controllers/board.controller.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"board.controller.js","sourceRoot":"","sources":["../../src/controllers/board.controller.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/lib/controllers/task.controller.js b/lib/controllers/task.controller.js
new file mode 100644
index 0000000..6370561
--- /dev/null
+++ b/lib/controllers/task.controller.js
@@ -0,0 +1,64 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const task_repo_1 = __importDefault(require("@src/repos/task.repo"));
+class TaskController {
+ constructor() {
+ // Get all tasks for a board
+ this.getTasksByBoardId = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const boardId = +req.params.boardId;
+ const tasks = await task_repo_1.default.getTasksByBoardId(boardId);
+ return res.json({ tasks });
+ };
+ // Get single task by boardId and taskId
+ this.getTaskByBoardId = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const boardId = +req.params.boardId;
+ const taskId = +req.params.taskId;
+ const task = await task_repo_1.default.getTaskByBoardId(boardId, taskId);
+ return res.json({ task });
+ };
+ // Create task for a board
+ this.createTask = async (req, res) => {
+ // Dummy form validation
+ if (!req.body.title) {
+ return res.status(400).json({ error: 'Task title required' });
+ }
+ const boardId = +req.params.boardId;
+ const taskData = req.body;
+ const task = await task_repo_1.default.createTask(boardId, taskData);
+ return res.status(201).json({ task });
+ };
+ // Update task for a board
+ this.updateTask = async (req, res) => {
+ // Dummy form validation
+ if (!req.body.title) {
+ return res.status(400).json({ error: 'Task title required' });
+ }
+ const boardId = +req.params.boardId;
+ const taskId = +req.params.taskId;
+ const taskData = req.body;
+ const task = await task_repo_1.default.updateTask(boardId, taskId, taskData);
+ return res.json({ task });
+ };
+ // Delete task for a board
+ this.deleteTask = async (req, res) => {
+ if (!req.headers.authorization) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+ const boardId = +req.params.boardId;
+ const taskId = +req.params.taskId;
+ await task_repo_1.default.deleteTask(boardId, taskId);
+ return res.status(204).end();
+ };
+ }
+}
+exports.default = new TaskController();
+//# sourceMappingURL=task.controller.js.map
\ No newline at end of file
diff --git a/lib/controllers/task.controller.js.map b/lib/controllers/task.controller.js.map
new file mode 100644
index 0000000..d5097fb
--- /dev/null
+++ b/lib/controllers/task.controller.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"task.controller.js","sourceRoot":"","sources":["../../src/controllers/task.controller.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/lib/controllers/user.controller.js b/lib/controllers/user.controller.js
new file mode 100644
index 0000000..751ac1d
--- /dev/null
+++ b/lib/controllers/user.controller.js
@@ -0,0 +1,31 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const user_repo_1 = __importDefault(require("@src/repos/user.repo"));
+class UserController {
+ constructor() {
+ this.getAll = async (_, res) => {
+ const users = await user_repo_1.default.getAll();
+ return res.status(200).json({ users });
+ };
+ this.add = async (req, res) => {
+ const user = req.body.user;
+ await user_repo_1.default.add(user);
+ return res.status(201).end();
+ };
+ this.update = async (req, res) => {
+ const user = req.body.user;
+ await user_repo_1.default.update(user);
+ return res.status(200).end();
+ };
+ this.delete = async (req, res) => {
+ const id = +req.params.id;
+ await user_repo_1.default.delete(id);
+ return res.status(200).end();
+ };
+ }
+}
+exports.default = new UserController();
+//# sourceMappingURL=user.controller.js.map
\ No newline at end of file
diff --git a/lib/controllers/user.controller.js.map b/lib/controllers/user.controller.js.map
new file mode 100644
index 0000000..d2585d7
--- /dev/null
+++ b/lib/controllers/user.controller.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"user.controller.js","sourceRoot":"","sources":["../../src/controllers/user.controller.ts"],"names":[],"mappings":";;;;;AACA,qEAA4C;AAG5C,MAAM,cAAc;IAApB;QACS,WAAM,GAAG,KAAK,EAAE,CAAU,EAAE,GAAa,EAAE,EAAE;YAClD,MAAM,KAAK,GAAG,MAAM,mBAAQ,CAAC,MAAM,EAAE,CAAC;YACtC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC;QAEK,QAAG,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACjD,MAAM,IAAI,GAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,mBAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEK,WAAM,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACpD,MAAM,IAAI,GAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,mBAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEK,WAAM,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACpD,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,mBAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,IAAI,cAAc,EAAE,CAAC"}
\ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 0000000..f399426
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,14 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+require("./pre-start"); // Must be the first import
+const jet_logger_1 = __importDefault(require("jet-logger"));
+const EnvVars_1 = __importDefault(require("@src/constants/EnvVars"));
+const server_1 = __importDefault(require("./server"));
+// **** Run **** //
+const SERVER_START_MSG = ('Express server started on port: ' +
+ EnvVars_1.default.Port.toString());
+server_1.default.listen(EnvVars_1.default.Port, () => jet_logger_1.default.info(SERVER_START_MSG));
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/lib/index.js.map b/lib/index.js.map
new file mode 100644
index 0000000..9562a51
--- /dev/null
+++ b/lib/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,uBAAqB,CAAC,2BAA2B;AACjD,4DAAgC;AAEhC,qEAA6C;AAC7C,sDAA8B;AAG9B,mBAAmB;AAEnB,MAAM,gBAAgB,GAAG,CAAC,kCAAkC;IAC1D,iBAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE3B,gBAAM,CAAC,MAAM,CAAC,iBAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,oBAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC"}
\ No newline at end of file
diff --git a/lib/models/board.model.js b/lib/models/board.model.js
new file mode 100644
index 0000000..12e0238
--- /dev/null
+++ b/lib/models/board.model.js
@@ -0,0 +1,48 @@
+"use strict";
+// **** Variables **** //
+Object.defineProperty(exports, "__esModule", { value: true });
+const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must be a string or an object with the appropriate board keys.';
+// **** Functions **** //
+/**
+ * Create new Board.
+ */
+function new_(userId, name, description, createdAt, updatedAt, id) {
+ const now = new Date().toISOString();
+ return {
+ id: (id !== null && id !== void 0 ? id : -1),
+ userId: (userId !== null && userId !== void 0 ? userId : -1),
+ name: (name !== null && name !== void 0 ? name : ''),
+ description,
+ createdAt: (createdAt !== null && createdAt !== void 0 ? createdAt : now),
+ updatedAt: (updatedAt !== null && updatedAt !== void 0 ? updatedAt : now),
+ };
+}
+/**
+ * Get board instance from object.
+ */
+function from(param) {
+ if (!isBoard(param)) {
+ throw new Error(INVALID_CONSTRUCTOR_PARAM);
+ }
+ const p = param;
+ return new_(p.userId, p.name, p.description, p.createdAt, p.updatedAt, p.id);
+}
+/**
+ * See if the param meets criteria to be a board.
+ */
+function isBoard(arg) {
+ return (!!arg &&
+ typeof arg === 'object' &&
+ 'id' in arg &&
+ 'userId' in arg &&
+ 'name' in arg &&
+ 'createdAt' in arg &&
+ 'updatedAt' in arg);
+}
+// **** Export default **** //
+exports.default = {
+ new: new_,
+ from,
+ isBoard,
+};
+//# sourceMappingURL=board.model.js.map
\ No newline at end of file
diff --git a/lib/models/board.model.js.map b/lib/models/board.model.js.map
new file mode 100644
index 0000000..057e59f
--- /dev/null
+++ b/lib/models/board.model.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"board.model.js","sourceRoot":"","sources":["../../src/models/board.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;AAEzB,MAAM,yBAAyB,GAAG,8EAA8E,CAAC;AAajH,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACZ,MAAe,EACf,IAAa,EACb,WAAoB,EACpB,SAAkB,EAClB,SAAkB,EAClB,EAAW;IAEX,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACN,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,MAAM,EAAE,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC;QAClB,WAAW;QACX,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;QAC7B,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;KAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,GAAG,KAAe,CAAC;IAC1B,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,GAAY;IAC5B,OAAO,CACN,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,QAAQ,IAAI,GAAG;QACf,MAAM,IAAI,GAAG;QACb,WAAW,IAAI,GAAG;QAClB,WAAW,IAAI,GAAG,CAClB,CAAC;AACH,CAAC;AAED,8BAA8B;AAE9B,kBAAe;IACd,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,OAAO;CACE,CAAC"}
\ No newline at end of file
diff --git a/lib/models/task.model.js b/lib/models/task.model.js
new file mode 100644
index 0000000..a2d31bd
--- /dev/null
+++ b/lib/models/task.model.js
@@ -0,0 +1,50 @@
+"use strict";
+// **** Variables **** //
+Object.defineProperty(exports, "__esModule", { value: true });
+const INVALID_CONSTRUCTOR_PARAM = 'titleOrObj arg must be a string or an object with the appropriate task keys.';
+// **** Functions **** //
+/**
+ * Create new Task.
+ */
+function new_(boardId, title, status, description, createdAt, updatedAt, id) {
+ const now = new Date().toISOString();
+ return {
+ id: (id !== null && id !== void 0 ? id : -1),
+ boardId: (boardId !== null && boardId !== void 0 ? boardId : -1),
+ title: (title !== null && title !== void 0 ? title : ''),
+ status: (status !== null && status !== void 0 ? status : 'todo'),
+ description,
+ createdAt: (createdAt !== null && createdAt !== void 0 ? createdAt : now),
+ updatedAt: (updatedAt !== null && updatedAt !== void 0 ? updatedAt : now),
+ };
+}
+/**
+ * Get task instance from object.
+ */
+function from(param) {
+ if (!isTask(param)) {
+ throw new Error(INVALID_CONSTRUCTOR_PARAM);
+ }
+ const p = param;
+ return new_(p.boardId, p.title, p.status, p.description, p.createdAt, p.updatedAt, p.id);
+}
+/**
+ * See if the param meets criteria to be a task.
+ */
+function isTask(arg) {
+ return (!!arg &&
+ typeof arg === 'object' &&
+ 'id' in arg &&
+ 'boardId' in arg &&
+ 'title' in arg &&
+ 'status' in arg &&
+ 'createdAt' in arg &&
+ 'updatedAt' in arg);
+}
+// **** Export default **** //
+exports.default = {
+ new: new_,
+ from,
+ isTask,
+};
+//# sourceMappingURL=task.model.js.map
\ No newline at end of file
diff --git a/lib/models/task.model.js.map b/lib/models/task.model.js.map
new file mode 100644
index 0000000..6bb99d4
--- /dev/null
+++ b/lib/models/task.model.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"task.model.js","sourceRoot":"","sources":["../../src/models/task.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;AAEzB,MAAM,yBAAyB,GAAG,8EAA8E,CAAC;AAcjH,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACZ,OAAgB,EAChB,KAAc,EACd,MAAwC,EACxC,WAAoB,EACpB,SAAkB,EAClB,SAAkB,EAClB,EAAW;IAEX,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACN,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,OAAO,EAAE,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,CAAC,CAAC,CAAC;QACxB,KAAK,EAAE,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC;QACpB,MAAM,EAAE,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,MAAM,CAAC;QAC1B,WAAW;QACX,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;QAC7B,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;KAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,GAAG,KAAc,CAAC;IACzB,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,GAAY;IAC3B,OAAO,CACN,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,SAAS,IAAI,GAAG;QAChB,OAAO,IAAI,GAAG;QACd,QAAQ,IAAI,GAAG;QACf,WAAW,IAAI,GAAG;QAClB,WAAW,IAAI,GAAG,CAClB,CAAC;AACH,CAAC;AAED,8BAA8B;AAE9B,kBAAe;IACd,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,MAAM;CACG,CAAC"}
\ No newline at end of file
diff --git a/lib/models/user.model.js b/lib/models/user.model.js
new file mode 100644
index 0000000..c4b977d
--- /dev/null
+++ b/lib/models/user.model.js
@@ -0,0 +1,54 @@
+"use strict";
+// **** Variables **** //
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.UserRoles = void 0;
+const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must a string or an ' +
+ 'object with the appropriate user keys.';
+var UserRoles;
+(function (UserRoles) {
+ UserRoles[UserRoles["Standard"] = 0] = "Standard";
+ UserRoles[UserRoles["Admin"] = 1] = "Admin";
+})(UserRoles || (exports.UserRoles = UserRoles = {}));
+// **** Functions **** //
+/**
+ * Create new User.
+ */
+function new_(name, email, role, pwdHash, id) {
+ return {
+ id: (id !== null && id !== void 0 ? id : -1),
+ name: (name !== null && name !== void 0 ? name : ''),
+ email: (email !== null && email !== void 0 ? email : ''),
+ role: (role !== null && role !== void 0 ? role : UserRoles.Standard),
+ pwdHash: (pwdHash !== null && pwdHash !== void 0 ? pwdHash : ''),
+ };
+}
+/**
+ * Get user instance from object.
+ */
+function from(param) {
+ // Check is user
+ if (!isUser(param)) {
+ throw new Error(INVALID_CONSTRUCTOR_PARAM);
+ }
+ // Get user instance
+ const p = param;
+ return new_(p.name, p.email, p.role, p.pwdHash, p.id);
+}
+/**
+ * See if the param meets criteria to be a user.
+ */
+function isUser(arg) {
+ return (!!arg &&
+ typeof arg === 'object' &&
+ 'id' in arg &&
+ 'email' in arg &&
+ 'name' in arg &&
+ 'role' in arg);
+}
+// **** Export default **** //
+exports.default = {
+ new: new_,
+ from,
+ isUser,
+};
+//# sourceMappingURL=user.model.js.map
\ No newline at end of file
diff --git a/lib/models/user.model.js.map b/lib/models/user.model.js.map
new file mode 100644
index 0000000..e57bffe
--- /dev/null
+++ b/lib/models/user.model.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"user.model.js","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;;AAEzB,MAAM,yBAAyB,GAAG,oCAAoC;IACpE,wCAAwC,CAAC;AAE3C,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,iDAAQ,CAAA;IACR,2CAAK,CAAA;AACP,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB;AAqBD,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACX,IAAa,EACb,KAAc,EACd,IAAgB,EAChB,OAAgB,EAChB,EAAW;IAEX,OAAO;QACL,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC;QAClB,KAAK,EAAE,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC;QACpB,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,SAAS,CAAC,QAAQ,CAAC;QAClC,OAAO,EAAE,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC;KACzB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IACzB,gBAAgB;IAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,oBAAoB;IACpB,MAAM,CAAC,GAAG,KAAc,CAAC;IACzB,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO,CACL,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,OAAO,IAAI,GAAG;QACd,MAAM,IAAI,GAAG;QACb,MAAM,IAAI,GAAG,CACd,CAAC;AACJ,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,MAAM;CACE,CAAC"}
\ No newline at end of file
diff --git a/lib/other/classes.js b/lib/other/classes.js
new file mode 100644
index 0000000..adca176
--- /dev/null
+++ b/lib/other/classes.js
@@ -0,0 +1,17 @@
+"use strict";
+/**
+ * Miscellaneous shared classes go here.
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.RouteError = void 0;
+/**
+ * Error with status code and message
+ */
+class RouteError extends Error {
+ constructor(status, message) {
+ super(message);
+ this.status = status;
+ }
+}
+exports.RouteError = RouteError;
+//# sourceMappingURL=classes.js.map
\ No newline at end of file
diff --git a/lib/other/classes.js.map b/lib/other/classes.js.map
new file mode 100644
index 0000000..2e5e091
--- /dev/null
+++ b/lib/other/classes.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"classes.js","sourceRoot":"","sources":["../../src/other/classes.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAKH;;GAEG;AACH,MAAa,UAAW,SAAQ,KAAK;IAEnC,YAAY,MAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAND,gCAMC"}
\ No newline at end of file
diff --git a/lib/other/types.js b/lib/other/types.js
new file mode 100644
index 0000000..11e638d
--- /dev/null
+++ b/lib/other/types.js
@@ -0,0 +1,3 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//# sourceMappingURL=types.js.map
\ No newline at end of file
diff --git a/lib/other/types.js.map b/lib/other/types.js.map
new file mode 100644
index 0000000..543f832
--- /dev/null
+++ b/lib/other/types.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/other/types.ts"],"names":[],"mappings":""}
\ No newline at end of file
diff --git a/lib/pre-start.js b/lib/pre-start.js
new file mode 100644
index 0000000..4dd85b6
--- /dev/null
+++ b/lib/pre-start.js
@@ -0,0 +1,31 @@
+"use strict";
+/**
+ * Pre-start is where we want to place things that must run BEFORE the express
+ * server is started. This is useful for environment variables, command-line
+ * arguments, and cron-jobs.
+ */
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+// NOTE: DO NOT IMPORT ANY SOURCE CODE HERE
+const path_1 = __importDefault(require("path"));
+const dotenv_1 = __importDefault(require("dotenv"));
+const ts_command_line_args_1 = require("ts-command-line-args");
+// **** Setup **** //
+// Command line arguments
+const args = (0, ts_command_line_args_1.parse)({
+ env: {
+ type: String,
+ defaultValue: 'development',
+ alias: 'e',
+ },
+});
+// Set the env file
+const result2 = dotenv_1.default.config({
+ path: path_1.default.join(__dirname, `../env/${args.env}.env`),
+});
+if (result2.error) {
+ throw result2.error;
+}
+//# sourceMappingURL=pre-start.js.map
\ No newline at end of file
diff --git a/lib/pre-start.js.map b/lib/pre-start.js.map
new file mode 100644
index 0000000..8bc6b66
--- /dev/null
+++ b/lib/pre-start.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"pre-start.js","sourceRoot":"","sources":["../src/pre-start.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;AAEH,2CAA2C;AAC3C,gDAAwB;AACxB,oDAA4B;AAC5B,+DAA6C;AAU7C,qBAAqB;AAErB,yBAAyB;AACzB,MAAM,IAAI,GAAG,IAAA,4BAAK,EAAQ;IACxB,GAAG,EAAE;QACH,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,aAAa;QAC3B,KAAK,EAAE,GAAG;KACX;CACF,CAAC,CAAC;AAEH,mBAAmB;AACnB,MAAM,OAAO,GAAG,gBAAM,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,IAAI,CAAC,GAAG,MAAM,CAAC;CACrD,CAAC,CAAC;AACH,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,CAAC,KAAK,CAAC;AACtB,CAAC"}
\ No newline at end of file
diff --git a/lib/public/scripts/http.js b/lib/public/scripts/http.js
new file mode 100644
index 0000000..799f8aa
--- /dev/null
+++ b/lib/public/scripts/http.js
@@ -0,0 +1,27 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Http = (() => {
+ // Setup request for json
+ var getOptions = (verb, data) => {
+ var options = {
+ dataType: 'json',
+ method: verb,
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ };
+ if (data) {
+ options.body = JSON.stringify(data);
+ }
+ return options;
+ };
+ // Set Http methods
+ return {
+ get: (path) => fetch(path, getOptions('GET')),
+ post: (path, data) => fetch(path, getOptions('POST', data)),
+ put: (path, data) => fetch(path, getOptions('PUT', data)),
+ delete: (path) => fetch(path, getOptions('DELETE')),
+ };
+})();
+//# sourceMappingURL=http.js.map
\ No newline at end of file
diff --git a/lib/public/scripts/http.js.map b/lib/public/scripts/http.js.map
new file mode 100644
index 0000000..088257d
--- /dev/null
+++ b/lib/public/scripts/http.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/public/scripts/http.js"],"names":[],"mappings":";;AAAA,IAAI,IAAI,GAAG,CAAC,GAAG,EAAE;IACf,yBAAyB;IACzB,IAAI,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,OAAO,GAAG;YACZ,QAAQ,EAAE,MAAM;YAChB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;gBACP,QAAQ,EAAE,kBAAkB;gBAC5B,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IACF,mBAAmB;IACnB,OAAO;QACL,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3D,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;KACpD,CAAC;AACJ,CAAC,CAAC,EAAE,CAAC"}
\ No newline at end of file
diff --git a/lib/public/scripts/users.js b/lib/public/scripts/users.js
new file mode 100644
index 0000000..790b41c
--- /dev/null
+++ b/lib/public/scripts/users.js
@@ -0,0 +1,154 @@
+"use strict";
+// ***** Start **** //
+Object.defineProperty(exports, "__esModule", { value: true });
+displayUsers();
+// ***** Fetch and display users **** //
+/**
+ * Call api
+ */
+function displayUsers() {
+ Http
+ .get('/api/users/all')
+ .then(resp => resp.json())
+ .then((resp) => {
+ var allUsers = resp.users;
+ // Empty the anchor
+ var allUsersAnchor = document.getElementById('all-users-anchor');
+ allUsersAnchor.innerHTML = '';
+ // Append users to anchor
+ allUsers.forEach((user) => {
+ allUsersAnchor.innerHTML += getUserDisplayEle(user);
+ });
+ });
+}
+/**
+ * Get user display element
+ */
+function getUserDisplayEle(user) {
+ return (`