This page will explain the programming framework and for this website and how the coding process is built to easily use templates or make updates to the contents/databases.
Future features to add:
Server is built using ExpressJS application with:
The files are all organized in the following folders:
Name | Function |
---|---|
config | contains database configuration for mySQL server |
contents | contains all the page contents in markdown files (.md) |
controllers | handles income requests/responses for routing subdomains |
inactive-pages | archive html/markdown files that are not used |
middlewares | handles authentication/validators for user accounts |
models | provide templates for navigation bars, lists, and database objects |
public | any assets (styles, js, html, resources) that is accessible through the browser |
routes | contains route paths for different subdomains with their actions |
services | contains backend functions to enable services for viewers |
temp | any test pages/scripts for the current interation |
utils | contains functions that simplify/organize the code |
views | contain pages/layouts to add specific partials to different templates |
Automated:
Name | Function |
---|---|
.vscode | automate sftp connection betweeen VSCode and the webhost |
bin | contains the executable server the build configs during debug/release |
node.modules | contains third-party libraries for NodeJS Express app |
package-lock.json | an automated record of all the NodeJS packages/versions |
The following descriptions will show files that create the foundation of the website:
Upon saving in VSCode, the code automatically uploads/downloads files between the local computer and the remotePath on KYLaNet's webhost.
{
"name": "Diagnostic KYLaNet",
"host": "ftp.***",
"protocol": "sftp",
"port": ***,
"username": ***,
"remotePath": ***,
"uploadOnSave": true,
"privateKeyPath": ***,
"passphrase": ***,
"ignore": [
".vscode",
".git",
".DS_Store",
"node_modules"
],
"connectTimeout":***,
"syncOption": {
"delete": ***
}
}
Some of these configurations include:
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
const session = require('express-session');
var hbs = require('express-handlebars');
var app = express();
app.use(connectLiveReload());
app.engine('hbs', hbs.engine({
allowProtoMethodsByDefault: true,
extname: 'hbs',
defaultLayout: 'noside.layout.hbs',
helpers: require('***').helpers,
layoutsDir: path.join(__dirname, '***'),
partialsDir : [
// path to your partials
path.join(__dirname, '***'),
]
}));
app.use(session({
secret: '***',
saveUninitialized: true,
resave: false,
cookie: { path: '/',
httpOnly: true,
secure: false,
maxAge: *** }}));
//#region engine setup
app.set('views', [
path.join(__dirname, '***')]);
app.set("view engine", "hbs");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "***")));
//#endregion
//#region routers
//routers
app.use("/",require("***/index.routes"));
app.use("/portfolio",require("***/portfolio.routes"));
app.use("/visualarts",require("***/creator.routes"));
app.use("/projects",require("***/projects.routes"));
//#endregion
//#region errors
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
res.locals.errCode = err.status?err.status:'500';
res.locals.errMsg = err.message;
res.locals.errName = err.name;
console.log('=== app Error ===');
console.error(err.stack);
// render the error page
res.status(err.status || 500);
res.render("error");
});
//#endregion
module.exports = app;
Some features:
The Resume page consists entirely of Markdown language
Header 1
==
Header 2
--
Continue typing
- then add a bullet point
- or (brackets) as normal
The hyperlinks are created [in these brackets]
###Markdown also applies to tables
| First | Second | Third Column |
| ----------- | ----------- | ----------- |
| This | is the | First Row |
| And | | So On |
The numbering
1. is also
2. the same
Controllers handles get/post information between the front-end users and the server.
This is especially useful for:
//Handling user login
const user_login_post = async (req, res) => {
await userService.validateUser(req,res);
let user = userService.getUserInfo();
if (user.authenticated) {
// simulating a database call
session = req.session;
session.user = user;
res.redirect(302, ("/user/profile/" + user.id));
}
else {
res.render("./user/login", {
title: "Login",
status: user.status,
layout: false
});
}
}
A model of what routers will send to the front-end
dataRouteModel: {
route:'/',
layout: false,
title: '',
session:null,
content: '',
modelSidenav: null,
modelToplist: null,
}
An example model of objects for the mySQL/mongoDB database
const Schema = new Schema({
name: {
type: String,
required: true,
},
value: {
type: Boolean,
required: true,
default: false,
},
}, { timestamps: true });
These functions initialize either when event handlers occur or when the page loads:
Some layouts used in KYLaNet:
The NoSide layout consists of:
<!DOCTYPE html>
<html>
<head>
{{>head}}
</head>
<body class="defBody">
{{>topnav}}
{{>toplist}}
{{>btnTop}}
<section class="secMain">
{{{body}}}
</section>
{{>footer}}
</body>
</html>
Some webservices include emailing the host owner and changing the layout based on who logs in:
var express = require('express');
var router = express.Router();
const emailService = require('../services/email.service');
const validator = require('../middlewares/validators/user.validator');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', {
title:'Home',
src:'home',
developed: true,
layout: 'def.layout.hbs' });
});
router.get('/contactus', function(req, res, next) {
res.render('contactus', {
title:'Contact Us',
src:'home',
layout: 'message.layout.hbs'});
});
router.get('/privacypolicy', function(req, res, next) {
res.render('./about/privacypolicy.about.hbs', {
title:'Privacy Policy',
src:'home',
layout: 'message.layout.hbs'});
});
router.post('/contactus', validator.emailUser,function (req,res,next){
res.render('contactus',{
title: 'Contact Us',
layout:'message.layout.hbs',
status: [{msg:'Email sent successfully!'},{msg:'Redirecting to home page in 3 seconds'}]
});
emailService.receiveEmail(req.body.name, req.body.email, req.body.subject, req.body.message)
});
module.exports = router;
Nodemailer creates a transporter to send the mail from the email input to the email listed in the transporter:
const nodemailer = require("nodemailer");
module.exports = {
receiveEmail: async (name, email, subject, message) => {
console.log("=== email service -- Func receiveEmail === ");
const transporter = nodemailer.createTransport({
host:"***.kylanet.com",
port: ***,
secure: true,
auth: {
user:"***.com",
pass: "***"
},
});
const mailOption = {
from: '***',
to: '***',
subject: subject,
text: `You got a message from
Email : ${email}
Name: ${name}
Message: ${message}`,
};
try {
await transporter.sendMail(mailOption);
console.log('--receiveEmail-- Message sent successfully!');
return Promise.resolve("Message Sent Successfully!");
} catch (err) {
console.log('--Error receiveEmail--', err);
}
}
}
During routing, the page will render pased text from the Content folder into HTML:
const fs = require("fs");
var marked = require('marked');
function loadContents(route) {
console.log("=== Func markdownService--loadContents ===");
let path = `./contents/${route}.content.md`;
console.log(path);
if (fs.existsSync(path)) {
// return a promise so that the html is there before rendering.
return new Promise(function (resolve, reject) {
fs.readFile(path, "utf8", (err, data) => {
let notFoundTemplate = `
<h2><i class="fa fa-exclamation-triangle text-warning"></i> 204 No Content</h2>
<p>The server successfully processed the request, but is not returning any content.</p>
<p>The content may be available again in the future.</p>`;
if (err) reject(notFoundTemplate);
//return resolve(converter.makeHtml(data));
return resolve(marked.parse(data));
// return resolve(data);
});
});
}
}
// ? to ? helper
function htmlEscapeToText (text)
{
return text.replace(/\&\#[0-9]*;|&/g, function (escapeCode) {
if (escapeCode.match(/amp/)) {
return '&';
}
return String.fromCharCode(escapeCode.match(/[0-9]+/));
});
}
module.exports = {
LoadContents: loadContents
};
KYLaNet primarily uses the NodeJS. To create NodeJS application:
Log into the cPanel and click Setup Node.js App
Configure the following:
Create package.json file in the NodeJS root folder
{
"name": ***,
"version": "1.0.0",
"description": ***,
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": ***,
"license": ***
}
Create an SSH connection to help install the proper node modules
Once connected, add your required node packages through the SSH connection
To sync your remote files locally, add an settings.json file in the .vscode folder
Lastly, configure your NodeJS app with a more simplified web application framework; KYLaNet uses Express.js
This website was first created in 2021, here is a full timeline of the modifications that were made:
Started by building the webhost from an Ubuntu server using my home network.
Bought the webhost service through HostArmada with the domain on NameCheap.
After manually coding the styles for navigation bars, I decided to use an Express.js app engine to simplify coding:
This was the start of the Folder Structure.
Implemented multiple components/services:
cPanel provides multiple website building options besides NodeJS (Node is what I picked to have full control over coding). There are Softaculous apps available:
User services was removed to implement later, after all website features are complete.
Some features include Softaculous apps that provide calendars/lists.
After a while, KYLaNet started having multiple errors such as:
Figured out that it was an issue with .htaccess
Restructured the theme and colour pallette.
Removed all the noise and cleaned up code.
Did not touch the website since the Reinvention in June but I could not access the website in a month.
There was an Error establishing a database connection error.
Added this current page in Projects to showcase my entire coding process in KYLaNet.
Note: This timeline view is sourced from dcode.