Initial commit of stuff migrated from inkletblot.com

This commit is contained in:
Solomon Laing 2020-01-16 20:48:27 +10:30
parent b854e199d9
commit 86e793d8cb
23 changed files with 2129 additions and 2 deletions

View File

@ -1,2 +1,35 @@
# forum.com # README for inkletblot.com
The angularjs front-end for my forum, recently moved from inkletblot.com
This is an angularjs project, currently it is a total rebuild of inkletblot.com using the framework.
In the future the forum will be separated from the gallery and 'things' pages.
> I know things is a stupid name, can you come up with a better one?
## TODO!
### General:
* Fix server responses to be all the same.
* this is kinda done, need to make all .sends() the same.
* Fix client catching of server errors.
* Generally strengthen server API, especially once forum is separate.
### Forum:
* ***Create Category, both client and server.***
* ***Create Topic, both client and server.***
* **Create Post/Reply, both client and server.**
* ***Fix and test signup.***
* Create edit post functionality.
* Create delete post functionality.
* Menu only shows applicable items based on user level.
* Update server/client/cookie to include all user info.
* implement correct session with server.
* reduce clients reliance on cookie info to prevent security threats.
### Gallery/Things:
*Deal with this once forum is totally complete, it is now main project*
## Interesting Ideas.
* Implement a text editor for posts?
* Add an account page for users to manage their accounts.
* Add admin ability to remove topics and categories.
* Figure out passing information down the line so that the post page shows the category as well as topic.

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

43
forum_bld.sql Normal file
View File

@ -0,0 +1,43 @@
DROP TABLE posts;
DROP TABLE topics;
DROP TABLE categories;
DROP TABLE users;
CREATE TABLE categories (
catNo INT(8) NOT NULL AUTO_INCREMENT,
catName VARCHAR(255) NOT NULL,
catDescr VARCHAR(255) NOT NULL,
PRIMARY KEY (catNo)
);
CREATE TABLE users (
userNo INT(8) NOT NULL AUTO_INCREMENT,
userName VARCHAR(255) NOT NULL,
userPass VARCHAR(255) NOT NULL,
userEmail VARCHAR(255) NOT NULL,
userDate DATETIME NOT NULL,
userLevel INT(8) NOT NULL,
PRIMARY KEY (userNo)
);
CREATE TABLE topics (
topicNo INT(8) NOT NULL AUTO_INCREMENT,
topicSubject VARCHAR(255) NOT NULL,
topicDate DATETIME NOT NULL,
topicCat INT(8) NOT NULL,
topicBy INT(8) NOT NULL,
PRIMARY KEY (topicNo),
FOREIGN KEY (topicCat) REFERENCES categories (catNo),
FOREIGN KEY (topicBy) REFERENCES users (userNo)
);
CREATE TABLE posts (
postNo INT(8) NOT NULL AUTO_INCREMENT,
postContent VARCHAR(255) NOT NULL,
postDate DATETIME NOT NULL,
postTopic INT(8) NOT NULL,
postBy INT(8) NOT NULL,
PRIMARY KEY (postNo),
FOREIGN KEY (postTopic) REFERENCES topics (topicNo),
FOREIGN KEY (postBy) REFERENCES users (userNo)
);

38
index.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title> Inklet's Space </title>
<meta charset="utf-8">
<meta name="description" content="Where to find Ink's things.">
<meta name="keywords" content="html,forms,css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="author" content="Solomon Laing" />
<meta name="content" content="this is very meta" />
<link rel="stylesheet" href="/styles/h5.css">
<link rel="icon" type="image/ico" href="favicon.ico">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular-route.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular-cookies.js"></script>
<script src="./scripts/main.js"></script>
<script src="./scripts/auth.controllers.js"></script>
<script src="./scripts/forum.controller.js"></script>
</head>
<body ng-app="daddy" ng-controller="bodyCtrlr" ng-init="setForum()">
<header ng-controller="headerCtrlr" ng-include="'views/header.html'">
</header>
<nav ng-controller="navCtrlr" ng-include="'views/nav.html'"></nav> <!-- have this so that the top of the page has a border. -->
<main ng-view>
</main>
<footer ng-include="'views/footer.html'">
</footer>
</body>
</html>

595
package-lock.json generated Normal file
View File

@ -0,0 +1,595 @@
{
"name": "forum.inkletblot.com",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
}
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"colors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"requires": {
"safe-buffer": "5.1.2"
}
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"corser": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
"integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c="
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
"requires": {
"ms": "^2.1.1"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ecstatic": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
"integrity": "sha1-bR3UmBTQBZRoLGUq22YHamnUbEg=",
"requires": {
"he": "^1.1.1",
"mime": "^1.6.0",
"minimist": "^1.1.0",
"url-join": "^2.0.5"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"eventemitter3": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
"integrity": "sha1-1lF2FjiH7lnzhtZMgmELaWpKdOs="
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
}
}
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"follow-redirects": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz",
"integrity": "sha1-jVvNxltxCP4VCGScecEtcy3O208=",
"requires": {
"debug": "^3.0.0"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8="
},
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"http-proxy": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
"integrity": "sha1-2+VfY+daNH2389mZdPJpKjFKajo=",
"requires": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
}
},
"http-server": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz",
"integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==",
"requires": {
"colors": "1.0.3",
"corser": "~2.0.0",
"ecstatic": "^3.0.0",
"http-proxy": "^1.8.1",
"opener": "~1.4.0",
"optimist": "0.6.x",
"portfinder": "^1.0.13",
"union": "~0.4.3"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE="
},
"mime-db": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
},
"mime-types": {
"version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"requires": {
"mime-db": "1.40.0"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"opener": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
"integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg="
},
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
},
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
}
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"portfinder": {
"version": "1.0.25",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
"integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==",
"requires": {
"async": "^2.6.2",
"debug": "^3.1.1",
"mkdirp": "^0.5.1"
}
},
"proxy-addr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
"integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.0"
}
},
"qs": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz",
"integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"union": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz",
"integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=",
"requires": {
"qs": "~2.3.3"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"url-join": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
"integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
}
}
}

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "forum.inkletblot.com",
"version": "1.0.0",
"description": "angularjs implementation of my forum on inkletblot.com",
"main": "server.js",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Solomon Laing",
"license": "MIT"
}

