Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Achievements [WIP] #239

Open
wants to merge 68 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
d46af97
Revamp beta dialog a bit, add help one, fix beta dialog script error,…
aydenp Sep 9, 2017
9472ecd
Fix javascript not automatically processing
aydenp Sep 9, 2017
9692b9c
Fix notification error
aydenp Sep 9, 2017
8fce51c
Fix get started padding
aydenp Sep 9, 2017
5afdd24
Fix password regex, captcha reset on sites without captcha
aydenp Sep 9, 2017
77e3481
Merge branch 'master' of https://www.github.com/dynasticdevelop/place
aydenp Sep 9, 2017
cf4b33d
FUCK U TRAVIS SUCK MY BALLS
aydenp Sep 9, 2017
69d806d
fix signups x2
nullpixel Sep 9, 2017
8e41439
Fix admin panel nav items
aydenp Sep 9, 2017
4769fea
Merge branch 'master' of https://www.github.com/dynasticdevelop/place
aydenp Sep 9, 2017
c505eac
Update user.js
aydenp Sep 10, 2017
25c8e91
Disable password Regex checking for now
nullpixel Sep 14, 2017
a4ed06a
updated timelapse url
deadbaed Sep 17, 2017
3f26c82
Add support for sign up/in banners
aydenp Oct 22, 2017
74adb7a
Allow null editors
aydenp Oct 22, 2017
98c7449
fix null error in leaderboard manager
nullpixel Oct 25, 2017
c80d8b1
Add maintenance configuration options to deal with situations better
nullpixel Nov 27, 2017
444a931
Fix regression introduced by c80d8b1a20b80139b9ce3b952d0a11836351f7d4
nullpixel Nov 29, 2017
d5cfaa4
Add logging for 2FA, fix rate limit store logging (#236)
aydenp Dec 23, 2017
54d8300
Update user.js
aydenp Dec 23, 2017
7d06972
-re
aydenp Dec 23, 2017
6cc38ec
Update logger.js
aydenp Dec 23, 2017
c10453f
Update logger.js
aydenp Dec 23, 2017
80cf39f
Update layout.pug
aydenp Dec 23, 2017
a95563a
Start block flags support
aydenp Dec 26, 2017
2e5de9c
Added IP and user agent views for admins ONLY (#237)
EricRabil Dec 28, 2017
b95fb8c
Fix #234
aydenp Dec 31, 2017
b5242df
Resize to 1600x1600 (#238)
nullpixel Dec 31, 2017
18c39bd
Start scalable zoom
aydenp Dec 31, 2017
a47c27c
Merge branch 'master' of https://github.com/dynastic/place
aydenp Dec 31, 2017
48aecd5
Bring back achievements tab
aydenp Dec 31, 2017
6cc8c15
Update resize.js
EricRabil Dec 31, 2017
021402c
Update resize.js
EricRabil Dec 31, 2017
4422150
To achieve, or not to achieve.
EricRabil Dec 31, 2017
8eef19c
Improved duplication removal from arrays
EricRabil Dec 31, 2017
cfbd4db
Fixed Mongoose deprecation warnings
EricRabil Dec 31, 2017
21e53eb
Ignore all subsequent changes to the achievements file
EricRabil Dec 31, 2017
0890cf2
Finish up zoom, minus grid
aydenp Dec 31, 2017
60c7e15
Deploy OCNFETTI
aydenp Jan 1, 2018
7dc7a55
Update resource version
aydenp Jan 1, 2018
18e5541
Merge branch 'master' of https://github.com/dynastic/place
aydenp Jan 1, 2018
71de6fb
Attempt to fix sizing issues
aydenp Jan 1, 2018
f76b93e
fix legit
nullpixel Jan 1, 2018
b4155e5
fix
nullpixel Jan 1, 2018
f91459b
fix?
nullpixel Jan 1, 2018
d98e918
fix x3
nullpixel Jan 1, 2018
c3f77a1
Accomodate peer-review requests
EricRabil Jan 1, 2018
e318384
Disabled confetti
EricRabil Jan 1, 2018
877a186
Ignored a dev file
EricRabil Jan 1, 2018
65483cd
lmao
nullpixel Jan 1, 2018
27625ee
Merge branch 'master' of github.com:nullpixel1/place
nullpixel Jan 1, 2018
558c4d4
Fix zoom scale during animation
aydenp Jan 3, 2018
c911fb3
Fix mouse wheel for Gecko browsers
aydenp Jan 3, 2018
19f1e90
Fix scroll wheel while in popout
aydenp Jan 3, 2018
a74175a
Fix wheel delta with new event
aydenp Jan 3, 2018
c1c9a19
Set zoomed in threshold to halfway between initial and zoomed in point
aydenp Jan 3, 2018
b38d292
Fix non-legit builds
aydenp Jan 3, 2018
9c5c58a
Fix hand element sizing
aydenp Jan 3, 2018
0cde988
Fix grid hint
aydenp Jan 3, 2018
2c515e7
Fix grid hint positioning during zoom
aydenp Jan 3, 2018
f1809b7
Update grid hint properly when using arrow navigation
aydenp Jan 3, 2018
ee00063
Better not ready message
aydenp Jan 3, 2018
8375a55
Fuck grid tbh
aydenp Jan 3, 2018
0cb2dd1
res version
aydenp Jan 3, 2018
5ea66e4
fuck travis and whoever did this
aydenp Jan 3, 2018
183f582
Bring feature/achievements up to date with master (#241)
aydenp Jan 3, 2018
ee58e05
Merge pull request #242 from dynastic/master
aydenp Jan 3, 2018
406f972
Merge branch 'master' into feature/achievements
nullpixel May 22, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ views/legit.*
config/community_guidelines.md
config/privacy_policy.md
config/tos.md
config/achievements.js
modules/*

### Linux ###
Expand Down
25 changes: 23 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const mongoose = require("mongoose");
mongoose.promise = global.Promise;
const recaptcha = require("express-recaptcha");
const readline = require("readline").createInterface({input: process.stdin, output: process.stdout});
const util = require("util");
const PaintingManager = require("./util/PaintingManager");
const HTTPServer = require("./util/HTTPServer");
const WebsocketServer = require("./util/WebsocketServer");
Expand Down Expand Up @@ -97,7 +99,8 @@ app.recreateServer = () => {
}
app.recreateServer();

mongoose.connect(app.config.database);
mongoose.connect(app.config.database, {useMongoClient: true});
mongoose.Promise = global.Promise;

// Process JS
app.javascriptProcessor = new JavaScriptProcessor(app);
Expand Down Expand Up @@ -129,4 +132,22 @@ app.recreateRoutes = () => {
manager.getAllPublicDirectoriesToRegister().then((directories) => continueWithServer(directories)).catch((err) => continueWithServer());
});
}
app.recreateRoutes();
app.recreateRoutes();
readline.on('line', i => {
try {
var output = eval(i)
output instanceof Promise
? output.then(a => {
console.log('Promise Resolved')
console.log(util.inspect(a, {depth: 0}))
}).catch(e => {
console.log('Promise Rejected')
console.log(e.stack)
})
: output instanceof Object
? console.log(util.inspect(output, {depth: 0}))
: console.log(output)
} catch (err) {
console.log(err.stack)
}
})
28 changes: 25 additions & 3 deletions client/js/place.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var size;

var SignInDialogController = DialogController($("#sign-in-dialog"));
var ChangelogDialogController = DialogController($("#changelog-dialog"));
var HelpDialogController = DialogController($("#help-dialog"));
var BetaDialogController = DialogController($("#beta-dialog"));
BetaDialogController.dialog.find("#signup").click(function() {
placeAjax.post("/api/beta-signup", null, null).then(data => {
Expand Down Expand Up @@ -107,7 +108,7 @@ var notificationHandler = {
let notif = new Notification(title, {
body: message
});
notif.addEventListener('click', () => {
notif.addEventListener('click', (e) => {
// focus on window
parent.focus();
window.focus(); // fallback
Expand Down Expand Up @@ -148,7 +149,7 @@ var place = {
notificationHandler: notificationHandler, hashHandler: hashHandler,
messages: null,
isOutdated: false, lastPixelUpdate: null,
colours: null, canPlaceCustomColours: false, hasTriedToFetchAvailability: false, customColour: null,
colours: null, pixelFlags: null, canPlaceCustomColours: false, hasTriedToFetchAvailability: false, customColour: null,
cursorX: 0, cursorY: 0,
templatesEnabled: false,

Expand Down Expand Up @@ -284,6 +285,7 @@ var place = {
placeAjax.get("/api/feature-availability", null, null).then((data) => {
this.hasTriedToFetchAvailability = true;
this.colours = data.availability.colours;
this.pixelFlags = data.availability.flags;
this.canPlaceCustomColours = data.availability.user && data.availability.user.canPlaceCustomColours;
this.templatesEnabled = data.availability.user && data.availability.user.hasTemplatesExperiment
this.layoutTemplates();
Expand Down Expand Up @@ -523,6 +525,16 @@ var place = {
this.colourPaletteOptionElements.push(elem[0]);
});
this.updateColourSelectorPosition();
if(this.pixelFlags && this.pixelFlags.length > 0) {
$("<div>").addClass("palette-separator").appendTo(contentContainer);
this.pixelFlags.forEach((flag, index) => {
var elem = $("<div>").addClass("colour-option flag-option").css("background-image", `url(${flag.image})`).attr("data-flag", index).attr("data-flag-id", flag.id).attr("title", `${flag.title}:\n${flag.description}`).attr("alt", flag.title);
if(flag.needsBorder) elem.addClass("is-white");
elem.appendTo(contentContainer);
this.colourPaletteOptionElements.push(elem[0]);
console.log(flag);
});
}
} else {
overlay.text(this.hasTriedToFetchAvailability ? "An error occurred while loading colours. Retrying…" : "Loading…").show();
}
Expand Down Expand Up @@ -1062,6 +1074,7 @@ var place = {
},

pickColourUnderCursor: function() {
if(!this.canPlaceCustomColours) return;
var cursor = this.getCanvasCursorPosition();
var colour = this.canvasController.getPixelColour(cursor.x, cursor.y);
$("#colour-picker").minicolors("value", "#" + colour);
Expand Down Expand Up @@ -1416,4 +1429,13 @@ if(place.isSignedIn()) {
$(document).ready(function() {
changelogController.getChangelogsForShow();
});
}
}

$(document).ready(function() {
if(hashHandler.getHash()["beta"] != null) {
hashHandler.deleteHashKey("beta");
BetaDialogController.show();
}
});

$("#nav-help > a").click(() => HelpDialogController.show());
11 changes: 2 additions & 9 deletions client/js/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function DialogController(dialog) {
e.preventDefault();
var form = $(this);
var call = form.attr("action");
var tab = form.parent().attr("tab-name");
var tab = form.parent().parent().attr("tab-name");
var data = form.serialize();
if(form.data("submitting")) return;
var submitButton = form.find("input[type=submit], button[type=submit]");
Expand Down Expand Up @@ -105,7 +105,7 @@ function DialogController(dialog) {
me.switchTab("2fa-auth");
return;
}
if(tab == "sign-up") grecaptcha.reset();
if(tab == "sign-up" && typeof grecaptcha != "undefined") grecaptcha.reset();
me.shake();
var error = "An unknown error occurred while attempting to authenticate you.";
if(err && err.message) error = err.message;
Expand Down Expand Up @@ -247,10 +247,3 @@ if(("standalone" in window.navigator) && window.navigator.standalone){

}, false);
}

$(document).ready(function() {
if(hashHandler.getHash()["beta"] != null) {
hashHandler.deleteHashKey("beta");
BetaDialogController.show();
}
});
126 changes: 126 additions & 0 deletions config/achievements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
const olderThan = (date = Date.now(), time = {milliseconds: 0, seconds: 0, minutes: 0, hours: 0, days: 0, weeks: 0, months: 0, years: 0}) => {
let computedTime = Date.now();
if (time.milliseconds) {
computedTime -= time.milliseconds;
}
if (time.seconds) {
computedTime -= time.seconds * 1000;
}
if (time.minutes) {
computedTime -= time.minutes * 1000 * 60;
}
if (time.hours) {
computedTime -= time.hours * 1000 * 60 * 60;
}
if (time.days) {
computedTime -= time.days * 1000 * 60 * 60 * 24;
}
if (time.weeks) {
computedTime -= time.weeks * 1000 * 60 * 60 * 24 * 7;
}
if (time.months) {
let cTime = new Date();
cTime.setTime(Date.now() - computedTime);
const newMonths = cTime.getMonth() + time.months;
cTime.setMonth(newMonths);
computedTime = cTime.getTime();
}
if (time.years) {
computedTime -= time.years * 1000 * 60 * 60 * 24 * 365;
}
console.log("Minimum: " + computedTime);
console.log("Date: " + date);
return computedTime > date;
};

module.exports = [
// User has placed at least five pixels
{
name: "First Pixel!",
description: "You've placed one pixel!",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 1;
}
},
{
name: "Ten Pixels!",
description: "Congrats on hitting ten pixels! Keep it going!",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 10;
}
},
{
name: "100 Pixels!",
description: "W00T! Let's go let's go let's go!!! Get to 1000 pixels!",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 100;
}
},
{
name: "1000 Pixels!",
description: "I see you, placing those pixels all sexy 'n shit.",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 1000;
}
},
{
name: "Addict",
description: "People can safely default to assuming you're on canvas.place",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 10000;
}
},
{
name: "Ultra-Addict",
description: "You play canvas.place so much, you should just run the website.",
imageURL: null,
meetsCriteria(user) {
return user.placeCount >= 50000;
}
},
{
name: "Beginner",
description: "You're just starting out, but don't fret. You're going great places.",
imageURL: null,
meetsCriteria(user) {
return olderThan(user.creationDate, {days: 1});
}
},
{
name: "Novice",
description: "You're wiser than the average fellow but have much left to learn.",
imageURL: null,
meetsCriteria(user) {
return olderThan(user.creationDate, {weeks: 1});
}
},
{
name: "Intermediate",
description: "You're getting the hang of it! Keep at it.",
imageURL: null,
meetsCriteria(user) {
return olderThan(user.creationDate, {months: 1});
}
},
{
name: "Advanced",
description: "You've got it! I consider you to be proficient at the art of placing.",
imageURL: null,
meetsCriteria(user) {
return olderThan(user.creationDate, {months: 6});
}
},
{
name: "Expert",
description: "You're better than me, so..",
imageURL: null,
meetsCriteria(user) {
return olderThan(user.creationDate, {years: 1});
}
}
];
12 changes: 9 additions & 3 deletions config/config.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ module.exports = {
"placeTimeout": 60,
'enableChangelogs': true,
'siteName': 'Place',
//"raven": "",
//"publicRaven": "",
// "raven": "",
// "publicRaven": "",
// "bugsnag": "",
'maintenance': {
'allowSignups': true,
'allowLogins': true,
'notice': undefined
},
"cachet": {
// Setup reporting error count as a metric to Cachet
"apiKey": "",
Expand Down Expand Up @@ -62,5 +67,6 @@ module.exports = {
"clientID": "",
"clientSecret": ""
}
}
},
"pixelFlags": []
};
9 changes: 7 additions & 2 deletions controllers/AccountPageController.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ exports.getAccount = (req, res, next) => {
User.findByUsername(req.params.username).then((user) => {
if(!user) return next();
if((user.banned || user.deactivated) && !(req.user.moderator || req.user.admin)) return next();
user.getInfo(req.place).then((info) => {
return req.responseFactory.sendRenderedResponse("public/account", { profileUser: user, profileUserInfo: info, hasNewPassword: req.query.hasNewPassword });
user.getInfo(req.place).then(async (info) => {
if (req.user.admin) {
const accessData = await user.getUniqueIPsAndUserAgents();
user.ipAddresses = accessData.ipAddresses;
user.userAgents = accessData.userAgents;
}
return req.responseFactory.sendRenderedResponse("public/account", { profileUser: user, profileUserInfo: info, hasNewPassword: req.query.hasNewPassword});
}).catch((err) => next());
}).catch((err) => next());
};
Expand Down
19 changes: 19 additions & 0 deletions controllers/AchievementsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const User = require("../models/user");

const handleBadRequest = (res, e) => {
console.error(e);
res.status(500).json({success: false, error: {message: "An error occurred while processing your request"}});
}

exports.getUserAchievements = (req, res, next) => {
if (!req.params.username) return res.status(400).json({success: false, error: {code: "bad_request", message: "The username parameter is rqeuired."}});
const name = req.params.username;
User.findByUsername(name).then(user => {
if (!user) {
return res.status(404).json({success: false, error: {code: "not_found", message: "The username provided does not match any registered users."}});
}
user.getAchievements().then(achievements => {
res.json({achievements, success: true});
}).catch((e) => handleBadRequest(res, e));
}).catch((e) => handleBadRequest(res, e));
}
20 changes: 18 additions & 2 deletions controllers/AuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@ const passport = require("passport");
const speakeasy = require("speakeasy");
const absoluteURLRegex = new RegExp('^(?:[a-z]+:)?(//)?', 'i');

const User = require('../models/user');

exports.postSignIn = (req, res, next) => {
const config = req.place.config;
require("../util/passport")(passport, req.place);
if (req.user) return res.redirect("/");
if (!req.body.username || !req.body.password) return res.status(400).json({success: false, error: {message: "A username and password are required."}});
passport.authenticate("local", function(err, user, info) {
if (!user) return res.status(403).json({success: false, error: info.error || {message: "A username and password are required."}});
if (!user.admin && config.maintenance && !config.maintenance.allowLogins) return res.status(403).json({
success: false,
error: {
message: 'Logins disabled. Please do not call this endpoint any futher.'
}
});
if (user.twoFactorAuthEnabled()) {
if(!req.body.totpToken) return res.status(403).json({success: false, error: {code: "totp_needed", message: "Two-factor authentication is enabled for this account. Please specify your two-factor authentication token."}});
if(!speakeasy.totp.verify({ secret: user.totpSecret, encoding: 'base32', token: req.body.totpToken, window: 6 })) return res.status(403).json({success: false, error: {code: "invalid_totp", message: "We couldn't sign you in with that two-factor authentication token. Make sure you're entering the right code and it is updated."}});
}
if(!!req.body.keepSignedIn) req.session.maxAge = 1000 * 60 * 60 * 24 * 7; // keep signed in for 7 days
if(req.body.keepSignedIn) req.session.maxAge = 1000 * 60 * 60 * 24 * 7; // keep signed in for 7 days
req.login(user, function(err) {
if (err) return res.status(500).json({success: true, error: {message: "An unknown error occurred."}});
return res.json({success: true});
Expand All @@ -23,6 +32,13 @@ exports.postSignIn = (req, res, next) => {
};

exports.postSignUp = (req, res, next) => {
const config = req.place.config;
if (config.maintenance && !config.maintenance.allowSignups) return res.status(403).json({
success: false,
error: {
message: 'Signups disabled. Please do not call this endpoint any futher.'
}
});
function sendError(error) {
res.json({success: false, error: error || {message: "An unknown error occurred", code: "unknown_error"}});
}
Expand All @@ -32,7 +48,7 @@ exports.postSignUp = (req, res, next) => {
function doSignup() {
User.register(req.body.username, req.body.password, req.place, function(user, error) {
if(!user) return sendError(error);
if(!!req.body.keepSignedIn) req.session.maxAge = 1000 * 60 * 60 * 24 * 7; // keep signed in for 7 days
if(req.body.keepSignedIn) req.session.maxAge = 1000 * 60 * 60 * 24 * 7; // keep signed in for 7 days
req.login(user, function(err) {
if (err) return sendError(null);
res.json({success: true});
Expand Down
Loading