diff --git a/adventure/config.example.json b/adventure/config.example.json index e8ff8f4..6722805 100644 --- a/adventure/config.example.json +++ b/adventure/config.example.json @@ -32,6 +32,7 @@ "viewDirectory": "views", "resDirectory": "res", "usersCanChangeTheme": true, + "allowContributions": true, "constants": { "tagMappings": { diff --git a/adventure/libraryRoutes.js b/adventure/libraryRoutes.js index 9021453..c7c7037 100644 --- a/adventure/libraryRoutes.js +++ b/adventure/libraryRoutes.js @@ -122,6 +122,39 @@ function libraryRoute(req, res) { }); } } + +// These are first so that they aren't overridden by the category routes +server.get("/library/contribute", restrictedRoute(), function (req, res) { + if (!config.allowContributions) { // If allowContributions is FALSE + return res.status(500).render("error", { + message: "Contributions aren't being accepted at this time." + }); + } + return res.render("contribute", { + platformMappingsInverted: formatting.invertObject(config.constants.platformMappings) + }); +}); +server.get("/library/my/contributions", restrictedRoute(), function (req, res) { + var page = req.query.page || 1; + var uuidAsBuf = req.user.UserID; + database.execute("SELECT COUNT(*) FROM `Contributions` WHERE `UserUUID` = ?", [uuidAsBuf] ,function (cErr, cRes, cFields) { + var count = cRes[0]["COUNT(*)"]; + var pages = Math.ceil(count / config.perPage); + database.execute("SELECT * FROM `Contributions` WHERE `UserUUID` = ? ORDER BY ContributionCreated DESC LIMIT ?,?", [uuidAsBuf, (page - 1) * config.perPage, config.perPage], function (coErr, coRes, coFields) { + var contributions = coRes.map(function (x) { + x.UserUUID = formatting.binToHex(x.UserUUID); + x.ContributionUUID = formatting.binToHex(x.ContributionUUID); + return x; + }); + return res.render("mycontributions", { + contributions: contributions, + page: page, + pages: pages + }); + }); + }); +}); + server.get("/library/:category", libraryRoute); server.get("/library/:category/:tag", libraryRoute); server.get("/library", function (req, res) { diff --git a/adventure/saContributionRoutes.js b/adventure/saContributionRoutes.js index 890c333..9bd29ae 100644 --- a/adventure/saContributionRoutes.js +++ b/adventure/saContributionRoutes.js @@ -1,4 +1,4 @@ -var express = require("express"), +var express = require("express"), fs = require("fs"), path = require("path"), middleware = require("./middleware.js"), @@ -18,7 +18,7 @@ server.get("/sa/contributions", restrictedRoute("sa"), function (req, res) { var pages = Math.ceil(count / config.perPage); database.execute("SELECT * FROM `Contributions` WHERE `Status` = ? ORDER BY ContributionCreated DESC LIMIT ?,?", [status, (page - 1) * config.perPage, config.perPage], function (coErr, coRes, coFields) { var contributions = coRes.map(function (x) { - x.UserUUID = formatting.binToHex(x.ContributionUUID); + x.UserUUID = formatting.binToHex(x.UserUUID); x.ContributionUUID = formatting.binToHex(x.ContributionUUID); return x; }); @@ -32,6 +32,55 @@ server.get("/sa/contributions", restrictedRoute("sa"), function (req, res) { }); }); +server.get("/sa/contribution/:contribution", restrictedRoute("sa"), function (req, res) { + database.execute("SELECT * FROM `Contributions` WHERE `ContributionUUID` = ?", [formatting.hexToBin(req.params.contribution)], function (cErr, cRes, cFields) { + // now get any perphiery stuff + + var contribution = cRes[0] || null; + if (cErr || contribution == null) { + return res.status(404).render("error", { + message: "There is no contribution." + }); + } + + var contributions = cRes.map(function (x) { + x.UserUUID = formatting.binToHex(x.UserUUID); + x.ContributionUUID = formatting.binToHex(x.ContributionUUID); + return x; + }); + + return res.render("saContribution", { + contribution: contribution, + platformMappingsInverted: formatting.invertObject(config.constants.platformMappings) + }); + + }); +}); + +server.post("/sa/rejectContribution/:contribution", restrictedRoute("sa"), urlencodedParser, function (req, res) { + if (req.body && req.body.rejectionReason) { + var uuid = req.params.contribution; + var uuidAsBuf = formatting.hexToBin(uuid); + var status = "Rejected"; + var rejectionReason = req.body.rejectionReason; + var userIdAsBuf = req.user.UserID; + database.execute("UPDATE `Contributions` SET `Status` = ?, `RejectionReason` = ?, ProcessTime = NOW(), ProcessBy = ? WHERE `ContributionUUID` = ?", [status, rejectionReason, userIdAsBuf, uuidAsBuf], function (scErr, scRes, scFields) { + if (scErr) { + return res.status(500).render("error", { + message: "The contribution could not be rejected." + }); + } else { + return res.redirect("/sa/contributions"); + } + }); + } else { + return res.status(400).render("error", { + message: "The request was malformed." + }); + } +}); + + module.exports = function (c, d) { config = c database = d; diff --git a/adventure/userRoutes.js b/adventure/userRoutes.js index fb73275..619f76b 100644 --- a/adventure/userRoutes.js +++ b/adventure/userRoutes.js @@ -114,6 +114,40 @@ server.get("/user/edit", restrictedRoute(), function (req, res) { return res.render("editProfile"); }); +server.get("/user/profile", restrictedRoute(), function (req, res) { + return res.redirect("/user/profile/" + req.user.ShortName); +}); + +server.get("/user/profile/:name", function (req, res) { + database.userByName(req.params.name, function (err, user) { + if (err) { + return res.status(500).render("error", { + message: "There was an error fetching from the database." + }); + } else if (user == null) { + database.userById(formatting.hexToBin(req.params.name), function (err, user) { + if (err) { + return res.status(500).render("error", { + message: "There was an error fetching from the database." + }); + } else if (user == null) { + return res.status(404).render("error", { + message: "There was no user." + }); + } else { + return res.redirect("/user/profile/" + user.ShortName); + } + }); + } else { + user.UserID = formatting.binToHex(user.UserID); + res.render("publicProfile", { + viewingUser: user, + userFlags: database.userFlags, + }); + } + }); +}); + server.post("/user/changepw", restrictedRoute(), urlencodedParser, function (req, res) { if (req.body && req.body.password && req.body.newPassword && req.body.newPasswordR) { formatting.checkPassword(req.body.password, req.user.Salt, req.user.Password, function(checkErr, success) { diff --git a/adventure/views/contribute.ejs b/adventure/views/contribute.ejs new file mode 100644 index 0000000..c0ef9b0 --- /dev/null +++ b/adventure/views/contribute.ejs @@ -0,0 +1,104 @@ +<%- include("head", {title: "Contribute"}) %> +