158
scripts/auth.controllers.js Normal file
View File

@ -0,0 +1,158 @@
daddy.controller("loginCtrlr", function($scope, $cookies, $location, $http, stateData){
let titles = {
login : "Login!",
signup : "Not a Member?"
}
$scope.titles = titles
let message = {
start : "Feel free to",
link : "Sign Up",
end : "at any time!"
}
$scope.message = message
$scope.setSignup = () => {
stateData.setPage("things")
$location.path("/signup")
}
$scope.login = () => {
$scope.status = true
$scope.loginStatus = "Logging you in..."
console.log("logging in")
console.log("requesting authentication from server")
$http({
url : server + "/auth/login?userName="+$scope.user.username+"&userPass="+$scope.user.password,
method : "GET"
}).then((res) => {
console.log(res)
if (res.status == 200) {
console.log("request granted")
let today = new Date()
let expired = new Date(today)
expired.setDate(today.getDate()+1)
$cookies.putObject('user', res.data[0], {expires : expired})
console.log("set cookie")
stateData.setUser(res.data[0])
console.log("set data")
stateData.setPage("things")
$location.path("/things")
}
}).catch((res) => {
if (res.status == 400) {
$scope.loginStatus = "Incorrect information!"
console.log("request denied")
} else if (res.status == 500) {
console.log("something went wrong: " + res)
}
})
}
})
daddy.controller("signupCtrlr", function($scope, $http, $location, stateData) {
let titles = {
form : "Sign up here!",
success : "Signup Success!"
}
$scope.titles = titles
let message = {
start : "You account has been created!",
line2 : "Feel free to",
link : "Login",
end : "whenever you like."
}
$scope.message = message
$scope.success = false
$scope.exists = false
$scope.status = false
$scope.setLogin = () => {
stateData.setPage("things")
$location.path("/login")
}
$scope.signup = () => {
$scope.userExists()
$scope.passwordsMatch()
$scope.emailGood()
if ($scope.match && !$scope.exists && $scope.goodemail) {
$scope.status = false
$scope.submit()
} else {
$scope.status = true
$scope.signupStatus = "Please correct errors above."
}
}
$scope.emailGood = () => {
if (validateEmail($scope.user.email)) {
$scope.goodemail = true
$scope.emailError = ""
} else {
$scope.goodemail = false
$scope.emailError = "< invalid email."
}
}
$scope.passwordsMatch = () => {
if ($scope.user.password != $scope.user.confirmPassword) {
$scope.match = false
$scope.passwordError = "< password does not match."
} else {
$scope.match = true
$scope.passwordError = ""
}
}
$scope.submit = () => {
$http({
url : server + "/auth/signup?userName=" + $scope.user.username + "&userPass=" + $scope.user.password + "&userEmail=" + $scope.user.email,
method : "POST"
}).then((res) => {
if (res.status == 200) {
console.log("user created successfully")
$scope.success = true
$scope.signupForm.$setPristine()
$scope.user.username = ""
$scope.user.password = ""
$scope.user.confirmPassword = ""
$scope.user.email = ""
}
}).catch((res) => {
if (res.status == 500) {
console.log("whoops...")
}
})
}
$scope.userExists = () => {
console.log("checking username is used?")
$http({
url : server + "/auth/exists?userName=" + $scope.user.username,
method : "POST"
}).then((res) => {
if (res.status == 200) {
console.log(res.data)
if (res.data == true) {
$scope.exists = true
$scope.usernameError= "< username already exists."
} else {
$scope.exists = false
$scope.usernameError = ""
}
}
}).catch((res) => {
if (res.status == 500) {
console.log ("something went wrong")
}
})
}
})

600
scripts/forum.controller.js Normal file
View File

