Practice refactoring an application

Assignment Help Operating System
Reference no: EM133280497

Objective: Work with a Postgres data source on the server and practice refactoring an application.

Getting Started:
Before we get started, we must add a new Postgres instance on our web-322 app in Elephant SQL.

• To begin: open your Assignment 4 folder in Visual Studio Code
• In this assignment, we will no longer be reading the files from the "data" folder, so remove this folder from the solution
• Inside your product-service.js module, delete any code that is not a module.exports function (ie: global variables, & "require" statements)
• Inside every single module.exports function (ie: module.exports.initialize(), module.exports.getAllProducts, module.exports.getProductsByCategory, etc.), remove all of the code and replace it with a return call to an "empty" promise that invokes reject() - (Note: we will be updating these later), ie:
return new Promise((resolve, reject) => { reject();
});

Installing "sequelize"
• Open the "integrated terminal" in Visual Studio Code and enter the commands to install the following modules:
o sequelize
o pg
o pg-hstore

• At the top of your product-service.js module, add the lines:
o const Sequelize = require('sequelize');
o var sequelize = new Sequelize('database', 'user', 'password', { host: 'host',
dialect: 'postgres', port: 5432,
dialectOptions: {
ssl: { rejectUnauthorized: false }
},
query: { raw: true }
});

Another Helper: formatDate

Part of the update to assignment 4 includes using real date values instead of strings. To help us keep our formatting consistent in the views from earlier assignments, you can use the following "formatDate" express-handlebars helper:

formatDate: function(dateObj){ let year = dateObj.getFullYear();
let month = (dateObj.getMonth() + 1).toString(); let day = dateObj.getDate().toString();
return `${year}-${month.padStart(2, '0')}-${day.padStart(2,'0')}`;
}

Creating Data Models
• Inside your product-service.js module (before your module.exports functions), define the following 2 data models and their relationship (HINT: See "Models (Tables) Introduction" in the Week 7 Notes for examples)

• belongsTo Relationship
Since a product belongs to a specific category, we must define a relationship between Products and Categories, specifically:

Product.belongsTo(Category, {foreignKey: 'category'});

This will ensure that our Product model gets a "category" column that will act as a foreign key to the Category model. When a Category is deleted, any associated Products will have a "null" value set to their "category" foreign key.

Update Existing product-service.js functions
Now that we have Sequelize set up properly, and our "Product" and "Category" models defined, we can use all of the Sequelize operations, discussed in the Week 7 Notes to update our product-service.js to work with the database:

initialize()
• This function will invoke the sequelize.sync() function, which will ensure that we can connect to the DB and that our Product and Category models are represented in the database as tables.
• If the sync() operation resolved successfully, invoke the resolve method for the promise to communicate back to server.js that the operation was a success.
• If there was an error at any time during this process, invoke the reject method for the promise and pass an appropriate message, ie: reject("unable to sync the database").

getAllProducts()
• This function will invoke the Product.findAll() function
• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

getProductsByCategory()
• This function will invoke the Product.findAll() function and filter the results by "category" (using the value passed to the function - ie: 1 or 2 or 3 ... etc)
• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

getProductsByMinDate()
• This function will invoke the Product.findAll() function and filter the results to only include products with the postDate value greater than or equal to the minDateStr (using the value passed to the function - ie: "2020-10-1"
... etc)
o NOTE: This can be accomplished using one of the many operators (see: "Operators" in: https://sequelize.org/v5/manual/querying.html), ie:

const { gte } = Sequelize.Op;

Product.findAll({ where: {
postDate: {
[gte]: new Date(minDateStr)
}
}
})

• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

getProductById()
• This function will invoke the Product.findAll() function and filter the results by "id" (using the value passed to the function - ie: 1 or 2 or 3 ... etc)
• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data[0], ie: only provide the first object) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

addProduct()