Contribute

+

Basic metadata

+
+
+
+ + + + e.g. Windows 95 + +
+
+ + + + e.g. OSR2 + +
+
+ + +
+
+ <% + // HACK: datetime-local != toISOString + function pad(number) { + if (number < 10) { + return '0' + number; + } + return number; + } + function shortIso(d) { + return d.getUTCFullYear() + + '-' + pad(d.getUTCMonth() + 1) + + '-' + pad(d.getUTCDate()) + + 'T' + pad(d.getUTCHours()) + + ':' + pad(d.getUTCMinutes()); + } + %> +
+
+ + + + If your browser doesn't support HTML 5 datetime fields, use a format like
2000-02-15T06:00
. +
+
+
+ + + + If your browser doesn't support HTML 5 datetime fields, use a format like
2000-02-15T06:00
. +
+
+
+
+
+ + + + This field is formatted in Markdown + +
+
+ + + + This field is formatted in Markdown + +
+
+
+ + +
+
+
+ + +
+
+ + + + This field is converted to the most sensible human-readable byte size. Enter 0 to blank. + +
+
+ + + + This field is converted to the most sensible human-readable byte size. Enter 0 to blank. + +
+
+ + Cancel +
+<%- include("foot") %> diff --git a/adventure/views/editProfile.ejs b/adventure/views/editProfile.ejs index fde4bf8..3bd6cbf 100644 --- a/adventure/views/editProfile.ejs +++ b/adventure/views/editProfile.ejs @@ -1,5 +1,6 @@ <%- include("head", {title: "Edit profile"}) %>

Edit profile

+View profile

Details

diff --git a/adventure/views/head.ejs b/adventure/views/head.ejs index d9169b0..a9e767e 100644 --- a/adventure/views/head.ejs +++ b/adventure/views/head.ejs @@ -79,6 +79,8 @@ <%= user.ShortName %> diff --git a/adventure/views/library.ejs b/adventure/views/library.ejs index 6f99350..ada9e1b 100644 --- a/adventure/views/library.ejs +++ b/adventure/views/library.ejs @@ -3,6 +3,9 @@ <% for (var i in categoryMappings) { %> <%= categoryMappings[i] %> <% } %> + <% if (config.allowContributions) { %> + Contribute + <% } %>
<% products.forEach(function(i, n, a) {%> diff --git a/adventure/views/libraryOS.ejs b/adventure/views/libraryOS.ejs index 5a3b0ff..580c0e3 100644 --- a/adventure/views/libraryOS.ejs +++ b/adventure/views/libraryOS.ejs @@ -3,6 +3,9 @@ <% for (var i in categoryMappings) { %> <%= categoryMappings[i] %> <% } %> + <% if (config.allowContributions) { %> + Contribute + <% } %>
diff --git a/adventure/views/mycontributions.ejs b/adventure/views/mycontributions.ejs new file mode 100644 index 0000000..0f4020e --- /dev/null +++ b/adventure/views/mycontributions.ejs @@ -0,0 +1,63 @@ +<%- include("head", {title: "My contributions"}) %> +

My contributions

+ + + + + + + + + <% (contributions || []).forEach(function(i, n, a) {%> + + + + + <% }); %> + +
NameStatus
+ <%= i.ProductTitle %> <%= i.ReleaseTitle %> + + <%= i.Status %> (<%= i.Status == "Rejected" && i.RejectionReason ? i.RejectionReason : i.ContributionCreated.toDateString() %>) +
+ +<%- include("foot") %> \ No newline at end of file diff --git a/adventure/views/publicProfile.ejs b/adventure/views/publicProfile.ejs new file mode 100644 index 0000000..4ffa444 --- /dev/null +++ b/adventure/views/publicProfile.ejs @@ -0,0 +1,24 @@ +<%- include("head", {title: viewingUser.ShortName + "\'s Profile"}) %> +

<%= viewingUser.ShortName %>

+

+<% if (viewingUser.UserFlags && viewingUser.UserFlags.length > 0) { %> +<% viewingUser.UserFlags.forEach(function (i, n, a) { %> +<%= i.LongName %> +<% }); %> +<% } %> +

+

Joined <%= new Date(viewingUser.RegistrationTime).toLocaleDateString() %>

+

Last Active <%= new Date(viewingUser.LastSeenTime).toLocaleString() %>

+<% if (user && config.usersCanChangeTheme) { %> +

Using Theme <%= viewingUser.ThemeName %>

+<% } %> +<% if (config.useVanilla) { %> +

Show profile on forum

+<% } %> +<% if (user && user.UserFlags.some(function (x) { return x.FlagName == "sa"; })) { %> +

Manage user

+<% } %> +<% if (user && user.ShortName == viewingUser.ShortName) { %> +

Edit profile

+<% } %> +<%- include("foot") %> diff --git a/adventure/views/saContribution.ejs b/adventure/views/saContribution.ejs new file mode 100644 index 0000000..32f0b9d --- /dev/null +++ b/adventure/views/saContribution.ejs @@ -0,0 +1,112 @@ +<%- include("head", {title: "Contribution: " + contribution.ProductTitle + " " + contribution.ReleaseTitle}) %> +

Contribution: <%= contribution.ProductTitle %> <%= contribution.ReleaseTitle %>

+

Basic metadata

+ +
+
+ + + + e.g. Windows 95 + +
+
+ + + + e.g. OSR2 + +
+
+ + +
+
+ <% + // HACK: datetime-local != toISOString + function pad(number) { + if (number < 10) { + return '0' + number; + } + return number; + } + function shortIso(d) { + return d.getUTCFullYear() + + '-' + pad(d.getUTCMonth() + 1) + + '-' + pad(d.getUTCDate()) + + 'T' + pad(d.getUTCHours()) + + ':' + pad(d.getUTCMinutes()); + } + %> +
+
+ + + + If your browser doesn't support HTML 5 datetime fields, use a format like
2000-02-15T06:00
. +
+
+
+ + + + If your browser doesn't support HTML 5 datetime fields, use a format like
2000-02-15T06:00
. +
+
+
+
+
+ + + + This field is formatted in Markdown + +
+
+ + + + This field is formatted in Markdown + +
+
+
+ + +
+
+
+ + +
+
+ + + + This field is converted to the most sensible human-readable byte size. Enter 0 to blank. + +
+
+ + + + This field is converted to the most sensible human-readable byte size. Enter 0 to blank. + +
+
+ + Cancel + +

Reject contribution

+
+
+ + +
+ +
+<%- include("foot") %> diff --git a/adventure/views/saContributions.ejs b/adventure/views/saContributions.ejs index 1a3c1f1..c58ca66 100644 --- a/adventure/views/saContributions.ejs +++ b/adventure/views/saContributions.ejs @@ -1,4 +1,5 @@ -<%- include("head", {title: "Contributions"}) %> +<%- include("head", {title: "Contributions"}) %> +

Contributions

@@ -11,11 +12,11 @@ <% (contributions || []).forEach(function(i, n, a) {%> - + <% }); %> diff --git a/adventure/views/saUser.ejs b/adventure/views/saUser.ejs index ba291a9..26f4a3a 100644 --- a/adventure/views/saUser.ejs +++ b/adventure/views/saUser.ejs @@ -1,5 +1,6 @@ <%- include("head", {title: "Editing user " + editingUser.ShortName}) %>

Editing user <%= editingUser.ShortName %>

+View profile

Details

- <%= i.ReleaseTitle %> + <%= i.ProductTitle %> <%= i.ReleaseTitle %> <%= i.UserUUID %><%= i.UserUUID %> - <%= i.Status %> (<%= i.ContributionCreated.toDateString() %>) + <%= i.Status %> (<%= i.Status == "Rejected" && i.RejectionReason ? i.RejectionReason : i.ContributionCreated.toDateString() %>)