mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
Merge branch 'develop' into release
This commit is contained in:
@@ -20,7 +20,8 @@ env:
|
|||||||
- DISABLE_REQUEST_LOGGING=true
|
- DISABLE_REQUEST_LOGGING=true
|
||||||
matrix:
|
matrix:
|
||||||
- TEST="lint"
|
- TEST="lint"
|
||||||
- TEST="test:api-v3" REQUIRES_SERVER=true COVERAGE=true
|
- TEST="test:api-v3:unit" REQUIRES_SERVER=true COVERAGE=true
|
||||||
|
- TEST="test:api-v3:integration" REQUIRES_SERVER=true COVERAGE=true
|
||||||
- TEST="test:sanity"
|
- TEST="test:sanity"
|
||||||
- TEST="test:content" COVERAGE=true
|
- TEST="test:content" COVERAGE=true
|
||||||
- TEST="test:common" COVERAGE=true
|
- TEST="test:common" COVERAGE=true
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ gulp.task('apidoc:clean', (done) => {
|
|||||||
clean(APIDOC_DEST_PATH, done);
|
clean(APIDOC_DEST_PATH, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('apidoc', ['apidoc:clean'], (done) => {
|
gulp.task('apidoc', gulp.series('apidoc:clean', (done) => {
|
||||||
let result = apidoc.createDoc({
|
let result = apidoc.createDoc({
|
||||||
src: APIDOC_SRC_PATH,
|
src: APIDOC_SRC_PATH,
|
||||||
dest: APIDOC_DEST_PATH,
|
dest: APIDOC_DEST_PATH,
|
||||||
@@ -19,8 +19,8 @@ gulp.task('apidoc', ['apidoc:clean'], (done) => {
|
|||||||
} else {
|
} else {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('apidoc:watch', ['apidoc'], () => {
|
gulp.task('apidoc:watch', gulp.series('apidoc', (done) => {
|
||||||
return gulp.watch(`${APIDOC_SRC_PATH}/**/*.js`, ['apidoc']);
|
return gulp.watch(`${APIDOC_SRC_PATH}/**/*.js`, gulp.series('apidoc', done));
|
||||||
});
|
}));
|
||||||
|
|||||||
@@ -2,12 +2,6 @@ import gulp from 'gulp';
|
|||||||
import babel from 'gulp-babel';
|
import babel from 'gulp-babel';
|
||||||
import webpackProductionBuild from '../webpack/build';
|
import webpackProductionBuild from '../webpack/build';
|
||||||
|
|
||||||
gulp.task('build', () => {
|
|
||||||
if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env
|
|
||||||
gulp.start('build:prod');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('build:src', () => {
|
gulp.task('build:src', () => {
|
||||||
return gulp.src('website/server/**/*.js')
|
return gulp.src('website/server/**/*.js')
|
||||||
.pipe(babel())
|
.pipe(babel())
|
||||||
@@ -20,18 +14,30 @@ gulp.task('build:common', () => {
|
|||||||
.pipe(gulp.dest('website/common/transpiled-babel/'));
|
.pipe(gulp.dest('website/common/transpiled-babel/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build:server', ['build:src', 'build:common']);
|
gulp.task('build:server', gulp.series('build:src', 'build:common', done => done()));
|
||||||
|
|
||||||
// Client Production Build
|
// Client Production Build
|
||||||
gulp.task('build:client', (done) => {
|
gulp.task('build:client', (done) => {
|
||||||
webpackProductionBuild((err, output) => {
|
webpackProductionBuild((err, output) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
console.log(output); // eslint-disable-line no-console
|
console.log(output); // eslint-disable-line no-console
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build:prod', [
|
gulp.task('build:prod', gulp.series(
|
||||||
'build:server',
|
'build:server',
|
||||||
'build:client',
|
'build:client',
|
||||||
'apidoc',
|
'apidoc',
|
||||||
]);
|
done => done()
|
||||||
|
));
|
||||||
|
|
||||||
|
let buildArgs = [];
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env
|
||||||
|
buildArgs.push('build:prod');
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('build', gulp.series(buildArgs, (done) => {
|
||||||
|
done();
|
||||||
|
}));
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import autoinc from 'mongoose-id-autoinc';
|
|
||||||
import logger from '../website/server/libs/logger';
|
import logger from '../website/server/libs/logger';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import repl from 'repl';
|
import repl from 'repl';
|
||||||
@@ -25,10 +24,10 @@ let improveRepl = (context) => {
|
|||||||
|
|
||||||
const isProd = nconf.get('NODE_ENV') === 'production';
|
const isProd = nconf.get('NODE_ENV') === 'production';
|
||||||
const mongooseOptions = !isProd ? {} : {
|
const mongooseOptions = !isProd ? {} : {
|
||||||
replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
|
keepAlive: 1,
|
||||||
server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
|
connectTimeoutMS: 30000,
|
||||||
|
useMongoClient: true,
|
||||||
};
|
};
|
||||||
autoinc.init(
|
|
||||||
mongoose.connect(
|
mongoose.connect(
|
||||||
nconf.get('NODE_DB_URI'),
|
nconf.get('NODE_DB_URI'),
|
||||||
mongooseOptions,
|
mongooseOptions,
|
||||||
@@ -36,12 +35,12 @@ let improveRepl = (context) => {
|
|||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
logger.info('Connected with Mongoose');
|
logger.info('Connected with Mongoose');
|
||||||
}
|
}
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('console', () => {
|
gulp.task('console', (done) => {
|
||||||
improveRepl(repl.start({
|
improveRepl(repl.start({
|
||||||
prompt: 'Habitica > ',
|
prompt: 'Habitica > ',
|
||||||
}).context);
|
}).context);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import mergeStream from 'merge-stream';
|
|||||||
import {basename} from 'path';
|
import {basename} from 'path';
|
||||||
import {sync} from 'glob';
|
import {sync} from 'glob';
|
||||||
import {each} from 'lodash';
|
import {each} from 'lodash';
|
||||||
|
import vinylBuffer from 'vinyl-buffer';
|
||||||
|
|
||||||
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
|
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
|
||||||
const MAX_SPRITESHEET_SIZE = 1024 * 1024 * 3;
|
const MAX_SPRITESHEET_SIZE = 1024 * 1024 * 3;
|
||||||
@@ -104,6 +105,7 @@ function createSpritesStream (name, src) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
let imgStream = spriteData.img
|
let imgStream = spriteData.img
|
||||||
|
.pipe(vinylBuffer())
|
||||||
.pipe(imagemin())
|
.pipe(imagemin())
|
||||||
.pipe(gulp.dest(IMG_DIST_PATH));
|
.pipe(gulp.dest(IMG_DIST_PATH));
|
||||||
|
|
||||||
@@ -117,8 +119,6 @@ function createSpritesStream (name, src) {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task('sprites:compile', ['sprites:clean', 'sprites:main', 'sprites:largeSprites', 'sprites:checkCompiledDimensions']);
|
|
||||||
|
|
||||||
gulp.task('sprites:main', () => {
|
gulp.task('sprites:main', () => {
|
||||||
let mainSrc = sync('website/raw_sprites/spritesmith/**/*.png');
|
let mainSrc = sync('website/raw_sprites/spritesmith/**/*.png');
|
||||||
return createSpritesStream('main', mainSrc);
|
return createSpritesStream('main', mainSrc);
|
||||||
@@ -133,7 +133,7 @@ gulp.task('sprites:clean', (done) => {
|
|||||||
clean(`${IMG_DIST_PATH}spritesmith*,${CSS_DIST_PATH}spritesmith*}`, done);
|
clean(`${IMG_DIST_PATH}spritesmith*,${CSS_DIST_PATH}spritesmith*}`, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('sprites:checkCompiledDimensions', ['sprites:main', 'sprites:largeSprites'], () => {
|
gulp.task('sprites:checkCompiledDimensions', gulp.series('sprites:main', 'sprites:largeSprites', (done) => {
|
||||||
console.log('Verifiying that images do not exceed max dimensions'); // eslint-disable-line no-console
|
console.log('Verifiying that images do not exceed max dimensions'); // eslint-disable-line no-console
|
||||||
|
|
||||||
let numberOfSheetsThatAreTooBig = 0;
|
let numberOfSheetsThatAreTooBig = 0;
|
||||||
@@ -159,4 +159,7 @@ gulp.task('sprites:checkCompiledDimensions', ['sprites:main', 'sprites:largeSpri
|
|||||||
} else {
|
} else {
|
||||||
console.log('All images are within the correct dimensions'); // eslint-disable-line no-console
|
console.log('All images are within the correct dimensions'); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
});
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
gulp.task('sprites:compile', gulp.series('sprites:clean', 'sprites:main', 'sprites:largeSprites', 'sprites:checkCompiledDimensions', done => done()));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import nodemon from 'gulp-nodemon';
|
|||||||
|
|
||||||
let pkg = require('../package.json');
|
let pkg = require('../package.json');
|
||||||
|
|
||||||
gulp.task('nodemon', () => {
|
gulp.task('nodemon', (done) => {
|
||||||
nodemon({
|
nodemon({
|
||||||
script: pkg.main,
|
script: pkg.main,
|
||||||
ignore: [
|
ignore: [
|
||||||
@@ -12,4 +12,5 @@ gulp.task('nodemon', () => {
|
|||||||
'common/dist/script/content/*',
|
'common/dist/script/content/*',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import gulp from 'gulp';
|
import gulp from 'gulp';
|
||||||
import runSequence from 'run-sequence';
|
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
|
|
||||||
@@ -39,23 +38,23 @@ let testBin = (string, additionalEnvVariables = '') => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('test:nodemon', () => {
|
gulp.task('test:nodemon', gulp.series(function setupNodemon (done) {
|
||||||
process.env.PORT = TEST_SERVER_PORT; // eslint-disable-line no-process-env
|
process.env.PORT = TEST_SERVER_PORT; // eslint-disable-line no-process-env
|
||||||
process.env.NODE_DB_URI = TEST_DB_URI; // eslint-disable-line no-process-env
|
process.env.NODE_DB_URI = TEST_DB_URI; // eslint-disable-line no-process-env
|
||||||
|
done();
|
||||||
runSequence('nodemon');
|
}, 'nodemon'));
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:prepare:mongo', (cb) => {
|
gulp.task('test:prepare:mongo', (cb) => {
|
||||||
mongoose.connect(TEST_DB_URI, (err) => {
|
mongoose.connect(TEST_DB_URI, (err) => {
|
||||||
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
|
if (err) return cb(`Unable to connect to mongo database. Are you sure it's running? \n\n${err}`);
|
||||||
mongoose.connection.db.dropDatabase();
|
mongoose.connection.dropDatabase((err2) => {
|
||||||
mongoose.connection.close();
|
if (err2) return cb(err2);
|
||||||
cb();
|
mongoose.connection.close(cb);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:prepare:server', ['test:prepare:mongo'], () => {
|
gulp.task('test:prepare:server', gulp.series('test:prepare:mongo', (done) => {
|
||||||
if (!server) {
|
if (!server) {
|
||||||
server = exec(testBin('node ./website/server/index.js', `NODE_DB_URI=${TEST_DB_URI} PORT=${TEST_SERVER_PORT}`), (error, stdout, stderr) => {
|
server = exec(testBin('node ./website/server/index.js', `NODE_DB_URI=${TEST_DB_URI} PORT=${TEST_SERVER_PORT}`), (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -64,16 +63,18 @@ gulp.task('test:prepare:server', ['test:prepare:mongo'], () => {
|
|||||||
if (stderr) {
|
if (stderr) {
|
||||||
console.error(stderr); // eslint-disable-line no-console
|
console.error(stderr); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:prepare:build', ['build']);
|
gulp.task('test:prepare:build', gulp.series('build', done => done()));
|
||||||
|
|
||||||
gulp.task('test:prepare', [
|
gulp.task('test:prepare', gulp.series(
|
||||||
'test:prepare:build',
|
'test:prepare:build',
|
||||||
'test:prepare:mongo',
|
'test:prepare:mongo',
|
||||||
]);
|
done => done()
|
||||||
|
));
|
||||||
|
|
||||||
gulp.task('test:sanity', (cb) => {
|
gulp.task('test:sanity', (cb) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
@@ -88,7 +89,7 @@ gulp.task('test:sanity', (cb) => {
|
|||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:common', ['test:prepare:build'], (cb) => {
|
gulp.task('test:common', gulp.series('test:prepare:build', (cb) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
testBin(COMMON_TEST_COMMAND),
|
testBin(COMMON_TEST_COMMAND),
|
||||||
(err) => {
|
(err) => {
|
||||||
@@ -99,17 +100,17 @@ gulp.task('test:common', ['test:prepare:build'], (cb) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:common:clean', (cb) => {
|
gulp.task('test:common:clean', (cb) => {
|
||||||
pipe(exec(testBin(COMMON_TEST_COMMAND), () => cb()));
|
pipe(exec(testBin(COMMON_TEST_COMMAND), () => cb()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:common:watch', ['test:common:clean'], () => {
|
gulp.task('test:common:watch', gulp.series('test:common:clean', () => {
|
||||||
gulp.watch(['common/script/**/*', 'test/common/**/*'], ['test:common:clean']);
|
return gulp.watch(['common/script/**/*', 'test/common/**/*'], gulp.series('test:common:clean', done => done()));
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:common:safe', ['test:prepare:build'], (cb) => {
|
gulp.task('test:common:safe', gulp.series('test:prepare:build', (cb) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
testBin(COMMON_TEST_COMMAND),
|
testBin(COMMON_TEST_COMMAND),
|
||||||
(err, stdout) => { // eslint-disable-line handle-callback-err
|
(err, stdout) => { // eslint-disable-line handle-callback-err
|
||||||
@@ -123,9 +124,9 @@ gulp.task('test:common:safe', ['test:prepare:build'], (cb) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:content', ['test:prepare:build'], (cb) => {
|
gulp.task('test:content', gulp.series('test:prepare:build', (cb) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
testBin(CONTENT_TEST_COMMAND),
|
testBin(CONTENT_TEST_COMMAND),
|
||||||
CONTENT_OPTIONS,
|
CONTENT_OPTIONS,
|
||||||
@@ -137,17 +138,17 @@ gulp.task('test:content', ['test:prepare:build'], (cb) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:content:clean', (cb) => {
|
gulp.task('test:content:clean', (cb) => {
|
||||||
pipe(exec(testBin(CONTENT_TEST_COMMAND), CONTENT_OPTIONS, () => cb()));
|
pipe(exec(testBin(CONTENT_TEST_COMMAND), CONTENT_OPTIONS, () => cb()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:content:watch', ['test:content:clean'], () => {
|
gulp.task('test:content:watch', gulp.series('test:content:clean', () => {
|
||||||
gulp.watch(['common/script/content/**', 'test/**'], ['test:content:clean']);
|
return gulp.watch(['common/script/content/**', 'test/**'], gulp.series('test:content:clean', done => done()));
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:content:safe', ['test:prepare:build'], (cb) => {
|
gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
testBin(CONTENT_TEST_COMMAND),
|
testBin(CONTENT_TEST_COMMAND),
|
||||||
CONTENT_OPTIONS,
|
CONTENT_OPTIONS,
|
||||||
@@ -162,7 +163,7 @@ gulp.task('test:content:safe', ['test:prepare:build'], (cb) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
}));
|
||||||
|
|
||||||
gulp.task('test:api-v3:unit', (done) => {
|
gulp.task('test:api-v3:unit', (done) => {
|
||||||
let runner = exec(
|
let runner = exec(
|
||||||
@@ -179,7 +180,7 @@ gulp.task('test:api-v3:unit', (done) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:api-v3:unit:watch', () => {
|
gulp.task('test:api-v3:unit:watch', () => {
|
||||||
gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], ['test:api-v3:unit']);
|
return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api-v3:unit', done => done()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:api-v3:integration', (done) => {
|
gulp.task('test:api-v3:integration', (done) => {
|
||||||
@@ -198,8 +199,10 @@ gulp.task('test:api-v3:integration', (done) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:api-v3:integration:watch', () => {
|
gulp.task('test:api-v3:integration:watch', () => {
|
||||||
gulp.watch(['website/server/controllers/api-v3/**/*', 'common/script/ops/*', 'website/server/libs/*.js',
|
return gulp.watch([
|
||||||
'test/api/v3/integration/**/*'], ['test:api-v3:integration']);
|
'website/server/controllers/api-v3/**/*', 'common/script/ops/*', 'website/server/libs/*.js',
|
||||||
|
'test/api/v3/integration/**/*',
|
||||||
|
], gulp.series('test:api-v3:integration', done => done()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:api-v3:integration:separate-server', (done) => {
|
gulp.task('test:api-v3:integration:separate-server', (done) => {
|
||||||
@@ -212,21 +215,17 @@ gulp.task('test:api-v3:integration:separate-server', (done) => {
|
|||||||
pipe(runner);
|
pipe(runner);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test', (done) => {
|
gulp.task('test', gulp.series(
|
||||||
runSequence(
|
|
||||||
'test:sanity',
|
'test:sanity',
|
||||||
'test:content',
|
'test:content',
|
||||||
'test:common',
|
'test:common',
|
||||||
'test:api-v3:unit',
|
'test:api-v3:unit',
|
||||||
'test:api-v3:integration',
|
'test:api-v3:integration',
|
||||||
done
|
done => done()
|
||||||
);
|
));
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:api-v3', (done) => {
|
gulp.task('test:api-v3', gulp.series(
|
||||||
runSequence(
|
|
||||||
'test:api-v3:unit',
|
'test:api-v3:unit',
|
||||||
'test:api-v3:integration',
|
'test:api-v3:integration',
|
||||||
done
|
done => done()
|
||||||
);
|
));
|
||||||
});
|
|
||||||
|
|||||||
@@ -93,9 +93,7 @@ const malformedStringExceptions = {
|
|||||||
feedPet: true,
|
feedPet: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('transifex', ['transifex:missingFiles', 'transifex:missingStrings', 'transifex:malformedStrings']);
|
gulp.task('transifex:missingFiles', (done) => {
|
||||||
|
|
||||||
gulp.task('transifex:missingFiles', () => {
|
|
||||||
let missingStrings = [];
|
let missingStrings = [];
|
||||||
|
|
||||||
eachTranslationFile(ALL_LANGUAGES, (error) => {
|
eachTranslationFile(ALL_LANGUAGES, (error) => {
|
||||||
@@ -109,9 +107,10 @@ gulp.task('transifex:missingFiles', () => {
|
|||||||
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('transifex:missingStrings', () => {
|
gulp.task('transifex:missingStrings', (done) => {
|
||||||
let missingStrings = [];
|
let missingStrings = [];
|
||||||
|
|
||||||
eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => {
|
eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => {
|
||||||
@@ -126,9 +125,10 @@ gulp.task('transifex:missingStrings', () => {
|
|||||||
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
let formattedMessage = formatMessageForPosting(message, missingStrings);
|
||||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('transifex:malformedStrings', () => {
|
gulp.task('transifex:malformedStrings', (done) => {
|
||||||
let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE));
|
||||||
let interpolationRegex = /<%= [a-zA-Z]* %>/g;
|
let interpolationRegex = /<%= [a-zA-Z]* %>/g;
|
||||||
let stringsToLookFor = getStringsWith(jsonFiles, interpolationRegex);
|
let stringsToLookFor = getStringsWith(jsonFiles, interpolationRegex);
|
||||||
@@ -170,4 +170,11 @@ gulp.task('transifex:malformedStrings', () => {
|
|||||||
let formattedMessage = formatMessageForPosting(message, stringsWithIncorrectNumberOfInterpolations);
|
let formattedMessage = formatMessageForPosting(message, stringsWithIncorrectNumberOfInterpolations);
|
||||||
postToSlack(formattedMessage, SLACK_CONFIG);
|
postToSlack(formattedMessage, SLACK_CONFIG);
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
'transifex',
|
||||||
|
gulp.series('transifex:missingFiles', 'transifex:missingStrings', 'transifex:malformedStrings'),
|
||||||
|
(done) => done()
|
||||||
|
);
|
||||||
@@ -8,10 +8,12 @@
|
|||||||
|
|
||||||
require('babel-register');
|
require('babel-register');
|
||||||
|
|
||||||
|
const gulp = require('gulp');
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env
|
if (process.env.NODE_ENV === 'production') { // eslint-disable-line no-process-env
|
||||||
require('./gulp/gulp-apidoc'); // eslint-disable-line global-require
|
require('./gulp/gulp-apidoc'); // eslint-disable-line global-require
|
||||||
require('./gulp/gulp-build'); // eslint-disable-line global-require
|
require('./gulp/gulp-build'); // eslint-disable-line global-require
|
||||||
} else {
|
} else {
|
||||||
require('glob').sync('./gulp/gulp-*').forEach(require); // eslint-disable-line global-require
|
require('glob').sync('./gulp/gulp-*').forEach(require); // eslint-disable-line global-require
|
||||||
require('gulp').task('default', ['test']); // eslint-disable-line global-require
|
require('gulp').task('default', gulp.series('test')); // eslint-disable-line global-require
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,71 +18,94 @@ var authorUuid = '3e595299-3d8a-4a10-bfe0-88f555e4aa0c'; //... own data is done
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var dbserver = 'localhost:27017'; // FOR TEST DATABASE
|
var connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
|
||||||
var dbserver = 'username:password@ds031379-a0.mongolab.com:31379'; // FOR PRODUCTION DATABASE
|
|
||||||
var dbname = 'habitrpg';
|
|
||||||
|
|
||||||
var mongo = require('mongoskin');
|
var monk = require('monk');
|
||||||
var _ = require('lodash');
|
var dbUsers = monk(connectionString).get('users', { castIds: false });
|
||||||
|
|
||||||
var dbUsers = mongo.db(dbserver + '/' + dbname + '?auto_reconnect').collection('users');
|
|
||||||
|
|
||||||
|
function processUsers(lastId) {
|
||||||
// specify a query to limit the affected users (empty for all users):
|
// specify a query to limit the affected users (empty for all users):
|
||||||
var query = {
|
var query = {
|
||||||
'auth.timestamps.loggedin':{$gt:new Date('2016-01-04')}
|
'auth.timestamps.loggedin':{$gt:new Date('2016-01-04')}
|
||||||
// '_id': authorUuid // FOR TESTING
|
// '_id': authorUuid // FOR TESTING
|
||||||
};
|
};
|
||||||
|
|
||||||
// specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
// specify a query to limit the affected users (empty for all users):
|
||||||
var fields = {
|
var fields = {
|
||||||
'flags.armoireEmpty':1,
|
'flags.armoireEmpty':1,
|
||||||
'items.gear.owned':1
|
'items.gear.owned':1
|
||||||
};
|
};
|
||||||
|
|
||||||
// specify user data to change:
|
if (lastId) {
|
||||||
|
query._id = {
|
||||||
|
$gt: lastId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUsers.find(query, {
|
||||||
|
sort: {_id: 1},
|
||||||
|
limit: 250,
|
||||||
|
fields: {
|
||||||
|
'flags.armoireEmpty':1,
|
||||||
|
'items.gear.owned':1
|
||||||
|
} // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||||
|
})
|
||||||
|
.then(updateUsers)
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
return exiting(1, 'ERROR! ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function updateUsers (users) {
|
||||||
|
if (!users || users.length === 0) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
displayData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userPromises = users.map(updateUser);
|
||||||
|
var lastUser = users[users.length - 1];
|
||||||
|
|
||||||
|
return Promise.all(userPromises)
|
||||||
|
.then(function () {
|
||||||
|
processUsers(lastUser._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUser (user) {
|
||||||
|
count++;
|
||||||
|
|
||||||
var set = {'migration':migrationName, 'flags.armoireEmpty':false};
|
var set = {'migration':migrationName, 'flags.armoireEmpty':false};
|
||||||
|
|
||||||
console.warn('Updating users...');
|
|
||||||
var progressCount = 1000;
|
|
||||||
var countSearched = 0;
|
|
||||||
var countModified = 0;
|
|
||||||
dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
|
|
||||||
if (err) { return exiting(1, 'ERROR! ' + err); }
|
|
||||||
if (!user) {
|
|
||||||
console.warn('All appropriate users found and modified.');
|
|
||||||
return displayData();
|
|
||||||
}
|
|
||||||
countSearched++;
|
|
||||||
|
|
||||||
if (user.flags.armoireEmpty) {
|
if (user.flags.armoireEmpty) {
|
||||||
// this user believes their armoire has no more items in it
|
// this user believes their armoire has no more items in it
|
||||||
if (user.items.gear.owned.weapon_armoire_barristerGavel && user.items.gear.owned.armor_armoire_barristerRobes && user.items.gear.owned.head_armoire_jesterCap && user.items.gear.owned.armor_armoire_jesterCostume && user.items.gear.owned.head_armoire_barristerWig && user.items.gear.owned.weapon_armoire_jesterBaton && user.items.gear.owned.weapon_armoire_lunarSceptre && user.items.gear.owned.armor_armoire_gladiatorArmor && user.items.gear.owned.weapon_armoire_basicCrossbow && user.items.gear.owned.head_armoire_gladiatorHelm && user.items.gear.owned.armor_armoire_lunarArmor && user.items.gear.owned.head_armoire_redHairbow && user.items.gear.owned.head_armoire_violetFloppyHat && user.items.gear.owned.head_armoire_rancherHat && user.items.gear.owned.shield_armoire_gladiatorShield && user.items.gear.owned.head_armoire_blueHairbow && user.items.gear.owned.weapon_armoire_mythmakerSword && user.items.gear.owned.head_armoire_royalCrown && user.items.gear.owned.head_armoire_hornedIronHelm && user.items.gear.owned.weapon_armoire_rancherLasso && user.items.gear.owned.armor_armoire_rancherRobes && user.items.gear.owned.armor_armoire_hornedIronArmor && user.items.gear.owned.armor_armoire_goldenToga && user.items.gear.owned.weapon_armoire_ironCrook && user.items.gear.owned.head_armoire_goldenLaurels && user.items.gear.owned.head_armoire_redFloppyHat && user.items.gear.owned.armor_armoire_plagueDoctorOvercoat && user.items.gear.owned.head_armoire_plagueDoctorHat && user.items.gear.owned.weapon_armoire_goldWingStaff && user.items.gear.owned.head_armoire_yellowHairbow && user.items.gear.owned.eyewear_armoire_plagueDoctorMask && user.items.gear.owned.head_armoire_blackCat && user.items.gear.owned.weapon_armoire_batWand && user.items.gear.owned.head_armoire_orangeCat && user.items.gear.owned.shield_armoire_midnightShield && user.items.gear.owned.armor_armoire_royalRobes && user.items.gear.owned.head_armoire_blueFloppyHat && user.items.gear.owned.shield_armoire_royalCane && user.items.gear.owned.weapon_armoire_shepherdsCrook && user.items.gear.owned.armor_armoire_shepherdRobes && user.items.gear.owned.head_armoire_shepherdHeaddress && user.items.gear.owned.weapon_armoire_blueLongbow && user.items.gear.owned.weapon_armoire_crystalCrescentStaff && user.items.gear.owned.head_armoire_crystalCrescentHat && user.items.gear.owned.armor_armoire_dragonTamerArmor && user.items.gear.owned.head_armoire_dragonTamerHelm && user.items.gear.owned.armor_armoire_crystalCrescentRobes && user.items.gear.owned.shield_armoire_dragonTamerShield && user.items.gear.owned.weapon_armoire_glowingSpear) {
|
if (user.items.gear.owned.weapon_armoire_barristerGavel && user.items.gear.owned.armor_armoire_barristerRobes && user.items.gear.owned.head_armoire_jesterCap && user.items.gear.owned.armor_armoire_jesterCostume && user.items.gear.owned.head_armoire_barristerWig && user.items.gear.owned.weapon_armoire_jesterBaton && user.items.gear.owned.weapon_armoire_lunarSceptre && user.items.gear.owned.armor_armoire_gladiatorArmor && user.items.gear.owned.weapon_armoire_basicCrossbow && user.items.gear.owned.head_armoire_gladiatorHelm && user.items.gear.owned.armor_armoire_lunarArmor && user.items.gear.owned.head_armoire_redHairbow && user.items.gear.owned.head_armoire_violetFloppyHat && user.items.gear.owned.head_armoire_rancherHat && user.items.gear.owned.shield_armoire_gladiatorShield && user.items.gear.owned.head_armoire_blueHairbow && user.items.gear.owned.weapon_armoire_mythmakerSword && user.items.gear.owned.head_armoire_royalCrown && user.items.gear.owned.head_armoire_hornedIronHelm && user.items.gear.owned.weapon_armoire_rancherLasso && user.items.gear.owned.armor_armoire_rancherRobes && user.items.gear.owned.armor_armoire_hornedIronArmor && user.items.gear.owned.armor_armoire_goldenToga && user.items.gear.owned.weapon_armoire_ironCrook && user.items.gear.owned.head_armoire_goldenLaurels && user.items.gear.owned.head_armoire_redFloppyHat && user.items.gear.owned.armor_armoire_plagueDoctorOvercoat && user.items.gear.owned.head_armoire_plagueDoctorHat && user.items.gear.owned.weapon_armoire_goldWingStaff && user.items.gear.owned.head_armoire_yellowHairbow && user.items.gear.owned.eyewear_armoire_plagueDoctorMask && user.items.gear.owned.head_armoire_blackCat && user.items.gear.owned.weapon_armoire_batWand && user.items.gear.owned.head_armoire_orangeCat && user.items.gear.owned.shield_armoire_midnightShield && user.items.gear.owned.armor_armoire_royalRobes && user.items.gear.owned.head_armoire_blueFloppyHat && user.items.gear.owned.shield_armoire_royalCane && user.items.gear.owned.weapon_armoire_shepherdsCrook && user.items.gear.owned.armor_armoire_shepherdRobes && user.items.gear.owned.head_armoire_shepherdHeaddress && user.items.gear.owned.weapon_armoire_blueLongbow && user.items.gear.owned.weapon_armoire_crystalCrescentStaff && user.items.gear.owned.head_armoire_crystalCrescentHat && user.items.gear.owned.armor_armoire_dragonTamerArmor && user.items.gear.owned.head_armoire_dragonTamerHelm && user.items.gear.owned.armor_armoire_crystalCrescentRobes && user.items.gear.owned.shield_armoire_dragonTamerShield && user.items.gear.owned.weapon_armoire_glowingSpear) {
|
||||||
// this user does have all the armoire items so we don't change the flag
|
// this user does have all the armoire items so we don't change the flag
|
||||||
// console.log("don't change: " + user._id); // FOR TESTING
|
// console.log("don't change: " + user._id); // FOR TESTING
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
countModified++;
|
|
||||||
// console.log("change: " + user._id); // FOR TESTING
|
// console.log("change: " + user._id); // FOR TESTING
|
||||||
dbUsers.update({_id: user._id}, {$set: set});
|
dbUsers.update({_id: user._id}, {$set: set});
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// this user already has armoire marked as containing items to be bought
|
// this user already has armoire marked as containing items to be bought
|
||||||
// so don't change the flag
|
// so don't change the flag
|
||||||
// console.log("DON'T CHANGE: " + user._id); // FOR TESTING
|
// console.log("DON'T CHANGE: " + user._id); // FOR TESTING
|
||||||
}
|
}
|
||||||
|
|
||||||
if (countSearched%progressCount == 0) console.warn(countSearched + ' ' + user._id);
|
if (count % progressCount == 0) console.warn(count + ' ' + user._id);
|
||||||
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function displayData() {
|
|
||||||
console.warn('\n' + countSearched + ' users searched\n');
|
|
||||||
console.warn('\n' + countModified + ' users modified\n');
|
|
||||||
return exiting(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function displayData() {
|
||||||
|
console.warn('\n' + count + ' users processed\n');
|
||||||
|
return exiting(0);
|
||||||
|
}
|
||||||
|
|
||||||
function exiting(code, msg) {
|
function exiting(code, msg) {
|
||||||
code = code || 0; // 0 = success
|
code = code || 0; // 0 = success
|
||||||
@@ -93,3 +116,5 @@ function exiting(code, msg) {
|
|||||||
}
|
}
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = processUsers;
|
||||||
|
|||||||
7828
package-lock.json
generated
7828
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
63
package.json
63
package.json
@@ -10,7 +10,6 @@
|
|||||||
"amplitude": "^2.0.3",
|
"amplitude": "^2.0.3",
|
||||||
"apidoc": "^0.17.5",
|
"apidoc": "^0.17.5",
|
||||||
"apn": "^1.7.6",
|
"apn": "^1.7.6",
|
||||||
"async": "^1.5.0",
|
|
||||||
"autoprefixer": "^6.4.0",
|
"autoprefixer": "^6.4.0",
|
||||||
"aws-sdk": "^2.0.25",
|
"aws-sdk": "^2.0.25",
|
||||||
"axios": "^0.16.0",
|
"axios": "^0.16.0",
|
||||||
@@ -35,7 +34,7 @@
|
|||||||
"compression": "^1.6.1",
|
"compression": "^1.6.1",
|
||||||
"cookie-session": "^1.2.0",
|
"cookie-session": "^1.2.0",
|
||||||
"coupon-code": "^0.4.5",
|
"coupon-code": "^0.4.5",
|
||||||
"cross-env": "^4.0.0",
|
"cross-env": "^5.1.3",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
"csv-stringify": "^1.0.2",
|
"csv-stringify": "^1.0.2",
|
||||||
"cwait": "~1.0.1",
|
"cwait": "~1.0.1",
|
||||||
@@ -44,22 +43,19 @@
|
|||||||
"express-basic-auth": "^1.0.1",
|
"express-basic-auth": "^1.0.1",
|
||||||
"express-validator": "^2.18.0",
|
"express-validator": "^2.18.0",
|
||||||
"extract-text-webpack-plugin": "^2.0.0-rc.3",
|
"extract-text-webpack-plugin": "^2.0.0-rc.3",
|
||||||
"glob": "^4.3.5",
|
"glob": "^7.1.2",
|
||||||
"got": "^6.1.1",
|
"got": "^6.1.1",
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^4.0.0",
|
||||||
"gulp-babel": "^6.1.2",
|
"gulp-babel": "^6.1.2",
|
||||||
"gulp-imagemin": "^2.4.0",
|
"gulp-imagemin": "^4.1.0",
|
||||||
"gulp-nodemon": "^2.0.4",
|
"gulp-nodemon": "^2.2.1",
|
||||||
"gulp-sourcemaps": "^1.6.0",
|
"gulp.spritesmith": "^6.9.0",
|
||||||
"gulp-uglify": "^1.4.2",
|
|
||||||
"gulp.spritesmith": "^4.1.0",
|
|
||||||
"habitica-markdown": "^1.3.0",
|
"habitica-markdown": "^1.3.0",
|
||||||
"hellojs": "^1.15.1",
|
"hellojs": "^1.15.1",
|
||||||
"html-webpack-plugin": "^2.8.1",
|
"html-webpack-plugin": "^2.8.1",
|
||||||
"image-size": "~0.3.2",
|
"image-size": "^0.6.2",
|
||||||
"in-app-purchase": "^1.1.6",
|
"in-app-purchase": "^1.1.6",
|
||||||
"intro.js": "^2.6.0",
|
"intro.js": "^2.6.0",
|
||||||
"jade": "~1.11.0",
|
|
||||||
"jquery": ">=3.0.0",
|
"jquery": ">=3.0.0",
|
||||||
"js2xmlparser": "~1.0.0",
|
"js2xmlparser": "~1.0.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
@@ -67,8 +63,7 @@
|
|||||||
"method-override": "^2.3.5",
|
"method-override": "^2.3.5",
|
||||||
"moment": "^2.13.0",
|
"moment": "^2.13.0",
|
||||||
"moment-recur": "git://github.com/habitrpg/moment-recur.git#f147ef27bbc26ca67638385f3db4a44084c76626",
|
"moment-recur": "git://github.com/habitrpg/moment-recur.git#f147ef27bbc26ca67638385f3db4a44084c76626",
|
||||||
"mongoose": "^4.8.6",
|
"mongoose": "^4.13.10",
|
||||||
"mongoose-id-autoinc": "~2013.7.14-4",
|
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"nconf": "~0.8.2",
|
"nconf": "~0.8.2",
|
||||||
"node-gcm": "^0.14.4",
|
"node-gcm": "^0.14.4",
|
||||||
@@ -84,24 +79,24 @@
|
|||||||
"popper.js": "^1.13.0",
|
"popper.js": "^1.13.0",
|
||||||
"postcss-easy-import": "^2.0.0",
|
"postcss-easy-import": "^2.0.0",
|
||||||
"ps-tree": "^1.0.0",
|
"ps-tree": "^1.0.0",
|
||||||
"pug": "^2.0.0-beta.12",
|
"pug": "^2.0.0-rc.4",
|
||||||
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
|
"push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9",
|
||||||
"pusher": "^1.3.0",
|
"pusher": "^1.3.0",
|
||||||
"request": "~2.74.0",
|
"request": "^2.83.0",
|
||||||
"rimraf": "^2.4.3",
|
"rimraf": "^2.4.3",
|
||||||
"run-sequence": "^1.1.4",
|
|
||||||
"sass-loader": "^6.0.2",
|
"sass-loader": "^6.0.2",
|
||||||
"shelljs": "^0.7.6",
|
"shelljs": "^0.8.1",
|
||||||
"stripe": "^4.2.0",
|
"stripe": "^4.2.0",
|
||||||
"superagent": "^3.4.3",
|
"superagent": "^3.4.3",
|
||||||
"svg-inline-loader": "^0.7.1",
|
"svg-inline-loader": "^0.7.1",
|
||||||
"svg-url-loader": "^2.0.2",
|
"svg-url-loader": "^2.0.2",
|
||||||
"svgo-loader": "^1.2.1",
|
"svgo-loader": "^1.2.1",
|
||||||
"universal-analytics": "~0.3.2",
|
"universal-analytics": "^0.4.16",
|
||||||
"url-loader": "^0.5.7",
|
"url-loader": "^0.5.7",
|
||||||
"useragent": "^2.1.9",
|
"useragent": "^2.1.9",
|
||||||
"uuid": "^3.0.1",
|
"uuid": "^3.0.1",
|
||||||
"validator": "^4.9.0",
|
"validator": "^4.9.0",
|
||||||
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vue": "^2.5.2",
|
"vue": "^2.5.2",
|
||||||
"vue-loader": "^13.3.0",
|
"vue-loader": "^13.3.0",
|
||||||
"vue-mugen-scroll": "^0.2.1",
|
"vue-mugen-scroll": "^0.2.1",
|
||||||
@@ -113,7 +108,7 @@
|
|||||||
"webpack": "^2.2.1",
|
"webpack": "^2.2.1",
|
||||||
"webpack-merge": "^4.0.0",
|
"webpack-merge": "^4.0.0",
|
||||||
"winston": "^2.1.0",
|
"winston": "^2.1.0",
|
||||||
"winston-loggly-bulk": "^1.4.2",
|
"winston-loggly-bulk": "^2.0.2",
|
||||||
"xml2js": "^0.4.4"
|
"xml2js": "^0.4.4"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -149,11 +144,11 @@
|
|||||||
"babel-plugin-istanbul": "^4.0.0",
|
"babel-plugin-istanbul": "^4.0.0",
|
||||||
"chai": "^3.4.0",
|
"chai": "^3.4.0",
|
||||||
"chai-as-promised": "^5.1.0",
|
"chai-as-promised": "^5.1.0",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^2.3.0",
|
||||||
"chromedriver": "^2.27.2",
|
"chromedriver": "^2.27.2",
|
||||||
"connect-history-api-fallback": "^1.1.0",
|
"connect-history-api-fallback": "^1.1.0",
|
||||||
"coveralls": "^2.11.2",
|
"coveralls": "^3.0.0",
|
||||||
"cross-spawn": "^5.0.1",
|
"cross-spawn": "^6.0.4",
|
||||||
"csv": "~0.3.6",
|
"csv": "~0.3.6",
|
||||||
"eslint": "^3.0.0",
|
"eslint": "^3.0.0",
|
||||||
"eslint-config-habitrpg": "^3.0.0",
|
"eslint-config-habitrpg": "^3.0.0",
|
||||||
@@ -162,25 +157,23 @@
|
|||||||
"eslint-plugin-html": "^2.0.0",
|
"eslint-plugin-html": "^2.0.0",
|
||||||
"eslint-plugin-mocha": "^4.7.0",
|
"eslint-plugin-mocha": "^4.7.0",
|
||||||
"eventsource-polyfill": "^0.9.6",
|
"eventsource-polyfill": "^0.9.6",
|
||||||
"expect.js": "~0.2.0",
|
"expect.js": "^0.3.1",
|
||||||
"http-proxy-middleware": "^0.17.0",
|
"http-proxy-middleware": "^0.17.0",
|
||||||
"istanbul": "^1.1.0-alpha.1",
|
"istanbul": "^1.1.0-alpha.1",
|
||||||
"karma": "^1.3.0",
|
"karma": "^2.0.0",
|
||||||
"karma-babel-preprocessor": "^6.0.1",
|
"karma-babel-preprocessor": "^7.0.0",
|
||||||
"karma-chai-plugins": "~0.6.0",
|
"karma-chai-plugins": "^0.9.0",
|
||||||
"karma-coverage": "^0.5.3",
|
"karma-coverage": "^1.1.1",
|
||||||
"karma-mocha": "^0.2.0",
|
"karma-mocha": "^1.3.0",
|
||||||
"karma-mocha-reporter": "^1.1.1",
|
"karma-mocha-reporter": "^2.2.5",
|
||||||
"karma-phantomjs-launcher": "^1.0.0",
|
"karma-phantomjs-launcher": "^1.0.0",
|
||||||
"karma-sinon-chai": "~1.2.0",
|
"karma-sinon-chai": "^1.3.3",
|
||||||
"karma-sinon-stub-promise": "^1.0.0",
|
"karma-sinon-stub-promise": "^1.0.0",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-spec-reporter": "0.0.24",
|
"karma-spec-reporter": "0.0.32",
|
||||||
"karma-webpack": "^2.0.2",
|
"karma-webpack": "^2.0.2",
|
||||||
"lcov-result-merger": "^1.0.2",
|
"lcov-result-merger": "^2.0.0",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^5.0.0",
|
||||||
"mongodb": "^2.2.33",
|
|
||||||
"mongoskin": "~2.1.0",
|
|
||||||
"monk": "^4.0.0",
|
"monk": "^4.0.0",
|
||||||
"nightwatch": "^0.9.12",
|
"nightwatch": "^0.9.12",
|
||||||
"phantomjs-prebuilt": "^2.1.12",
|
"phantomjs-prebuilt": "^2.1.12",
|
||||||
|
|||||||
@@ -314,5 +314,33 @@ describe('POST /challenges', () => {
|
|||||||
groupLeader = await groupLeader.sync();
|
groupLeader = await groupLeader.sync();
|
||||||
expect(groupLeader.achievements.joinedChallenge).to.be.true;
|
expect(groupLeader.achievements.joinedChallenge).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets summary to challenges name when not supplied', async () => {
|
||||||
|
const name = 'Test Challenge';
|
||||||
|
const challenge = await groupLeader.post('/challenges', {
|
||||||
|
group: group._id,
|
||||||
|
name,
|
||||||
|
shortName: 'TC Label',
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
||||||
|
|
||||||
|
expect(updatedChallenge.summary).to.eql(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets summary to challenges', async () => {
|
||||||
|
const name = 'Test Challenge';
|
||||||
|
const summary = 'Test Summary Challenge';
|
||||||
|
const challenge = await groupLeader.post('/challenges', {
|
||||||
|
group: group._id,
|
||||||
|
name,
|
||||||
|
shortName: 'TC Label',
|
||||||
|
summary,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
||||||
|
|
||||||
|
expect(updatedChallenge.summary).to.eql(summary);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -71,11 +71,9 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns the update chat when previous message parameter is passed and the chat is updated', async () => {
|
it('returns the update chat when previous message parameter is passed and the chat is updated', async () => {
|
||||||
await expect(user.del(`/groups/${groupWithChat._id}/chat/${nextMessage.id}?previousMsg=${message.id}`))
|
let deleteResult = await user.del(`/groups/${groupWithChat._id}/chat/${nextMessage.id}?previousMsg=${message.id}`);
|
||||||
.eventually
|
|
||||||
.is.an('array')
|
expect(deleteResult[0].id).to.eql(message.id);
|
||||||
.to.include(message)
|
|
||||||
.to.be.lengthOf(1);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ describe('POST /chat', () => {
|
|||||||
// Email sent to mods
|
// Email sent to mods
|
||||||
await sleep(0.5);
|
await sleep(0.5);
|
||||||
expect(email.sendTxn).to.be.calledOnce;
|
expect(email.sendTxn).to.be.calledOnce;
|
||||||
expect(email.sendTxn.args[0][1]).to.be.eql('slur-report-to-mods');
|
expect(email.sendTxn.args[0][1]).to.eql('slur-report-to-mods');
|
||||||
|
|
||||||
// Slack message to mods
|
// Slack message to mods
|
||||||
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
||||||
@@ -287,7 +287,7 @@ describe('POST /chat', () => {
|
|||||||
// Email sent to mods
|
// Email sent to mods
|
||||||
await sleep(0.5);
|
await sleep(0.5);
|
||||||
expect(email.sendTxn).to.be.calledThrice;
|
expect(email.sendTxn).to.be.calledThrice;
|
||||||
expect(email.sendTxn.args[2][1]).to.be.eql('slur-report-to-mods');
|
expect(email.sendTxn.args[2][1]).to.eql('slur-report-to-mods');
|
||||||
|
|
||||||
// Slack message to mods
|
// Slack message to mods
|
||||||
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
||||||
@@ -364,6 +364,30 @@ describe('POST /chat', () => {
|
|||||||
expect(message.message.id).to.exist;
|
expect(message.message.id).to.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('creates a chat with user styles', async () => {
|
||||||
|
const mount = 'test-mount';
|
||||||
|
const pet = 'test-pet';
|
||||||
|
const style = 'test-style';
|
||||||
|
const userWithStyle = await generateUser({
|
||||||
|
'items.currentMount': mount,
|
||||||
|
'items.currentPet': pet,
|
||||||
|
'preferences.style': style,
|
||||||
|
});
|
||||||
|
await userWithStyle.sync();
|
||||||
|
|
||||||
|
const message = await userWithStyle.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage});
|
||||||
|
|
||||||
|
expect(message.message.id).to.exist;
|
||||||
|
expect(message.message.userStyles.items.currentMount).to.eql(userWithStyle.items.currentMount);
|
||||||
|
expect(message.message.userStyles.items.currentPet).to.eql(userWithStyle.items.currentPet);
|
||||||
|
expect(message.message.userStyles.preferences.style).to.eql(userWithStyle.preferences.style);
|
||||||
|
expect(message.message.userStyles.preferences.hair).to.eql(userWithStyle.preferences.hair);
|
||||||
|
expect(message.message.userStyles.preferences.skin).to.eql(userWithStyle.preferences.skin);
|
||||||
|
expect(message.message.userStyles.preferences.shirt).to.eql(userWithStyle.preferences.shirt);
|
||||||
|
expect(message.message.userStyles.preferences.chair).to.eql(userWithStyle.preferences.chair);
|
||||||
|
expect(message.message.userStyles.preferences.background).to.eql(userWithStyle.preferences.background);
|
||||||
|
});
|
||||||
|
|
||||||
it('adds backer info to chat', async () => {
|
it('adds backer info to chat', async () => {
|
||||||
const backerInfo = {
|
const backerInfo = {
|
||||||
npc: 'Town Crier',
|
npc: 'Town Crier',
|
||||||
|
|||||||
@@ -44,6 +44,32 @@ describe('POST /group', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets summary to groups name when not supplied', async () => {
|
||||||
|
const name = 'Test Group';
|
||||||
|
const group = await user.post('/groups', {
|
||||||
|
name,
|
||||||
|
type: 'guild',
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedGroup = await user.get(`/groups/${group._id}`);
|
||||||
|
|
||||||
|
expect(updatedGroup.summary).to.eql(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets summary to groups', async () => {
|
||||||
|
const name = 'Test Group';
|
||||||
|
const summary = 'Test Summary';
|
||||||
|
const group = await user.post('/groups', {
|
||||||
|
name,
|
||||||
|
type: 'guild',
|
||||||
|
summary,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedGroup = await user.get(`/groups/${group._id}`);
|
||||||
|
|
||||||
|
expect(updatedGroup.summary).to.eql(summary);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('Guilds', () => {
|
context('Guilds', () => {
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ describe('POST /groups/:groupId/leave', () => {
|
|||||||
it('deletes non existant party from user when user tries to leave', async () => {
|
it('deletes non existant party from user when user tries to leave', async () => {
|
||||||
let nonExistentPartyId = generateUUID();
|
let nonExistentPartyId = generateUUID();
|
||||||
let userWithNonExistentParty = await generateUser({'party._id': nonExistentPartyId});
|
let userWithNonExistentParty = await generateUser({'party._id': nonExistentPartyId});
|
||||||
expect(userWithNonExistentParty.party._id).to.be.eql(nonExistentPartyId);
|
expect(userWithNonExistentParty.party._id).to.eql(nonExistentPartyId);
|
||||||
|
|
||||||
await expect(userWithNonExistentParty.post(`/groups/${nonExistentPartyId}/leave`))
|
await expect(userWithNonExistentParty.post(`/groups/${nonExistentPartyId}/leave`))
|
||||||
.to.eventually.be.rejected;
|
.to.eventually.be.rejected;
|
||||||
|
|||||||
@@ -120,16 +120,16 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
|
|||||||
await leader.post(`/groups/${guild._id}/removeMember/${invitedUser._id}`);
|
await leader.post(`/groups/${guild._id}/removeMember/${invitedUser._id}`);
|
||||||
|
|
||||||
expect(email.sendTxn).to.be.calledOnce;
|
expect(email.sendTxn).to.be.calledOnce;
|
||||||
expect(email.sendTxn.args[0][0]._id).to.be.eql(invitedUser._id);
|
expect(email.sendTxn.args[0][0]._id).to.eql(invitedUser._id);
|
||||||
expect(email.sendTxn.args[0][1]).to.be.eql('guild-invite-rescinded');
|
expect(email.sendTxn.args[0][1]).to.eql('guild-invite-rescinded');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends email to removed user', async () => {
|
it('sends email to removed user', async () => {
|
||||||
await leader.post(`/groups/${guild._id}/removeMember/${member._id}`);
|
await leader.post(`/groups/${guild._id}/removeMember/${member._id}`);
|
||||||
|
|
||||||
expect(email.sendTxn).to.be.calledOnce;
|
expect(email.sendTxn).to.be.calledOnce;
|
||||||
expect(email.sendTxn.args[0][0]._id).to.be.eql(member._id);
|
expect(email.sendTxn.args[0][0]._id).to.eql(member._id);
|
||||||
expect(email.sendTxn.args[0][1]).to.be.eql('kicked-from-guild');
|
expect(email.sendTxn.args[0][1]).to.eql('kicked-from-guild');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -255,16 +255,16 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
|
|||||||
await partyLeader.post(`/groups/${party._id}/removeMember/${partyInvitedUser._id}`);
|
await partyLeader.post(`/groups/${party._id}/removeMember/${partyInvitedUser._id}`);
|
||||||
|
|
||||||
expect(email.sendTxn).to.be.calledOnce;
|
expect(email.sendTxn).to.be.calledOnce;
|
||||||
expect(email.sendTxn.args[0][0]._id).to.be.eql(partyInvitedUser._id);
|
expect(email.sendTxn.args[0][0]._id).to.eql(partyInvitedUser._id);
|
||||||
expect(email.sendTxn.args[0][1]).to.be.eql('party-invite-rescinded');
|
expect(email.sendTxn.args[0][1]).to.eql('party-invite-rescinded');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends email to removed user', async () => {
|
it('sends email to removed user', async () => {
|
||||||
await partyLeader.post(`/groups/${party._id}/removeMember/${partyMember._id}`);
|
await partyLeader.post(`/groups/${party._id}/removeMember/${partyMember._id}`);
|
||||||
|
|
||||||
expect(email.sendTxn).to.be.calledOnce;
|
expect(email.sendTxn).to.be.calledOnce;
|
||||||
expect(email.sendTxn.args[0][0]._id).to.be.eql(partyMember._id);
|
expect(email.sendTxn.args[0][0]._id).to.eql(partyMember._id);
|
||||||
expect(email.sendTxn.args[0][1]).to.be.eql('kicked-from-party');
|
expect(email.sendTxn.args[0][1]).to.eql('kicked-from-party');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe('POST /user/feed/:pet/:food', () => {
|
|||||||
data: user.items.pets['Wolf-Base'],
|
data: user.items.pets['Wolf-Base'],
|
||||||
message: t('messageDontEnjoyFood', {
|
message: t('messageDontEnjoyFood', {
|
||||||
egg: pet.text(),
|
egg: pet.text(),
|
||||||
foodText: food.text(),
|
foodText: food.textThe(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handle Mongoose Validation errors', () => {
|
it('handle Mongoose Validation errors', () => {
|
||||||
let error = new Error('User validation failed.');
|
let error = new Error('User validation failed');
|
||||||
error.name = 'ValidationError';
|
error.name = 'ValidationError';
|
||||||
|
|
||||||
error.errors = {
|
error.errors = {
|
||||||
@@ -151,7 +151,7 @@ describe('errorHandler', () => {
|
|||||||
expect(res.json).to.be.calledWith({
|
expect(res.json).to.be.calledWith({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'BadRequest',
|
error: 'BadRequest',
|
||||||
message: 'User validation failed.',
|
message: 'User validation failed',
|
||||||
errors: [
|
errors: [
|
||||||
{ path: 'auth.local.email', message: 'Invalid email.', value: 'not an email' },
|
{ path: 'auth.local.email', message: 'Invalid email.', value: 'not an email' },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ describe('shared.ops.feed', () => {
|
|||||||
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
||||||
expect(message).to.eql(i18n.t('messageLikesFood', {
|
expect(message).to.eql(i18n.t('messageLikesFood', {
|
||||||
egg: pet.text(),
|
egg: pet.text(),
|
||||||
foodText: food.text(),
|
foodText: food.textThe(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
expect(user.items.food.Meat).to.equal(1);
|
expect(user.items.food.Meat).to.equal(1);
|
||||||
@@ -143,7 +143,7 @@ describe('shared.ops.feed', () => {
|
|||||||
expect(data).to.eql(user.items.pets['Wolf-Spooky']);
|
expect(data).to.eql(user.items.pets['Wolf-Spooky']);
|
||||||
expect(message).to.eql(i18n.t('messageLikesFood', {
|
expect(message).to.eql(i18n.t('messageLikesFood', {
|
||||||
egg: pet.text(),
|
egg: pet.text(),
|
||||||
foodText: food.text(),
|
foodText: food.textThe(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
expect(user.items.food.Milk).to.equal(1);
|
expect(user.items.food.Milk).to.equal(1);
|
||||||
@@ -161,7 +161,7 @@ describe('shared.ops.feed', () => {
|
|||||||
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
||||||
expect(message).to.eql(i18n.t('messageDontEnjoyFood', {
|
expect(message).to.eql(i18n.t('messageDontEnjoyFood', {
|
||||||
egg: pet.text(),
|
egg: pet.text(),
|
||||||
foodText: food.text(),
|
foodText: food.textThe(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
expect(user.items.food.Milk).to.equal(1);
|
expect(user.items.food.Milk).to.equal(1);
|
||||||
|
|||||||
@@ -291,11 +291,14 @@ describe('shared.ops.scoreTask', () => {
|
|||||||
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
||||||
expectGainedPoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
expectGainedPoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
||||||
expect(daily.completed).to.eql(true);
|
expect(daily.completed).to.eql(true);
|
||||||
|
expect(daily.history.length).to.eql(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('up, down', () => {
|
it('up, down', () => {
|
||||||
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
scoreTask({user: ref.afterUser, task: daily, direction: 'up'});
|
||||||
|
expect(daily.history.length).to.eql(1);
|
||||||
scoreTask({user: ref.afterUser, task: daily, direction: 'down'});
|
scoreTask({user: ref.afterUser, task: daily, direction: 'down'});
|
||||||
|
expect(daily.history.length).to.eql(0);
|
||||||
expectClosePoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
expectClosePoints(ref.beforeUser, ref.afterUser, freshDaily, daily);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import * as Tasks from '../../website/server/models/task';
|
|||||||
|
|
||||||
afterEach((done) => {
|
afterEach((done) => {
|
||||||
sandbox.restore();
|
sandbox.restore();
|
||||||
mongoose.connection.db.dropDatabase(done);
|
mongoose.connection.dropDatabase(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
export { sleep } from './sleep';
|
export { sleep } from './sleep';
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export async function getProperty (collectionName, id, path) {
|
|||||||
// resets the db to an empty state and creates a tavern document
|
// resets the db to an empty state and creates a tavern document
|
||||||
export async function resetHabiticaDB () {
|
export async function resetHabiticaDB () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
mongoose.connection.db.dropDatabase((dbErr) => {
|
mongoose.connection.dropDatabase((dbErr) => {
|
||||||
if (dbErr) return reject(dbErr);
|
if (dbErr) return reject(dbErr);
|
||||||
let groups = mongoose.connection.db.collection('groups');
|
let groups = mongoose.connection.db.collection('groups');
|
||||||
let users = mongoose.connection.db.collection('users');
|
let users = mongoose.connection.db.collection('users');
|
||||||
@@ -119,7 +119,7 @@ before((done) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
after((done) => {
|
after((done) => {
|
||||||
mongoose.connection.db.dropDatabase((err) => {
|
mongoose.connection.dropDatabase((err) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
mongoose.connection.close(done);
|
mongoose.connection.close(done);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,5 +5,6 @@
|
|||||||
--growl
|
--growl
|
||||||
--globals io
|
--globals io
|
||||||
-r babel-polyfill
|
-r babel-polyfill
|
||||||
--compilers js:babel-register
|
--require babel-register
|
||||||
--require ./test/helpers/globals.helper
|
--require ./test/helpers/globals.helper
|
||||||
|
--exit
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ div
|
|||||||
div(:class='{sticky: user.preferences.stickyHeader}')
|
div(:class='{sticky: user.preferences.stickyHeader}')
|
||||||
router-view
|
router-view
|
||||||
app-footer
|
app-footer
|
||||||
|
|
||||||
audio#sound(autoplay, ref="sound")
|
audio#sound(autoplay, ref="sound")
|
||||||
source#oggSource(type="audio/ogg", :src="sound.oggSource")
|
source#oggSource(type="audio/ogg", :src="sound.oggSource")
|
||||||
source#mp3Source(type="audio/mp3", :src="sound.mp3Source")
|
source#mp3Source(type="audio/mp3", :src="sound.mp3Source")
|
||||||
@@ -83,10 +82,14 @@ div
|
|||||||
|
|
||||||
.container-fluid {
|
.container-fluid {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
flex: 1 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height: calc(100% - 56px); /* 56px is the menu */
|
height: calc(100% - 56px); /* 56px is the menu */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -400,7 +403,16 @@ export default {
|
|||||||
if (item.purchaseType === 'card') {
|
if (item.purchaseType === 'card') {
|
||||||
this.selectedSpellToBuy = item;
|
this.selectedSpellToBuy = item;
|
||||||
|
|
||||||
|
// hide the dialog
|
||||||
this.$root.$emit('bv::hide::modal', 'buy-modal');
|
this.$root.$emit('bv::hide::modal', 'buy-modal');
|
||||||
|
// remove the dialog from our modal-stack,
|
||||||
|
// the default hidden event is delayed
|
||||||
|
this.$root.$emit('bv::modal::hidden', {
|
||||||
|
target: {
|
||||||
|
id: 'buy-modal',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -411,6 +423,7 @@ export default {
|
|||||||
if (this.selectedSpellToBuy.pinType === 'card') {
|
if (this.selectedSpellToBuy.pinType === 'card') {
|
||||||
const newUserGp = castResult.data.data.user.stats.gp;
|
const newUserGp = castResult.data.data.user.stats.gp;
|
||||||
this.$store.state.user.data.stats.gp = newUserGp;
|
this.$store.state.user.data.stats.gp = newUserGp;
|
||||||
|
this.text(this.$t('sentCardToUser', { profileName: member.profile.name }));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedSpellToBuy = null;
|
this.selectedSpellToBuy = null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.row
|
.row.footer-row
|
||||||
buy-gems-modal(v-if='user')
|
buy-gems-modal(v-if='user')
|
||||||
modify-inventory(v-if="isUserLoaded")
|
modify-inventory(v-if="isUserLoaded")
|
||||||
footer.col-12(:class="{expanded: isExpandedFooter}")
|
footer.col-12(:class="{expanded: isExpandedFooter}")
|
||||||
@@ -117,6 +117,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.footer-row {
|
||||||
|
margin: 0;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
color: #c3c0c7;
|
color: #c3c0c7;
|
||||||
z-index: 17;
|
z-index: 17;
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async loadChallenge () {
|
async loadChallenge () {
|
||||||
this.challenge = await this.$store.dispatch('challenges:getChallenge', {challengeId: this.searchId});
|
this.challenge = await this.$store.dispatch('challenges:getChallenge', {challengeId: this.searchId});
|
||||||
this.members = await this.$store.dispatch('members:getChallengeMembers', {challengeId: this.searchId});
|
this.members = await this.loadMembers({ challengeId: this.searchId, includeAllPublicFields: true });
|
||||||
let tasks = await this.$store.dispatch('tasks:getChallengeTasks', {challengeId: this.searchId});
|
let tasks = await this.$store.dispatch('tasks:getChallengeTasks', {challengeId: this.searchId});
|
||||||
this.tasksByType = {
|
this.tasksByType = {
|
||||||
habit: [],
|
habit: [],
|
||||||
@@ -293,6 +293,21 @@ export default {
|
|||||||
this.tasksByType[task.type].push(task);
|
this.tasksByType[task.type].push(task);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for loading members of a group, with optional parameters for
|
||||||
|
* modifying requests.
|
||||||
|
*
|
||||||
|
* @param {Object} payload Used for modifying requests for members
|
||||||
|
*/
|
||||||
|
loadMembers (payload = null) {
|
||||||
|
// Remove unnecessary data
|
||||||
|
if (payload && payload.groupId) {
|
||||||
|
delete payload.groupId;
|
||||||
|
}
|
||||||
|
return this.$store.dispatch('members:getChallengeMembers', payload);
|
||||||
|
},
|
||||||
|
|
||||||
editTask (task) {
|
editTask (task) {
|
||||||
this.taskFormPurpose = 'edit';
|
this.taskFormPurpose = 'edit';
|
||||||
this.editingTask = cloneDeep(task);
|
this.editingTask = cloneDeep(task);
|
||||||
@@ -334,7 +349,9 @@ export default {
|
|||||||
this.$store.state.memberModalOptions.challengeId = this.challenge._id;
|
this.$store.state.memberModalOptions.challengeId = this.challenge._id;
|
||||||
this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings
|
this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings
|
||||||
this.$store.state.memberModalOptions.group = this.group;
|
this.$store.state.memberModalOptions.group = this.group;
|
||||||
|
this.$store.state.memberModalOptions.memberCount = this.challenge.memberCount;
|
||||||
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
||||||
|
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
|
||||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||||
},
|
},
|
||||||
async joinChallenge () {
|
async joinChallenge () {
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ div
|
|||||||
.svg-icon(v-html="icons.like")
|
.svg-icon(v-html="icons.like")
|
||||||
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
|
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
|
||||||
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
|
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
|
||||||
// @TODO make copyAsTodo work in Tavern, guilds, party (inbox can be done later)
|
|
||||||
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
|
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
|
||||||
.svg-icon(v-html="icons.copy")
|
.svg-icon(v-html="icons.copy")
|
||||||
| {{$t('copyAsTodo')}}
|
| {{$t('copyAsTodo')}}
|
||||||
// @TODO make copyAsTodo work in the inbox
|
|
||||||
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
|
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
|
||||||
.svg-icon(v-html="icons.report")
|
.svg-icon(v-html="icons.report")
|
||||||
| {{$t('report')}}
|
| {{$t('report')}}
|
||||||
@@ -140,7 +138,6 @@ export default {
|
|||||||
mixins: [styleHelper],
|
mixins: [styleHelper],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
copyingMessage: {},
|
|
||||||
icons: Object.freeze({
|
icons: Object.freeze({
|
||||||
like: likeIcon,
|
like: likeIcon,
|
||||||
copy: copyIcon,
|
copy: copyIcon,
|
||||||
@@ -241,9 +238,7 @@ export default {
|
|||||||
this.$emit('messaged-liked', message);
|
this.$emit('messaged-liked', message);
|
||||||
},
|
},
|
||||||
copyAsTodo (message) {
|
copyAsTodo (message) {
|
||||||
// @TODO: Move to Habitica Event
|
this.$root.$emit('habitica::copy-as-todo', message);
|
||||||
this.copyingMessage = message;
|
|
||||||
this.$root.$emit('bv::show::modal', 'copyAsTodo');
|
|
||||||
},
|
},
|
||||||
async report () {
|
async report () {
|
||||||
this.$root.$emit('habitica::report-chat', {
|
this.$root.$emit('habitica::report-chat', {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
.row(v-if='user._id !== msg.uuid')
|
.row(v-if='user._id !== msg.uuid')
|
||||||
div(:class='inbox ? "col-4" : "col-2"')
|
div(:class='inbox ? "col-4" : "col-2"')
|
||||||
avatar(
|
avatar(
|
||||||
v-if='cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected',
|
v-if='msg.userStyles || (cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected)',
|
||||||
:member="cachedProfileData[msg.uuid]",
|
:member="msg.userStyles || cachedProfileData[msg.uuid]",
|
||||||
:avatarOnly="true",
|
:avatarOnly="true",
|
||||||
:hideClassBadge='true',
|
:hideClassBadge='true',
|
||||||
@click.native="showMemberModal(msg.uuid)",
|
@click.native="showMemberModal(msg.uuid)",
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
@show-member-modal='showMemberModal')
|
@show-member-modal='showMemberModal')
|
||||||
div(:class='inbox ? "col-4" : "col-2"')
|
div(:class='inbox ? "col-4" : "col-2"')
|
||||||
avatar(
|
avatar(
|
||||||
v-if='cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected',
|
v-if='msg.userStyles || (cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected)',
|
||||||
:member="cachedProfileData[msg.uuid]",
|
:member="msg.userStyles || cachedProfileData[msg.uuid]",
|
||||||
:avatarOnly="true",
|
:avatarOnly="true",
|
||||||
:hideClassBadge='true',
|
:hideClassBadge='true',
|
||||||
@click.native="showMemberModal(msg.uuid)",
|
@click.native="showMemberModal(msg.uuid)",
|
||||||
@@ -117,12 +117,12 @@ export default {
|
|||||||
// @TODO: We need a different lazy load mechnism.
|
// @TODO: We need a different lazy load mechnism.
|
||||||
// But honestly, adding a paging route to chat would solve this
|
// But honestly, adding a paging route to chat would solve this
|
||||||
messages () {
|
messages () {
|
||||||
|
this.loadProfileCache();
|
||||||
return this.chat;
|
return this.chat;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
messages (oldValue, newValue) {
|
messages () {
|
||||||
if (newValue.length === oldValue.length) return;
|
|
||||||
this.loadProfileCache();
|
this.loadProfileCache();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -139,18 +139,28 @@ export default {
|
|||||||
this._loadProfileCache(screenPosition);
|
this._loadProfileCache(screenPosition);
|
||||||
}, 1000),
|
}, 1000),
|
||||||
async _loadProfileCache (screenPosition) {
|
async _loadProfileCache (screenPosition) {
|
||||||
|
if (this.loading) return;
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
let promises = [];
|
let promises = [];
|
||||||
|
const noProfilesLoaded = Object.keys(this.cachedProfileData).length === 0;
|
||||||
|
|
||||||
// @TODO: write an explination
|
// @TODO: write an explination
|
||||||
if (screenPosition && Math.floor(screenPosition) + 1 > this.currentProfileLoadedEnd / 10) {
|
// @TODO: Remove this after enough messages are cached
|
||||||
|
if (!noProfilesLoaded && screenPosition && Math.floor(screenPosition) + 1 > this.currentProfileLoadedEnd / 10) {
|
||||||
this.currentProfileLoadedEnd = 10 * (Math.floor(screenPosition) + 1);
|
this.currentProfileLoadedEnd = 10 * (Math.floor(screenPosition) + 1);
|
||||||
} else if (screenPosition) {
|
} else if (!noProfilesLoaded && screenPosition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let aboutToCache = {};
|
let aboutToCache = {};
|
||||||
this.messages.forEach(message => {
|
this.messages.forEach(message => {
|
||||||
let uuid = message.uuid;
|
let uuid = message.uuid;
|
||||||
|
|
||||||
|
if (message.userStyles) {
|
||||||
|
this.$set(this.cachedProfileData, uuid, message.userStyles);
|
||||||
|
}
|
||||||
|
|
||||||
if (Boolean(uuid) && !this.cachedProfileData[uuid] && !aboutToCache[uuid]) {
|
if (Boolean(uuid) && !this.cachedProfileData[uuid] && !aboutToCache[uuid]) {
|
||||||
if (uuid === 'system' || this.currentProfileLoadedCount === this.currentProfileLoadedEnd) return;
|
if (uuid === 'system' || this.currentProfileLoadedCount === this.currentProfileLoadedEnd) return;
|
||||||
aboutToCache[uuid] = {};
|
aboutToCache[uuid] = {};
|
||||||
@@ -176,6 +186,8 @@ export default {
|
|||||||
this.$set(this.cachedProfileData, uuid, {rejected: true});
|
this.$set(this.cachedProfileData, uuid, {rejected: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
},
|
},
|
||||||
displayDivider (message) {
|
displayDivider (message) {
|
||||||
if (this.currentDayDividerDisplay !== moment(message.timestamp).day()) {
|
if (this.currentDayDividerDisplay !== moment(message.timestamp).day()) {
|
||||||
|
|||||||
@@ -1,64 +1,66 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
b-modal#copyAsTodo(:title="$t('copyMessageAsToDo')", :hide-footer="true", size='md')
|
b-modal#copyAsTodo(:title="$t('copyMessageAsToDo')", :hide-footer="true", size='md')
|
||||||
.form-group
|
.form-group
|
||||||
input.form-control(type='text', v-model='text')
|
input.form-control(type='text', v-model='task.text')
|
||||||
.form-group
|
.form-group
|
||||||
textarea.form-control(rows='5', v-model='notes' focus-element='true')
|
textarea.form-control(rows='5', v-model='task.notes' focus-element='true')
|
||||||
|
|
||||||
hr
|
hr
|
||||||
|
task(v-if='task._id', :isUser="isUser", :task="task")
|
||||||
// @TODO: Implement when tasks are done
|
|
||||||
//div.task-column.preview
|
|
||||||
div(v-init='popoverOpen = false', class='task todo uncompleted color-neutral', popover-trigger='mouseenter', data-popover-html="{{popoverOpen ? '' : notes | markdown}}", popover-placement="top")
|
|
||||||
.task-meta-controls
|
|
||||||
span(v-if='!obj._locked')
|
|
||||||
span.task-notes(v-show='notes', @click='popoverOpen = !popoverOpen', popover-trigger='click', data-popover-html="{{notes | markdown}}", popover-placement="top")
|
|
||||||
span.glyphicon.glyphicon-comment
|
|
||||||
|
|
|
||||||
|
|
||||||
div.task-text
|
|
||||||
div(v-markdown='text', target='_blank')
|
|
||||||
|
|
||||||
.modal-footer
|
.modal-footer
|
||||||
button.btn.btn-secondary(@click='close()') {{ $t('close') }}
|
button.btn.btn-secondary(@click='close()') {{ $t('close') }}
|
||||||
button.btn.btn-primary(@click='saveTodo()') {{ $t('submit') }}
|
button.btn.btn-primary(@click='saveTodo()') {{ $t('submit') }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions } from 'client/libs/store';
|
||||||
import markdownDirective from 'client/directives/markdown';
|
import markdownDirective from 'client/directives/markdown';
|
||||||
|
import notificationsMixin from 'client/mixins/notifications';
|
||||||
|
import Task from 'client/components/tasks/task';
|
||||||
|
|
||||||
|
import taskDefaults from 'common/script/libs/taskDefaults';
|
||||||
|
|
||||||
|
const baseUrl = 'https://habitica.com';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
directives: {
|
directives: {
|
||||||
markdown: markdownDirective,
|
markdown: markdownDirective,
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
Task,
|
||||||
|
},
|
||||||
|
mixins: [notificationsMixin],
|
||||||
props: ['copyingMessage', 'groupName', 'groupId'],
|
props: ['copyingMessage', 'groupName', 'groupId'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
text: '',
|
isUser: true,
|
||||||
notes: '',
|
task: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
mounted () {
|
||||||
copyingMessage () {
|
this.$root.$on('habitica::copy-as-todo', message => {
|
||||||
this.text = this.copyingMessage.text;
|
const notes = `${message.user} wrote in [${this.groupName}](${baseUrl}/groups/guild/${this.groupId})`;
|
||||||
let baseUrl = 'https://habitica.com';
|
const newTask = {
|
||||||
this.notes = `[${this.copyingMessage.user}](${baseUrl}/static/home/#?memberId=${this.copyingMessage.uuid}) wrote in [${this.groupName}](${baseUrl}/groups/guild/${this.groupId})`;
|
text: message.text,
|
||||||
|
type: 'todo',
|
||||||
|
notes,
|
||||||
|
};
|
||||||
|
this.task = taskDefaults(newTask);
|
||||||
|
this.$root.$emit('bv::show::modal', 'copyAsTodo');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
destroyed () {
|
||||||
|
this.$root.$off('habitica::copy-as-todo');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
createTask: 'tasks:create',
|
||||||
|
}),
|
||||||
close () {
|
close () {
|
||||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||||
},
|
},
|
||||||
saveTodo () {
|
saveTodo () {
|
||||||
// let newTask = {
|
this.createTask(this.task);
|
||||||
// text: this.text,
|
this.text(this.$t('messageAddedAsToDo'));
|
||||||
// type: 'todo',
|
|
||||||
// notes: this.notes,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// @TODO: Add after tasks: User.addTask({body:newTask});
|
|
||||||
// @TODO: Notification.text(window.env.t('messageAddedAsToDo'));
|
|
||||||
|
|
||||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
community-guidelines
|
community-guidelines
|
||||||
.row
|
.row
|
||||||
.col-12.hr
|
.col-12.hr
|
||||||
chat-message(:chat.sync='group.chat', :group-id='group._id', group-name='group.name')
|
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
|
||||||
.col-12.col-sm-4.sidebar
|
.col-12.col-sm-4.sidebar
|
||||||
.row(:class='{"guild-background": !isParty}')
|
.row(:class='{"guild-background": !isParty}')
|
||||||
.col-12
|
.col-12
|
||||||
@@ -375,6 +375,7 @@ export default {
|
|||||||
silverGuildBadgeIcon,
|
silverGuildBadgeIcon,
|
||||||
bronzeGuildBadgeIcon,
|
bronzeGuildBadgeIcon,
|
||||||
}),
|
}),
|
||||||
|
members: [],
|
||||||
selectedQuest: {},
|
selectedQuest: {},
|
||||||
sections: {
|
sections: {
|
||||||
quest: true,
|
quest: true,
|
||||||
@@ -456,14 +457,43 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
load () {
|
acceptCommunityGuidelines () {
|
||||||
this.fetchGuild();
|
this.$store.dispatch('user:set', {'flags.communityGuidelinesAccepted': true});
|
||||||
|
},
|
||||||
|
async load () {
|
||||||
|
if (this.isParty) {
|
||||||
|
this.searchId = 'party';
|
||||||
|
// @TODO: Set up from old client. Decide what we need and what we don't
|
||||||
|
// Check Desktop notifs
|
||||||
|
// Load invites
|
||||||
|
}
|
||||||
|
await this.fetchGuild();
|
||||||
|
// Fetch group members on load
|
||||||
|
this.members = await this.loadMembers({
|
||||||
|
groupId: this.group._id,
|
||||||
|
includeAllPublicFields: true,
|
||||||
|
});
|
||||||
this.$root.$on('updatedGroup', group => {
|
this.$root.$on('updatedGroup', group => {
|
||||||
let updatedGroup = extend(this.group, group);
|
let updatedGroup = extend(this.group, group);
|
||||||
this.$set(this.group, updatedGroup);
|
this.$set(this.group, updatedGroup);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for loading members of a group, with optional parameters for
|
||||||
|
* modifying requests.
|
||||||
|
*
|
||||||
|
* @param {Object} payload Used for modifying requests for members
|
||||||
|
*/
|
||||||
|
loadMembers (payload = null) {
|
||||||
|
// Remove unnecessary data
|
||||||
|
if (payload && payload.challengeId) {
|
||||||
|
delete payload.challengeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.$store.dispatch('members:getGroupMembers', payload);
|
||||||
|
},
|
||||||
|
|
||||||
// @TODO: abstract autocomplete
|
// @TODO: abstract autocomplete
|
||||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||||
getCoord (e, text) {
|
getCoord (e, text) {
|
||||||
@@ -500,6 +530,9 @@ export default {
|
|||||||
showMemberModal () {
|
showMemberModal () {
|
||||||
this.$store.state.memberModalOptions.groupId = this.group._id;
|
this.$store.state.memberModalOptions.groupId = this.group._id;
|
||||||
this.$store.state.memberModalOptions.group = this.group;
|
this.$store.state.memberModalOptions.group = this.group;
|
||||||
|
this.$store.state.memberModalOptions.memberCount = this.group.memberCount;
|
||||||
|
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
||||||
|
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
|
||||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||||
},
|
},
|
||||||
async sendMessage () {
|
async sendMessage () {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ div
|
|||||||
span.dropdown-icon-item
|
span.dropdown-icon-item
|
||||||
.svg-icon.inline(v-html="icons.removeIcon")
|
.svg-icon.inline(v-html="icons.removeIcon")
|
||||||
span.text {{$t('removeManager2')}}
|
span.text {{$t('removeManager2')}}
|
||||||
.row(v-if='groupId === "challenge"')
|
.row(v-if='isLoadMoreAvailable')
|
||||||
.col-12.text-center
|
.col-12.text-center
|
||||||
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
|
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
|
||||||
.row.gradient(v-if='members.length > 3')
|
.row.gradient(v-if='members.length > 3')
|
||||||
@@ -296,6 +296,11 @@ export default {
|
|||||||
isAdmin () {
|
isAdmin () {
|
||||||
return Boolean(this.user.contributor.admin);
|
return Boolean(this.user.contributor.admin);
|
||||||
},
|
},
|
||||||
|
isLoadMoreAvailable () {
|
||||||
|
// Only available if the current length of `members` is less than the
|
||||||
|
// total size of the Group/Challenge
|
||||||
|
return this.members.length < this.$store.state.memberModalOptions.memberCount;
|
||||||
|
},
|
||||||
groupIsSubscribed () {
|
groupIsSubscribed () {
|
||||||
return this.group.purchased.active;
|
return this.group.purchased.active;
|
||||||
},
|
},
|
||||||
@@ -311,16 +316,6 @@ export default {
|
|||||||
sortedMembers () {
|
sortedMembers () {
|
||||||
let sortedMembers = this.members;
|
let sortedMembers = this.members;
|
||||||
|
|
||||||
if (this.searchTerm) {
|
|
||||||
sortedMembers = sortedMembers.filter(member => {
|
|
||||||
return (
|
|
||||||
member.profile.name
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(this.searchTerm.toLowerCase()) !== -1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEmpty(this.sortOption)) {
|
if (!isEmpty(this.sortOption)) {
|
||||||
// Use the memberlist filtered by searchTerm
|
// Use the memberlist filtered by searchTerm
|
||||||
sortedMembers = orderBy(sortedMembers, [this.sortOption.param], [this.sortOption.order]);
|
sortedMembers = orderBy(sortedMembers, [this.sortOption.param], [this.sortOption.order]);
|
||||||
@@ -337,6 +332,15 @@ export default {
|
|||||||
group () {
|
group () {
|
||||||
this.getMembers();
|
this.getMembers();
|
||||||
},
|
},
|
||||||
|
// Watches `searchTerm` and if present, performs a `searchMembers` action
|
||||||
|
// and usual `getMembers` otherwise
|
||||||
|
searchTerm () {
|
||||||
|
if (this.searchTerm) {
|
||||||
|
this.searchMembers(this.searchTerm);
|
||||||
|
} else {
|
||||||
|
this.getMembers();
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sendMessage (member) {
|
sendMessage (member) {
|
||||||
@@ -345,22 +349,24 @@ export default {
|
|||||||
userName: member.profile.name,
|
userName: member.profile.name,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async getMembers () {
|
async searchMembers (searchTerm = '') {
|
||||||
let groupId = this.groupId;
|
this.members = await this.$store.state.memberModalOptions.fetchMoreMembers({
|
||||||
if (groupId && groupId !== 'challenge') {
|
challengeId: this.challengeId,
|
||||||
let members = await this.$store.dispatch('members:getGroupMembers', {
|
groupId: this.groupId,
|
||||||
groupId,
|
searchTerm,
|
||||||
includeAllPublicFields: true,
|
includeAllPublicFields: true,
|
||||||
});
|
});
|
||||||
this.members = members;
|
},
|
||||||
|
async getMembers () {
|
||||||
|
let groupId = this.groupId;
|
||||||
|
|
||||||
|
if (groupId && groupId !== 'challenge') {
|
||||||
let invites = await this.$store.dispatch('members:getGroupInvites', {
|
let invites = await this.$store.dispatch('members:getGroupInvites', {
|
||||||
groupId,
|
groupId,
|
||||||
includeAllPublicFields: true,
|
includeAllPublicFields: true,
|
||||||
});
|
});
|
||||||
this.invites = invites;
|
this.invites = invites;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
|
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
|
||||||
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
||||||
}
|
}
|
||||||
@@ -425,9 +431,11 @@ export default {
|
|||||||
const lastMember = this.members[this.members.length - 1];
|
const lastMember = this.members[this.members.length - 1];
|
||||||
if (!lastMember) return;
|
if (!lastMember) return;
|
||||||
|
|
||||||
let newMembers = await this.$store.dispatch('members:getChallengeMembers', {
|
let newMembers = await this.$store.state.memberModalOptions.fetchMoreMembers({
|
||||||
challengeId: this.challengeId,
|
challengeId: this.challengeId,
|
||||||
|
groupId: this.groupId,
|
||||||
lastMemberId: lastMember._id,
|
lastMemberId: lastMember._id,
|
||||||
|
includeAllPublicFields: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.members = this.members.concat(newMembers);
|
this.members = this.members.concat(newMembers);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ div
|
|||||||
.grey-progress-bar
|
.grey-progress-bar
|
||||||
.collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}")
|
.collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}")
|
||||||
strong {{group.quest.progress.collect[key]}} / {{value.count}}
|
strong {{group.quest.progress.collect[key]}} / {{value.count}}
|
||||||
|
span.float-right {{parseFloat(user.party.quest.progress.collectedItems) || 0}} items found
|
||||||
.boss-info(v-if='questData.boss')
|
.boss-info(v-if='questData.boss')
|
||||||
.row
|
.row
|
||||||
.col-6
|
.col-6
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
.row
|
.row
|
||||||
.hr.col-12
|
.hr.col-12
|
||||||
chat-message(:chat.sync='group.chat', :group-id='group._id', group-name='group.name')
|
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
|
||||||
|
|
||||||
.col-12.col-sm-4.sidebar
|
.col-12.col-sm-4.sidebar
|
||||||
.section
|
.section
|
||||||
|
|||||||
@@ -160,9 +160,10 @@ export default {
|
|||||||
},
|
},
|
||||||
openPartyModal () {
|
openPartyModal () {
|
||||||
if (this.user.party._id) {
|
if (this.user.party._id) {
|
||||||
|
// Set the party details for the members-modal component
|
||||||
this.$store.state.memberModalOptions.groupId = this.user.party._id;
|
this.$store.state.memberModalOptions.groupId = this.user.party._id;
|
||||||
// @TODO: do we need to fetch party?
|
this.$store.state.memberModalOptions.viewingMembers = this.partyMembers;
|
||||||
// this.$store.state.memberModalOptions.group = this.$store.state.party;
|
this.$store.state.memberModalOptions.group = this.user.party;
|
||||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -174,9 +175,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async created () {
|
created () {
|
||||||
if (this.user.party && this.user.party._id) {
|
if (this.user.party && this.user.party._id) {
|
||||||
await this.getPartyMembers(true);
|
this.$store.state.memberModalOptions.groupId = this.user.party._id;
|
||||||
|
this.getPartyMembers();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
div.clearfix(slot="modal-footer")
|
div.clearfix(slot="modal-footer")
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
||||||
@import '~client/assets/scss/colors.scss';
|
@import '~client/assets/scss/colors.scss';
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(50% - (16px));
|
left: calc(50% - (16px));
|
||||||
bottom: -($badge-size / 2);
|
bottom: -($badge-size / 2);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ div
|
|||||||
questInfo(:quest="item")
|
questInfo(:quest="item")
|
||||||
div(v-else)
|
div(v-else)
|
||||||
h4.popover-content-title(v-once) {{ item.text }}
|
h4.popover-content-title(v-once) {{ item.text }}
|
||||||
.popover-content-text(v-if="showNotes", v-once) {{ item.notes }}
|
.popover-content-text(v-if='showNotes && item.key !== "armoire"', v-once) {{ item.notes }}
|
||||||
|
.popover-content-text(v-if='showNotes && item.key === "armoire"') {{ item.notes }}
|
||||||
div(v-if="item.event") {{ limitedString }}
|
div(v-if="item.event") {{ limitedString }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ transition(name="fade")
|
|||||||
.text.col-7.offset-1
|
.text.col-7.offset-1
|
||||||
div
|
div
|
||||||
| {{message}}
|
| {{message}}
|
||||||
.icon.col-4
|
.icon.col-4.d-flex.align-items-center
|
||||||
div.svg-icon(v-html="icons.health", v-if='notification.type === "hp"')
|
div.svg-icon(v-html="icons.health", v-if='notification.type === "hp"')
|
||||||
div.svg-icon(v-html="icons.gold", v-if='notification.type === "gp"')
|
div.svg-icon(v-html="icons.gold", v-if='notification.type === "gp"')
|
||||||
div.svg-icon(v-html="icons.star", v-if='notification.type === "xp"')
|
div.svg-icon(v-html="icons.star", v-if='notification.type === "xp"')
|
||||||
@@ -24,10 +24,10 @@ transition(name="fade")
|
|||||||
.text.col-12
|
.text.col-12
|
||||||
div(v-html='notification.text')
|
div(v-html='notification.text')
|
||||||
.row(v-if='notification.type === "drop"')
|
.row(v-if='notification.type === "drop"')
|
||||||
.col-2
|
.col-3
|
||||||
.icon-item
|
.icon-item
|
||||||
div(:class='notification.icon')
|
div(:class='notification.icon')
|
||||||
.text.col-9
|
.text.col-8
|
||||||
div(v-html='notification.text')
|
div(v-html='notification.text')
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -150,6 +150,9 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
message () {
|
message () {
|
||||||
|
if (this.notification.flavorMessage) {
|
||||||
|
return this.notification.flavorMessage;
|
||||||
|
}
|
||||||
let localeKey = this.negative === 'negative' ? 'lost' : 'gained';
|
let localeKey = this.negative === 'negative' ? 'lost' : 'gained';
|
||||||
if (this.notification.type === 'hp') localeKey += 'Health';
|
if (this.notification.type === 'hp') localeKey += 'Health';
|
||||||
if (this.notification.type === 'mp') localeKey += 'Mana';
|
if (this.notification.type === 'mp') localeKey += 'Mana';
|
||||||
|
|||||||
@@ -617,6 +617,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let groupInvite = '';
|
let groupInvite = '';
|
||||||
|
if (this.$route.query && this.$route.query.p) {
|
||||||
|
groupInvite = this.$route.query.p;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.$route.query && this.$route.query.groupInvite) {
|
if (this.$route.query && this.$route.query.groupInvite) {
|
||||||
groupInvite = this.$route.query.groupInvite;
|
groupInvite = this.$route.query.groupInvite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,22 +188,12 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$root.$on('castEnd', (target, type, $event) => {
|
|
||||||
this.castEnd(target, type, $event);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('keyup', this.handleKeyUp);
|
|
||||||
|
|
||||||
// @TODO: should we abstract the drawer state/local store to a library and mixing combo? We use a similar pattern in equipment
|
// @TODO: should we abstract the drawer state/local store to a library and mixing combo? We use a similar pattern in equipment
|
||||||
const spellDrawerState = getLocalSetting(CONSTANTS.keyConstants.SPELL_DRAWER_STATE);
|
const spellDrawerState = getLocalSetting(CONSTANTS.keyConstants.SPELL_DRAWER_STATE);
|
||||||
if (spellDrawerState === CONSTANTS.valueConstants.DRAWER_CLOSED) {
|
if (spellDrawerState === CONSTANTS.valueConstants.DRAWER_CLOSED) {
|
||||||
this.$store.state.spellOptions.spellDrawOpen = false;
|
this.$store.state.spellOptions.spellDrawOpen = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
|
||||||
this.$root.$off('castEnd');
|
|
||||||
document.removeEventListener('keyup', this.handleKeyUp);
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({user: 'user.data'}),
|
...mapState({user: 'user.data'}),
|
||||||
openStatus () {
|
openStatus () {
|
||||||
@@ -211,10 +201,6 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleKeyUp (keyEvent) {
|
|
||||||
if (keyEvent.keyCode !== 27) return;
|
|
||||||
this.castCancel();
|
|
||||||
},
|
|
||||||
drawerToggled (newState) {
|
drawerToggled (newState) {
|
||||||
this.$store.state.spellOptions.spellDrawOpen = newState;
|
this.$store.state.spellOptions.spellDrawOpen = newState;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
.col-4(v-for="tag in tags")
|
.col-4(v-for="tag in tags")
|
||||||
.custom-control.custom-checkbox
|
.custom-control.custom-checkbox
|
||||||
input.custom-control-input(type="checkbox", :value="tag.id", v-model="selectedTags", :id="`tag-${tag.id}`")
|
input.custom-control-input(type="checkbox", :value="tag.id", v-model="selectedTags", :id="`tag-${tag.id}`")
|
||||||
label.custom-control-label(:title="tag.name", :for="`tag-${tag.id}`") {{tag.name}}
|
label.custom-control-label(:title="tag.name", :for="`tag-${tag.id}`", v-markdown="tag.name")
|
||||||
.tags-footer
|
.tags-footer
|
||||||
span.clear-tags(@click="clearTags()") {{$t("clearTags")}}
|
span.clear-tags(@click="clearTags()") {{$t("clearTags")}}
|
||||||
span.close-tags(@click="close()") {{$t("close")}}
|
span.close-tags(@click="close()") {{$t("close")}}
|
||||||
@@ -95,8 +95,13 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import markdownDirective from 'client/directives/markdown';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['tags', 'value'],
|
props: ['tags', 'value'],
|
||||||
|
directives: {
|
||||||
|
markdown: markdownDirective,
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
selectedTags: [],
|
selectedTags: [],
|
||||||
|
|||||||
@@ -84,14 +84,13 @@
|
|||||||
.svg-icon.challenge.broken(v-html="icons.brokenChallengeIcon", v-if='task.challenge.broken', @click='handleBrokenTask(task)')
|
.svg-icon.challenge.broken(v-html="icons.brokenChallengeIcon", v-if='task.challenge.broken', @click='handleBrokenTask(task)')
|
||||||
.d-flex.align-items-center(v-if="hasTags", :id="`tags-icon-${task._id}`")
|
.d-flex.align-items-center(v-if="hasTags", :id="`tags-icon-${task._id}`")
|
||||||
.svg-icon.tags(v-html="icons.tags")
|
.svg-icon.tags(v-html="icons.tags")
|
||||||
#tags-popover
|
|
||||||
b-popover(
|
b-popover(
|
||||||
v-if="hasTags",
|
v-if="hasTags",
|
||||||
:target="`tags-icon-${task._id}`",
|
:target="`tags-icon-${task._id}`",
|
||||||
triggers="hover",
|
triggers="hover",
|
||||||
placement="bottom",
|
placement="bottom",
|
||||||
container="tags-popover",
|
|
||||||
)
|
)
|
||||||
|
.tags-popover
|
||||||
.d-flex.align-items-center.tags-container
|
.d-flex.align-items-center.tags-container
|
||||||
.tags-popover-title(v-once) {{ `${$t('tags')}:` }}
|
.tags-popover-title(v-once) {{ `${$t('tags')}:` }}
|
||||||
.tag-label(v-for="tag in getTagsFor(task)") {{tag}}
|
.tag-label(v-for="tag in getTagsFor(task)") {{tag}}
|
||||||
@@ -455,7 +454,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#tags-popover /deep/ {
|
.tags-popover /deep/ {
|
||||||
.tags-container {
|
.tags-container {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
@@ -759,9 +758,9 @@ export default {
|
|||||||
dropNotes = Content.eggs[drop.key].notes();
|
dropNotes = Content.eggs[drop.key].notes();
|
||||||
this.drop(this.$t('messageDropEgg', {dropText, dropNotes}), drop);
|
this.drop(this.$t('messageDropEgg', {dropText, dropNotes}), drop);
|
||||||
} else if (drop.type === 'Food') {
|
} else if (drop.type === 'Food') {
|
||||||
dropText = Content.food[drop.key].text();
|
dropText = Content.food[drop.key].textA();
|
||||||
dropNotes = Content.food[drop.key].notes();
|
dropNotes = Content.food[drop.key].notes();
|
||||||
this.drop(this.$t('messageDropFood', {dropArticle: drop.article, dropText, dropNotes}), drop);
|
this.drop(this.$t('messageDropFood', {dropText, dropNotes}), drop);
|
||||||
} else if (drop.type === 'Quest') {
|
} else if (drop.type === 'Quest') {
|
||||||
// TODO $rootScope.selectedQuest = Content.quests[drop.key];
|
// TODO $rootScope.selectedQuest = Content.quests[drop.key];
|
||||||
// $rootScope.openModal('questDrop', {controller:'PartyCtrl', size:'sm'});
|
// $rootScope.openModal('questDrop', {controller:'PartyCtrl', size:'sm'});
|
||||||
|
|||||||
@@ -143,7 +143,7 @@
|
|||||||
.tags-none {{$t('none')}}
|
.tags-none {{$t('none')}}
|
||||||
.dropdown-toggle
|
.dropdown-toggle
|
||||||
span.category-select(v-else)
|
span.category-select(v-else)
|
||||||
.category-label(v-for='tagName in truncatedSelectedTags', :title="tagName") {{ tagName }}
|
.category-label(v-for='tagName in truncatedSelectedTags', :title="tagName", v-markdown='tagName')
|
||||||
.tags-more(v-if='remainingSelectedTags.length > 0') +{{ $t('more', { count: remainingSelectedTags.length }) }}
|
.tags-more(v-if='remainingSelectedTags.length > 0') +{{ $t('more', { count: remainingSelectedTags.length }) }}
|
||||||
.dropdown-toggle
|
.dropdown-toggle
|
||||||
tags-popup(v-if="showTagsSelect", :tags="user.tags", v-model="task.tags", @close='closeTagsPopup()')
|
tags-popup(v-if="showTagsSelect", :tags="user.tags", v-model="task.tags", @close='closeTagsPopup()')
|
||||||
@@ -346,7 +346,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
label {
|
label {
|
||||||
margin-bottom: 8px;
|
max-height: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,6 +637,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import TagsPopup from './tagsPopup';
|
import TagsPopup from './tagsPopup';
|
||||||
import { mapGetters, mapActions, mapState } from 'client/libs/store';
|
import { mapGetters, mapActions, mapState } from 'client/libs/store';
|
||||||
|
import markdownDirective from 'client/directives/markdown';
|
||||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||||
import clone from 'lodash/clone';
|
import clone from 'lodash/clone';
|
||||||
import Datepicker from 'vuejs-datepicker';
|
import Datepicker from 'vuejs-datepicker';
|
||||||
@@ -664,6 +665,9 @@ export default {
|
|||||||
toggleSwitch,
|
toggleSwitch,
|
||||||
draggable,
|
draggable,
|
||||||
},
|
},
|
||||||
|
directives: {
|
||||||
|
markdown: markdownDirective,
|
||||||
|
},
|
||||||
// purpose is either create or edit, task is the task created or edited
|
// purpose is either create or edit, task is the task created or edited
|
||||||
props: ['task', 'purpose', 'challengeId', 'groupId'],
|
props: ['task', 'purpose', 'challengeId', 'groupId'],
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
@@ -239,11 +239,13 @@ export default {
|
|||||||
user: message.user,
|
user: message.user,
|
||||||
uuid: message.uuid,
|
uuid: message.uuid,
|
||||||
id: message.id,
|
id: message.id,
|
||||||
|
contributor: message.contributor,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (message.sent) {
|
if (message.sent) {
|
||||||
newMessage.user = this.user.profile.name;
|
newMessage.user = this.user.profile.name;
|
||||||
newMessage.uuid = this.user._id;
|
newMessage.uuid = this.user._id;
|
||||||
|
newMessage.contributor = this.user.contributor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newMessage.text) conversations[userId].messages.push(newMessage);
|
if (newMessage.text) conversations[userId].messages.push(newMessage);
|
||||||
@@ -306,6 +308,7 @@ export default {
|
|||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
user: this.user.profile.name,
|
user: this.user.profile.name,
|
||||||
uuid: this.user._id,
|
uuid: this.user._id,
|
||||||
|
contributor: this.user.contributor,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.activeChat = convoFound.messages;
|
this.activeChat = convoFound.messages;
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import isArray from 'lodash/isArray';
|
|||||||
// @TODO: Let's separate some of the business logic out of Vue if possible
|
// @TODO: Let's separate some of the business logic out of Vue if possible
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
handleCastCancelKeyUp (keyEvent) {
|
||||||
|
if (keyEvent.keyCode !== 27) return;
|
||||||
|
this.castCancel();
|
||||||
|
},
|
||||||
async castStart (spell) {
|
async castStart (spell) {
|
||||||
if (this.$store.state.spellOptions.castingSpell) {
|
if (this.$store.state.spellOptions.castingSpell) {
|
||||||
this.castCancel();
|
this.castCancel();
|
||||||
@@ -47,6 +51,13 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
this.castEnd(tasks, spell.target);
|
this.castEnd(tasks, spell.target);
|
||||||
|
} else {
|
||||||
|
// If the cast target has to be selected (and can be cancelled)
|
||||||
|
document.addEventListener('keyup', this.handleCastCancelKeyUp);
|
||||||
|
|
||||||
|
this.$root.$on('castEnd', (target, type, $event) => {
|
||||||
|
this.castEnd(target, type, $event);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async castEnd (target, type) {
|
async castEnd (target, type) {
|
||||||
@@ -61,17 +72,12 @@ export default {
|
|||||||
if (target && target.challenge && target.challenge.id) return this.text(this.$t('invalidTarget'));
|
if (target && target.challenge && target.challenge.id) return this.text(this.$t('invalidTarget'));
|
||||||
if (target && target.group && target.group.id) return this.text(this.$t('invalidTarget'));
|
if (target && target.group && target.group.id) return this.text(this.$t('invalidTarget'));
|
||||||
|
|
||||||
// @TODO: just call castCancel?
|
|
||||||
this.$store.state.spellOptions.castingSpell = false;
|
|
||||||
this.potionClickMode = false;
|
|
||||||
|
|
||||||
this.spell.cast(this.user, target);
|
this.spell.cast(this.user, target);
|
||||||
// User.save(); // @TODO:
|
|
||||||
|
|
||||||
let spell = this.spell;
|
let spell = this.spell;
|
||||||
let targetId = target ? target._id : null;
|
let targetId = target ? target._id : null;
|
||||||
this.spell = null;
|
|
||||||
this.applyingAction = false;
|
this.castCancel();
|
||||||
|
|
||||||
let spellUrl = `/api/v3/user/class/cast/${spell.key}`;
|
let spellUrl = `/api/v3/user/class/cast/${spell.key}`;
|
||||||
if (targetId) spellUrl += `?targetId=${targetId}`;
|
if (targetId) spellUrl += `?targetId=${targetId}`;
|
||||||
@@ -123,6 +129,10 @@ export default {
|
|||||||
this.spell = null;
|
this.spell = null;
|
||||||
document.querySelector('body').style.cursor = 'initial';
|
document.querySelector('body').style.cursor = 'initial';
|
||||||
this.$store.state.spellOptions.castingSpell = false;
|
this.$store.state.spellOptions.castingSpell = false;
|
||||||
|
|
||||||
|
// Remove listeners
|
||||||
|
this.$root.$off('castEnd');
|
||||||
|
document.removeEventListener('keyup', this.handleCastCancelKeyUp);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,15 +7,21 @@ let apiV3Prefix = '/api/v3';
|
|||||||
export async function getGroupMembers (store, payload) {
|
export async function getGroupMembers (store, payload) {
|
||||||
let url = `${apiV3Prefix}/groups/${payload.groupId}/members`;
|
let url = `${apiV3Prefix}/groups/${payload.groupId}/members`;
|
||||||
|
|
||||||
|
const params = {};
|
||||||
|
|
||||||
if (payload.includeAllPublicFields) {
|
if (payload.includeAllPublicFields) {
|
||||||
url += '?includeAllPublicFields=true';
|
params.includeAllPublicFields = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.lastMemberId) {
|
||||||
|
params.lastId = payload.lastMemberId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.searchTerm) {
|
if (payload.searchTerm) {
|
||||||
url += `?search=${payload.searchTerm}`;
|
params.search = payload.searchTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = await axios.get(url);
|
let response = await axios.get(url, { params });
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,17 +41,23 @@ export async function getGroupInvites (store, payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getChallengeMembers (store, payload) {
|
export async function getChallengeMembers (store, payload) {
|
||||||
let url = `${apiV3Prefix}/challenges/${payload.challengeId}/members?includeAllPublicFields=true`;
|
let url = `${apiV3Prefix}/challenges/${payload.challengeId}/members`;
|
||||||
|
|
||||||
|
const params = {};
|
||||||
|
|
||||||
|
if (payload.includeAllPublicFields) {
|
||||||
|
params.includeAllPublicFields = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (payload.lastMemberId) {
|
if (payload.lastMemberId) {
|
||||||
url += `&lastId=${payload.lastMemberId}`;
|
params.lastId = payload.lastMemberId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.searchTerm) {
|
if (payload.searchTerm) {
|
||||||
url += `&search=${payload.searchTerm}`;
|
params.search = payload.searchTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = await axios.get(url);
|
let response = await axios.get(url, { params });
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,16 @@ import { getDropClass } from 'client/libs/notifications';
|
|||||||
export function buyItem (store, params) {
|
export function buyItem (store, params) {
|
||||||
const quantity = params.quantity || 1;
|
const quantity = params.quantity || 1;
|
||||||
const user = store.state.user.data;
|
const user = store.state.user.data;
|
||||||
|
|
||||||
|
const userPinned = user.pinnedItems.slice();
|
||||||
let opResult = buyOp(user, {params, quantity});
|
let opResult = buyOp(user, {params, quantity});
|
||||||
|
|
||||||
|
// @TODO: Currently resetting the pinned items will reset the market. Purchasing some items does not reset pinned.
|
||||||
|
// For now, I've added this hack for items like contributor gear to update while I am working on add more computed
|
||||||
|
// properties to the market. We will use this quick fix while testing the other changes.
|
||||||
|
user.pinnedItems = userPinned;
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: opResult,
|
result: opResult,
|
||||||
httpCall: axios.post(`/api/v3/user/buy/${params.key}`),
|
httpCall: axios.post(`/api/v3/user/buy/${params.key}`),
|
||||||
@@ -51,6 +59,7 @@ async function buyArmoire (store, params) {
|
|||||||
if (buyResult) {
|
if (buyResult) {
|
||||||
const resData = buyResult;
|
const resData = buyResult;
|
||||||
const item = resData.armoire;
|
const item = resData.armoire;
|
||||||
|
const message = result.data.message;
|
||||||
|
|
||||||
const isExperience = item.type === 'experience';
|
const isExperience = item.type === 'experience';
|
||||||
if (item.type === 'gear') {
|
if (item.type === 'gear') {
|
||||||
@@ -59,12 +68,22 @@ async function buyArmoire (store, params) {
|
|||||||
store.state.user.data.stats.gp -= armoire.value;
|
store.state.user.data.stats.gp -= armoire.value;
|
||||||
|
|
||||||
// @TODO: We might need to abstract notifications to library rather than mixin
|
// @TODO: We might need to abstract notifications to library rather than mixin
|
||||||
|
const notificationOptions = isExperience ?
|
||||||
|
{
|
||||||
|
text: `+ ${item.value}`,
|
||||||
|
type: 'xp',
|
||||||
|
flavorMessage: message,
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
text: message,
|
||||||
|
type: 'drop',
|
||||||
|
icon: getDropClass({type: item.type, key: item.dropKey}),
|
||||||
|
};
|
||||||
|
|
||||||
store.dispatch('snackbars:add', {
|
store.dispatch('snackbars:add', {
|
||||||
title: '',
|
title: '',
|
||||||
text: isExperience ? item.value : item.dropText,
|
|
||||||
type: isExperience ? 'xp' : 'drop',
|
|
||||||
icon: isExperience ? null : getDropClass({type: item.type, key: item.dropKey}),
|
|
||||||
timeout: true,
|
timeout: true,
|
||||||
|
...notificationOptions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,37 +261,97 @@
|
|||||||
"premiumPotionAddlNotes": "Not usable on quest pet eggs.",
|
"premiumPotionAddlNotes": "Not usable on quest pet eggs.",
|
||||||
|
|
||||||
"foodMeat": "Meat",
|
"foodMeat": "Meat",
|
||||||
|
"foodMeatThe": "the Meat",
|
||||||
|
"foodMeatA": "Meat",
|
||||||
"foodMilk": "Milk",
|
"foodMilk": "Milk",
|
||||||
|
"foodMilkThe": "the Milk",
|
||||||
|
"foodMilkA": "Milk",
|
||||||
"foodPotatoe": "Potato",
|
"foodPotatoe": "Potato",
|
||||||
|
"foodPotatoeThe": "the Potato",
|
||||||
|
"foodPotatoeA": "a Potato",
|
||||||
"foodStrawberry": "Strawberry",
|
"foodStrawberry": "Strawberry",
|
||||||
|
"foodStrawberryThe": "the Strawberry",
|
||||||
|
"foodStrawberryA": "a Strawberry",
|
||||||
"foodChocolate": "Chocolate",
|
"foodChocolate": "Chocolate",
|
||||||
|
"foodChocolateThe": "the Chocolate",
|
||||||
|
"foodChocolateA": "Chocolate",
|
||||||
"foodFish": "Fish",
|
"foodFish": "Fish",
|
||||||
|
"foodFishThe": "the Fish",
|
||||||
|
"foodFishA": "a Fish",
|
||||||
"foodRottenMeat": "Rotten Meat",
|
"foodRottenMeat": "Rotten Meat",
|
||||||
|
"foodRottenMeatThe": "the Rotten Meat",
|
||||||
|
"foodRottenMeatA": "Rotten Meat",
|
||||||
"foodCottonCandyPink": "Pink Cotton Candy",
|
"foodCottonCandyPink": "Pink Cotton Candy",
|
||||||
|
"foodCottonCandyPinkThe": "the Pink Cotton Candy",
|
||||||
|
"foodCottonCandyPinkA": "Pink Cotton Candy",
|
||||||
"foodCottonCandyBlue": "Blue Cotton Candy",
|
"foodCottonCandyBlue": "Blue Cotton Candy",
|
||||||
|
"foodCottonCandyBlueThe": "the Blue Cotton Candy",
|
||||||
|
"foodCottonCandyBlueA": "Blue Cotton Candy",
|
||||||
"foodHoney": "Honey",
|
"foodHoney": "Honey",
|
||||||
|
"foodHoneyThe": "the Honey",
|
||||||
|
"foodHoneyA": "Honey",
|
||||||
|
|
||||||
"foodCakeSkeleton": "Bare Bones Cake",
|
"foodCakeSkeleton": "Bare Bones Cake",
|
||||||
|
"foodCakeSkeletonThe": "the Bare Bones Cake",
|
||||||
|
"foodCakeSkeletonA": "a Bare Bones Cake",
|
||||||
"foodCakeBase": "Basic Cake",
|
"foodCakeBase": "Basic Cake",
|
||||||
|
"foodCakeBaseThe": "the Basic Cake",
|
||||||
|
"foodCakeBaseA": "a Basic Cake",
|
||||||
"foodCakeCottonCandyBlue": "Candy Blue Cake",
|
"foodCakeCottonCandyBlue": "Candy Blue Cake",
|
||||||
|
"foodCakeCottonCandyBlueThe": "the Candy Blue Cake",
|
||||||
|
"foodCakeCottonCandyBlueA": "a Candy Blue Cake",
|
||||||
"foodCakeCottonCandyPink": "Candy Pink Cake",
|
"foodCakeCottonCandyPink": "Candy Pink Cake",
|
||||||
|
"foodCakeCottonCandyPinkThe": "the Candy Pink Cake",
|
||||||
|
"foodCakeCottonCandyPinkA": "a Candy Pink Cake",
|
||||||
"foodCakeShade": "Chocolate Cake",
|
"foodCakeShade": "Chocolate Cake",
|
||||||
|
"foodCakeShadeThe": "the Chocolate Cake",
|
||||||
|
"foodCakeShadeA": "a Chocolate Cake",
|
||||||
"foodCakeWhite": "Cream Cake",
|
"foodCakeWhite": "Cream Cake",
|
||||||
|
"foodCakeWhiteThe": "the Cream Cake",
|
||||||
|
"foodCakeWhiteA": "a Cream Cake",
|
||||||
"foodCakeGolden": "Honey Cake",
|
"foodCakeGolden": "Honey Cake",
|
||||||
|
"foodCakeGoldenThe": "the Honey Cake",
|
||||||
|
"foodCakeGoldenA": "a Honey Cake",
|
||||||
"foodCakeZombie": "Rotten Cake",
|
"foodCakeZombie": "Rotten Cake",
|
||||||
|
"foodCakeZombieThe": "the Rotten Cake",
|
||||||
|
"foodCakeZombieA": "a Rotten Cake",
|
||||||
"foodCakeDesert": "Sand Cake",
|
"foodCakeDesert": "Sand Cake",
|
||||||
|
"foodCakeDesertThe": "the Sand Cake",
|
||||||
|
"foodCakeDesertA": "a Sand Cake",
|
||||||
"foodCakeRed": "Strawberry Cake",
|
"foodCakeRed": "Strawberry Cake",
|
||||||
|
"foodCakeRedThe": "the Strawberry Cake",
|
||||||
|
"foodCakeRedA": "a Strawberry Cake",
|
||||||
|
|
||||||
"foodCandySkeleton": "Bare Bones Candy",
|
"foodCandySkeleton": "Bare Bones Candy",
|
||||||
|
"foodCandySkeletonThe": "the Bare Bones Candy",
|
||||||
|
"foodCandySkeletonA": "Bare Bones Candy",
|
||||||
"foodCandyBase": "Basic Candy",
|
"foodCandyBase": "Basic Candy",
|
||||||
|
"foodCandyBaseThe": "the Basic Candy",
|
||||||
|
"foodCandyBaseA": "Basic Candy",
|
||||||
"foodCandyCottonCandyBlue": "Sour Blue Candy",
|
"foodCandyCottonCandyBlue": "Sour Blue Candy",
|
||||||
|
"foodCandyCottonCandyBlueThe": "the Sour Blue Candy",
|
||||||
|
"foodCandyCottonCandyBlueA": "Sour Blue Candy",
|
||||||
"foodCandyCottonCandyPink": "Sour Pink Candy",
|
"foodCandyCottonCandyPink": "Sour Pink Candy",
|
||||||
|
"foodCandyCottonCandyPinkThe": "the Sour Pink Candy",
|
||||||
|
"foodCandyCottonCandyPinkA": "Sour Pink Candy",
|
||||||
"foodCandyShade": "Chocolate Candy",
|
"foodCandyShade": "Chocolate Candy",
|
||||||
|
"foodCandyShadeThe": "the Chocolate Candy",
|
||||||
|
"foodCandyShadeA": "Chocolate Candy",
|
||||||
"foodCandyWhite": "Vanilla Candy",
|
"foodCandyWhite": "Vanilla Candy",
|
||||||
|
"foodCandyWhiteThe": "the Vanilla Candy",
|
||||||
|
"foodCandyWhiteA": "Vanilla Candy",
|
||||||
"foodCandyGolden": "Honey Candy ",
|
"foodCandyGolden": "Honey Candy ",
|
||||||
|
"foodCandyGoldenThe": "the Honey Candy",
|
||||||
|
"foodCandyGoldenA": "Honey Candy",
|
||||||
"foodCandyZombie": "Rotten Candy",
|
"foodCandyZombie": "Rotten Candy",
|
||||||
|
"foodCandyZombieThe": "the Rotten Candy",
|
||||||
|
"foodCandyZombieA": "Rotten Candy",
|
||||||
"foodCandyDesert": "Sand Candy",
|
"foodCandyDesert": "Sand Candy",
|
||||||
|
"foodCandyDesertThe": "the Sand Candy",
|
||||||
|
"foodCandyDesertA": "Sand Candy",
|
||||||
"foodCandyRed": "Cinnamon Candy",
|
"foodCandyRed": "Cinnamon Candy",
|
||||||
|
"foodCandyRedThe": "the Cinnamon Candy",
|
||||||
|
"foodCandyRedA": "Cinnamon Candy",
|
||||||
|
|
||||||
"foodSaddleText": "Saddle",
|
"foodSaddleText": "Saddle",
|
||||||
"foodSaddleNotes": "Instantly raises one of your pets into a mount.",
|
"foodSaddleNotes": "Instantly raises one of your pets into a mount.",
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
"weaponSpecialSkiText": "Ski-sassin Pole",
|
"weaponSpecialSkiText": "Ski-sassin Pole",
|
||||||
"weaponSpecialSkiNotes": "A weapon capable of destroying hordes of enemies! It also helps the user make very nice parallel turns. Increases Strength by <%= str %>. Limited Edition 2013-2014 Winter Gear.",
|
"weaponSpecialSkiNotes": "A weapon capable of destroying hordes of enemies! It also helps the user make very nice parallel turns. Increases Strength by <%= str %>. Limited Edition 2013-2014 Winter Gear.",
|
||||||
"weaponSpecialCandycaneText": "Candy Cane Staff",
|
"weaponSpecialCandycaneText": "Candy Cane Staff",
|
||||||
"weaponSpecialCandycaneNotes": "A powerful mage's staff. Powerfully DELICIOUS, we mean! Two-handed weapon. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.",
|
"weaponSpecialCandycaneNotes": "A powerful mage's staff. Powerfully DELICIOUS, we mean! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.",
|
||||||
"weaponSpecialSnowflakeText": "Snowflake Wand",
|
"weaponSpecialSnowflakeText": "Snowflake Wand",
|
||||||
"weaponSpecialSnowflakeNotes": "This wand sparkles with unlimited healing power. Increases Intelligence by <%= int %>. Limited Edition 2013-2014 Winter Gear.",
|
"weaponSpecialSnowflakeNotes": "This wand sparkles with unlimited healing power. Increases Intelligence by <%= int %>. Limited Edition 2013-2014 Winter Gear.",
|
||||||
|
|
||||||
@@ -1591,5 +1591,6 @@
|
|||||||
"eyewearMystery301703Notes": "Perfect for a fancy masquerade or for stealthily moving through a particularly well-dressed crowd. Confers no benefit. March 3017 Subscriber Item.",
|
"eyewearMystery301703Notes": "Perfect for a fancy masquerade or for stealthily moving through a particularly well-dressed crowd. Confers no benefit. March 3017 Subscriber Item.",
|
||||||
|
|
||||||
"eyewearArmoirePlagueDoctorMaskText": "Plague Doctor Mask",
|
"eyewearArmoirePlagueDoctorMaskText": "Plague Doctor Mask",
|
||||||
"eyewearArmoirePlagueDoctorMaskNotes": "An authentic mask worn by the doctors who battle the Plague of Procrastination. Confers no benefit. Enchanted Armoire: Plague Doctor Set (Item 2 of 3)."
|
"eyewearArmoirePlagueDoctorMaskNotes": "An authentic mask worn by the doctors who battle the Plague of Procrastination. Confers no benefit. Enchanted Armoire: Plague Doctor Set (Item 2 of 3).",
|
||||||
|
"twoHandedItem": "Two-handed item."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,6 +173,8 @@
|
|||||||
"achievementBewilderText": "Helped defeat the Be-Wilder during the 2016 Spring Fling Event!",
|
"achievementBewilderText": "Helped defeat the Be-Wilder during the 2016 Spring Fling Event!",
|
||||||
"checkOutProgress": "Check out my progress in Habitica!",
|
"checkOutProgress": "Check out my progress in Habitica!",
|
||||||
"cards": "Cards",
|
"cards": "Cards",
|
||||||
|
"sentCardToUser": "You sent a card to <%= profileName %>",
|
||||||
|
"cardReceivedFrom": "<%= cardType %> from <%= userName %>",
|
||||||
"cardReceived": "You received a <span class=\"notification-bold-blue\"><%= card %></span>",
|
"cardReceived": "You received a <span class=\"notification-bold-blue\"><%= card %></span>",
|
||||||
"greetingCard": "Greeting Card",
|
"greetingCard": "Greeting Card",
|
||||||
"greetingCardExplanation": "You both receive the Cheery Chum achievement!",
|
"greetingCardExplanation": "You both receive the Cheery Chum achievement!",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
"messageCannotFeedPet": "Can't feed this pet.",
|
"messageCannotFeedPet": "Can't feed this pet.",
|
||||||
"messageAlreadyMount": "You already have that mount. Try feeding another pet.",
|
"messageAlreadyMount": "You already have that mount. Try feeding another pet.",
|
||||||
"messageEvolve": "You have tamed <%= egg %>, let's go for a ride!",
|
"messageEvolve": "You have tamed <%= egg %>, let's go for a ride!",
|
||||||
"messageLikesFood": "<%= egg %> really likes the <%= foodText %>!",
|
"messageLikesFood": "<%= egg %> really likes <%= foodText %>!",
|
||||||
"messageDontEnjoyFood": "<%= egg %> eats the <%= foodText %> but doesn't seem to enjoy it.",
|
"messageDontEnjoyFood": "<%= egg %> eats <%= foodText %> but doesn't seem to enjoy it.",
|
||||||
"messageBought": "Bought <%= itemText %>",
|
"messageBought": "Bought <%= itemText %>",
|
||||||
"messageEquipped": " <%= itemText %> equipped.",
|
"messageEquipped": " <%= itemText %> equipped.",
|
||||||
"messageUnEquipped": "<%= itemText %> unequipped.",
|
"messageUnEquipped": "<%= itemText %> unequipped.",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"messageNotEnoughGold": "Not Enough Gold",
|
"messageNotEnoughGold": "Not Enough Gold",
|
||||||
"messageTwoHandedEquip": "Wielding <%= twoHandedText %> takes two hands, so <%= offHandedText %> has been unequipped.",
|
"messageTwoHandedEquip": "Wielding <%= twoHandedText %> takes two hands, so <%= offHandedText %> has been unequipped.",
|
||||||
"messageTwoHandedUnequip": "Wielding <%= twoHandedText %> takes two hands, so it was unequipped when you armed yourself with <%= offHandedText %>.",
|
"messageTwoHandedUnequip": "Wielding <%= twoHandedText %> takes two hands, so it was unequipped when you armed yourself with <%= offHandedText %>.",
|
||||||
"messageDropFood": "You've found <%= dropArticle %><%= dropText %>!",
|
"messageDropFood": "You've found <%= dropText %>!",
|
||||||
"messageDropEgg": "You've found a <%= dropText %> Egg!",
|
"messageDropEgg": "You've found a <%= dropText %> Egg!",
|
||||||
"messageDropPotion": "You've found a <%= dropText %> Hatching Potion!",
|
"messageDropPotion": "You've found a <%= dropText %> Hatching Potion!",
|
||||||
"messageDropQuest": "You've found a quest!",
|
"messageDropQuest": "You've found a quest!",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"messageHealthAlreadyMin": "Oh no! You have already run out of health so it's too late to buy a health potion, but don't worry - you can revive!",
|
"messageHealthAlreadyMin": "Oh no! You have already run out of health so it's too late to buy a health potion, but don't worry - you can revive!",
|
||||||
|
|
||||||
"armoireEquipment": "<%= image %> You found a piece of rare Equipment in the Armoire: <%= dropText %>! Awesome!",
|
"armoireEquipment": "<%= image %> You found a piece of rare Equipment in the Armoire: <%= dropText %>! Awesome!",
|
||||||
"armoireFood": "<%= image %> You rummage in the Armoire and find <%= dropArticle %><%= dropText %>. What's that doing in here?",
|
"armoireFood": "<%= image %> You rummage in the Armoire and find <%= dropText %>. What's that doing in here?",
|
||||||
"armoireExp": "You wrestle with the Armoire and gain Experience. Take that!",
|
"armoireExp": "You wrestle with the Armoire and gain Experience. Take that!",
|
||||||
|
|
||||||
"messageInsufficientGems": "Not enough gems!",
|
"messageInsufficientGems": "Not enough gems!",
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
"petNotOwned": "You do not own this pet.",
|
"petNotOwned": "You do not own this pet.",
|
||||||
"mountNotOwned": "You do not own this mount.",
|
"mountNotOwned": "You do not own this mount.",
|
||||||
"earnedCompanion": "With all your productivity, you've earned a new companion. Feed it to make it grow!",
|
"earnedCompanion": "With all your productivity, you've earned a new companion. Feed it to make it grow!",
|
||||||
"feedPet": "Feed <%= article %><%= text %> to your <%= name %>?",
|
"feedPet": "Feed <%= text %> to your <%= name %>?",
|
||||||
"useSaddle": "Saddle <%= pet %>?",
|
"useSaddle": "Saddle <%= pet %>?",
|
||||||
"raisedPet": "You grew your <%= pet %>!",
|
"raisedPet": "You grew your <%= pet %>!",
|
||||||
"earnedSteed": "By completing your tasks, you've earned a faithful steed!",
|
"earnedSteed": "By completing your tasks, you've earned a faithful steed!",
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export const ITEM_LIST = {
|
|||||||
premiumHatchingPotions: { localeKey: 'hatchingPotion', isEquipment: false },
|
premiumHatchingPotions: { localeKey: 'hatchingPotion', isEquipment: false },
|
||||||
eggs: { localeKey: 'eggSingular', isEquipment: false },
|
eggs: { localeKey: 'eggSingular', isEquipment: false },
|
||||||
quests: { localeKey: 'quest', isEquipment: false },
|
quests: { localeKey: 'quest', isEquipment: false },
|
||||||
food: { localeKey: 'foodText', isEquipment: false },
|
food: { localeKey: 'foodTextThe', isEquipment: false },
|
||||||
Saddle: { localeKey: 'foodSaddleText', isEquipment: false },
|
Saddle: { localeKey: 'foodSaddleText', isEquipment: false },
|
||||||
bundles: { localeKey: 'discountBundle', isEquipment: false },
|
bundles: { localeKey: 'discountBundle', isEquipment: false },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import t from '../translation';
|
||||||
|
|
||||||
import {weapon as baseWeapon} from './sets/base';
|
import {weapon as baseWeapon} from './sets/base';
|
||||||
|
|
||||||
import {weapon as healerWeapon} from './sets/healer';
|
import {weapon as healerWeapon} from './sets/healer';
|
||||||
@@ -22,4 +24,43 @@ let weapon = {
|
|||||||
armoire: armoireWeapon,
|
armoire: armoireWeapon,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add Two Handed message to all weapons
|
||||||
|
const rtlLanguages = [
|
||||||
|
'ae', /* Avestan */
|
||||||
|
'ar', /* 'العربية', Arabic */
|
||||||
|
'arc', /* Aramaic */
|
||||||
|
'bcc', /* 'بلوچی مکرانی', Southern Balochi */
|
||||||
|
'bqi', /* 'بختياري', Bakthiari */
|
||||||
|
'ckb', /* 'Soranî / کوردی', Sorani */
|
||||||
|
'dv', /* Dhivehi */
|
||||||
|
'fa', /* 'فارسی', Persian */
|
||||||
|
'glk', /* 'گیلکی', Gilaki */
|
||||||
|
'he', /* 'עברית', Hebrew */
|
||||||
|
'ku', /* 'Kurdî / كوردی', Kurdish */
|
||||||
|
'mzn', /* 'مازِرونی', Mazanderani */
|
||||||
|
'nqo', /* N'Ko */
|
||||||
|
'pnb', /* 'پنجابی', Western Punjabi */
|
||||||
|
'ps', /* 'پښتو', Pashto, */
|
||||||
|
'sd', /* 'سنڌي', Sindhi */
|
||||||
|
'ug', /* 'Uyghurche / ئۇيغۇرچە', Uyghur */
|
||||||
|
'ur', /* 'اردو', Urdu */
|
||||||
|
'yi', /* 'ייִדיש', Yiddish */
|
||||||
|
];
|
||||||
|
for (let key in weapon) {
|
||||||
|
const set = weapon[key];
|
||||||
|
for (let weaponKey in set) {
|
||||||
|
const item = set[weaponKey];
|
||||||
|
const oldnotes = item.notes;
|
||||||
|
item.notes = (lang) => {
|
||||||
|
const twoHandedText = item.twoHanded ? t('twoHandedItem')(lang) : '';
|
||||||
|
|
||||||
|
if (rtlLanguages.indexOf(lang) !== -1) {
|
||||||
|
return `${twoHandedText} ${oldnotes(lang)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${oldnotes(lang)} ${twoHandedText}`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = weapon;
|
module.exports = weapon;
|
||||||
|
|||||||
@@ -276,8 +276,9 @@ let canDropCakeFood = false;
|
|||||||
api.food = {
|
api.food = {
|
||||||
Meat: {
|
Meat: {
|
||||||
text: t('foodMeat'),
|
text: t('foodMeat'),
|
||||||
|
textA: t('foodMeatA'),
|
||||||
|
textThe: t('foodMeatThe'),
|
||||||
target: 'Base',
|
target: 'Base',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -285,8 +286,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Milk: {
|
Milk: {
|
||||||
text: t('foodMilk'),
|
text: t('foodMilk'),
|
||||||
|
textA: t('foodMilkA'),
|
||||||
|
textThe: t('foodMilkThe'),
|
||||||
target: 'White',
|
target: 'White',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -294,8 +296,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Potatoe: {
|
Potatoe: {
|
||||||
text: t('foodPotatoe'),
|
text: t('foodPotatoe'),
|
||||||
|
textA: t('foodPotatoeA'),
|
||||||
|
textThe: t('foodPotatoeThe'),
|
||||||
target: 'Desert',
|
target: 'Desert',
|
||||||
article: 'a ',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -303,8 +306,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Strawberry: {
|
Strawberry: {
|
||||||
text: t('foodStrawberry'),
|
text: t('foodStrawberry'),
|
||||||
|
textA: t('foodStrawberryA'),
|
||||||
|
textThe: t('foodStrawberryThe'),
|
||||||
target: 'Red',
|
target: 'Red',
|
||||||
article: 'a ',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -312,8 +316,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Chocolate: {
|
Chocolate: {
|
||||||
text: t('foodChocolate'),
|
text: t('foodChocolate'),
|
||||||
|
textA: t('foodChocolateA'),
|
||||||
|
textThe: t('foodChocolateThe'),
|
||||||
target: 'Shade',
|
target: 'Shade',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -321,8 +326,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Fish: {
|
Fish: {
|
||||||
text: t('foodFish'),
|
text: t('foodFish'),
|
||||||
|
textA: t('foodFishA'),
|
||||||
|
textThe: t('foodFishThe'),
|
||||||
target: 'Skeleton',
|
target: 'Skeleton',
|
||||||
article: 'a ',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -330,8 +336,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
RottenMeat: {
|
RottenMeat: {
|
||||||
text: t('foodRottenMeat'),
|
text: t('foodRottenMeat'),
|
||||||
|
textA: t('foodRottenMeatA'),
|
||||||
|
textThe: t('foodRottenMeatThe'),
|
||||||
target: 'Zombie',
|
target: 'Zombie',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -339,8 +346,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
CottonCandyPink: {
|
CottonCandyPink: {
|
||||||
text: t('foodCottonCandyPink'),
|
text: t('foodCottonCandyPink'),
|
||||||
|
textA: t('foodCottonCandyPinkA'),
|
||||||
|
textThe: t('foodCottonCandyPinkThe'),
|
||||||
target: 'CottonCandyPink',
|
target: 'CottonCandyPink',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -348,8 +356,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
CottonCandyBlue: {
|
CottonCandyBlue: {
|
||||||
text: t('foodCottonCandyBlue'),
|
text: t('foodCottonCandyBlue'),
|
||||||
|
textA: t('foodCottonCandyBlueA'),
|
||||||
|
textThe: t('foodCottonCandyBlueThe'),
|
||||||
target: 'CottonCandyBlue',
|
target: 'CottonCandyBlue',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -357,8 +366,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Honey: {
|
Honey: {
|
||||||
text: t('foodHoney'),
|
text: t('foodHoney'),
|
||||||
|
textA: t('foodHoneyA'),
|
||||||
|
textThe: t('foodHoneyThe'),
|
||||||
target: 'Golden',
|
target: 'Golden',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyNormalFood;
|
return canBuyNormalFood;
|
||||||
},
|
},
|
||||||
@@ -376,8 +386,9 @@ api.food = {
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
Cake_Skeleton: {
|
Cake_Skeleton: {
|
||||||
text: t('foodCakeSkeleton'),
|
text: t('foodCakeSkeleton'),
|
||||||
|
textA: t('foodCakeSkeletonA'),
|
||||||
|
textThe: t('foodCakeSkeletonThe'),
|
||||||
target: 'Skeleton',
|
target: 'Skeleton',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -385,8 +396,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Base: {
|
Cake_Base: {
|
||||||
text: t('foodCakeBase'),
|
text: t('foodCakeBase'),
|
||||||
|
textA: t('foodCakeBaseA'),
|
||||||
|
textThe: t('foodCakeBaseThe'),
|
||||||
target: 'Base',
|
target: 'Base',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -394,8 +406,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_CottonCandyBlue: {
|
Cake_CottonCandyBlue: {
|
||||||
text: t('foodCakeCottonCandyBlue'),
|
text: t('foodCakeCottonCandyBlue'),
|
||||||
|
textA: t('foodCakeCottonCandyBlueA'),
|
||||||
|
textThe: t('foodCakeCottonCandyBlueThe'),
|
||||||
target: 'CottonCandyBlue',
|
target: 'CottonCandyBlue',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -403,8 +416,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_CottonCandyPink: {
|
Cake_CottonCandyPink: {
|
||||||
text: t('foodCakeCottonCandyPink'),
|
text: t('foodCakeCottonCandyPink'),
|
||||||
|
textA: t('foodCakeCottonCandyPinkA'),
|
||||||
|
textThe: t('foodCakeCottonCandyPinkThe'),
|
||||||
target: 'CottonCandyPink',
|
target: 'CottonCandyPink',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -412,8 +426,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Shade: {
|
Cake_Shade: {
|
||||||
text: t('foodCakeShade'),
|
text: t('foodCakeShade'),
|
||||||
|
textA: t('foodCakeShadeA'),
|
||||||
|
textThe: t('foodCakeShadeThe'),
|
||||||
target: 'Shade',
|
target: 'Shade',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -421,8 +436,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_White: {
|
Cake_White: {
|
||||||
text: t('foodCakeWhite'),
|
text: t('foodCakeWhite'),
|
||||||
|
textA: t('foodCakeWhiteA'),
|
||||||
|
textThe: t('foodCakeWhiteThe'),
|
||||||
target: 'White',
|
target: 'White',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -430,8 +446,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Golden: {
|
Cake_Golden: {
|
||||||
text: t('foodCakeGolden'),
|
text: t('foodCakeGolden'),
|
||||||
|
textA: t('foodCakeGoldenA'),
|
||||||
|
textThe: t('foodCakeGoldenThe'),
|
||||||
target: 'Golden',
|
target: 'Golden',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -439,8 +456,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Zombie: {
|
Cake_Zombie: {
|
||||||
text: t('foodCakeZombie'),
|
text: t('foodCakeZombie'),
|
||||||
|
textA: t('foodCakeZombieA'),
|
||||||
|
textThe: t('foodCakeZombieThe'),
|
||||||
target: 'Zombie',
|
target: 'Zombie',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -448,8 +466,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Desert: {
|
Cake_Desert: {
|
||||||
text: t('foodCakeDesert'),
|
text: t('foodCakeDesert'),
|
||||||
|
textA: t('foodCakeDesertA'),
|
||||||
|
textThe: t('foodCakeDesertThe'),
|
||||||
target: 'Desert',
|
target: 'Desert',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -457,8 +476,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Cake_Red: {
|
Cake_Red: {
|
||||||
text: t('foodCakeRed'),
|
text: t('foodCakeRed'),
|
||||||
|
textA: t('foodCakeRedA'),
|
||||||
|
textThe: t('foodCakeRedThe'),
|
||||||
target: 'Red',
|
target: 'Red',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCakeFood;
|
return canBuyCakeFood;
|
||||||
},
|
},
|
||||||
@@ -466,8 +486,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Skeleton: {
|
Candy_Skeleton: {
|
||||||
text: t('foodCandySkeleton'),
|
text: t('foodCandySkeleton'),
|
||||||
|
textA: t('foodCandySkeletonA'),
|
||||||
|
textThe: t('foodCandySkeletonThe'),
|
||||||
target: 'Skeleton',
|
target: 'Skeleton',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -475,8 +496,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Base: {
|
Candy_Base: {
|
||||||
text: t('foodCandyBase'),
|
text: t('foodCandyBase'),
|
||||||
|
textA: t('foodCandyBaseA'),
|
||||||
|
textThe: t('foodCandyBaseThe'),
|
||||||
target: 'Base',
|
target: 'Base',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -484,8 +506,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_CottonCandyBlue: {
|
Candy_CottonCandyBlue: {
|
||||||
text: t('foodCandyCottonCandyBlue'),
|
text: t('foodCandyCottonCandyBlue'),
|
||||||
|
textA: t('foodCandyCottonCandyBlueA'),
|
||||||
|
textThe: t('foodCandyCottonCandyBlueThe'),
|
||||||
target: 'CottonCandyBlue',
|
target: 'CottonCandyBlue',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -493,8 +516,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_CottonCandyPink: {
|
Candy_CottonCandyPink: {
|
||||||
text: t('foodCandyCottonCandyPink'),
|
text: t('foodCandyCottonCandyPink'),
|
||||||
|
textA: t('foodCandyCottonCandyPinkA'),
|
||||||
|
textThe: t('foodCandyCottonCandyPinkThe'),
|
||||||
target: 'CottonCandyPink',
|
target: 'CottonCandyPink',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -502,8 +526,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Shade: {
|
Candy_Shade: {
|
||||||
text: t('foodCandyShade'),
|
text: t('foodCandyShade'),
|
||||||
|
textA: t('foodCandyShadeA'),
|
||||||
|
textThe: t('foodCandyShadeThe'),
|
||||||
target: 'Shade',
|
target: 'Shade',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -511,8 +536,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_White: {
|
Candy_White: {
|
||||||
text: t('foodCandyWhite'),
|
text: t('foodCandyWhite'),
|
||||||
|
textA: t('foodCandyWhiteA'),
|
||||||
|
textThe: t('foodCandyWhiteThe'),
|
||||||
target: 'White',
|
target: 'White',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -520,8 +546,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Golden: {
|
Candy_Golden: {
|
||||||
text: t('foodCandyGolden'),
|
text: t('foodCandyGolden'),
|
||||||
|
textA: t('foodCandyGoldenA'),
|
||||||
|
textThe: t('foodCandyGoldenThe'),
|
||||||
target: 'Golden',
|
target: 'Golden',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -529,8 +556,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Zombie: {
|
Candy_Zombie: {
|
||||||
text: t('foodCandyZombie'),
|
text: t('foodCandyZombie'),
|
||||||
|
textA: t('foodCandyZombieA'),
|
||||||
|
textThe: t('foodCandyZombieThe'),
|
||||||
target: 'Zombie',
|
target: 'Zombie',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -538,8 +566,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Desert: {
|
Candy_Desert: {
|
||||||
text: t('foodCandyDesert'),
|
text: t('foodCandyDesert'),
|
||||||
|
textA: t('foodCandyDesertA'),
|
||||||
|
textThe: t('foodCandyDesertThe'),
|
||||||
target: 'Desert',
|
target: 'Desert',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
@@ -547,8 +576,9 @@ api.food = {
|
|||||||
},
|
},
|
||||||
Candy_Red: {
|
Candy_Red: {
|
||||||
text: t('foodCandyRed'),
|
text: t('foodCandyRed'),
|
||||||
|
textA: t('foodCandyRedA'),
|
||||||
|
textThe: t('foodCandyRedThe'),
|
||||||
target: 'Red',
|
target: 'Red',
|
||||||
article: '',
|
|
||||||
canBuy () {
|
canBuy () {
|
||||||
return canBuyCandyFood;
|
return canBuyCandyFood;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -77,8 +77,7 @@ module.exports = function randomDrop (user, options, req = {}, analytics) {
|
|||||||
user.items.food[drop.key] += 1;
|
user.items.food[drop.key] += 1;
|
||||||
drop.type = 'Food';
|
drop.type = 'Food';
|
||||||
drop.dialog = i18n.t('messageDropFood', {
|
drop.dialog = i18n.t('messageDropFood', {
|
||||||
dropArticle: drop.article,
|
dropText: drop.textA(req.language),
|
||||||
dropText: drop.text(req.language),
|
|
||||||
dropNotes: drop.notes(req.language),
|
dropNotes: drop.notes(req.language),
|
||||||
}, req.language);
|
}, req.language);
|
||||||
} else if (rarity > 0.3) { // eggs 30% chance
|
} else if (rarity > 0.3) { // eggs 30% chance
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module.exports = function buyArmoire (user, req = {}, analytics) {
|
|||||||
drop = randomVal(eligibleEquipment);
|
drop = randomVal(eligibleEquipment);
|
||||||
|
|
||||||
if (user.items.gear.owned[drop.key]) {
|
if (user.items.gear.owned[drop.key]) {
|
||||||
throw new NotAuthorized(i18n.t('equipmentAlradyOwned', req.language));
|
throw new NotAuthorized(i18n.t('equipmentAlreadyOwned', req.language));
|
||||||
}
|
}
|
||||||
|
|
||||||
user.items.gear.owned[drop.key] = true;
|
user.items.gear.owned[drop.key] = true;
|
||||||
@@ -74,14 +74,12 @@ module.exports = function buyArmoire (user, req = {}, analytics) {
|
|||||||
|
|
||||||
message = i18n.t('armoireFood', {
|
message = i18n.t('armoireFood', {
|
||||||
image: `<span class="Pet_Food_${drop.key} pull-left"></span>`,
|
image: `<span class="Pet_Food_${drop.key} pull-left"></span>`,
|
||||||
dropArticle: drop.article,
|
|
||||||
dropText: drop.text(req.language),
|
dropText: drop.text(req.language),
|
||||||
}, req.language);
|
}, req.language);
|
||||||
armoireResp = {
|
armoireResp = {
|
||||||
type: 'food',
|
type: 'food',
|
||||||
dropKey: drop.key,
|
dropKey: drop.key,
|
||||||
dropArticle: drop.article,
|
dropText: drop.textA(req.language),
|
||||||
dropText: drop.text(req.language),
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let armoireExp = Math.floor(randomVal.trueRandom() * 40 + 10);
|
let armoireExp = Math.floor(randomVal.trueRandom() * 40 + 10);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ module.exports = function feed (user, req = {}) {
|
|||||||
} else {
|
} else {
|
||||||
let messageParams = {
|
let messageParams = {
|
||||||
egg: pet.text(req.language),
|
egg: pet.text(req.language),
|
||||||
foodText: food.text(req.language),
|
foodText: food.textThe(req.language),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (food.target === pet.potion || pet.type === 'premium') {
|
if (food.target === pet.potion || pet.type === 'premium') {
|
||||||
|
|||||||
@@ -243,11 +243,24 @@ module.exports = function scoreTask (options = {}, req = {}) {
|
|||||||
if (user.addNotification) user.addNotification('STREAK_ACHIEVEMENT');
|
if (user.addNotification) user.addNotification('STREAK_ACHIEVEMENT');
|
||||||
}
|
}
|
||||||
task.completed = true;
|
task.completed = true;
|
||||||
|
|
||||||
|
// Save history entry for daily
|
||||||
|
task.history = task.history || [];
|
||||||
|
let historyEntry = {
|
||||||
|
date: Number(new Date()),
|
||||||
|
value: task.value,
|
||||||
|
};
|
||||||
|
task.history.push(historyEntry);
|
||||||
} else if (direction === 'down') {
|
} else if (direction === 'down') {
|
||||||
// Remove a streak achievement if streak was a multiple of 21 and the daily was undone
|
// Remove a streak achievement if streak was a multiple of 21 and the daily was undone
|
||||||
if (task.streak !== 0 && task.streak % 21 === 0) user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0;
|
if (task.streak !== 0 && task.streak % 21 === 0) user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0;
|
||||||
task.streak -= 1;
|
task.streak -= 1;
|
||||||
task.completed = false;
|
task.completed = false;
|
||||||
|
|
||||||
|
// Delete history entry when daily unchecked
|
||||||
|
if (task.history || task.history.length > 0) {
|
||||||
|
task.history.splice(-1, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (task.type === 'todo') {
|
} else if (task.type === 'todo') {
|
||||||
|
|||||||
@@ -248,7 +248,8 @@ function _getMembersForItem (type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.query.search) {
|
if (req.query.search) {
|
||||||
query['profile.name'] = {$regex: req.query.search};
|
// Creates a RegExp expression when querying for profile.name
|
||||||
|
query['profile.name'] = { $regex: new RegExp(req.query.search, 'i') };
|
||||||
}
|
}
|
||||||
} else if (type === 'group-invites') {
|
} else if (type === 'group-invites') {
|
||||||
if (group.type === 'guild') { // eslint-disable-line no-lonely-if
|
if (group.type === 'guild') { // eslint-disable-line no-lonely-if
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ api.updateTask = {
|
|||||||
* {"success":true,"data":{"delta":0.9746999906450404,"_tmp":{},"hp":49.06645205596985,"mp":37.2008917491047,"exp":101.93810026267543,"gp":77.09694176716997,"lvl":19,"class":"rogue","points":0,"str":5,"con":3,"int":3,"per":8,"buffs":{"str":9,"int":9,"per":9,"con":9,"stealth":0,"streaks":false,"snowball":false,"spookySparkles":false,"shinySeed":false,"seafoam":false},"training":{"int":0,"per":0,"str":0,"con":0}},"notifications":[]}
|
* {"success":true,"data":{"delta":0.9746999906450404,"_tmp":{},"hp":49.06645205596985,"mp":37.2008917491047,"exp":101.93810026267543,"gp":77.09694176716997,"lvl":19,"class":"rogue","points":0,"str":5,"con":3,"int":3,"per":8,"buffs":{"str":9,"int":9,"per":9,"con":9,"stealth":0,"streaks":false,"snowball":false,"spookySparkles":false,"shinySeed":false,"seafoam":false},"training":{"int":0,"per":0,"str":0,"con":0}},"notifications":[]}
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Example result with item drop:
|
* @apiSuccessExample {json} Example result with item drop:
|
||||||
* {"success":true,"data":{"delta":1.0259567046270648,"_tmp":{"quest":{"progressDelta":1.2362778290756147,"collection":1},"drop":{"target":"Zombie","article":"","canDrop":true,"value":1,"key":"RottenMeat","type":"Food","dialog":"You've found Rotten Meat! Feed this to a pet and it may grow into a sturdy steed."}},"hp":50,"mp":66.2390716654227,"exp":143.93810026267545,"gp":135.12889840462591,"lvl":20,"class":"rogue","points":0,"str":6,"con":3,"int":3,"per":8,"buffs":{"str":10,"int":10,"per":10,"con":10,"stealth":0,"streaks":false,"snowball":false,"spookySparkles":false,"shinySeed":false,"seafoam":false},"training":{"int":0,"per":0,"str":0,"con":0}},"notifications":[]}
|
* {"success":true,"data":{"delta":1.0259567046270648,"_tmp":{"quest":{"progressDelta":1.2362778290756147,"collection":1},"drop":{"target":"Zombie","canDrop":true,"value":1,"key":"RottenMeat","type":"Food","dialog":"You've found Rotten Meat! Feed this to a pet and it may grow into a sturdy steed."}},"hp":50,"mp":66.2390716654227,"exp":143.93810026267545,"gp":135.12889840462591,"lvl":20,"class":"rogue","points":0,"str":6,"con":3,"int":3,"per":8,"buffs":{"str":10,"int":10,"per":10,"con":10,"stealth":0,"streaks":false,"snowball":false,"spookySparkles":false,"shinySeed":false,"seafoam":false},"training":{"int":0,"per":0,"str":0,"con":0}},"notifications":[]}
|
||||||
*
|
*
|
||||||
* @apiUse TaskNotFound
|
* @apiUse TaskNotFound
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -357,14 +357,15 @@ export function cron (options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// add history entry when task was not completed
|
||||||
task.history.push({
|
task.history.push({
|
||||||
date: Number(new Date()),
|
date: Number(new Date()),
|
||||||
value: task.value,
|
value: task.value,
|
||||||
});
|
});
|
||||||
task.completed = false;
|
}
|
||||||
|
|
||||||
|
task.completed = false;
|
||||||
setIsDueNextDue(task, user, now);
|
setIsDueNextDue(task, user, now);
|
||||||
|
|
||||||
if (completed || scheduleMisses > 0) {
|
if (completed || scheduleMisses > 0) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
import autoinc from 'mongoose-id-autoinc';
|
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
|
|
||||||
@@ -12,17 +11,16 @@ mongoose.Promise = Bluebird;
|
|||||||
|
|
||||||
// Do not connect to MongoDB when in maintenance mode
|
// Do not connect to MongoDB when in maintenance mode
|
||||||
if (MAINTENANCE_MODE !== 'true') {
|
if (MAINTENANCE_MODE !== 'true') {
|
||||||
let mongooseOptions = !IS_PROD ? {} : {
|
const mongooseOptions = !IS_PROD ? {} : {
|
||||||
replset: { socketOptions: { keepAlive: 120, connectTimeoutMS: 30000 } },
|
keepAlive: 120,
|
||||||
server: { socketOptions: { keepAlive: 120, connectTimeoutMS: 30000 } },
|
connectTimeoutMS: 30000,
|
||||||
|
useMongoClient: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NODE_DB_URI = nconf.get('IS_TEST') ? nconf.get('TEST_DB_URI') : nconf.get('NODE_DB_URI');
|
const NODE_DB_URI = nconf.get('IS_TEST') ? nconf.get('TEST_DB_URI') : nconf.get('NODE_DB_URI');
|
||||||
|
|
||||||
let db = mongoose.connect(NODE_DB_URI, mongooseOptions, (err) => {
|
mongoose.connect(NODE_DB_URI, mongooseOptions, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
logger.info('Connected with Mongoose.');
|
logger.info('Connected with Mongoose.');
|
||||||
});
|
});
|
||||||
|
|
||||||
autoinc.init(db);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ module.exports = function errorHandler (err, req, res, next) { // eslint-disable
|
|||||||
|
|
||||||
// Handle mongoose validation errors
|
// Handle mongoose validation errors
|
||||||
if (err.name === 'ValidationError') {
|
if (err.name === 'ValidationError') {
|
||||||
responseErr = new BadRequest(err.message); // TODO standard message? translate?
|
const model = err.message.split(' ')[0];
|
||||||
|
responseErr = new BadRequest(`${model} validation failed`);
|
||||||
responseErr.errors = map(err.errors, (mongooseErr) => {
|
responseErr.errors = map(err.errors, (mongooseErr) => {
|
||||||
return {
|
return {
|
||||||
message: mongooseErr.message,
|
message: mongooseErr.message,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const SESSION_SECRET = nconf.get('SESSION_SECRET');
|
|||||||
const TEN_YEARS = 1000 * 60 * 60 * 24 * 365 * 10;
|
const TEN_YEARS = 1000 * 60 * 60 * 24 * 365 * 10;
|
||||||
|
|
||||||
module.exports = function attachMiddlewares (app, server) {
|
module.exports = function attachMiddlewares (app, server) {
|
||||||
app.set('view engine', 'jade');
|
app.set('view engine', 'pug');
|
||||||
app.set('views', `${__dirname}/../../views`);
|
app.set('views', `${__dirname}/../../views`);
|
||||||
|
|
||||||
app.use(domainMiddleware(server, mongoose));
|
app.use(domainMiddleware(server, mongoose));
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const TOP_LEVEL_CONTROLLERS_PATH = path.join(__dirname, '/../controllers/top-lev
|
|||||||
const v3app = express();
|
const v3app = express();
|
||||||
|
|
||||||
// re-set the view options because they are not inherited from the top level app
|
// re-set the view options because they are not inherited from the top level app
|
||||||
v3app.set('view engine', 'jade');
|
v3app.set('view engine', 'pug');
|
||||||
v3app.set('views', `${__dirname}/../../views`);
|
v3app.set('views', `${__dirname}/../../views`);
|
||||||
|
|
||||||
v3app.use(expressValidator());
|
v3app.use(expressValidator());
|
||||||
|
|||||||
@@ -466,9 +466,54 @@ export function chatDefaults (msg, user) {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setUserStyles (newMessage, user) {
|
||||||
|
let userStyles = {};
|
||||||
|
userStyles.items = {gear: {}};
|
||||||
|
|
||||||
|
let userCopy = user;
|
||||||
|
if (user.toObject) userCopy = user.toObject();
|
||||||
|
|
||||||
|
if (userCopy.items) {
|
||||||
|
userStyles.items.gear = {};
|
||||||
|
userStyles.items.gear.costume = Object.assign({}, userCopy.items.gear.costume);
|
||||||
|
userStyles.items.gear.equipped = Object.assign({}, userCopy.items.gear.equipped);
|
||||||
|
|
||||||
|
userStyles.items.currentMount = userCopy.items.currentMount;
|
||||||
|
userStyles.items.currentPet = userCopy.items.currentPet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (userCopy.preferences) {
|
||||||
|
userStyles.preferences = {};
|
||||||
|
if (userCopy.preferences.style) userStyles.preferences.style = userCopy.preferences.style;
|
||||||
|
userStyles.preferences.hair = userCopy.preferences.hair;
|
||||||
|
userStyles.preferences.skin = userCopy.preferences.skin;
|
||||||
|
userStyles.preferences.shirt = userCopy.preferences.shirt;
|
||||||
|
userStyles.preferences.chair = userCopy.preferences.chair;
|
||||||
|
userStyles.preferences.size = userCopy.preferences.size;
|
||||||
|
userStyles.preferences.chair = userCopy.preferences.chair;
|
||||||
|
userStyles.preferences.background = userCopy.preferences.background;
|
||||||
|
userStyles.preferences.costume = userCopy.preferences.costume;
|
||||||
|
}
|
||||||
|
|
||||||
|
userStyles.stats = {};
|
||||||
|
if (userCopy.stats && userCopy.stats.buffs) {
|
||||||
|
userStyles.stats.buffs = {
|
||||||
|
seafoam: userCopy.stats.buffs.seafoam,
|
||||||
|
shinySeed: userCopy.stats.buffs.shinySeed,
|
||||||
|
spookySparkles: userCopy.stats.buffs.spookySparkles,
|
||||||
|
snowball: userCopy.stats.buffs.snowball,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
newMessage.userStyles = userStyles;
|
||||||
|
}
|
||||||
|
|
||||||
schema.methods.sendChat = function sendChat (message, user, metaData) {
|
schema.methods.sendChat = function sendChat (message, user, metaData) {
|
||||||
let newMessage = chatDefaults(message, user);
|
let newMessage = chatDefaults(message, user);
|
||||||
|
|
||||||
|
if (user) setUserStyles(newMessage, user);
|
||||||
|
|
||||||
// Optional data stored in the chat message but not returned
|
// Optional data stored in the chat message but not returned
|
||||||
// to the users that can be stored for debugging purposes
|
// to the users that can be stored for debugging purposes
|
||||||
if (metaData) {
|
if (metaData) {
|
||||||
@@ -736,7 +781,7 @@ async function _updateUserWithRetries (userId, updates, numTry = 1, query = {})
|
|||||||
return raw;
|
return raw;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (numTry < MAX_UPDATE_RETRIES) {
|
if (numTry < MAX_UPDATE_RETRIES) {
|
||||||
return _updateUserWithRetries(userId, updates, ++numTry);
|
return _updateUserWithRetries(userId, updates, ++numTry, query);
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,23 @@ export let TaskSchema = new Schema({
|
|||||||
return !validator.isUUID(val);
|
return !validator.isUUID(val);
|
||||||
},
|
},
|
||||||
msg: 'Task short names cannot be uuids.',
|
msg: 'Task short names cannot be uuids.',
|
||||||
|
}, {
|
||||||
|
validator (alias) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Task.findOne({ // eslint-disable-line no-use-before-define
|
||||||
|
_id: { $ne: this._id },
|
||||||
|
userId: this.userId,
|
||||||
|
alias,
|
||||||
|
}).exec().then((task) => {
|
||||||
|
let aliasAvailable = !task;
|
||||||
|
|
||||||
|
return aliasAvailable ? resolve() : reject();
|
||||||
|
}).catch(() => {
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
msg: 'Task alias already used on another task.',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
tags: [{
|
tags: [{
|
||||||
@@ -193,20 +210,6 @@ TaskSchema.methods.scoreChallengeTask = async function scoreChallengeTask (delta
|
|||||||
|
|
||||||
export let Task = mongoose.model('Task', TaskSchema);
|
export let Task = mongoose.model('Task', TaskSchema);
|
||||||
|
|
||||||
Task.schema.path('alias').validate(function valiateAliasNotTaken (alias, respond) {
|
|
||||||
Task.findOne({
|
|
||||||
_id: { $ne: this._id },
|
|
||||||
userId: this.userId,
|
|
||||||
alias,
|
|
||||||
}).exec().then((task) => {
|
|
||||||
let aliasAvailable = !task;
|
|
||||||
|
|
||||||
respond(aliasAvailable);
|
|
||||||
}).catch(() => {
|
|
||||||
respond(false);
|
|
||||||
});
|
|
||||||
}, 'Task alias already used on another task.');
|
|
||||||
|
|
||||||
// habits and dailies shared fields
|
// habits and dailies shared fields
|
||||||
let habitDailySchema = () => {
|
let habitDailySchema = () => {
|
||||||
return {history: Array}; // [{date:Date, value:Number}], // this causes major performance problems
|
return {history: Array}; // [{date:Date, value:Number}], // this causes major performance problems
|
||||||
|
|||||||
Reference in New Issue
Block a user