• Before we can work with productData correctly, we must once again make sure the published property is set properly. Recall: to ensure that this value is set correctly, before you start working with the productData object, add the line:
o productData.published = (productData.published) ? true : false;
• Additionally, we must ensure that any blank values ("") for properties are set to null. For example, if the user didn't enter a Title (causing productData.title to be ""), this needs to be set to null (ie: productData.title = null). You can iterate over every property in an object (to check for empty values and replace them with null) using a
for...in loop.
• Finally, we must assign a value for postDate. This will simply be the current date, ie "new Date()"
• Now that the published property is explicitly set (true or false), all of the remaining "" are replaced with null, and the "postDate" value is set we can invoke the Product.create() function
• If the Product.create() operation resolved successfully, invoke the resolve method for the promise to communicate back to server.js that the operation was a success.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "unable to create product".

getPublishedProducts()
• This function will invoke the Product.findAll() function and filter the results by "published" (using the value true)
• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

getPublishedProductsByCategory()
• This function will invoke the Product.findAll() function and filter the results by "published" and "category" (using the valuetrue for "published" and the value passed to the function - ie: 1 or 2 or 3 ... etc for "category" )
• If the Product.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

getCategories()
• This function will invoke the Category.findAll() function
• If the Category.findAll() operation resolved successfully, invoke the resolve method for the promise (with the data) to communicate back to server.js that the operation was a success and to provide the data.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "no results returned".

Updating the Navbar & Existing views (.hbs)
If we test the server now and simply navigate between the pages, we will see that everything still works, except we no longer have any products in our "Demos" or "Product" views, and no categories within our "Categories" view. This is to be expected (since there is nothing in the database), however we are not seeing an any error messages (just empty tables). To solve this, we must update our server.js file:

• /demos route
o Where we would normally render the "products" view with data
• ie: res.render("demos", {products:data});
we must place a condition there first so that it will only render "products" if data.length> 0. Otherwise, render the page with an error message,
• ie: res.render("demos",{ message: "no results" });
o If we test the server now, we should see our "no results" message in the /demos route
o NOTE: We must still show messages if the promise(s) are rejected, as before
• /categories route
o Using the same logic as above (for the /products route) update the /categories route as well
o If we test the server now, we should see our "no results" message in the /categories route
o NOTE: We must still show an error message if the promise is rejected, as before

For this assignment, we will also be moving the "Add Product" link and inserting it into the "demos" view, as well as writing code to handle adding a new Category

