mirror of
https://github.com/HabitRPG/habitica.git
synced 2026-05-20 19:48:38 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b57fb94579 | |||
| 42805a2792 |
Generated
+97
@@ -35,6 +35,7 @@
|
|||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^5.0.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
|
"express-sitemap-xml": "^3.1.0",
|
||||||
"express-validator": "^5.2.0",
|
"express-validator": "^5.2.0",
|
||||||
"firebase-admin": "^12.1.1",
|
"firebase-admin": "^12.1.1",
|
||||||
"glob": "^8.1.0",
|
"glob": "^8.1.0",
|
||||||
@@ -10140,6 +10141,30 @@
|
|||||||
"basic-auth": "^2.0.1"
|
"basic-auth": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-sitemap-xml": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-sitemap-xml/-/express-sitemap-xml-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-rhm4ydngymgQlUyKor2kiY9Xf3wWWb/tbXYVMvidxyA83D1JjKOqYo23clhMvwJ+fk2ht11KtJwcaHnhhdo4PQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-memoize": "^4.0.1",
|
||||||
|
"xmlbuilder": "^15.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express-validator": {
|
"node_modules/express-validator": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-5.3.1.tgz",
|
||||||
@@ -14862,6 +14887,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/map-age-cleaner": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-defer": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/map-cache": {
|
"node_modules/map-cache": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
|
||||||
@@ -17227,6 +17264,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-defer": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-event": {
|
"node_modules/p-event": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz",
|
||||||
@@ -17306,6 +17352,32 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-memoize": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-memoize/-/p-memoize-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-ijdh0DP4Mk6J4FXlOM6vPPoCjPytcEseW8p/k5SDTSSfGV3E9bpt9Yzfifvzp6iohIieoLTkXRb32OWV0fB2Lw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"map-age-cleaner": "^0.1.3",
|
||||||
|
"mimic-fn": "^3.0.0",
|
||||||
|
"p-settle": "^4.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/p-memoize?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-memoize/node_modules/mimic-fn": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-pipe": {
|
"node_modules/p-pipe": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz",
|
||||||
@@ -17326,6 +17398,31 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-reflect": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-reflect/-/p-reflect-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-settle": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-settle/-/p-settle-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-limit": "^2.2.2",
|
||||||
|
"p-reflect": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-timeout": {
|
"node_modules/p-timeout": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^5.0.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
|
"express-sitemap-xml": "^3.1.0",
|
||||||
"express-validator": "^5.2.0",
|
"express-validator": "^5.2.0",
|
||||||
"firebase-admin": "^12.1.1",
|
"firebase-admin": "^12.1.1",
|
||||||
"glob": "^8.1.0",
|
"glob": "^8.1.0",
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Habitica - FAQ</title>
|
||||||
|
<meta name="description" content="Frequently Asked Questions about Habitica, the gamified task manager.">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700,700i|Roboto:400,400i,700,700i" rel="stylesheet">
|
||||||
|
<link rel="shortcut icon" sizes="48x48" href="/static/icons/favicon.ico">
|
||||||
|
<link rel="shortcut icon" sizes="192x192" href="/static/icons/favicon_192x192.png">
|
||||||
|
<link rel="mask-icon" href="/static/icons/favicon.ico">
|
||||||
|
<meta property="og:image" content="/static/emails/images/meta-image.png" />
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="text/javascript" src="//cloudfront.loggly.com/js/loggly.tracker-latest.min.js" async></script>
|
||||||
|
<!-- Translations -->
|
||||||
|
<script type='text/javascript' src='/api/v4/i18n/core' vite-ignore></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -68,8 +68,12 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
upDate (after) {
|
upDate (after) {
|
||||||
this.value = after;
|
// zero out the time so the server doesn't shift the day across a DST boundary on save
|
||||||
this.$emit('update:date', after);
|
const normalized = after
|
||||||
|
? new Date(after.getFullYear(), after.getMonth(), after.getDate())
|
||||||
|
: null;
|
||||||
|
this.value = normalized;
|
||||||
|
this.$emit('update:date', normalized);
|
||||||
},
|
},
|
||||||
setToday () {
|
setToday () {
|
||||||
this.upDate(moment().toDate());
|
this.upDate(moment().toDate());
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ export default defineConfig({
|
|||||||
include: [/moment-recur/, /node_modules/]
|
include: [/moment-recur/, /node_modules/]
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: path.resolve(__dirname, 'index.html'),
|
||||||
|
faq: path.resolve(__dirname, 'index-faq.html'),
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
experimentalMinChunkSize: 20000
|
experimentalMinChunkSize: 20000
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
moveTask,
|
moveTask,
|
||||||
setNextDue,
|
setNextDue,
|
||||||
requiredGroupFields,
|
requiredGroupFields,
|
||||||
|
normalizeDailyStartDate,
|
||||||
} from '../../libs/tasks/utils';
|
} from '../../libs/tasks/utils';
|
||||||
import common from '../../../common';
|
import common from '../../../common';
|
||||||
import { apiError } from '../../libs/apiError';
|
import { apiError } from '../../libs/apiError';
|
||||||
@@ -648,13 +649,10 @@ api.updateTask = {
|
|||||||
task.group.managerNotes = sanitizedObj.managerNotes;
|
task.group.managerNotes = sanitizedObj.managerNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For daily tasks, update start date based on timezone to maintain consistency
|
|
||||||
if (task.type === 'daily'
|
if (task.type === 'daily'
|
||||||
&& task.startDate
|
&& task.startDate
|
||||||
) {
|
) {
|
||||||
task.startDate = moment(task.startDate).utcOffset(
|
task.startDate = normalizeDailyStartDate(task.startDate, user);
|
||||||
-user.preferences.timezoneOffset,
|
|
||||||
).startOf('day').toDate();
|
|
||||||
|
|
||||||
// If the daily task was set to repeat monthly on a day of the month, and the start date was
|
// If the daily task was set to repeat monthly on a day of the month, and the start date was
|
||||||
// updated, the task will then need to be updated to repeat on the same day of the month as
|
// updated, the task will then need to be updated to repeat on the same day of the month as
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import nconf from 'nconf';
|
||||||
import { serveClient } from '../../libs/client';
|
import { serveClient } from '../../libs/client';
|
||||||
|
|
||||||
const api = {};
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
|
||||||
// All requests to /new_app (except /new_app/static) should serve the new client in development
|
const api = {};
|
||||||
// if (IS_PROD && IS_NEW_CLIENT_ENABLED) {
|
|
||||||
|
|
||||||
// All the routes (except for the api and payments routes) serve the new client side
|
// All the routes (except for the api and payments routes) serve the new client side
|
||||||
// The code that does it can be found in /middlewares/notFound.js
|
// The code that does it can be found in /middlewares/notFound.js
|
||||||
@@ -16,4 +16,22 @@ api.getNewClient = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
api.getFAQEntryPoint = {
|
||||||
|
method: 'GET',
|
||||||
|
url: '/static/faq',
|
||||||
|
noLanguage: true,
|
||||||
|
async handler (req, res) {
|
||||||
|
return serveClient(res, 'index-faq.html');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
api.robotsTxt = {
|
||||||
|
method: 'GET',
|
||||||
|
url: '/robots.txt',
|
||||||
|
noLanguage: true,
|
||||||
|
async handler (req, res) {
|
||||||
|
res.type('text/plain');
|
||||||
|
res.send(`User-agent: *\nAllow: /\nSitemap: ${BASE_URL}/sitemap.xml`);
|
||||||
|
},
|
||||||
|
};
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ const ROOT = `${__dirname}/../../../`;
|
|||||||
|
|
||||||
const TEN_MINUTES = 1000 * 60 * 10;
|
const TEN_MINUTES = 1000 * 60 * 10;
|
||||||
|
|
||||||
export function serveClient (expressRes) { // eslint-disable-line import/prefer-default-export
|
export function serveClient (expressRes, file = 'index.html') { // eslint-disable-line import/prefer-default-export
|
||||||
return expressRes.sendFile('./website/client/dist/index.html', { root: ROOT, maxAge: TEN_MINUTES });
|
return expressRes.sendFile(`./website/client/dist/${file}`, { root: ROOT, maxAge: TEN_MINUTES });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import moment from 'moment';
|
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import forEach from 'lodash/forEach';
|
import forEach from 'lodash/forEach';
|
||||||
@@ -9,6 +8,7 @@ import {
|
|||||||
setNextDue,
|
setNextDue,
|
||||||
validateTaskAlias,
|
validateTaskAlias,
|
||||||
requiredGroupFields,
|
requiredGroupFields,
|
||||||
|
normalizeDailyStartDate,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { model as Challenge } from '../../models/challenge';
|
import { model as Challenge } from '../../models/challenge';
|
||||||
import { model as Group } from '../../models/group';
|
import { model as Group } from '../../models/group';
|
||||||
@@ -80,13 +80,8 @@ async function createTasks (req, res, options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set startDate to midnight in the user's timezone
|
|
||||||
if (taskType === 'daily') {
|
if (taskType === 'daily') {
|
||||||
const awareStartDate = moment(newTask.startDate).utcOffset(-user.preferences.timezoneOffset);
|
newTask.startDate = normalizeDailyStartDate(newTask.startDate, user);
|
||||||
if (awareStartDate.format('HMsS') !== '0000') {
|
|
||||||
awareStartDate.startOf('day');
|
|
||||||
newTask.startDate = awareStartDate.toDate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setNextDue(newTask, user);
|
setNextDue(newTask, user);
|
||||||
|
|||||||
@@ -59,6 +59,21 @@ export function moveTask (order, taskId, to) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeDailyStartDate (date, user) {
|
||||||
|
if (!date) return date;
|
||||||
|
const utcView = moment.utc(date);
|
||||||
|
const looksLikeMidnightLocal = utcView.second() === 0
|
||||||
|
&& utcView.millisecond() === 0
|
||||||
|
&& [0, 15, 30, 45].includes(utcView.minute());
|
||||||
|
if (looksLikeMidnightLocal) {
|
||||||
|
return new Date(date);
|
||||||
|
}
|
||||||
|
return moment(date)
|
||||||
|
.utcOffset(-(user.preferences.timezoneOffset || 0))
|
||||||
|
.startOf('day')
|
||||||
|
.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
export function setNextDue (task, user, dueDateOption) {
|
export function setNextDue (task, user, dueDateOption) {
|
||||||
if (task.type !== 'daily') return;
|
if (task.type !== 'daily') return;
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
logRequestData,
|
logRequestData,
|
||||||
logSlowRequests,
|
logSlowRequests,
|
||||||
} from './requestLogHandler';
|
} from './requestLogHandler';
|
||||||
|
import sitemap from './sitemap';
|
||||||
|
|
||||||
const IS_PROD = nconf.get('IS_PROD');
|
const IS_PROD = nconf.get('IS_PROD');
|
||||||
const DISABLE_LOGGING = nconf.get('DISABLE_REQUEST_LOGGING') === 'true';
|
const DISABLE_LOGGING = nconf.get('DISABLE_REQUEST_LOGGING') === 'true';
|
||||||
@@ -74,6 +75,8 @@ export default function attachMiddlewares (app, server) {
|
|||||||
referrerPolicy: false,
|
referrerPolicy: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
app.use(sitemap);
|
||||||
|
|
||||||
// add res.respond and res.t
|
// add res.respond and res.t
|
||||||
app.use(responseHandler);
|
app.use(responseHandler);
|
||||||
app.use(attachTranslateFunction);
|
app.use(attachTranslateFunction);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import expressSitemapXml from 'express-sitemap-xml';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
|
||||||
|
function makeSitemapUrls () {
|
||||||
|
return [
|
||||||
|
'/',
|
||||||
|
'/static/login',
|
||||||
|
'/static/register',
|
||||||
|
'/stati/community-guidelines',
|
||||||
|
'/static/contact',
|
||||||
|
'/static/faq',
|
||||||
|
'/static/features',
|
||||||
|
'/static/group-plans',
|
||||||
|
'/static/news',
|
||||||
|
'/static/overview',
|
||||||
|
'/static/press-kit',
|
||||||
|
'/static/privacy',
|
||||||
|
'/static/terms',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default expressSitemapXml(makeSitemapUrls, BASE_URL);
|
||||||
Reference in New Issue
Block a user