Skip to content

Commit eb5dae3

Browse files
committed
* added authorization in server side (API are safe now)
* review functionality added
1 parent 9fbfeb1 commit eb5dae3

12 files changed

+238
-63
lines changed

JupiterAirAPI/.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
/node_modules
44

55
#config
6-
/config/default.json
6+
/config/default.json
7+
8+
#angular UI
9+
/public

JupiterAirAPI/controllers/airline.js

+108-42
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,69 @@ const mongoose = require('mongoose');
22
let Airline = require('../models/Airline');
33

44
module.exports.addAirlineDetails = (req, res) => {
5-
let airline = new Airline();
6-
airline.name = req.body.name;
7-
airline.slogan = req.body.slogan;
8-
airline.founded_on = req.body.founded_on;
9-
airline.origin_contry = req.body.origin_contry;
10-
airline.hubs = req.body.hubs;
11-
airline.focus_cities = req.body.focus_cities;
12-
airline.best_travel_reward = req.body.best_travel_reward;
13-
airline.save((err) => {
14-
if (err) { console.error(err) }
15-
res.status(200);
16-
res.json(airline);
17-
});
18-
console.log(req.body);
19-
console.log(airline);
5+
6+
if (!req.payload._id) {
7+
res.status(401).json({
8+
"message": "UnauthorizedError: Dont try in novice hacker way"
9+
});
10+
} else {
11+
let airline = new Airline();
12+
airline.name = req.body.name;
13+
airline.slogan = req.body.slogan;
14+
airline.founded_on = req.body.founded_on;
15+
airline.origin_contry = req.body.origin_contry;
16+
airline.hubs = req.body.hubs;
17+
airline.focus_cities = req.body.focus_cities;
18+
airline.best_travel_reward = req.body.best_travel_reward;
19+
airline.save((err) => {
20+
if (err) { console.error(err) }
21+
res.status(200);
22+
res.json(airline);
23+
});
24+
}
2025
}
2126
module.exports.updateAirlineDetails = (req, res) => {
22-
Airline.findByIdAndUpdate(
23-
{ _id: req.params.id },
24-
{
25-
$set: {
26-
name: req.body.name,
27-
slogan: req.body.slogan,
28-
founded_on: req.body.founded_on,
29-
origin_contry: req.body.origin_contry,
30-
hubs: req.body.hubs,
31-
focus_cities: req.body.focus_cities,
32-
best_travel_reward: req.body.best_travel_reward
33-
}
34-
}, (err, item) => {
35-
if (err) {
36-
res.json({ mag: "Unable to update item", err: err });
37-
} else {
38-
res.json({ msg: 'Item updated successfully' });
39-
}
27+
if (!req.payload._id) {
28+
res.status(401).json({
29+
"message": "UnauthorizedError: Dont try in novice hacker way"
4030
});
41-
31+
} else {
32+
Airline.findByIdAndUpdate(
33+
{ _id: req.params.id },
34+
{
35+
$set: {
36+
name: req.body.name,
37+
slogan: req.body.slogan,
38+
founded_on: req.body.founded_on,
39+
origin_contry: req.body.origin_contry,
40+
hubs: req.body.hubs,
41+
focus_cities: req.body.focus_cities,
42+
best_travel_reward: req.body.best_travel_reward
43+
}
44+
}, (err, item) => {
45+
if (err) {
46+
res.json({ msg: "Unable to update item", err: err });
47+
} else {
48+
res.json({ msg: 'Item updated successfully' });
49+
}
50+
});
51+
}
4252
}
4353
module.exports.deleteAirlineDetails = (req, res) => {
44-
Airline.remove(
45-
{ _id: req.params.id }, (err, item) => {
46-
if (err) {
47-
res.json({ mag: "Unable to delete item", err: err });
48-
} else {
49-
res.json({ msg: 'Item delete successfully' });
50-
}
54+
if (!req.payload._id) {
55+
res.status(401).json({
56+
"message": "UnauthorizedError: Dont try in novice hacker way"
5157
});
58+
} else {
59+
Airline.remove(
60+
{ _id: req.params.id }, (err, item) => {
61+
if (err) {
62+
res.json({ msg: "Unable to delete item", err: err });
63+
} else {
64+
res.json({ msg: 'Item delete successfully' });
65+
}
66+
});
67+
}
5268
}
5369
module.exports.getAirlinesDetails = (req, res) => {
5470

@@ -57,4 +73,54 @@ module.exports.getAirlinesDetails = (req, res) => {
5773
});
5874
}
5975
module.exports.getAirlineDetails = (req, res) => {
60-
}
76+
}
77+
module.exports.submitReview = (req, res) => {
78+
if (!req.payload._id) {
79+
res.status(401).json({
80+
"message": "UnauthorizedError: Dont try in novice hacker way"
81+
});
82+
} else {
83+
let userid = req.payload._id;
84+
let airlineid = req.params.id;
85+
Airline.findById({ _id: airlineid },
86+
(err, item) => {
87+
if (err) {
88+
res.json({ msg: "Unable to get airline", err: err });
89+
} else {
90+
let existingRating = item.rating.find(function (ele) {
91+
return ele.username == userid;
92+
});
93+
let existingComment = item.comments.find(function (ele) {
94+
return ele.username == userid;
95+
});
96+
if (existingRating) {
97+
item.rating.id(existingRating._id).rate = req.body.rating;
98+
item.comments.id(existingComment._id).comment = req.body.comment;
99+
item.save();
100+
res.json({ msg: 'Ratings updated successful' });
101+
} else {
102+
Airline.findByIdAndUpdate({ _id: airlineid }, {
103+
$push: {
104+
rating: {
105+
username: userid,
106+
rate: req.body.rating
107+
},
108+
comments: {
109+
username: userid,
110+
comment: req.body.comment
111+
}
112+
}
113+
}, (err, data) => {
114+
if (err) {
115+
res.json({ msg: "Unable to store your review", err: err });
116+
} else {
117+
res.json({ msg: 'Ratings updated successful' });
118+
}
119+
});
120+
}
121+
}
122+
})
123+
}
124+
}
125+
126+

JupiterAirAPI/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ app.use(function (err, req, res, next) {
3838
}
3939
});
4040

41-
app.get('/', (req, res) => res.send('Dont try to play with our API'));
41+
app.use('/', express.static('public'));
4242

4343
app.listen(PORT
4444
, () => console.log(`app listening on port ${PORT}!`));

JupiterAirAPI/routes/api.route.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,19 @@ router.use(function timeLog(req, res, next) {
1818
let ctrlAuth = require('../controllers/authentication');
1919
let airline_controller = require('../controllers/airline');
2020

21-
// define the home page route
22-
router.get('/admin', auth, function (req, res) {
23-
res.send('Airlines home page')
24-
})
2521
// retrive the airlines
2622
router.get('/airlines', airline_controller.getAirlinesDetails)
2723
// retrive the airline
2824
router.get('/airline/:id', airline_controller.getAirlineDetails)
2925
// add the airlines
30-
router.post('/airline', airline_controller.addAirlineDetails)
26+
router.post('/airline', auth, airline_controller.addAirlineDetails)
3127
// update the airlines
32-
router.put('/airline/:id', airline_controller.updateAirlineDetails)
28+
router.put('/airline/:id', auth, airline_controller.updateAirlineDetails)
3329
// delete the airlines
34-
router.delete('/airline/:id', airline_controller.deleteAirlineDetails)
30+
router.delete('/airline/:id', auth, airline_controller.deleteAirlineDetails)
31+
32+
// add review
33+
router.post('/airline/:id/review', auth, airline_controller.submitReview)
3534

3635
// authentication
3736
router.post('/register', ctrlAuth.register);

JupiterAirUI/angular.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"build": {
1414
"builder": "@angular-devkit/build-angular:browser",
1515
"options": {
16-
"outputPath": "dist/JupiterAirUI",
16+
"outputPath": "../JupiterAirAPI/public",
1717
"index": "src/index.html",
1818
"main": "src/main.ts",
1919
"polyfills": "src/polyfills.ts",

JupiterAirUI/src/app/app.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ <h5 class="my-0 mr-md-auto font-weight-normal">
99
<a class="py-2 px-2 d-none d-md-inline-block" href="#">Product</a>
1010
</div>
1111
</nav>
12-
<span *ngIf="auth.isLoggedIn()">Welcome {{auth.getUserDetails()?.username}}</span>
12+
<span *ngIf="auth.isLoggedIn()">Welcome {{auth.getUserDetails()?.name}}</span>
1313
<a *ngIf="!auth.isLoggedIn()" routerLink="login" class="btn btn-outline-primary">login</a>
1414
<a *ngIf="auth.isLoggedIn()" (click)="auth.logout()" class="btn btn-outline-primary ml-3">logout</a>
1515
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#star_review{
2+
cursor: pointer;
3+
}
4+
.fill-star{
5+
color: gold;
6+
}

JupiterAirUI/src/app/home/home.component.html

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<div class="alert alert-danger alert-dismissible" *ngIf="isWarning">
2+
{{warningMessage}}</div>
13
<section class="row">
24
<div *ngFor="let airline of airlineList" class="col-md-4 col-sm-6">
35
<div class="card mb-4 box-shadow">
@@ -11,9 +13,10 @@ <h4>{{airline.name}}</h4>
1113
<div class="d-flex justify-content-between align-items-center">
1214
<div class="btn-group">
1315
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="viewAirlineDetails(viewAirlineTemplate,airline)">View</button>
14-
<button type="button" class="btn btn-sm btn-outline-secondary">Comment</button>
16+
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="addReview(addReviewTemplate,airline)">Add Review</button>
1517
</div>
16-
<small class="text-muted">9 mins</small>
18+
<span class="badge badge-success">{{getAverageRating(airline.rating)}} star</span>
19+
<small class="text-muted">{{airline.comments.length}} Comments</small>
1720
</div>
1821
</div>
1922
</div>
@@ -34,9 +37,49 @@ <h4 class="modal-title">{{airlineSingle.name}}</h4>
3437
<br/> Hubs : {{airlineSingle.hubs}}
3538
<br/> Rewards received: {{airlineSingle.best_travel_reward}}
3639
</p>
40+
<h5>Comments:</h5>
41+
<ul>
42+
<li *ngFor="let comment of airlineSingle.comments">{{comment.comment}}</li>
43+
</ul>
44+
<span class="alert alert-info" *ngIf="!airlineSingle.comments.length">Be the first reviewer!</span>
3745
</div>
3846
<div class="modal-footer">
3947
<!-- <button type="button" class="btn btn-outline-dark" (click)="c('Close click')">Cancel</button> -->
4048
<button type="button" class="btn btn-dark" (click)="c('close')">Close</button>
4149
</div>
50+
</ng-template>
51+
52+
53+
<ng-template #addReviewTemplate let-c="close" let-d="dismiss">
54+
<div class="modal-header">
55+
<h4 class="modal-title">{{airlineSingle.name}}</h4>
56+
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
57+
<span aria-hidden="true">&times;</span>
58+
</button>
59+
</div>
60+
<div class="modal-body">
61+
<form #reviewform>
62+
<div id="star_review">
63+
<input type="radio" name="rating" value="1" />1,
64+
<input type="radio" name="rating" value="2" />2,
65+
<input type="radio" name="rating" value="3" />3,
66+
<input type="radio" name="rating" value="4" />4,
67+
<input type="radio" name="rating" value="5" checked/>5
68+
<i class="material-icons" (mouseenter)="mouseStarEnter(1)">star</i>
69+
<i class="material-icons" (mouseenter)="mouseStarEnter(2)">star</i>
70+
<i class="material-icons" (mouseenter)="mouseStarEnter(3)">star</i>
71+
<i class="material-icons" (mouseenter)="mouseStarEnter(4)">star</i>
72+
<i class="material-icons" (mouseenter)="mouseStarEnter(5)">star</i>
73+
</div>
74+
<div class="form-group">
75+
<label for="comment">Comment:</label>
76+
<textarea class="form-control" id="comment" name="comment" [(ngModel)]="comment"></textarea>
77+
</div>
78+
<button class="btn btn-primary" type="submit" (click)="c(reviewform)">Submit</button>
79+
</form>
80+
</div>
81+
<div class="modal-footer">
82+
<!-- <button type="button" class="btn btn-outline-dark" (click)="c('Close click')">Cancel</button> -->
83+
<!-- <button type="button" class="btn btn-dark" (click)="c('close')">Close</button> -->
84+
</div>
4285
</ng-template>

JupiterAirUI/src/app/home/home.component.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
22
import { AirlineService } from '../services/airline.service';
33
import { Airline } from '../models/Airline';
44
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';
5+
import { AuthenticationService } from '../services/authentication.service';
56

67
@Component({
78
selector: 'app-home',
@@ -12,7 +13,10 @@ export class HomeComponent implements OnInit {
1213

1314
airlineList: Airline[];
1415
airlineSingle: Airline;
15-
constructor(private airlineService: AirlineService, private modalService: NgbModal) { }
16+
isWarning = false;
17+
warningMessage: String;
18+
19+
constructor(private airlineService: AirlineService, private modalService: NgbModal, private authService: AuthenticationService) { }
1620

1721
ngOnInit() {
1822
this.loadAirlines();
@@ -37,6 +41,7 @@ export class HomeComponent implements OnInit {
3741
});
3842
}
3943
private getDismissReason(reason: any): string {
44+
this.airlineSingle = new Airline();
4045
if (reason === ModalDismissReasons.ESC) {
4146
return 'by pressing ESC';
4247
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
@@ -45,4 +50,44 @@ export class HomeComponent implements OnInit {
4550
return `with: ${reason}`;
4651
}
4752
}
53+
getAverageRating(rating: any) {
54+
if (rating.length === 0) {
55+
return 'No';
56+
}
57+
const avgRate = rating.reduce(function (ele, currentValue) {
58+
return ele.rate + currentValue.rate;
59+
});
60+
return (avgRate.rate || avgRate) / rating.length;
61+
}
62+
showWarning(message: String) {
63+
this.isWarning = true;
64+
this.warningMessage = message;
65+
}
66+
addReview(content, airline: Airline) {
67+
if (!this.authService.isLoggedIn()) { this.showWarning('You should login first before review'); return; }
68+
this.airlineSingle = airline;
69+
this.modalService.open(content).result.then((result) => {
70+
const reviewData = {
71+
airline_id: this.airlineSingle._id,
72+
rating: result.rating.value,
73+
comment: result.comment.value
74+
};
75+
this.airlineService.submitReview(reviewData).subscribe(res => {
76+
console.log(res);
77+
this.loadAirlines();
78+
}, err => {
79+
// if(err.statusText===" ")
80+
console.error(err);
81+
});
82+
}, (reason) => {
83+
console.log(`Dismissed ${this.getDismissReason(reason)}`);
84+
});
85+
}
86+
87+
mouseStarEnter(position: Number) {
88+
for (let i = 0; i < position; i++) {
89+
console.log(i);
90+
91+
}
92+
}
4893
}

0 commit comments

Comments
 (0)