BitBytes-team / Project-6

0 stars 1 forks source link

Epic 1:Develop - Database Integration #1

Closed ruchitha007 closed 1 year ago

ruchitha007 commented 1 year ago

As a developer, I want the assignee to convert the web server to use the MongoDB database instead of magic models. This will ensure that the application fetches data from a database, eliminating dependencies on magic models and conforming to the specified API.

Acceptance criteria :

Update webServer.js to remove all references to magic models, including the line: var models = require('./modelData/photoApp.js').models;

Create MongoDB schemas and models for users and photos.

Implement API route '/test' to return schema information and object counts from the MongoDB database.

Develop API route '/user/list' to return a list of user properties suitable for the navigation sidebar, including '_id', 'first_name', and 'last_name'.

Implement API route '/user/:id' to provide detailed user information for a given user ID, including '_id', 'first_name', 'last_name', 'location', 'description', and 'occupation'. Handle invalid user IDs with a 400 HTTP status response and an informative message.

Develop API route '/photosOfUser/:id' to return user photos and comments, including '_id', 'user_id', 'comments', 'file_name', and 'date_time'. Ensure comments include 'comment', 'date_time', '_id', and 'user' with minimal user information. Handle invalid user IDs with a 400 HTTP status response and an informative message.

Ensure that the responses align with the needs of the UI views without altering the database schema.

Implement object cloning using JSON serialization to create copies of MongoDB models without Mongoose-specific modifications.

Sharu201101 commented 1 year ago

webserver.js const mongoose = require("mongoose"); mongoose.Promise = require("bluebird");

const async = require("async");

const express = require("express"); const app = express();

// Load the Mongoose schema for User, Photo, and SchemaInfo const User = require("./schema/user.js"); const Photo = require("./schema/photo.js"); const SchemaInfo = require("./schema/schemaInfo.js");

// XXX - Your submission should work without this line. Comment out or delete // this line for tests and before submission! //const models = require("./modelData/photoApp.js").models; mongoose.set("strictQuery", false); mongoose.connect("mongodb://127.0.0.1/project6", { useNewUrlParser: true, useUnifiedTopology: true, });

// We have the express static module // (http://expressjs.com/en/starter/static-files.html) do all the work for us. app.use(express.static(__dirname));

app.get("/", function (request, response) { response.send("Simple web server of files from " + __dirname); });

