From 51545ce82f80f49589ec92329e6341b1f2e44cef Mon Sep 17 00:00:00 2001 From: hanahhleee Date: Tue, 10 Oct 2023 22:17:06 -0400 Subject: [PATCH 1/4] Implemented function and route --- backend/api-spec.json | 158 ++++++++++++++++++++------ backend/src/customers/controllers.ts | 163 ++++++++++++++++++++------- backend/src/customers/models.ts | 46 +++++--- backend/src/customers/views.ts | 111 ++++++++++++++---- backend/src/index.ts | 6 +- backend/src/swagger.ts | 2 +- backend/tests/customer.test.ts | 17 ++- 7 files changed, 371 insertions(+), 132 deletions(-) diff --git a/backend/api-spec.json b/backend/api-spec.json index bb25212..63cc082 100644 --- a/backend/api-spec.json +++ b/backend/api-spec.json @@ -5,7 +5,7 @@ "title": "My API", "description": "Documentation automatically generated by the swagger-autogen module." }, - "host": "localhost:3000", + "host": "localhost:8000", "basePath": "/", "tags": [ { @@ -52,7 +52,7 @@ } } }, - "/users/": { + "/clusters/": { "get": { "description": "", "parameters": [], @@ -64,19 +64,47 @@ }, "post": { "description": "", - "parameters": [], + "parameters": [ + { + "name": "body", + "in": "body", + "schema": { + "type": "object", + "properties": { + "location": { + "example": "any" + } + } + } + } + ], "responses": { - "200": { - "description": "OK" + "201": { + "description": "Created" } } } }, - "/customers/": { - "get": { - "tags": [ - "Customers" + "/clusters/delete/{id}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/clusters/nets/": { + "get": { "description": "", "parameters": [], "responses": { @@ -86,9 +114,6 @@ } }, "post": { - "tags": [ - "Customers" - ], "description": "", "parameters": [ { @@ -97,16 +122,10 @@ "schema": { "type": "object", "properties": { - "name": { + "clusterID": { "example": "any" }, - "age": { - "example": "any" - }, - "title": { - "example": "any" - }, - "company": { + "type": { "example": "any" } } @@ -120,11 +139,8 @@ } } }, - "/customers/{id}": { + "/clusters/nets/{id}": { "get": { - "tags": [ - "Customers" - ], "description": "", "parameters": [ { @@ -141,11 +157,8 @@ } } }, - "/customers/updateName/{id}": { - "put": { - "tags": [ - "Customers" - ], + "/clusters/net/delete/{id}": { + "delete": { "description": "", "parameters": [ { @@ -153,20 +166,65 @@ "in": "path", "required": true, "type": "string" - }, + } + ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/clusters/data/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + }, + "apost": { + "description": "", + "parameters": [ { "name": "body", "in": "body", "schema": { "type": "object", "properties": { - "name": { + "netID": { + "example": "any" + }, + "date": { + "example": "any" + }, + "water_collected": { "example": "any" } } } } ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/clusters/data/{id}": { + "get": { + "description": "", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], "responses": { "200": { "description": "OK" @@ -174,13 +232,41 @@ } } }, - "/customers/resetAges": { - "post": { - "tags": [ - "Customers" + "/clusters/data/delete/{id}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/clusters/{minDate}/{maxDate}/": { + "get": { "description": "", - "parameters": [], + "parameters": [ + { + "name": "minDate", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "maxDate", + "in": "path", + "required": true, + "type": "string" + } + ], "responses": { "200": { "description": "OK" diff --git a/backend/src/customers/controllers.ts b/backend/src/customers/controllers.ts index a07f7f3..64d6729 100644 --- a/backend/src/customers/controllers.ts +++ b/backend/src/customers/controllers.ts @@ -1,63 +1,142 @@ import mongoose from "mongoose"; -import { CustomerModel, Customer } from "./models"; +import { Cluster, ClusterModel, Net, NetModel, Data, DataModel } from "./models"; /** - * Finds all customer docs in DB - * @returns promise with all customer docs or error + * Finds all cluster docs in DB + * @returns promise with all cluster docs or error */ -const getCustomers = async () => CustomerModel.find({}); +const getClusters = async () => ClusterModel.find({}); /** - * Finds a customer doc by id - * @param id customer id - * @returns promise with customer doc or error + * Inserts new cluster into DB + * @param location list of locations + * @returns promise with new cluster doc or error */ -const getCustomerById = async (id: mongoose.Types.ObjectId) => - CustomerModel.find({ _id: id }); +const insertCluster = async ( + location: [number] +) => ClusterModel.create(new Cluster(location)); /** - * Updates the name of a customer in DB - * @param id customer id - * @param name new name - * @returns promise with original customer doc or error + * Removes cluster by id from DB + * @param id cluster id + * @returns doc containg bool acknowledged and number deletedCount */ -const updateName = async (id: mongoose.Types.ObjectId, name: string) => - CustomerModel.findOneAndUpdate({ _id: id }, { name: name }); +const deleteCluster = async (id : string) => { + ClusterModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); + NetModel.deleteMany({clusterID : id}); // FIX: make sure all associated nets are deleted when cluster is deleted + // DataModel.deleteMany({netID : id}); // FIX: delete data docs associated with above nets (idk how to do this rn) +} /** - * Inserts new customer into DB - * @param name customer name - * @param age customer age - * @param title customer job title - * @param company customer job company - * @returns promise with new customer doc or error + * Finds all net docs in DB + * @returns promise with all net docs or error */ -const insertCustomer = async ( - name: string, - age: number, - title: string, - company: string -) => CustomerModel.create(new Customer(name, age, title, company)); +const getNets = async () => NetModel.find({}); /** - * Resets ages of all customers in DB to 0 - * @returns number of customers whose age was reset + * Finds all net docs by cluster id + * @param id cluster id + * @returns promise with net docs or error */ -const resetAges = async () => { - const customers = await getCustomers(); - customers.forEach(async (customer) => { - customer.age = 0; - await customer.save(); - }); +const getNetByClusterId = async (id: string) => + NetModel.find({ clusterID: id }); - return customers.length; -}; +/** + * Inserts new net into DB + * @param clusterID cluster id + * @param type type of net + * @returns promise with new net doc or error + */ +const insertNet = async ( + clusterID: string, + type: string +) => NetModel.create(new Net(clusterID, type)); + +/** + * Removes net by id from DB + * @param id net id + * @returns doc containg bool acknowledged and number deletedCount + */ +const deleteNet = async ( id : string) => { + NetModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); + DataModel.deleteMany({netID : id}); // FIX: for some reason the data is not deleted +} + +/** + * Finds all data docs in DB + * @returns promise with all data docs or error + */ +const getData = async () => DataModel.find({}); + +/** + * Finds all data docs by net id + * @param id net id + * @returns promise with data doc or error + */ +const getDataByNetId = async (id: string) => + DataModel.find({ netID: id }); + +/** + * Inserts new data into DB + * @param netID net id + * @param date date of data collected + * @param water_collected amount of water collected + * @returns promise with new data doc or error + */ +const insertData = async ( + netID: string, + date: Date, + water_collected: number +) => DataModel.create(new Data(netID, date, water_collected)); + +/** + * Removes data by id from DB + * @param id data id + * @returns doc containg bool acknowledged and number deletedCount + */ +const deleteData = async ( id : string) => + DataModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); + +/** + * Finds all data docs from clusters in list clusterIds + * @param clusterIds list of clusterIDs + * @param minDate earliest date to query data + * @param minDate latest date to query data + * @returns data docs or error + */ +const getAllDocsByClusterIDs = async ( + clusterIds: string[], + minDate: Date, + maxDate: Date +) => { + console.log(clusterIds) + const cursor1 = NetModel.find({clusterID: {"$in": clusterIds}}); + const netIds = []; + for await(const doc of cursor1) { + netIds.push(doc.id) + } + console.log(netIds); + const cursor2 = DataModel.find({netID: {"$in": netIds}, date: { $gte: minDate, $lte: maxDate }}); + const datas = []; + for await(const doc of cursor2) { + datas.push(doc) + } + console.log(datas) + return datas; +} export default { - getCustomers, - getCustomerById, - updateName, - insertCustomer, - resetAges, + getClusters, + insertCluster, + deleteCluster, + getNets, + getNetByClusterId, + insertNet, + deleteNet, + getData, + getDataByNetId, + insertData, + deleteData, + getAllDocsByClusterIDs }; diff --git a/backend/src/customers/models.ts b/backend/src/customers/models.ts index 7772d6e..34da9f5 100644 --- a/backend/src/customers/models.ts +++ b/backend/src/customers/models.ts @@ -1,34 +1,46 @@ import { getModelForClass, prop } from "@typegoose/typegoose"; -class Job { - constructor(title: string, company: string) { - this.title = title; - this.company = company; +class Data { + constructor(netID: string, date: Date, water_collected: number) { + this.netID = netID; + this.date = date; + this.water_collected = water_collected; } @prop() - public title!: string; + public netID!: string; @prop() - public company!: string; + public date!: Date; + + @prop() + public water_collected!: number; } -class Customer { - constructor(name: string, age: number, title: string, company: string) { - this.name = name; - this.age = age; - this.job = new Job(title, company); +class Net { + constructor(clusterID: string, type: string) { + this.clusterID = clusterID; + this.type = type; } @prop() - public name!: string; + public clusterID!: string; @prop() - public age!: number; + public type!: string; +} + +class Cluster { + constructor(location: [number]) { + this.location = location; + } - // nesting a sub-document @prop() - public job!: Job; + public location!: [number]; } -const CustomerModel = getModelForClass(Customer); -export { Customer, CustomerModel }; + +const ClusterModel = getModelForClass(Cluster); +const NetModel = getModelForClass(Net); +const DataModel = getModelForClass(Data); + +export { Cluster, ClusterModel, Net, NetModel, Data, DataModel }; diff --git a/backend/src/customers/views.ts b/backend/src/customers/views.ts index b7770e4..3252bdf 100644 --- a/backend/src/customers/views.ts +++ b/backend/src/customers/views.ts @@ -1,51 +1,116 @@ import { Router } from "express"; import mongoose from "mongoose"; -import CustomerController from "./controllers"; +import DocController from "./controllers"; // Note: we should use a try/catch to choose successJson or errorJson for responses // this has been left out of this snippet for brevity import { successJson, errorJson } from "../utils/jsonResponses"; -const customerRouter = Router(); +const docRouter = Router(); -customerRouter.get("/", async (req, res) => { - // #swagger.tags = ['Customers'] - res.status(200).send(await CustomerController.getCustomers()); +docRouter.get("/", async (req, res) => { + res.status(200).send(await DocController.getClusters()); }); -customerRouter.get("/:id", async (req, res) => { - // #swagger.tags = ['Customers'] - const id = new mongoose.Types.ObjectId(req.params.id); +docRouter.post("/", async (req, res) => { + const { location } = req.body; + res + .status(201) + .send( + successJson( + await DocController.insertCluster(location) + ) + ); +}); + +docRouter.delete("/delete/:id", async (req, res) => { + const id = req.params.id; + res + .status(201) + .send( + successJson( + await DocController.deleteCluster(id) + ) + ); +}); + +docRouter.get("/nets/", async (req, res) => { + res.status(200).send(await DocController.getNets()); +}); + +docRouter.get("/nets/:id", async (req, res) => { + const id = req.params.id; res .status(200) - .send(successJson(await CustomerController.getCustomerById(id))); + .send(successJson(await DocController.getNetByClusterId(id))); +}); + +docRouter.post("/nets/", async (req, res) => { + const { clusterID, type } = req.body; + res + .status(201) + .send( + successJson( + await DocController.insertNet(clusterID, type) + ) + ); }); -customerRouter.post("/", async (req, res) => { - // #swagger.tags = ['Customers'] - const { name, age, title, company } = req.body; +docRouter.delete("/net/delete/:id", async (req, res) => { + const id = req.params.id; res .status(201) .send( successJson( - await CustomerController.insertCustomer(name, age, title, company) + await DocController.deleteNet(id) ) ); }); -customerRouter.put("/updateName/:id", async (req, res) => { - // #swagger.tags = ['Customers'] - const id = new mongoose.Types.ObjectId(req.params.id); - const name = req.body.name; +docRouter.get("/data/", async (req, res) => { + res.status(200).send(await DocController.getData()); +}); + +docRouter.get("/data/:id", async (req, res) => { + const id = req.params.id; res .status(200) - .send(successJson(await CustomerController.updateName(id, name))); + .send(successJson(await DocController.getDataByNetId(id))); }); -customerRouter.post("/resetAges", async (req, res) => { - // #swagger.tags = ['Customers'] - const numResets = await CustomerController.resetAges(); - res.status(200).send(successJson(numResets)); +docRouter.post("/data/", async (req, res) => { + const { netID, date, water_collected } = req.body; + res + .status(201) + .send( + successJson( + await DocController.insertData(netID, date, water_collected) + ) + ); +}); + +docRouter.delete("/data/delete/:id", async (req, res) => { + const id = req.params.id; + res + .status(201) + .send( + successJson( + await DocController.deleteData(id) + ) + ); +}); + +const clusterIds = ["65258f01ba4c14948edd4526", "65258d88899b7e221c1d33eb"] // NOTE: temp hardcoded list of clusterIDs for testing +docRouter.get("/:minDate/:maxDate/", async (req, res) => { + let minDate = new Date(); // FIX: right now minDate and maxDate are required fields but they should be able to be left empty + let maxDate = new Date(); + if (req.params.minDate) {minDate = new Date(req.params.minDate)} + else {minDate = new Date("2023-01-01")}; + if (req.params.maxDate) {maxDate = new Date(req.params.maxDate)} // Assumes the date is valid with correct syntax + else {maxDate = new Date(new Date().toJSON().slice(0, 10))}; + res + .status(200) + .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); }); -export default customerRouter; +export default docRouter; diff --git a/backend/src/index.ts b/backend/src/index.ts index 53c5ba1..ce68578 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,6 @@ import express from "express"; import bodyParser from "body-parser"; -import userRouter from "./users/views"; -import customerRouter from "./customers/views"; +import DocRouter from "./customers/views"; import swaggerUI from "swagger-ui-express"; import spec from "../api-spec.json"; import { dbConnect } from "./database"; @@ -15,8 +14,7 @@ app.use("/api-docs", swaggerUI.serve, swaggerUI.setup(spec)); /** * Sub-routers for our main router, we should have one sub-router per "entity" in the application */ -app.use("/users", userRouter); -app.use("/customers", customerRouter); +app.use("/clusters", DocRouter); /** * Some dummy routes to illustrate express syntax diff --git a/backend/src/swagger.ts b/backend/src/swagger.ts index 4084a6a..eb3f000 100644 --- a/backend/src/swagger.ts +++ b/backend/src/swagger.ts @@ -7,7 +7,7 @@ const doc = { description: "Documentation automatically generated by the swagger-autogen module.", }, - host: "localhost:3000", + host: "localhost:8000", // NOTE: changed this from 3000 -> 8000 basePath: "/", schemes: ["http", "https"], consumes: ["application/json"], diff --git a/backend/tests/customer.test.ts b/backend/tests/customer.test.ts index 2207f30..416d1ba 100644 --- a/backend/tests/customer.test.ts +++ b/backend/tests/customer.test.ts @@ -1,6 +1,6 @@ import { dbConnect, dbDisconnect } from "../src/database"; -import CustomerController from "../src/customers/controllers"; -import { Customer } from "../src/customers/models"; +import ClusterController from "../src/customers/controllers"; +import { Cluster, ClusterModel, Net, NetModel, Data, DataModel } from "../src/customers/models"; beforeAll(async () => { await dbConnect(); @@ -10,13 +10,12 @@ afterAll(async () => { await dbDisconnect(); }); -describe("Customer Retreival Tests", () => { - test("Get all customers", async () => { - const allCustomers = await CustomerController.getCustomers(); - expect(allCustomers.length).toBeGreaterThan(0); - for (let customer of allCustomers) { - expect(customer.name).toBeDefined(); - expect(customer.age).toBeDefined(); +// FIX: add comprehensive testing here +describe("Cluster Retreival Tests", () => { + test("Get all clusters", async () => { + const allClusters = await ClusterController.getClusters(); + for (let cluster of allClusters) { + expect(cluster.location).toBeDefined(); } }); }); From d5a392d2fbfc2dd89e6ed1916e6928c2ccd91a25 Mon Sep 17 00:00:00 2001 From: Kaden Lei Date: Fri, 13 Oct 2023 15:23:11 -0400 Subject: [PATCH 2/4] Made date params optional --- backend/api-spec.json | 2 +- backend/src/customers/controllers.ts | 85 ++++++++++++++++------------ backend/src/customers/views.ts | 73 +++++++++--------------- 3 files changed, 75 insertions(+), 85 deletions(-) diff --git a/backend/api-spec.json b/backend/api-spec.json index 63cc082..fc1c093 100644 --- a/backend/api-spec.json +++ b/backend/api-spec.json @@ -185,7 +185,7 @@ } } }, - "apost": { + "post": { "description": "", "parameters": [ { diff --git a/backend/src/customers/controllers.ts b/backend/src/customers/controllers.ts index 64d6729..5f08c19 100644 --- a/backend/src/customers/controllers.ts +++ b/backend/src/customers/controllers.ts @@ -1,6 +1,14 @@ import mongoose from "mongoose"; -import { Cluster, ClusterModel, Net, NetModel, Data, DataModel } from "./models"; +import { + Cluster, + ClusterModel, + Net, + NetModel, + Data, + DataModel, +} from "./models"; +import { type } from "os"; /** * Finds all cluster docs in DB @@ -13,20 +21,19 @@ const getClusters = async () => ClusterModel.find({}); * @param location list of locations * @returns promise with new cluster doc or error */ -const insertCluster = async ( - location: [number] -) => ClusterModel.create(new Cluster(location)); +const insertCluster = async (location: [number]) => + ClusterModel.create(new Cluster(location)); /** * Removes cluster by id from DB * @param id cluster id * @returns doc containg bool acknowledged and number deletedCount */ -const deleteCluster = async (id : string) => { - ClusterModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); - NetModel.deleteMany({clusterID : id}); // FIX: make sure all associated nets are deleted when cluster is deleted +const deleteCluster = async (id: string) => { + ClusterModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); + NetModel.deleteMany({ clusterID: id }); // FIX: make sure all associated nets are deleted when cluster is deleted // DataModel.deleteMany({netID : id}); // FIX: delete data docs associated with above nets (idk how to do this rn) -} +}; /** * Finds all net docs in DB @@ -48,20 +55,19 @@ const getNetByClusterId = async (id: string) => * @param type type of net * @returns promise with new net doc or error */ -const insertNet = async ( - clusterID: string, - type: string -) => NetModel.create(new Net(clusterID, type)); +const insertNet = async (clusterID: string, type: string) => + NetModel.create(new Net(clusterID, type)); /** * Removes net by id from DB * @param id net id * @returns doc containg bool acknowledged and number deletedCount */ -const deleteNet = async ( id : string) => { - NetModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); - DataModel.deleteMany({netID : id}); // FIX: for some reason the data is not deleted -} +const deleteNet = async (id: string) => { + console.log(id); + NetModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); + DataModel.deleteMany({ netID: id }); // FIX: for some reason the data is not deleted +}; /** * Finds all data docs in DB @@ -74,8 +80,7 @@ const getData = async () => DataModel.find({}); * @param id net id * @returns promise with data doc or error */ -const getDataByNetId = async (id: string) => - DataModel.find({ netID: id }); +const getDataByNetId = async (id: string) => DataModel.find({ netID: id }); /** * Inserts new data into DB @@ -84,19 +89,16 @@ const getDataByNetId = async (id: string) => * @param water_collected amount of water collected * @returns promise with new data doc or error */ -const insertData = async ( - netID: string, - date: Date, - water_collected: number -) => DataModel.create(new Data(netID, date, water_collected)); +const insertData = async (netID: string, date: Date, water_collected: number) => + DataModel.create(new Data(netID, date, water_collected)); /** * Removes data by id from DB * @param id data id * @returns doc containg bool acknowledged and number deletedCount */ -const deleteData = async ( id : string) => - DataModel.deleteOne({_id : new mongoose.Types.ObjectId(id)}); +const deleteData = async (id: string) => + DataModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); /** * Finds all data docs from clusters in list clusterIds @@ -107,24 +109,33 @@ const deleteData = async ( id : string) => */ const getAllDocsByClusterIDs = async ( clusterIds: string[], - minDate: Date, - maxDate: Date + minDate?: Date, + maxDate?: Date ) => { - console.log(clusterIds) - const cursor1 = NetModel.find({clusterID: {"$in": clusterIds}}); + console.log(clusterIds); + if (typeof minDate === undefined) { + minDate = new Date("2023-01-01"); + } + if (typeof maxDate === undefined) { + maxDate = new Date(new Date().toJSON().slice(0, 10)); + } + const cursor1 = NetModel.find({ clusterID: { $in: clusterIds } }); const netIds = []; - for await(const doc of cursor1) { - netIds.push(doc.id) + for await (const doc of cursor1) { + netIds.push(doc.id); } console.log(netIds); - const cursor2 = DataModel.find({netID: {"$in": netIds}, date: { $gte: minDate, $lte: maxDate }}); + const cursor2 = DataModel.find({ + netID: { $in: netIds }, + date: { $gte: minDate, $lte: maxDate }, + }); const datas = []; - for await(const doc of cursor2) { - datas.push(doc) + for await (const doc of cursor2) { + datas.push(doc); } - console.log(datas) + console.log(datas); return datas; -} +}; export default { getClusters, @@ -138,5 +149,5 @@ export default { getDataByNetId, insertData, deleteData, - getAllDocsByClusterIDs + getAllDocsByClusterIDs, }; diff --git a/backend/src/customers/views.ts b/backend/src/customers/views.ts index 3252bdf..bf18f9b 100644 --- a/backend/src/customers/views.ts +++ b/backend/src/customers/views.ts @@ -16,22 +16,12 @@ docRouter.post("/", async (req, res) => { const { location } = req.body; res .status(201) - .send( - successJson( - await DocController.insertCluster(location) - ) - ); + .send(successJson(await DocController.insertCluster(location))); }); docRouter.delete("/delete/:id", async (req, res) => { const id = req.params.id; - res - .status(201) - .send( - successJson( - await DocController.deleteCluster(id) - ) - ); + res.status(201).send(successJson(await DocController.deleteCluster(id))); }); docRouter.get("/nets/", async (req, res) => { @@ -40,31 +30,19 @@ docRouter.get("/nets/", async (req, res) => { docRouter.get("/nets/:id", async (req, res) => { const id = req.params.id; - res - .status(200) - .send(successJson(await DocController.getNetByClusterId(id))); + res.status(200).send(successJson(await DocController.getNetByClusterId(id))); }); docRouter.post("/nets/", async (req, res) => { const { clusterID, type } = req.body; res .status(201) - .send( - successJson( - await DocController.insertNet(clusterID, type) - ) - ); + .send(successJson(await DocController.insertNet(clusterID, type))); }); docRouter.delete("/net/delete/:id", async (req, res) => { const id = req.params.id; - res - .status(201) - .send( - successJson( - await DocController.deleteNet(id) - ) - ); + res.status(201).send(successJson(await DocController.deleteNet(id))); }); docRouter.get("/data/", async (req, res) => { @@ -73,9 +51,7 @@ docRouter.get("/data/", async (req, res) => { docRouter.get("/data/:id", async (req, res) => { const id = req.params.id; - res - .status(200) - .send(successJson(await DocController.getDataByNetId(id))); + res.status(200).send(successJson(await DocController.getDataByNetId(id))); }); docRouter.post("/data/", async (req, res) => { @@ -83,34 +59,37 @@ docRouter.post("/data/", async (req, res) => { res .status(201) .send( - successJson( - await DocController.insertData(netID, date, water_collected) - ) + successJson(await DocController.insertData(netID, date, water_collected)) ); }); docRouter.delete("/data/delete/:id", async (req, res) => { const id = req.params.id; - res - .status(201) - .send( - successJson( - await DocController.deleteData(id) - ) - ); + res.status(201).send(successJson(await DocController.deleteData(id))); }); -const clusterIds = ["65258f01ba4c14948edd4526", "65258d88899b7e221c1d33eb"] // NOTE: temp hardcoded list of clusterIDs for testing -docRouter.get("/:minDate/:maxDate/", async (req, res) => { +const clusterIds = ["65258f01ba4c14948edd4526", "65258d88899b7e221c1d33eb"]; // NOTE: temp hardcoded list of clusterIDs for testing +docRouter.get("/:minDate?/:maxDate?/", async (req, res) => { let minDate = new Date(); // FIX: right now minDate and maxDate are required fields but they should be able to be left empty let maxDate = new Date(); - if (req.params.minDate) {minDate = new Date(req.params.minDate)} - else {minDate = new Date("2023-01-01")}; - if (req.params.maxDate) {maxDate = new Date(req.params.maxDate)} // Assumes the date is valid with correct syntax - else {maxDate = new Date(new Date().toJSON().slice(0, 10))}; + if (req.params.minDate) { + minDate = new Date(req.params.minDate); + } else { + minDate = new Date("2023-01-01"); + } + if (req.params.maxDate) { + maxDate = new Date(req.params.maxDate); + } // Assumes the date is valid with correct syntax + else { + maxDate = new Date(new Date().toJSON().slice(0, 10)); + } res .status(200) - .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); + .send( + successJson( + await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate) + ) + ); }); export default docRouter; From fc7b43c73a990c2e756f3bbe5906293e532ff184 Mon Sep 17 00:00:00 2001 From: hanahhleee Date: Fri, 13 Oct 2023 18:00:06 -0400 Subject: [PATCH 3/4] Updated function --- backend/api-spec.json | 49 +++++++++++++++++++- backend/src/customers/controllers.ts | 36 +++++---------- backend/src/customers/views.ts | 69 +++++++++++++++------------- backend/src/swagger.ts | 2 +- backend/tests/customer.test.ts | 1 - 5 files changed, 97 insertions(+), 60 deletions(-) diff --git a/backend/api-spec.json b/backend/api-spec.json index fc1c093..c0f610a 100644 --- a/backend/api-spec.json +++ b/backend/api-spec.json @@ -250,7 +250,7 @@ } } }, - "/clusters/{minDate}/{maxDate}/": { + "/clusters/clusterData/dates/{minDate}/{maxDate}/": { "get": { "description": "", "parameters": [ @@ -273,6 +273,53 @@ } } } + }, + "/clusters/clusterData/min/{minDate}": { + "get": { + "description": "", + "parameters": [ + { + "name": "minDate", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/clusters/clusterData/max/{maxDate}": { + "get": { + "description": "", + "parameters": [ + { + "name": "maxDate", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/clusters/clusterData/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + } } } } \ No newline at end of file diff --git a/backend/src/customers/controllers.ts b/backend/src/customers/controllers.ts index 5f08c19..be7743a 100644 --- a/backend/src/customers/controllers.ts +++ b/backend/src/customers/controllers.ts @@ -1,15 +1,8 @@ import mongoose from "mongoose"; - -import { - Cluster, - ClusterModel, - Net, - NetModel, - Data, - DataModel, -} from "./models"; +import { Cluster, ClusterModel, Net, NetModel, Data, DataModel } from "./models"; import { type } from "os"; +/** NOTE: THESE FUNCTIONS ARE TEMPORARY AND FOR TESTING PURPOSES ONLY */ /** * Finds all cluster docs in DB * @returns promise with all cluster docs or error @@ -31,8 +24,8 @@ const insertCluster = async (location: [number]) => */ const deleteCluster = async (id: string) => { ClusterModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); - NetModel.deleteMany({ clusterID: id }); // FIX: make sure all associated nets are deleted when cluster is deleted - // DataModel.deleteMany({netID : id}); // FIX: delete data docs associated with above nets (idk how to do this rn) + NetModel.deleteMany({ clusterID: id }); // FIX: does not delete associated net docs + // TODO: delete associated data docs }; /** @@ -66,7 +59,7 @@ const insertNet = async (clusterID: string, type: string) => const deleteNet = async (id: string) => { console.log(id); NetModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); - DataModel.deleteMany({ netID: id }); // FIX: for some reason the data is not deleted + DataModel.deleteMany({ netID: id }); // FIX: does not delete associated data docs }; /** @@ -100,6 +93,8 @@ const insertData = async (netID: string, date: Date, water_collected: number) => const deleteData = async (id: string) => DataModel.deleteOne({ _id: new mongoose.Types.ObjectId(id) }); +/** NOTE: END OF TEMPORARY FUNCTIONS */ + /** * Finds all data docs from clusters in list clusterIds * @param clusterIds list of clusterIDs @@ -109,22 +104,15 @@ const deleteData = async (id: string) => */ const getAllDocsByClusterIDs = async ( clusterIds: string[], - minDate?: Date, - maxDate?: Date + minDate: Date, + maxDate: Date ) => { - console.log(clusterIds); - if (typeof minDate === undefined) { - minDate = new Date("2023-01-01"); - } - if (typeof maxDate === undefined) { - maxDate = new Date(new Date().toJSON().slice(0, 10)); - } const cursor1 = NetModel.find({ clusterID: { $in: clusterIds } }); const netIds = []; for await (const doc of cursor1) { netIds.push(doc.id); } - console.log(netIds); + const cursor2 = DataModel.find({ netID: { $in: netIds }, date: { $gte: minDate, $lte: maxDate }, @@ -133,7 +121,7 @@ const getAllDocsByClusterIDs = async ( for await (const doc of cursor2) { datas.push(doc); } - console.log(datas); + return datas; }; @@ -149,5 +137,5 @@ export default { getDataByNetId, insertData, deleteData, - getAllDocsByClusterIDs, + getAllDocsByClusterIDs }; diff --git a/backend/src/customers/views.ts b/backend/src/customers/views.ts index bf18f9b..4df7dbd 100644 --- a/backend/src/customers/views.ts +++ b/backend/src/customers/views.ts @@ -8,20 +8,19 @@ import { successJson, errorJson } from "../utils/jsonResponses"; const docRouter = Router(); +// NOTE: THESE ROUTES ARE TEMPORARY AND FOR TESTING PURPOSES ONLY docRouter.get("/", async (req, res) => { res.status(200).send(await DocController.getClusters()); }); docRouter.post("/", async (req, res) => { const { location } = req.body; - res - .status(201) - .send(successJson(await DocController.insertCluster(location))); + res.status(201).send(successJson(await DocController.insertCluster(location))); }); docRouter.delete("/delete/:id", async (req, res) => { const id = req.params.id; - res.status(201).send(successJson(await DocController.deleteCluster(id))); + res.status(201).send(successJson( await DocController.deleteCluster(id))); }); docRouter.get("/nets/", async (req, res) => { @@ -35,9 +34,7 @@ docRouter.get("/nets/:id", async (req, res) => { docRouter.post("/nets/", async (req, res) => { const { clusterID, type } = req.body; - res - .status(201) - .send(successJson(await DocController.insertNet(clusterID, type))); + res.status(201).send( successJson(await DocController.insertNet(clusterID, type))); }); docRouter.delete("/net/delete/:id", async (req, res) => { @@ -56,40 +53,46 @@ docRouter.get("/data/:id", async (req, res) => { docRouter.post("/data/", async (req, res) => { const { netID, date, water_collected } = req.body; - res - .status(201) - .send( - successJson(await DocController.insertData(netID, date, water_collected)) - ); + res.status(201).send(successJson(await DocController.insertData(netID, date, water_collected))); }); docRouter.delete("/data/delete/:id", async (req, res) => { const id = req.params.id; res.status(201).send(successJson(await DocController.deleteData(id))); }); +// NOTE: END OF TEMPORARY ROUTES + +const clusterIds = ["65258f01ba4c14948edd4526", "65258d88899b7e221c1d33eb"] // NOTE: temp hardcoded list of clusterIDs for testing +docRouter.get("/clusterData/dates/:minDate/:maxDate/", async (req, res) => { + let minDate = new Date(req.params.minDate); + let maxDate = new Date(req.params.maxDate); + res + .status(200) + .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); +}); + +docRouter.get("/clusterData/min/:minDate", async (req, res) => { + let minDate = new Date(req.params.minDate); + let maxDate = new Date(new Date().toJSON().slice(0, 10)); + res + .status(200) + .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); +}); + +docRouter.get("/clusterData/max/:maxDate", async (req, res) => { + let minDate = new Date("2023-01-01"); + let maxDate = new Date(req.params.maxDate); + res + .status(200) + .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); +}); -const clusterIds = ["65258f01ba4c14948edd4526", "65258d88899b7e221c1d33eb"]; // NOTE: temp hardcoded list of clusterIDs for testing -docRouter.get("/:minDate?/:maxDate?/", async (req, res) => { - let minDate = new Date(); // FIX: right now minDate and maxDate are required fields but they should be able to be left empty - let maxDate = new Date(); - if (req.params.minDate) { - minDate = new Date(req.params.minDate); - } else { - minDate = new Date("2023-01-01"); - } - if (req.params.maxDate) { - maxDate = new Date(req.params.maxDate); - } // Assumes the date is valid with correct syntax - else { - maxDate = new Date(new Date().toJSON().slice(0, 10)); - } +docRouter.get("/clusterData/", async (req, res) => { + let minDate = new Date("2023-01-01"); + let maxDate = new Date(new Date().toJSON().slice(0, 10)); res .status(200) - .send( - successJson( - await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate) - ) - ); + .send(successJson(await DocController.getAllDocsByClusterIDs(clusterIds, minDate, maxDate))); }); -export default docRouter; +export default docRouter; \ No newline at end of file diff --git a/backend/src/swagger.ts b/backend/src/swagger.ts index eb3f000..cd527f1 100644 --- a/backend/src/swagger.ts +++ b/backend/src/swagger.ts @@ -7,7 +7,7 @@ const doc = { description: "Documentation automatically generated by the swagger-autogen module.", }, - host: "localhost:8000", // NOTE: changed this from 3000 -> 8000 + host: "localhost:8000", basePath: "/", schemes: ["http", "https"], consumes: ["application/json"], diff --git a/backend/tests/customer.test.ts b/backend/tests/customer.test.ts index 416d1ba..efbee60 100644 --- a/backend/tests/customer.test.ts +++ b/backend/tests/customer.test.ts @@ -10,7 +10,6 @@ afterAll(async () => { await dbDisconnect(); }); -// FIX: add comprehensive testing here describe("Cluster Retreival Tests", () => { test("Get all clusters", async () => { const allClusters = await ClusterController.getClusters(); From f9c8cf4a922aa9914c81ee3c1c8d4b1733a0f1da Mon Sep 17 00:00:00 2001 From: Josh Feuerstein Date: Mon, 16 Oct 2023 13:46:03 -0400 Subject: [PATCH 4/4] added pr-template --- .github/CODEOWNERS | 5 +++++ .github/pull_request_template.md | 31 +++++++++++++++++++++++++++++++ yarn.lock | 4 ++++ 3 files changed, 40 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/pull_request_template.md create mode 100644 yarn.lock diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..98d0cf8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# Users who will be automatically be notified & added as reviewers when a PR is made (should be TL) + +- @jfeuerstein + +# Change the user above as necessary \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..25a88fe --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,31 @@ + + + + +## Overview + + + +## Changes Made + + + +## Test Coverage + + + +## Related PRs or Issues (delete if not applicable) + + + +## Screenshots (delete if not applicable) + + + +
+ + Screen Shot Name + + + +
\ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..fb57ccd --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +