Comment app.js and server.js

This commit is contained in:
Thomas Wade 2018-10-30 18:11:54 +10:30
parent 30a618ad06
commit 14233b6954
2 changed files with 55 additions and 10 deletions

View File

@ -5,12 +5,8 @@ var bodyParser = require('body-parser'); // Data conversion, JSON parsing
// Set up Express // Set up Express
var app = express(); var app = express();
app.use(express.static("./static/")); // Serve static files from /static/ app.use(express.static("./static/")); // Serve static files from /static
app.use(express.json()); // Parse JSON in requests app.use(express.json()); // Parse JSON in requests
// app.use("/", (req, res, next) => // Finally send a 404 page
// {
// res.status(404).sendFile("404.html", {"root": "./"});
// });
// Posts route, return posts.json // Posts route, return posts.json
app.get("/api/posts", function(req, res) app.get("/api/posts", function(req, res)
@ -18,32 +14,39 @@ app.get("/api/posts", function(req, res)
res.json(JSON.parse(fs.readFileSync('./data/posts.json'))); res.json(JSON.parse(fs.readFileSync('./data/posts.json')));
}); });
// Posts route, digest received post // Posts route, digest incoming post
app.post("/api/posts", function(req, res) app.post("/api/posts", function(req, res)
{ {
// Read in posts.json
var postsFile = fs.readFileSync('./data/posts.json'); var postsFile = fs.readFileSync('./data/posts.json');
var posts = JSON.parse(postsFile); var posts = JSON.parse(postsFile);
// Verify incoming post matches expected schema
var incomingData = req.body; var incomingData = req.body;
if (validatePost(incomingData)) if (validatePost(incomingData))
{ {
// Prepend the incoming post to the post list
posts.unshift(incomingData); posts.unshift(incomingData);
} }
else else
{ {
// Complain that we haven't been given what we're expecting
res.status(400).json({"error":"Failed to validate post"}); res.status(400).json({"error":"Failed to validate post"});
return; return;
} }
// Try to save the updated posts object
fs.writeFile('./data/posts.json', JSON.stringify(posts), (e) => fs.writeFile('./data/posts.json', JSON.stringify(posts), (e) =>
{ {
if (e) if (e)
{ {
// Tell the client we've hit a snag and dump the error to the console
res.sendStatus(500); res.sendStatus(500);
throw e; throw e;
} }
}); });
// Tell the client all is good and that they shouldn't expect any content
res.sendStatus(204); res.sendStatus(204);
}); });
@ -71,7 +74,17 @@ app.listen(8080, function()
console.log("Listening on port 8080"); console.log("Listening on port 8080");
}); });
// Validates a post object conforms to the standard we're expecting // Verifies the post object conforms to the standard we're expecting
// Each post should conform to the following template:
// {
// "title":"",
// "author":"",
// "date":0,
// "tags":[
// ""
// ],
// "content":""
// }
function validatePost(post) function validatePost(post)
{ {
try try

View File

@ -1,8 +1,10 @@
var app = angular.module("app", ["ngRoute", "ngSanitize", "ngTagsInput"]); var app = angular.module("app", ["ngRoute", "ngSanitize", "ngTagsInput"]);
// Provider configuration
app.config( app.config(
function ($routeProvider, $locationProvider) function ($routeProvider, $locationProvider)
{ {
// Configure routes
$routeProvider $routeProvider
.when("/", {templateUrl: "views/blog.html", controller: "blog"}) .when("/", {templateUrl: "views/blog.html", controller: "blog"})
.when("/create", {templateUrl: "views/create.html", controller: "create"}) .when("/create", {templateUrl: "views/create.html", controller: "create"})
@ -10,35 +12,45 @@ app.config(
.when("/faq", {templateUrl: "views/faq.html", controller: "faq"}) .when("/faq", {templateUrl: "views/faq.html", controller: "faq"})
.otherwise({templateUrl: "404.html"}); .otherwise({templateUrl: "404.html"});
// Enable HTML5-style routing
// URLs will be shown as http://host/view instead of http://host/#!/view
$locationProvider.html5Mode({enabled: true, requireBase: false}); $locationProvider.html5Mode({enabled: true, requireBase: false});
} }
); );
// Non-provider configuration
app.run(($anchorScroll) => app.run(($anchorScroll) =>
{ {
// Apply 100px scroll offset to compensate for fixed header
$anchorScroll.yOffset = 100; $anchorScroll.yOffset = 100;
}) })
// Blog view controller
app.controller("blog", ["$scope", "$http", app.controller("blog", ["$scope", "$http",
function($scope, $http) function($scope, $http)
{ {
$scope.posts = []; $scope.posts = [];
// Retrieve posts from server and populate array
$http.get("/api/posts") $http.get("/api/posts")
.then((r) => { $scope.posts = angular.fromJson(r.data); }); .then((r) => { $scope.posts = angular.fromJson(r.data); });
} }
]); ]);
// Create view controller
app.controller("create", ["$scope", "$http", app.controller("create", ["$scope", "$http",
function($scope, $http) function($scope, $http)
{ {
// Initialise fields
$scope.title = ""; $scope.title = "";
$scope.author = ""; $scope.author = "";
$scope.content = ""; $scope.content = "";
$scope.tags = []; $scope.tags = [];
// Disable preview by default
$scope.previewing = false; $scope.previewing = false;
// Handle post submission
$scope.onSubmit = function() $scope.onSubmit = function()
{ {
// Create the post object // Create the post object
@ -59,24 +71,31 @@ app.controller("create", ["$scope", "$http",
$scope.content = ""; $scope.content = "";
$scope.tags = []; $scope.tags = [];
// Alert the user that it has been submitted
alert("Post has been submitted."); alert("Post has been submitted.");
} }
// Handle tag additions
$scope.onTagAdding = ($tag) => $scope.onTagAdding = ($tag) =>
{ {
// Prepend a hash if the tag doesn't already start with one
if (!$tag.text.startsWith("#")) if (!$tag.text.startsWith("#"))
$tag.text = "#" + $tag.text; $tag.text = "#" + $tag.text;
// Return whether the tag has already been added
return $scope.tags.indexOf($tag.text) === -1; return $scope.tags.indexOf($tag.text) === -1;
} }
// Toggle post preview
$scope.onPreview = () => $scope.onPreview = () =>
{ {
// Invert preview switch
$scope.previewing = !$scope.previewing; $scope.previewing = !$scope.previewing;
// Update HTML on preview to avoid parsing for each character change // Update HTML on preview to avoid parsing for each character change
$scope.previewHtml = () => $scope.previewHtml = () =>
{ {
// Only parse if there is content and if the preview is toggling on
return $scope.content && $scope.previewing return $scope.content && $scope.previewing
? marked($scope.content) ? marked($scope.content)
: ""; : "";
@ -85,46 +104,54 @@ app.controller("create", ["$scope", "$http",
} }
]); ]);
// About view controller
app.controller("about", ["$scope", "$http", app.controller("about", ["$scope", "$http",
function($scope, $http) function($scope, $http)
{ {
$scope.aboutContent = ""; $scope.aboutContent = "";
// Get about content from the server and populate the view
$http.get("/api/about") $http.get("/api/about")
.then((r) => { $scope.aboutContent = angular.fromJson(r.data).content; }); .then((r) => { $scope.aboutContent = angular.fromJson(r.data).content; });
} }
]); ]);
// FAQ view controller
app.controller("faq", ["$scope", "$http", "$location", "$anchorScroll", app.controller("faq", ["$scope", "$http", "$location", "$anchorScroll",
function($scope, $http, $location, $anchorScroll) function($scope, $http, $location, $anchorScroll)
{ {
$scope.entries = [] $scope.entries = []
// Get FAQ entries from the server and populate the array
$http.get("/api/faq") $http.get("/api/faq")
.then((r) => { $scope.entries = angular.fromJson(r.data) }); .then((r) => { $scope.entries = angular.fromJson(r.data) });
// Handle scrolling to different entries
$scope.scrollTo = (hash) => $scope.scrollTo = (hash) =>
{ {
// Use $anchorScroll to avoid weird issues with hashes in the URL
$anchorScroll(hash); $anchorScroll(hash);
}; };
} }
]); ]);
// Navbar controller
app.controller("navButtons", ["$scope", "$location", app.controller("navButtons", ["$scope", "$location",
function($scope, $location) function($scope, $location)
{ {
// Set the current relative path // Set the current relative path
// Helpful to set the navButtons appropriately when refreshing // Useful for setting the navButtons appropriately when navigating to a deep linked view
$scope.current = $location.path(); $scope.current = $location.path();
// Changes location to the given target and sets the current path // Handle navButton clicks
$scope.navClick = (target) => $scope.navClick = (target) =>
{ {
// Change location to the given target and set the current path
$location.path(target); $location.path(target);
$scope.current = target; $scope.current = target;
} }
// Applies the 'current' class if the target matches the current path // Apply the 'current' class if the target matches the current path
$scope.isCurrent = (target) => $scope.isCurrent = (target) =>
{ {
return $scope.current == target ? "current" : ""; return $scope.current == target ? "current" : "";
@ -136,21 +163,26 @@ app.controller("navButtons", ["$scope", "$location",
app.controller("head", ["$scope", app.controller("head", ["$scope",
function($scope) function($scope)
{ {
// Set the pag title
$scope.title = "Lemonblog"; $scope.title = "Lemonblog";
} }
]); ]);
// Footer controller
app.controller("footer", ["$scope", app.controller("footer", ["$scope",
function($scope) function($scope)
{ {
// Set the current year for the copyright string
$scope.year = new Date().getFullYear(); $scope.year = new Date().getFullYear();
} }
]); ]);
// Markdown filter
app.filter("markdown", () => app.filter("markdown", () =>
{ {
return function(input) return function(input)
{ {
// Parse input as markdown and return resulting HTML
return marked(input); return marked(input);
} }
}); });