@ -0,0 +1,600 @@
daddy.controller("forumCtrlr", function($scope, $http, $location) {
$scope.titles = {
main : {
heading : "Welcome!",
},
recent : {
heading : "Recent Posts",
list : "Catergory",
last : "Last Topic"
}
}
$scope.errors = {
topic : {
show : false,
text : "None yet!"
},
catagory : {
show : false,
text: "None yet!"
}
}
$scope.getCategories = () => {
console.log("getting categories form server")
$http({
url : server + "/forum/category/all",
method : "GET"
}).then((res) => {
if (res.status == 200) {
if (res.data.length == 0) {
$scope.errors.catagory.show = true
} else {
$scope.categories = res.data
for (let i = 0; i < res.data.length; i++) {
$http({
url : server + "/forum/category/topic/last?cat=" + res.data[i].catNo,
method : "GET"
}).then((res) => {
if (res.status == 200) {
console.log("topicNo: " + res.data.topicNo)
// if (res.data.topicNo == null) {
// $scope.errors.topic.show = true
// } else {
res.data.topicDate = niceDate(res.data.topicDate)
$scope.categories[i].lastTopic = res.data
// }
} else {
console.log("server has encountered an error: " + res.status)
}
})
}
console.log(res)
}
}
}).catch((res) => {
console.log("server has encountered an error: " + res.status)
})
}
$scope.setCat = (catNo) => {
$location.path("/categories/"+catNo)
}
$scope.setTopic = (topicNo) => {
$location.path("/topics/"+topicNo)
}
})
daddy.controller("createTopicCtrlr", function($scope, $location, $http, stateData) {
$scope.titles = {
form : "Create a topic!"
}
$scope.status = {
show : false,
text : ""
}
let error = {
loggedIn : {
show : false,
text1 : "You must be",
link1 : "Logged In",
text2 : "to create a topic!"
},
userLevel : {
show : false,
text1 : "No categories have been created, please contact an administrator about creating some.",
text2 : "Administrator contact: solomonlaing@inkletblot.com"
},
category : {
show : false
}
}
$scope.error = error
$scope.start = () => {
if (stateData.state.user.userName == null) {
console.log("not logged in.")
error.loggedIn.show = true
}
if (stateData.state.user.userLevel == 0) {
console.log("user not an admin.")
error.userLevel.show = true
}
$scope.getCategories()
}
$scope.getCategories = () => {
console.log("getting categories form server")
$http({
url : server + "/forum/category/all",
method : "GET"
}).then((res) => {
if (res.status == 200) {
if (res.data.length == 0) {
$scope.errors.catagory.show = true
} else {
$scope.categories = res.data
console.log(res)
}
}
}).catch((res) => {
console.log("server has encountered an error: " + res.status)
})
}
$scope.setLogin = () => {
$location.path("/login")
stateData.setPage("things")
}
$scope.createTopic = () => {
console.log("sending new topic to server!!")
let formData = new FormData()
formData.append('topicSubject', $scope.topic.topicSubject)
formData.append('topicCat', $scope.topic.topicCat)
formData.append('userNo', stateData.state.user.userNo)
$http({
url : server + "/forum/topic/create",
method : "POST",
data : formData,
headers : { 'Content-Type' : undefined },
transformRequest : angular.identity
}).then((res) => {
if (res.status == 200) {
console.log("topic submitted")
$scope.createPost($scope.topic.postContent, res.data.topicNo)
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: " + res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
$scope.createPost = (postContent, topicNo) => {
console.log("sending new post to server")
let formData = new FormData()
formData.append('postContent', postContent)
formData.append('topicNo', topicNo)
formData.append('userNo', stateData.state.user.userNo)
$http({
url : server + "/forum/topic/post/create",
method : "POST",
data : formData,
headers : { 'Content-Type' : undefined },
transformRequest : angular.identity
}).then((res) => {
if (res.status == 200) {
console.log("post added")
$location.path("/topics/" + topicNo)
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: " + res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
})
daddy.controller("createCategoryCtrlr", function($scope, $http, $location, stateData) {
let error = {
loggedIn : {
show : false,
text1 : "You must be",
link1 : "Logged In",
text2 : "to create a category!"
},
userLevel : {
show : false,
text1 : "You must be an administrator to create a category!"
}
}
$scope.error = error
$scope.titles = {
form : "Create a Category!"
}
$scope.status = {
show : false,
text : ""
}
$scope.start = () => {
if (stateData.state.user.userName == null) {
error.loggedIn.show = true
}
if (stateData.state.user.userLevel == 0) {
error.userLevel.show = true
}
}
$scope.setLogin = () => {
$location.path("/login")
stateData.setPage("things")
}
$scope.createCategory = () => {
$scope.status.show = true
$scope.status.text = "Adding category..."
let formData = new FormData()
formData.append('catName', $scope.category.catName)
formData.append('catDescr', $scope.category.catDescr)
console.log("sending to server...")
$http({
url : server + "/forum/category/create",
method : "POST",
data : formData,
headers : { 'Content-Type' : undefined },
transformRequest : angular.identity
}).then((res) => {
if (res.status == 200) {
console.log("category submitted")
$location.path("/categories/" + res.data.catNo)
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: " + res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
})
daddy.controller("topicsCtrlr", function($scope, $routeParams, $timeout, $http, $location, stateData) {
$scope.error = false
$scope.message = {
start : null,
link : "Go Back!"
}
$scope.logged = {
text1 : "You must be",
link1 : "logged in",
text2 : "to reply. You can also",
link2 : "sign up",
text3 : "for an account."
}
$scope.status = {
show : false,
text : "",
}
$scope.first = {
show : false,
text : "Be the first to create a post, write below..."
}
$scope.getTopic = () => {
console.log("getting topic")
$http({
url : server + "/forum/topic?topic=" + $routeParams.topicNo,
method : "GET"
}).then((res) => {
console.log("got something")
if (res.status == 200) {
let topic = res.data
// if (res.data.posts.length == 0) {
// $scope.first.show = true
// }
console.log("got topics!")
for (let i = 0; i < topic.posts.length; i++) {
topic.posts[i].postDate = niceDate(topic.posts[i].postDate)
}
$scope.topic = topic
}
}).catch((res) => {
if (res.status == 404) {
console.log(res.data)
$scope.error = true
$scope.message.start = "No such topic,"
} else if (res.status == 500) {
console.log(res.data)
$scope.error = true
$scope.message.start = "An error has occured: " + res.status
} else {
console.log(res)
}
})
}
$scope.makeReply = (topicNo) => {
console.log("sending new post to server")
let formData = new FormData()
formData.append('postContent', $scope.reply.postContent)
formData.append('topicNo', topicNo)
formData.append('userNo', stateData.state.user.userNo)
$http({
url : server + "/forum/topic/post/create",
method : "POST",
data : formData,
headers : { 'Content-Type' : undefined },
transformRequest : angular.identity
}).then((res) => {
if (res.status == 200) {
console.log("post added")
$scope.reply.postContent = ""
$timeout(function() { $scope.getTopic() }, 2000)
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: ")
console.log(res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
$scope.setLogin = () => {
$location.path("/login")
}
$scope.setSignup = () => {
$location.path("/signup")
}
$scope.deletePost = (postNo) => {
if (!window.confirm("Are you sure you want to delete this post?")) {
return
}
$http({
url : server + "/forum/topic/post/delete?postNo=" + postNo,
method : "POST"
}).then((res) => {
if (res.status == 200) {
console.log("post deleted")
for (let i = 0; i < $scope.topic.posts.length; i++) {
if ($scope.topic.posts[i].postNo == postNo) {
$scope.topic.posts[i].postContent = "[deleted]"
}
}
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: ")
console.log(res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
$scope.editPost = (postNo, postContent) => {
/* This is incomplete, need to figure out hiding the edit box after edit. Would rather not use timeout. */
console.log("submitting edited post")
let formData = new FormData()
formData.append("postNo", postNo)
formData.append("postContent", postContent)
$http({
url : server + "/forum/topic/post/edit",
method : "POST",
data : formData,
headers : { 'Content-Type' : undefined },
transformRequest : angular.identity
}).then((res) => {
if (res.status == 200) {
console.log("post edited")
for (let i = 0; i < $scope.topic.posts.length; i++) {
if ($scope.topic.posts[i].postNo == postNo) {
$scope.topic.posts[i].postContent = postContent + " [edited]"
}
}
}
}).catch((res) => {
if (res.status == 500) {
console.log("something went wrong: ")
console.log(res.data)
$scope.status.text = "Something went wrong: " + res.status
}
})
}
})
daddy.controller("topicCtrlr", function($scope, $http, $location, stateData) {
$scope.titles = {
heading : "Topics",
subtitle : "Most recent topics by category.",
list : "Topic",
last : "Category"
}
$scope.errors = {
error : {
show : false,
message : null
},
topic : {
show : false,
text : "None yet!"
}
}
$scope.getTopics = () => {
console.log("getting topics")
$http({
url : server + "/forum/topic/all",
method : "GET"
}).then((res) => {
if (res.status == 200) {
let topics = res.data
if (topics.length == 0) {
$scope.erros.topic.show = true
} else if (topics.length > 10) {
topics = topics.slice(0, 9)
}
for (let i = 0; i < topics.length; i++) {
topics[i].topicDate = niceDate(topics[i].topicDate)
}
$scope.topics = topics
}
}).catch((res) => {
if (res.status == 500) {
console.log(res.data)
$scope.errors.error.show = true
$scope.errors.error.start = "An error has occured: " + res.status
} else {
console.log(res)
}
})
}
$scope.setCat = (catNo) => {
$location.path("/categories/"+catNo)
}
$scope.setTopic = (topicNo) => {
$location.path("/topics/"+topicNo)
}
})
daddy.controller("categoriesCtrlr", function($scope, $http, $routeParams, $location, stateData) {
$scope.errors = {
exists : {
show : false,
text1 : "No such category,",
link1 : "Go Back!"
},
empty : {
show : false,
text : "No topics have been created yet..."
}
}
$scope.titles = {
topic : "topic",
date : "date"
}
$scope.getCat = () => {
console.log("getting category")
$http({
url : server + "/forum/category?cat=" + $routeParams.catNo,
method : "GET"
}).then((res) => {
console.log(res)
if (res.status == 200) {
let category = res.data
if (category.topics.length == 0) {
$scope.errors.empty.show = true
} else {
for (let i = 0; i < category.topics.length; i++) {
category.topics[i].topicDate = niceDate(category.topics[i].topicDate)
}
}
$scope.category = category
}
}).catch((res) => {
if (res.status == 404) {
console.log(res.data)
$scope.errors.exists.show = true
} else if (res.status == 500) {
console.log(res.data)
} else {
console.log(res)
}
})
}
$scope.setTopic = (topicNo) => {
$location.path("/topics/"+topicNo)
}
$scope.setForum = () => {
$location.path("/")
}
})
daddy.controller("categoryCtrlr", function($scope, $http, $location, stateData) {
$scope.titles = {
heading : "Categories",
subtitle : "Most recent categories and topics.",
list : "Catergory",
last : "Last Topic"
}
$scope.errors = {
topic : {
show : false,
text : "None yet!"
},
catagory : {
show : false,
text: "None yet!"
}
}
$scope.getCategories = () => {
console.log("getting categories form server")
$http({
url : server + "/forum/category/all",
method : "GET"
}).then((res) => {
if (res.status == 200) {
if (res.data.length == 0) {
$scope.errors.catagory.show = true
} else {
$scope.categories = res.data
for (let i = 0; i < res.data.length; i++) {
$http({
url : server + "/forum/category/topic/last?cat=" + res.data[i].catNo,
method : "GET"
}).then((res) => {
if (res.status == 200) {
console.log("topicNo: " + res.data.topicNo)
// if (res.data.topicNo == null) {
// $scope.errors.topic.show = true
// } else {
res.data.topicDate = niceDate(res.data.topicDate)
$scope.categories[i].lastTopic = res.data
// }
} else {
console.log("server has encountered an error: " + res.status)
}
})
}
console.log(res)
}
}
}).catch((res) => {
console.log("server has encountered an error: " + res.status)
})
}
$scope.setCat = (catNo) => {
$location.path("/categories/"+catNo)
}
$scope.setTopic = (topicNo) => {
$location.path("/topics/"+topicNo)
}
})
niceDate = (string) => {
let date = new Date(string)
return "on " + date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() + " at " + date.getHours() + ":" + date.getMinutes()
}
isNum = (str) => {
let re = /^[0-9]+$/
return re.test(String(str).toLowerCase())
}

167
scripts/main.js Normal file
View File

@ -0,0 +1,167 @@
let daddy = angular.module("daddy", ["ngRoute", "ngAnimate", "ngCookies"])
let server = "http://127.0.0.1:7001"
daddy.controller("bodyCtrlr", function($scope, $cookies, stateData){
$scope.state = stateData.state
let user = $cookies.getObject('user')
if (user == null) {
stateData.logOut()
} else {
stateData.setUser(user)
}
})
daddy.controller("headerCtrlr", function($scope){
$scope.subtitle = "Inks forum."
})
daddy.controller("navCtrlr", function($scope, $location, $cookies, stateData){
$scope.setLogin = () => {
$location.path("/login")
}
$scope.setSignup = () => {
$location.path("/signup")
}
$scope.setForum = () => {
$location.path("/")
stateData.setPage('forum')
}
$scope.setTopics = () => {
$location.path("/topics")
stateData.setPage('topics')
}
$scope.setTopicCreate = () => {
$location.path("/topics/create")
stateData.setPage('topics')
}
$scope.setCategories = () => {
$location.path("/categories")
stateData.setPage('categories')
}
$scope.setCategoryCreate = () => {
$location.path("/categories/create")
stateData.setPage('categories')
}
switch ($location.path()) {
case "":
case "/":
$scope.setForum()
break
case "/topics":
$scope.setTopics()
// this has to be done in the controller
break
case "/topics/create":
$scope.setTopicCreate()
break
case "/categories":
$scope.setCategories()
// this has to be done in the controller
break
case "/catagories/create":
$scope.setCategoryCreate()
break
case "/login":
$scope.setLogin()
break
case "/signup":
$scope.setSignup()
break
}
$scope.logOut = () => {
$cookies.remove('user')
stateData.logOut()
}
})
// naming conventions here are very confusing:
// the main topics page is topic and the specific topics page is topics, by specific I mean the :topicNo one.
// the same goes for categories, category is the main page and the spcefics are categories.
daddy.config(function ($routeProvider) {
$routeProvider.when("/", {templateUrl : "views/home.html", controller : "forumCtrlr"})
$routeProvider.when("/topics/create", {templateUrl : "views/create_topic.html", controller : "createTopicCtrlr"})
$routeProvider.when("/topics", {templateUrl : "views/topic.html", controller : "topicCtrlr"})
$routeProvider.when("/topics/:topicNo", {templateUrl : "views/topics.html", controller : "topicsCtrlr"})
$routeProvider.when("/categories/create", {templateUrl : "views/create_category.html", controller : "createCategoryCtrlr"})
$routeProvider.when("/categories", {templateUrl : "views/category.html", controller : "categoryCtrlr"})
$routeProvider.when("/categories/:catNo", {templateUrl : "views/categories.html", controller : "categoriesCtrlr"})
$routeProvider.when("/login", {templateUrl : "views/login.html", controller : "loginCtrlr"})
$routeProvider.when("/signup", {templateUrl : "views/signup.html", controller : "signupCtrlr"})
$routeProvider.otherwise({template : "<article><section class='item border'><h1>404 ... no clue fam ... try something else?</h1></section></article>"})
})
daddy.factory('stateData', function(){
let state = {
page : "forum",
title : "Forum;",
user : {
userNo : null,
userName : null,
userLevel : 0
},
content : {
gallery : null
}
}
setPage = (newPage) => {
state.page = newPage
switch (state.page) {
case "forum":
state.title = "Forum;"
break
case "topics":
state.title = "Topics;"
break
case "categories":
state.title = "Categories;"
break
}
}
logOut = () => {
state.user.userNo = null
state.user.userName = null
state.user.userLevel = 0
}
setUser = (user) => {
state.user.userNo = user.userNo
state.user.userName = user.userName
state.user.userLevel = user.userLevel
}
return {
state : state,
setPage : setPage,
logOut: logOut,
setUser: setUser
}
})
function getDate() {
let date = new Date()
let out = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() + " - " + date.getHours() + ":" + date.getMinutes()
return out
}
function validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}

20
server.js Normal file
View File

@ -0,0 +1,20 @@
let express = require('express')
let cors = require('cors')
let app = express()
app.use(express.static('./'))
app.use(cors({
origin: "http://localhost:7001"
}))
app.get('/', (req, res) => {
res.sendFile('./index.html')
})
let port = 7000
app.listen(port, () => {
console.log("Listening on port "+port+"...");
console.log("Go to: http://localhost:"+port+" or http://127.0.0.1:"+port+" to view...")
})

211
styles/h5.css Normal file
View File

@ -0,0 +1,211 @@
/* General CSS for all pages */
body{
position: relative;
width: 80%;
left: 10%;
background-color:#0F0F0F;
text-align: center; /* make sure IE centers the page too */
font-family: sans-serif;
color: lightgrey;
}
header{
text-align: left;
padding-left: 8%;
}
article{
margin-top: 5px;
border: 5px dashed pink;
border-top: none;
float: left;
padding: 20px 30px;
text-align: left;
width: 95%; /* fill up the entire div */
margin-bottom: 10px;
}
footer {
text-align: center;
font-size: 9pt;
color: #FAFAFA;
}
h1 {
font-size: 50pt;
margin-bottom: -25px;
}
h3 {
margin: 0;
padding: 0;
}
a:link, a:visited, a:hover, a:active{
text-decoration: none;
color: purple;
}
.status {
color: crimson;
}
.link {
color: pink;
}
.link:hover {
color: #009FC1;
text-decoration: underline;
}
.error {
text-align: center;
}
form {
display: inline-block;
}
input, label, textarea, select {
margin-bottom: 10px;
}
/* END Geteral CSS */
/* CSS for menu on forum and gallery */
nav {
margin-top: 2.5%;
float: left;
border: 5px dashed pink;
border-bottom: none; /* avoid a double border */
clear: both; /* clear:both makes sure the content div doesn't float next to this one but stays under it */
width:95%;
height:50px;
padding: 0 30px;
text-align: left;
font-size: 85%;
}
nav .mitem {
background-color: #2E2E2E;
border: 3px dashed pink;
float: left;
padding: 10px 0px 10px 0px;
text-decoration: none;
color: #FAFAFA;
margin-right: 10px;
margin-top: -25px;
}
nav .msub {
padding: 10px;
text-decoration: none;
color: #FAFAFA;
box-sizing: border-box;
}
nav span {
box-sizing: border-box;
padding: 10px;
}
nav .msub:hover {
background-color: #009FC1;
}
nav .msub:link, nav .msub:visited, nav .msub:active {
color: #FAFAFA;
}
nav .userbar {
float: right;
}
/* END menu CSS */
/* CSS for things */
.item{
display: inline-block;
position: relative;
margin: 50px;
margin-top: -10px;
text-align: center;
}
.block{
position: relative;
background: pink;
}
.blockTitle{
font-size: 20pt;
margin-bottom: -25px;
}
.CLICK{
font-size: 40pt;
padding-top: 8px;
}
/* END things CSS */
.left {
display: block;
float: left;
}
.right {
display: block;
float: right;
}
.center {
display: block;
margin: auto;
width: min-content;
margin-bottom: 50px;
}
.border {
border: 3px dashed pink;
padding: 25px;
}
.stretch {
display: block;
}
/* START forum CSS */
table {
text-align: left;
border-collapse: collapse;
width: 100%;
}
table, td, th {
border: 1px solid pink;
}
table a:hover {
color: pink;
text-decoration: none;
}
th {
background-color: #2E2E2E;
color: #FAFAFA;
padding: 5px;
}
td {
padding: 5px;
}
.right {
margin: 0 5px 0 10px;
float: right;
}
/* END forum CSS */

22
views/categories.html Normal file
View File

@ -0,0 +1,22 @@
<article ng-controller="categoriesCtrlr" ng-init="getCat()">
<section ng-if="!errors.exists.show" class="item stretch border">
<h3>{{category.catName}}</h3>
<p><em>{{category.catDescr}}</em></p>
<table>
<tr>
<th>{{titles.topic}}</th>
<th>{{titles.date}}</th>
</tr>
<tr ng-repeat="topic in category.topics">
<td><span class="link" ng-click="setTopic(topic.topicNo)">{{topic.topicSubject}}</span></td>
<td>{{topic.topicDate}}</td>
</tr>
<tr ng-if="errors.empty.show">
<td colspan="2">{{errors.empty.text}}</td>
</tr>
</table>
</section>
<section ng-if="errors.exists.show" class="item left border">
<p>{{errors.exists.text1}} <span class="link" ng-click="setForum()">{{errors.exists.link1}}</span></p>
</section>
</article>

21
views/category.html Normal file
View File

@ -0,0 +1,21 @@
<article ng-controller="categoryCtrlr" ng-init="getCategories()">
<section class="item stretch border">
<h3>{{titles.heading}}</h3>
<p><em>{{titles.subtitle}}</em></p>
<table>
<tr>
<th>{{titles.list}}</th>
<th>{{titles.last}}</th>
</tr>
<tr ng-repeat="cat in categories">
<td><span class="link" ng-click="setCat(cat.catNo)">{{cat.catName}}</span> <br />
{{cat.catDescr}} </td>
<td ng-if="!(cat.lastTopic.topicNo == null)"><span class="link" ng-click="setTopic(cat.lastTopic.topicNo)">{{cat.lastTopic.topicSubject}}</span> {{cat.lastTopic.topicDate}}</td>
<td ng-if="cat.lastTopic.topicNo == null">{{errors.topic.text}}</td>
</tr>
<tr ng-if="errors.catagory.show">
<td colspan="2">{{errors.catagory.text}}</td>
</tr>
</table>
</section>
</article>

View File

@ -0,0 +1,17 @@
<article ng-controller="createCategoryCtrlr" ng-init="start()">
<section ng-show="!(error.userLevel.show)" class="item border">
<h3>{{titles.form}}</h3>
<form id="categoryForm" name="categoryForm" ng-submit="createCategory()">
<label for="catName">Name: </label> <br />
<input type="text" name="catName" ng-model="category.catName" placeholder="A name for the category" required /> <br />
<label for="catDescr">Description: </label> <br />
<textarea name="catDescr" ng-model="category.catDescr" placeholder="A description for the category" required ></textarea> <br />
<input type="submit" value="Add Category" ng-model="category.submit" />
</form>
<p class="status" ng-show="status.show">{{status.text}}</p>
</section>
<section ng-show="error.userLevel.show" class="item border">
<p ng-show="error.userName.show">{{error.loggedIn.text1}} <span class="link" ng-click="setLogin()">{{error.loggedIn.link1}}</span> {{error.loggedIn.text2}}</p>
<p ng-show="!(erro.userName.show)">{{error.userLevel.text1}}</p>
</section>
</article>

23
views/create_topic.html Normal file
View File

@ -0,0 +1,23 @@
<article ng-controller="createTopicCtrlr" ng-init="start()">
<section ng-show="!(error.loggedIn.show)" class="item border">
<h3>{{titles.form}}</h3>
<p ng-show="error.category.show && !error.userLevel.show">{{error.category.text1}} <span class="link" ng-click="setCreateCat()">{{error.category.link1}}</span> {{error.category.text2}}</p>
<p ng-show="error.category.show && error.userLevel.show">{{error.userLevel.text1}} <br /> {{error.userLevel.text2}}</p>
<form ng-show="!error.category.show" ng-submit="createTopic()">
<label for="topicSubject">Subject: </label></br>
<input type="text" name="topicSubject" ng-model="topic.topicSubject" placeholder="What's this topic about?" required /><br />
<label for="topicCat">Category: </label></br>
<select name="topicCat" ng-model="topic.topicCat" required>
<option selected disabled hidden style='display: none' value=''></option>
<option ng-repeat="category in categories" value="{{category.catNo}}">{{category.catName}}</option>
</select><br />
<label for="postContent">Message: </label></br>
<textarea name="postContent" ng-model="topic.postContent" placeholder="The first post in the topic..." required></textarea><br />
<input type="submit" ng-model="topic.submit" value="Create topic" />
</form>
<p class="status" ng-show="status.show">{{status.text}}</p>
</section>
<section ng-show="error.loggedIn.show" class="item border">
<p>{{error.loggedIn.text1}} <span class="link" ng-click="setLogin()">{{error.loggedIn.link1}}</span> {{error.loggedIn.text2}}</p>
</section>
</article>

1
views/footer.html Normal file
View File

@ -0,0 +1 @@
<p>Copyright &copy; inkletblot.com 2018 and forever.</p>

4
views/header.html Normal file
View File

@ -0,0 +1,4 @@
<h1>{{state.title}}</h1>
<h4>{{subtitle}}</h4>
<!-- <h1>Things;</h1>
<h4>Ink's things.</h4> -->

25
views/home.html Normal file
View File

@ -0,0 +1,25 @@
<article ng-controller="forumCtrlr" ng-init="getCategories()">
<section class="item">
<h3>{{titles.main.heading}}</h3>
</section>
<section class="item left border">
<h3>{{titles.recent.heading}}</h3> <br />
<table>
<tr>
<th>{{titles.recent.list}}</th>
<th>{{titles.recent.last}}</th>
</tr>
<tr ng-repeat="cat in categories">
<td><span class="link" ng-click="setCat(cat.catNo)">{{cat.catName}}</span> <br />
{{cat.catDescr}} </td>
<td ng-if="!(cat.lastTopic.topicNo == null)"><span class="link" ng-click="setTopic(cat.lastTopic.topicNo)">{{cat.lastTopic.topicSubject}}</span> {{cat.lastTopic.topicDate}}</td>
<td ng-if="cat.lastTopic.topicNo == null">{{errors.topic.text}}</td>
</tr>
<tr ng-if="errors.catagory.show">
<td colspan="2">{{errors.catagory.text}}</td>
</tr>
</table>
</section>
</article>

17
views/login.html Normal file
View File

@ -0,0 +1,17 @@
<article ng-controller="loginCtrlr">
<section class="item stretch border">
<h3>{{titles.signup}}</h3>
<p>{{message.start}} <span class="link" ng-click="setSignup()">{{message.link}}</span> {{message.end}}</p>
</section>
<section class="item center border">
<h3>{{titles.login}}</h3> <br />
<form id="loginForm" name="loginForm" ng-submit="login()" enctype="application/x-www-form-urlencoded">
<label for="username">Username: </label> <br />
<input type="text" name="username" ng-model="user.username" placeholder="Your username" required /> <br />
<label for="password">Password: </label> <br />
<input type="password" name="password" ng-model="user.password" placeholder="Your password" required /> <br />
<input type="submit" name="submit" ng-model="user.Submit" value="Log In" />
</form>
<p class="status" ng-show="status">{{loginStatus}}</p>
</section>
</article>

26
views/nav.html Normal file
View File

@ -0,0 +1,26 @@
<span class="mitem">
<span class="msub" ng-click="setForum()">Forum</span>
</span>
<span class="mitem">
<span class="msub" ng-click="setCategories()">Categories<spanext ng-if="state.page == 'categories'"> ></spanext></span>
<span ng-if="state.page == 'categories'" class="msub" ng-click="setCategoryCreate()">Create a Category</span>
</span>
<span class="mitem">
<span class="msub" ng-click="setTopics()">Topics<spanext ng-if="state.page == 'topics'"> ></spanext></span>
<span ng-if="state.page == 'topics'" class="msub" ng-click="setTopicCreate()">Create a Topic</span>
</span>
<div class="userbar">
<span ng-show="state.user.userNo != null" class="mitem">
<span>Welcome {{state.user.userName}}!</span>
<span class="msub" ng-click="logOut()">Log Out</span>
</span>
<span ng-show="state.user.userNo == null" class="mitem">
<span class="msub" ng-click="setLogin()">Log in</span>
</span>
<span ng-show="state.user.userNo == null" class="mitem">
<span class="msub" ng-click="setSignup()">Sign Up</span>
</span>
</div>

23
views/signup.html Normal file
View File

@ -0,0 +1,23 @@
<article ng-controller="signupCtrlr">
<section class="item center border">
<h3>{{titles.form}}</h3> <br />
<form id="signupForm" name="signupForm" ng-submit="signup()" enctype="application/x-www-form-urlencoded">
<label for="username">Username: </label> <br />
<input type="text" name="username" ng-model="user.username" placeholder="Your username" required /> {{usernameError}} <br />
<label for="email">Email: </label> <br />
<input type="text" name="email" ng-model="user.email" placeholder="Your email" required /> {{emailError}}<br />
<label for="password">Password: </label> <br />
<input type="password" name="password" ng-model="user.password" placeholder="Your password" required />
<br />
<label for="password">Confirm Password: </label> <br />
<input type="password" name="confirmPassword" ng-model="user.confirmPassword"
placeholder="Your password, again" required /> {{passwordError}}<br />
<input type="submit" name="submit" ng-model="user.Submit" value="Sign Up" />
</form>
<p class="status" ng-show="status">{{signupStatus}}</p>
</section>
<section class="item center border" ng-show="success">
<h3>{{titles.success}}</h3>
<p>{{message.start}} <br /> {{message.line2}} <span class="link" ng-click="setLogin()">{{message.link}}</span> {{message.end}}</p>
</section>
</article>

20
views/topic.html Normal file
View File

@ -0,0 +1,20 @@
<article ng-controller="topicCtrlr" ng-init="getTopics()">
<section class="item stretch border">
<h3>{{titles.heading}}</h3>
<p><em>{{titles.subtitle}}</em></p>
<table>
<tr>
<th>{{titles.list}}</th>
<th>{{titles.last}}</th>
</tr>
<tr ng-repeat="topic in topics">
<td><span class="link" ng-click="setTopic(topic.topicNo)">{{topic.topicSubject}}</span> {{topic.topicDate}}</td>
<td><span class="link" ng-click="setCat(topic.topicCat.catNo)">{{topic.topicCat.catName}}</span></td>
</tr>
</table>
<p ng-if="errors.topic.show">{{errors.topic.text}}</p>
</section>
<section ng-show="errors.error.show" class="item left border">
<p>{{errors.error.message}}</p>
</section>
</article>

47
views/topics.html Normal file
View File

@ -0,0 +1,47 @@
<article ng-controller="topicsCtrlr" ng-init="getTopic()">
<section ng-show="!error" class="item stretch border">
<table>
<tr>
<th colspan="2">{{topic.topicSubject}}</th>
</tr>
<tr ng-show="first.show">
<td colspan="2">
<p>{{first.text}}</p>
</td>
</tr>
<tr ng-repeat="post in topic.posts">
<td ng-show="state.user.userNo != post.user.userNo">{{post.postContent}}</td>
<td ng-show="state.user.userNo == post.user.userNo" ng-init="showEditor = false">{{post.postContent}} <span class="link right"
ng-click="deletePost(post.postNo)">[delete]</span> <span class="link right"
ng-click="showEditor = !showEditor">[edit]</span>
<div ng-show="showEditor">
<br />
<form name="editForm" id="editForm" ng-submit="editPost(post.postNo, edit.editContent)">
<textarea name="editContent" ng-model="edit.editContent" placeholder="{{post.postContent}}" required></textarea>
<br />
<input type="submit" name="editSubmit" ng-model="edit.submit" value="Edit" />
</form>
</div>
</td>
<td>{{post.user.userName}}<br />{{post.postDate}}</td>
</tr>
<tr>
<td colspan="2" ng-show="state.user.userNo == null">{{logged.text1}} <span class="link"
ng-click="setLogin()">{{logged.link1}}</span> {{logged.text2}} <span class="link"
ng-click="setSignup()">{{logged.link2}}</span> {{logged.text3}}</td>
<td colspan="2" ng-show="state.user.userNo != null">
<form name="replyForm" id="replyForm" ng-submit="makeReply(topic.topicNo)">
<label for="replyCotnent">Reply:</label>
<textarea name="replyContent" ng-model="reply.postContent" required></textarea>
<input type="submit" name="replySubmit" ng-model="reply.submit" value="Reply" />
</form>
<p class="status" ng-show="status.show">{{status.text}}</p>
</td>
</tr>
</table>
</section>
<section ng-show="error" class="item left border">
<p>{{message.start}} <span class="link" ng-click="setForum()">{{message.link}}</span></p>
</section>
</article>