• "Add Product"
o Remove the link ( {{#navLink}} ... {{/navLink}} ) from the "navbar-nav" element inside the main.hbs file
o Inside the "demos.hbs" view (Inside the <h2>Demos</h2> element), add the below code to create a "button" that links to the "/products/add" route:
• <a href="/products/add" class="btn btn-success pull-right">Add Product</a>
• "Add Category"
o You will notice that currently, we have no way of adding a new category. However, while we're adding our "add" buttons, it makes sense to create an "add Category" button as well (we'll code the route and product service function later in this assignment).
o Inside the "categories.hbs" view (Inside the <h2>Categories</h2> element), add the below code to create a "button" that links to the "/categories/add" route:
• <a href="/categories/add" class="btn btn-success pull-right">Add Category</a>

Adding new product-service.js functions
So far, all our product-service functions have focused primarily on fetching Product / Category data as well as adding new Products. If we want to allow our users to add Categories as well, we must add some additional logic to our product-service.

Additionally, we will also let users delete Products and Categories. To achieve this, the following (promise-based) functions must be added to product-service.js:

addCategory(categoryData)
• Like addProduct(productData),we must ensure that any blank values in categoryData are set to null (follow the same procedure)
• Now that all of the "" are replaced with null, we can invoke the Category.create() function
• If the Category.create() operation resolved successfully, invoke the resolve method for the promise to communicate back to server.js that the operation was a success.
• If there was an error at any time during this process, invoke the reject method and pass a meaningful message, ie: "unable to create category"

deleteCategoryById(id)
• The purpose of this method is simply to "delete" categories using Category.destroy() for a specific category by "id". Ensure that this function returns a promise and only "resolves" if the Category was deleted ("destroyed"). "Reject" the promise if the "destroy" method encountered an error (was rejected).

deleteProductById(id)
• This method is nearly identical to the "deleteCategoryById(id)" function above, only instead of invoking "Category.destroy()" for a specific id, it will instead use Product.destroy()

Updating Routes (server.js) to Add / Remove Categories & Products
Now that we have our product-service up to date to deal with adding / removing product and category data, we need to update our server.js file to expose a few new routes that provide a form for the user to enter data (GET) and for the server to receive data (POST) as well as let the user delete products / categories by Id.

Additionally, since categories does not require users to upload an image, we should also include the regular express.urlencoded() middleware:

• app.use(express.urlencoded({extended: true}));

Once this is complete, add the following routes:

/categories/add

• This GET route is very similar to your current "/products/add" route - only instead of "rendering" the "addProduct" view, we will instead set up the route to "render" an "addCategory" view (added later)

/categories/add
• This POST route is very similar to the logic inside the "processProduct()" function within your current "/product/add" POST route - only instead of calling the addProduct() product-service function, you will instead call your newly created addCategory() function with the POST data in req.body (NOTE: there's also no "featureImage" property that needs to be set)
• Instead of redirecting to /demos when the promise has resolved (using .then()), we will instead redirect to
/categories

/categories/delete/:id
• This GET route will invoke your newly created deleteCategoryById(id)product-service method. If the function resolved successfully, redirect the user to the "/categories" view. If the operation encountered an error, return a status code of 500 and the plain text: "Unable to Remove Category / Category not found)"

/demos/delete/:id
• This GET route functions almost exactly the same as the route above, only instead of invoking deleteCategoryById(id), it will instead invoke deleteProductById(id) and return an appropriate error message if the operation encountered an error
Updating Views to Add & Delete Categories / Products
In order to provide user interfaces to all of our new functionality, we need to add / modify some views within the "views" directory of our app:

addCategory.hbs
• Fundamentally, this view is nearly identical to the addProduct.hbs view, however there are a few key changes:
o The header (<h2>...</h2>) must read "Add Category"
o The form must submit to "/categories/add" and the "enctype" property can be removed (multipart/form-data no longer required)
o There must be only one input field (type: "text", name: "category", label: "Category:")
• NOTE: You may wish to add the autofocus attribute here, since it is the only form control available to the user
o The submit button must read "Add Category"
• When complete, your view should appear as:

categories.hbs
• To enable users to access also delete categories, we need to make one important change to our current categories.hbs file:
o Add a "remove" link for every category within in a new column of the table (at the end) - Note: The header for the column should not contain any text (ie: <th></th>). The links in every row should be styled as a button (ie: class="btn btn-danger") with the text "remove" and simply link to the newly created GET route "categories/delete/categoryId" where categoryId is the categoryid of the category in the current row.

Once this button is clicked, the category will be deleted and the user will be redirected back to the "/categories" list. (Hint: See the sample solution if you need help with the table formatting)

Updating the "Categories" List when Adding a new Product
Now that users can add new Categories, it makes sense that all of the Categories are available when adding a new Product, should consist of all the current categories in the database (instead of just 1...5). To support this new functionality, we must make a few key changes to the corresponding route & view:

"/products/add" route
• Since the "addProduct" view will now be working with actual Categories, we need to update the route to make a call to our product-service module to "getCategories".
• Once the getCategories() operation has resolved, we then "render" the " addProduct view (as before), however this time we will and pass in the data from the promise, as "categories", ie: res.render("addProduct",
{categories: data});
• If the getCategories() promise is rejected (using .catch), "render" the "addProduct" view anyway (as before), however instead of sending the data from the promise, send an empty array for "categories, ie: res.render("addProduct", {categories: []});
"addProduct.hbs" view
• Update the: <select class="form-control" name="category" id="category">...</select> element to use the new handlebars code:

{{#if categories}}

<select class="form-control" name="category" id="category">
<option value="">Select Category</option>
{{#each categories}}
<option value="{{id}}">{{category}}</option>
{{/each}}
</select>
{{else}}
<div>No Categories</div>
{{/if}}

• Now, if we have any categories in the system, they will show up in our view - otherwise we will show a div element that states "No Categories"

Updating server.js, product-service.js & demos.hbs to Delete Products
To make the user-interface more usable, we should allow users to also remove (delete) products that they no longer wish to be in the system. This will involve:
• Creating a new function (ie: deleteProductById(id)) in product-service.js to "delete" products using Product.destroy()

• Create a new GET route (ie: "/demos/delete/:id") that will invoke your newly created deleteProductById(id)product-service method. If the function resolved successfully, redirect the user to the "/demos" view. If the operation encountered an error, return a status code of 500 and the plain text: "Unable to Remove Product / Product not found)"
• Update the demos.hbs view to include a "remove" link for every product within in a new column of the table (at the end) - Note: The header for the column should not contain any text. The links in every row should be styled as a button (ie: class="btn btn-danger") with the text "remove" and link to the newly created GET route "product/delete/id" where id is the id of the product in the current row. Once this button is clicked, the product will be deleted and the user will be redirected back to the "/demos" list.

• Lastly, use Postman to test deleting a product. Take a screenshot and attach to the submission

Attachment:- Application.rar

Reference no: EM133280497

Questions Cloud

Define malnutrition and identify a specific disease : Define malnutrition and identify a specific disease that can result from it. Evaluate nutritional recommendations to help combat the disease
Give examples of outcomes from the amplified limbic system : Give examples of outcomes from the amplified limbic system, and/or delayed prefrontal cortex experienced by any of these adolescents
What role should designers and integrators play : What role should designers and integrators play in helping learners navigate misinformation and the potential for radicalization
What did you like about the guest speaker presentation : What did you like about the guest speaker presentation? Would you consider a career in the guest speaker's field? Why or why not
Practice refactoring an application : Work with a Postgres data source on the server and practice refactoring an application and Create a new GET route
What are some popular archetypes that have religious origin : What are some popular archetypes that have a religious origin? What are some examples of a story with a religious allegory? What makes it an allegory
What is a quasi-judicial body : What is a quasi-judicial body, and what kinds of decisions can be reached through adjudication and other quasi-judicial proceedings
Discuss criticisms and alternatives to james-lange theory : Discuss the criticisms and alternatives to the James-Lange theory of emotions. Focus on Schacter and Singer's cognitive theory of emotion
Explain risk and present the different components of risk : "Visibility and velocity are the foundations for a responsive supply chain", explain this statement in more details and give an example

Reviews

Write a Review

Operating System Questions & Answers

  Maintaining network configuration

In a Windows 2003 server network discuss various devices such as: repeaters, routers and gateways. Detemrine the functions for those devices? At which layer of the OSI model do those devices operate?

  Discuss how the contents of a directory are impacted

Discuss how the contents of a directory are impacted (and when and/or if they are available for use) when a file system is mounted on that directory.

  Describe the type of flaw or condition within the os

Describe the type of flaw or condition within the OS that allowed the attack and how the flaw was addressed or countered. You need at least two references.

  Add support for php files on the www.private_club.com

Require anyone accessing the directory to login using the login "member" and password "secret"

  What are entities that are swapped out of the main memory

What are the entities that are swapped out of the main memory while swapping the process out of the main memory? What is Fork swap?

  Erm in practice at university of california health system

Explain how improvement is measured with KPIs and give one example related to Human Capital and how this KPI might help you improve your organization.

  Implement dynamic scheduling

Lab Context-switching, Kernel Instrumentation, and Dynamic Scheduling - context-switching to handle corner cases when instrumenting XINU to monitor system

  How operating system is clearly superior for any application

Consider the advantages and disadvantages of each major operating system that Amy might use on the Web server. If you don't think that one operating system is clearly superior for this application, describe why.

  Identify and describe three concerns dealing with internet

A process is said to be I/O-bound if it requires a lot of I/O operations, whereas a process that consists of mostly computations within the CPU/memory system is said to be compute-bound

  CYS403 Network and Application Security Assignment

CYS403 Network and Application Security Assignment Help and Solution, Excelsior College - Assessment Writing Service - configure a RADIUS server.

  Different memory allocation and deallocation techniques

The objective of this is to simulate and evaluate different memory allocation/deallocation techniques (first fit, next fit, best fit, and worst fit)when a linked list is used to keep track of memory usage.

  Developing ipv6

What is the primary reason for developing IPv6

Free Assignment Quote

Assured A++ Grade

Get guaranteed satisfaction & time on delivery in every assignment order you paid with us! We ensure premium quality solution document along with free turntin report!

All rights reserved! Copyrights ©2019-2020 ExpertsMind IT Educational Pvt Ltd