diff --git a/README.md b/README.md index e0d208d..59489da 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# forum.com -The angularjs front-end for my forum, recently moved from inkletblot.com +# README for 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. \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..abeb8dd Binary files /dev/null and b/favicon.ico differ diff --git a/forum_bld.sql b/forum_bld.sql new file mode 100644 index 0000000..5901869 --- /dev/null +++ b/forum_bld.sql @@ -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) +); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..dcc7592 --- /dev/null +++ b/index.html @@ -0,0 +1,38 @@ + + + + + + Inklet's Space + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..723fd5f --- /dev/null +++ b/package-lock.json @@ -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=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c5b6bcc --- /dev/null +++ b/package.json @@ -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" +} diff --git a/scripts/auth.controllers.js b/scripts/auth.controllers.js new file mode 100644 index 0000000..5037e1e --- /dev/null +++ b/scripts/auth.controllers.js @@ -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") + } + }) + } + +}) \ No newline at end of file diff --git a/scripts/forum.controller.js b/scripts/forum.controller.js new file mode 100644 index 0000000..487f7e2 --- /dev/null +++ b/scripts/forum.controller.js @@ -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()) +} \ No newline at end of file diff --git a/scripts/main.js b/scripts/main.js new file mode 100644 index 0000000..c0ecc5c --- /dev/null +++ b/scripts/main.js @@ -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 : "

404 ... no clue fam ... try something else?

"}) +}) + +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()); +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..5410bf1 --- /dev/null +++ b/server.js @@ -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...") +}) \ No newline at end of file diff --git a/styles/h5.css b/styles/h5.css new file mode 100644 index 0000000..87ee684 --- /dev/null +++ b/styles/h5.css @@ -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 */ \ No newline at end of file diff --git a/views/categories.html b/views/categories.html new file mode 100644 index 0000000..1ebd439 --- /dev/null +++ b/views/categories.html @@ -0,0 +1,22 @@ +
+
+

{{category.catName}}

+

{{category.catDescr}}

+ + + + + + + + + + + + +
{{titles.topic}}{{titles.date}}
{{topic.topicSubject}}{{topic.topicDate}}
{{errors.empty.text}}
+
+
+

{{errors.exists.text1}} {{errors.exists.link1}}

+
+
\ No newline at end of file diff --git a/views/category.html b/views/category.html new file mode 100644 index 0000000..7b67d0e --- /dev/null +++ b/views/category.html @@ -0,0 +1,21 @@ +
+
+

{{titles.heading}}

+

{{titles.subtitle}}

+ + + + + + + + + + + + + +
{{titles.list}}{{titles.last}}
{{cat.catName}}
+ {{cat.catDescr}}
{{cat.lastTopic.topicSubject}} {{cat.lastTopic.topicDate}}{{errors.topic.text}}
{{errors.catagory.text}}
+
+
\ No newline at end of file diff --git a/views/create_category.html b/views/create_category.html new file mode 100644 index 0000000..3795acb --- /dev/null +++ b/views/create_category.html @@ -0,0 +1,17 @@ +
+
+

{{titles.form}}

+
+
+
+
+
+ +
+

{{status.text}}

+
+
+

{{error.loggedIn.text1}} {{error.loggedIn.link1}} {{error.loggedIn.text2}}

+

{{error.userLevel.text1}}

+
+
\ No newline at end of file diff --git a/views/create_topic.html b/views/create_topic.html new file mode 100644 index 0000000..4c1443d --- /dev/null +++ b/views/create_topic.html @@ -0,0 +1,23 @@ +
+
+

{{titles.form}}

+

{{error.category.text1}} {{error.category.link1}} {{error.category.text2}}

+

{{error.userLevel.text1}}
{{error.userLevel.text2}}

+
+
+
+
+
+
+
+ +
+

{{status.text}}

+
+
+

{{error.loggedIn.text1}} {{error.loggedIn.link1}} {{error.loggedIn.text2}}

+
+
\ No newline at end of file diff --git a/views/footer.html b/views/footer.html new file mode 100644 index 0000000..3139320 --- /dev/null +++ b/views/footer.html @@ -0,0 +1 @@ +

Copyright © inkletblot.com 2018 and forever.

\ No newline at end of file diff --git a/views/header.html b/views/header.html new file mode 100644 index 0000000..95f8755 --- /dev/null +++ b/views/header.html @@ -0,0 +1,4 @@ +

{{state.title}}

+

{{subtitle}}

+ \ No newline at end of file diff --git a/views/home.html b/views/home.html new file mode 100644 index 0000000..9986835 --- /dev/null +++ b/views/home.html @@ -0,0 +1,25 @@ +
+ +
+

{{titles.main.heading}}

+
+ +
+

{{titles.recent.heading}}


+ + + + + + + + + + + + + +
{{titles.recent.list}}{{titles.recent.last}}
{{cat.catName}}
+ {{cat.catDescr}}
{{cat.lastTopic.topicSubject}} {{cat.lastTopic.topicDate}}{{errors.topic.text}}
{{errors.catagory.text}}
+
+
\ No newline at end of file diff --git a/views/login.html b/views/login.html new file mode 100644 index 0000000..f90cf88 --- /dev/null +++ b/views/login.html @@ -0,0 +1,17 @@ +
+
+

{{titles.signup}}

+

{{message.start}} {{message.link}} {{message.end}}

+
+
+

{{titles.login}}


+
+
+
+
+
+ +
+

{{loginStatus}}

+
+
\ No newline at end of file diff --git a/views/nav.html b/views/nav.html new file mode 100644 index 0000000..04c3f0d --- /dev/null +++ b/views/nav.html @@ -0,0 +1,26 @@ + + Forum + + + + Categories > + Create a Category + + + + Topics > + Create a Topic + + +
+ + Welcome {{state.user.userName}}! + Log Out + + + Log in + + + Sign Up + +
\ No newline at end of file diff --git a/views/signup.html b/views/signup.html new file mode 100644 index 0000000..3bc8c96 --- /dev/null +++ b/views/signup.html @@ -0,0 +1,23 @@ +
+
+

{{titles.form}}


+
+
+ {{usernameError}}
+
+ {{emailError}}
+
+ +
+
+ {{passwordError}}
+ +
+

{{signupStatus}}

+
+
+

{{titles.success}}

+

{{message.start}}
{{message.line2}} {{message.link}} {{message.end}}

+
+
\ No newline at end of file diff --git a/views/topic.html b/views/topic.html new file mode 100644 index 0000000..27c9566 --- /dev/null +++ b/views/topic.html @@ -0,0 +1,20 @@ +
+
+

{{titles.heading}}

+

{{titles.subtitle}}

+ + + + + + + + + +
{{titles.list}}{{titles.last}}
{{topic.topicSubject}} {{topic.topicDate}}{{topic.topicCat.catName}}
+

{{errors.topic.text}}

+
+
+

{{errors.error.message}}

+
+
\ No newline at end of file diff --git a/views/topics.html b/views/topics.html new file mode 100644 index 0000000..7b79c5c --- /dev/null +++ b/views/topics.html @@ -0,0 +1,47 @@ +
+
+ + + + + + + + + + + + + + + + +
{{topic.topicSubject}}
+

{{first.text}}

+
{{post.postContent}}{{post.postContent}} [delete] [edit] +
+
+
+ +
+ +
+
+
{{post.user.userName}}
{{post.postDate}}
{{logged.text1}} {{logged.link1}} {{logged.text2}} {{logged.link2}} {{logged.text3}} +
+ + + +
+

{{status.text}}

+
+
+
+

{{message.start}} {{message.link}}

+
+
+