app.get("/test/:p1", function (request, response) { // Express parses the ":p1" from the URL and returns it in the request.params // objects. console.log("/test called with param1 = ", request.params.p1);

const param = request.params.p1 || "info";

if (param === "info") { // Fetch the SchemaInfo. There should only one of them. The query of {} will // match it. SchemaInfo.find({}, function (err, info) { if (err) { // Query returned an error. We pass it back to the browser with an // Internal Service Error (500) error code. console.error("Error in /user/info:", err); response.status(500).send(JSON.stringify(err)); return; } if (info.length === 0) { // Query didn't return an error but didn't find the SchemaInfo object - // This is also an internal error return. response.status(500).send("Missing SchemaInfo"); return; }

  // We got the object - return it in JSON format.
  console.log("SchemaInfo", info[0]);
  response.end(JSON.stringify(info[0]));
});

} else if (param === "counts") { // In order to return the counts of all the collections we need to do an // async call to each collections. That is tricky to do so we use the async // package do the work. We put the collections into array and use async.each // to do each .count() query. const collections = [ { name: "user", collection: User }, { name: "photo", collection: Photo }, { name: "schemaInfo", collection: SchemaInfo }, ]; async.each( collections, function (col, done_callback) { col.collection.countDocuments({}, function (err, count) { col.count = count; done_callback(err); }); }, function (err) { if (err) { response.status(500).send(JSON.stringify(err)); } else { const obj = {}; for (let i = 0; i < collections.length; i++) { obj[collections[i].name] = collections[i].count; } response.end(JSON.stringify(obj)); } } ); } else { response.status(400).send("Bad param " + param); } });

app.get("/user/list", function (request, response) { User.find({}, "_id first_name last_name", function (err, users) { if (err) { console.error("Error in /user/list:", err); response.status(500).send(JSON.stringify(err)); } else { // Convert the users to the required format const userList = users.map(user => ({ _id: user._id, first_name: user.first_name, last_name: user.last_name, })); response.status(200).json(userList); } }); });

app.get("/user/:id", function (request, response) { const id = request.params.id; //if (user === null) { //console.log("User with _id:" + id + " not found."); //response.status(400).send("Not found"); //return; //} User.findById(id, "_id first_name last_name location description occupation", function (err, user) { if (err) { console.error("Error in /user/:id:", err); response.status(500).send(JSON.stringify(err)); } else if (!user) { response.status(400).send("User not found"); } else { response.status(200).json(user); } }); });

app.get("/photosOfUser/:id", function (request, response) { const id = request.params.id; Photo.find({ user_id: id }, function (err, photos) { if (err !== null) { response.status(400).send("error");

} else if (photos.length === 0) {
  response.status(400).send("no such user photos");

} else {
  var functionStack = [];
  var info = JSON.parse(JSON.stringify(photos));
  for (var i = 0; i < info.length; i++) {
    delete info[i].__v;
    var comments = info[i].comments;

    comments.forEach(function (comment) {
      var uid = comment.user_id;

      functionStack.push(function (callback) {
        User.findOne({
          _id: uid
          // eslint-disable-next-line no-shadow
        }, function (err, result) {
          if (err !== null) {
            response.status(400).send("error");
          } else {
            var userInfo = JSON.parse(JSON.stringify(result));
            var user = {
              _id: uid,
              first_name: userInfo.first_name,
              last_name: userInfo.last_name
            };
            comment.user = user;
          }
          callback();
        });
      });
      delete comment.user_id;
    });

  }

  // eslint-disable-next-line no-unused-vars
  async.parallel(functionStack, function (res) {
    response.status(200).send(info);
  });
}

}); });

const server = app.listen(3000, function () { const port = server.address().port; console.log( "Listening at http://localhost:" + port + " exporting the directory " + __dirname ); });

photoapp.js "use strict"; / jshint node: true / /*

!", user: jo, photo_id: photo1._id };

var comment2 = { _id: "57231f1a30e4351f4e9f4bea", date_time: "2013-09-06 14:02:00", comment: "This is another comment, with a bit more text; " + "if the text gets long enough, does it wrap properly " + "from line to line?", user: jo, photo_id: photo1._id };

var comment3 = { _id: "57231f1a30e4351f4e9f4beb", date_time: "2013-09-08 14:06:00", comment: "If you see this text in boldface " + "then HTML escaping isn't working properly.", user: jo, photo_id: photo1._id };

var comment4 = { _id: "57231f1a30e4351f4e9f4bec", date_time: "2009-09-14 18:07:00", comment: "If there is one thing the history of evolution has" + " taught us it's that life will not be contained. Life breaks " + "free, it expands to new territories and crashes through " + "barriers, painfully, maybe even dangerously, but, uh... well, " + "there it is. Life finds a way.", user: im, photo_id: photo2._id };

var comment5 = { _id: "57231f1a30e4351f4e9f4bed", date_time: "2013-11-28 17:45:13", comment: "Back from my trip. Did IQs just... drop sharply while I was " + "away?", user: er, photo_id: photo5._id };

var comment6 = { _id: "57231f1a30e4351f4e9f4bee", date_time: "2013-11-02 14:07:00", comment: "Hey Rey, great form. Love what " + "you do with the scavenged tech, got any tips?", user: er, photo_id: photo7._id };

var comment7 = { _id: "57231f1a30e4351f4e9f4bef", date_time: "2013-11-02 14:07:00", comment: "Definitely! I love your work! I'm away on a trip at " + "the moment, but let's meet up when I get back! :)", user: rk, photo_id: photo7._id };

var comment8 = { _id: "57231f1a30e4351f4e9f4bf0", date_time: "2010-09-06 13:59:33", comment: "Made a new friend today! Well, they followed me " + "home, anyway.", user: rk, photo_id: photo8._id };

var comment9 = { _id: "57231f1a30e4351f4e9f4bf1", date_time: "2008-10-16 18:04:55", comment: "Wouldn't get anywhere without this beauty! " + "Completely built from scraps by hand, but she goes at top " + "speeds that'll rival any First Order piece of junk.", user: rk, photo_id: photo12._id };

var comment10 = { _id: "57231f1a30e4351f4e9f4bf2", date_time: "2013-12-04 13:12:00", comment: "What do you mean you haven't heard of second " + "breakfast?", user: pt, photo_id: photo10._id };

var comment11 = { _id: "57231f1a30e4351f4e9f4bf3", date_time: "2013-09-04 10:14:32", comment: "Beautiful yet cold and aloof. Loner. Does not obey, " + "occasionally chooses to cooperate. ", user: al, photo_id: photo11._id };

var comment12 = { _id: "57231f1a30e4351f4e9f4bf4", date_time: "2016-01-04 2:00:01", comment: "Which one are you?", user: al, photo_id: photo9._id };

var comment13 = { _id: "57231f1a30e4351f4e9f4bf5", date_time: "2016-01-04 2:04:01", comment: "The tall one.", user: pt, photo_id: photo9._id };

var comments = [comment1, comment2, comment3, comment4, comment5, comment6, comment7, comment8, comment9, comment10, comment11, comment12, comment13];

comments.forEach(function (comment) { var photo = photos.filter(function (photo) { return (photo._id === comment.photo_id); })[0]; //only one match. return the content of the match inside the array

if (!photo.comments) { photo.comments = []; } photo.comments.push(comment); });

var userListModel = function() { return users; };

var userModel = function(userId) { for (var i = 0; i < users.length; i++) { if (users[i]._id === userId) { return users[i]; } } return null; };

var photoOfUserModel = function(userId) { return photos.filter(function (photo) { return (photo.user_id === userId); }); };

var schemaModel = function() { return schemaInfo; };

var models = { userListModel: userListModel, userModel: userModel, photoOfUserModel: photoOfUserModel, schemaInfo: schemaModel };

if( typeof exports !== 'undefined' ) { // We're being loaded by the Node.js module loader ('require') so we use its // conventions of returning the object in exports. exports.models = models; } else { // We're not in the Note.js module loader so we assume we're being loaded // by the browser into the DOM. window.models = models; } })();

Sharu201101 commented 1 year ago

I've completed the development tasks for the database integration. All references to magic models have been removed, and MongoDB schemas/models are in place. The API routes have been implemented as specified, and object cloning through JSON serialization is working. Ready for code review.