Merge branch 'develop' of github.com:HabitRPG/habitrpg into develop

This commit is contained in:
Matteo Pagliazzi 2016-05-24 13:11:33 +02:00
commit 6ce2f53503
17 changed files with 131 additions and 126 deletions

View file

@ -8,7 +8,7 @@ import content from './content/index';
const DROP_ANIMALS = keys(content.pets);
function beastMasterProgress (pets) {
function beastMasterProgress (pets = {}) {
let count = 0;
each(DROP_ANIMALS, (animal) => {
@ -19,7 +19,7 @@ function beastMasterProgress (pets) {
return count;
}
function dropPetsCurrentlyOwned (pets) {
function dropPetsCurrentlyOwned (pets = {}) {
let count = 0;
each(DROP_ANIMALS, (animal) => {
@ -30,7 +30,7 @@ function dropPetsCurrentlyOwned (pets) {
return count;
}
function mountMasterProgress (mounts) {
function mountMasterProgress (mounts = {}) {
let count = 0;
each(DROP_ANIMALS, (animal) => {
@ -41,7 +41,7 @@ function mountMasterProgress (mounts) {
return count;
}
function remainingGearInSet (userGear, set) {
function remainingGearInSet (userGear = {}, set) {
let gear = filter(content.gear.flat, (item) => {
let setMatches = item.klass === set;
let hasItem = userGear[item.key];
@ -54,7 +54,7 @@ function remainingGearInSet (userGear, set) {
return count;
}
function questsOfCategory (userQuests, category) {
function questsOfCategory (userQuests = {}, category) {
let quests = filter(content.quests, (quest) => {
let categoryMatches = quest.category === category;
let hasQuest = userQuests[quest.key];

View file

@ -21,7 +21,7 @@ module.exports = function sortTask (user, req = {}) {
if (index === -1) {
throw new NotFound(i18n.t('messageTaskNotFound', req.language));
}
if (!to && !fromParam) {
if (to == null && fromParam == null) { // eslint-disable-line eqeqeq
throw new BadRequest('?to=__&from=__ are required');
}

View file

@ -10,6 +10,7 @@
"TEST_DB_URI":"mongodb://localhost/habitrpg_test",
"NODE_ENV":"development",
"CRON_SAFE_MODE":"false",
"CRON_SEMI_SAFE_MODE":"false",
"MAINTENANCE_MODE": "false",
"SESSION_SECRET":"YOUR SECRET HERE",
"ADMIN_EMAIL": "you@example.com",

View file

@ -3,7 +3,7 @@ import {
generateUser,
} from '../../../../helpers/api-v3-integration.helper';
xdescribe('POST /debug/make-admin (pended for v3 prod testing)', () => {
describe('POST /debug/make-admin (pended for v3 prod testing)', () => {
let user;
before(async () => {

View file

@ -1,47 +1,53 @@
"use strict";
habitrpg.controller("HallHeroesCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', '$resource',
function($scope, $rootScope, User, Notification, ApiUrl, $resource) {
var Hero = $resource(ApiUrl.get() + '/api/v3/hall/heroes/:uid', {uid:'@_id'});
habitrpg.controller("HallHeroesCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', 'Hall',
function($scope, $rootScope, User, Notification, ApiUrl, Hall) {
$scope.hero = undefined;
$scope.loadHero = function(uuid){
Hero.query({uid:uuid}, function (heroData) {
$scope.hero = heroData.data;
$scope.currentHeroIndex = undefined;
$scope.heroes = [];
Hall.getHeroes()
.then(function (response) {
$scope.heroes = response.data.data;
});
$scope.loadHero = function(uuid, heroIndex) {
$scope.currentHeroIndex = heroIndex;
Hall.getHero(uuid)
.then(function (response) {
$scope.hero = response.data.data;
});
}
$scope.saveHero = function(hero) {
$scope.hero.contributor.admin = ($scope.hero.contributor.level > 7) ? true : false;
hero.$save(function(){
Notification.text("User updated");
$scope.hero = undefined;
$scope._heroID = undefined;
Hero.query({}, function (heroesData) {
$scope.heroes = heroesData.data;
Hall.updateHero($scope.hero)
.then(function (response) {
Notification.text("User updated");
$scope.hero = undefined;
$scope._heroID = undefined;
$scope.heroes[$scope.currentHeroIndex] = response.data.data;
$scope.currentHeroIndex = undefined;
});
})
}
Hero.query({}, function (heroesData) {
$scope.heroes = heroesData.data;
});
$scope.populateContributorInput = function(id) {
$scope.populateContributorInput = function(id, index) {
$scope._heroID = id;
window.scrollTo(0,200);
$scope.loadHero(id);
window.scrollTo(0, 200);
$scope.loadHero(id, index);
};
}]);
habitrpg.controller("HallPatronsCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', '$resource',
function($scope, $rootScope, User, Notification, ApiUrl, $resource) {
var Patron = $resource(ApiUrl.get() + '/api/v3/hall/patrons/:uid', {uid:'@_id'});
habitrpg.controller("HallPatronsCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', 'Hall',
function($scope, $rootScope, User, Notification, ApiUrl, Hall) {
var page = 0;
$scope.patrons = [];
$scope.loadMore = function(){
Patron.query({page: page++}, function(patronsData){
$scope.patrons = $scope.patrons.concat(patronsData.data);
})
$scope.loadMore = function() {
Hall.getPatrons(page++)
.then(function (response) {
$scope.patrons = $scope.patrons.concat(response.data.data);
});
}
$scope.loadMore();

View file

@ -193,24 +193,27 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
// Don't allow creation of an empty checklist item
// TODO Provide UI feedback that this item is still blank
} else if ($index == task.checklist.length - 1) {
Tasks.addChecklistItem(task._id, task.checklist[$index]);
task.checklist.push({completed:false,text:''});
focusChecklist(task,task.checklist.length-1);
Tasks.addChecklistItem(task._id, task.checklist[$index])
.then(function (response) {
task.checklist[$index] = response.data.data.checklist[$index];
});
task.checklist.push({completed:false, text:''});
focusChecklist(task, task.checklist.length - 1);
} else {
$scope.saveTask(task, true);
focusChecklist(task, $index + 1);
}
}
$scope.removeChecklistItem = function(task, $event, $index, force){
$scope.removeChecklistItem = function(task, $event, $index, force) {
// Remove item if clicked on trash icon
if (force) {
Tasks.removeChecklistItem(task._id, task.checklist[$index].id);
if (task.checklist[$index].id) Tasks.removeChecklistItem(task._id, task.checklist[$index].id);
task.checklist.splice($index, 1);
} else if (!task.checklist[$index].text) {
// User deleted all the text and is now wishing to delete the item
// saveTask will prune the empty item
Tasks.removeChecklistItem(task._id, task.checklist[$index].id);
if (task.checklist[$index].id) Tasks.removeChecklistItem(task._id, task.checklist[$index].id);
// Move focus if the list is still non-empty
if ($index > 0)
focusChecklist(task, $index-1);

View file

@ -0,0 +1,41 @@
'use strict';
angular.module('habitrpg')
.factory('Hall', [ '$rootScope', 'ApiUrl', '$http',
function($rootScope, ApiUrl, $http) {
var apiV3Prefix = '/api/v3';
var Hall = {};
Hall.getHeroes = function () {
return $http({
method: 'GET',
url: apiV3Prefix + '/hall/heroes',
});
}
Hall.getHero = function (uuid) {
return $http({
method: 'GET',
url: apiV3Prefix + '/hall/heroes/' + uuid,
});
}
Hall.updateHero = function (heroDetails) {
return $http({
method: 'PUT',
url: apiV3Prefix + '/hall/heroes/' + heroDetails._id,
data: heroDetails,
});
}
Hall.getPatrons = function (page) {
if (!page) page = 0;
return $http({
method: 'GET',
url: apiV3Prefix + '/hall/patrons?page=' + page,
});
}
return Hall;
}]);

View file

@ -1,6 +1,6 @@
'use strict';
var TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt'];
var TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
angular.module('habitrpg')
.factory('Tasks', ['$rootScope', 'Shared', '$http',

View file

@ -56,6 +56,7 @@
"js/services/socialServices.js",
"js/services/statServices.js",
"js/services/userServices.js",
"js/services/hallServices.js",
"js/filters/money.js",
"js/filters/roundLargeNumbers.js",

View file

@ -88,21 +88,20 @@ api.setCron = {
*
* @apiSuccess {Object} data An empty Object
*/
// TODO: Re-enable after v3 prod testing is done
// api.makeAdmin = {
// method: 'POST',
// url: '/debug/make-admin',
// middlewares: [ensureDevelpmentMode, authWithHeaders()],
// async handler (req, res) {
// let user = res.locals.user;
//
// user.contributor.admin = true;
//
// await user.save();
//
// res.respond(200, {});
// },
// };
api.makeAdmin = {
method: 'POST',
url: '/debug/make-admin',
middlewares: [ensureDevelpmentMode, authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
user.contributor.admin = true;
await user.save();
res.respond(200, {});
},
};
/**
* @api {post} /api/v3/debug/modify-inventory Manipulate user's inventory

View file

@ -357,7 +357,7 @@ function _generateWebhookTaskData (task, direction, delta, stats, user) {
}
/**
* @api {put} /api/v3/tasks/:taskId/score/:direction Score a task
* @api {post} /api/v3/tasks/:taskId/score/:direction Score a task
* @apiVersion 3.0.0
* @apiName ScoreTask
* @apiGroup Task

View file

@ -48,6 +48,15 @@ _.each(staticPages, (name) => {
};
});
api.redirectApi = {
method: 'GET',
url: '/static/api',
runCron: false,
async handler (req, res) {
res.redirect(301, '/apidoc');
},
};
let shareables = ['level-up', 'hatch-pet', 'raise-pet', 'unlock-quest', 'won-challenge', 'achievement'];
_.each(shareables, (name) => {

View file

@ -5,6 +5,7 @@ import _ from 'lodash';
import nconf from 'nconf';
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
const CRON_SEMI_SAFE_MODE = nconf.get('CRON_SEMI_SAFE_MODE') === 'true';
const shouldDo = common.shouldDo;
const scoreTask = common.ops.scoreTask;
// const maxPMs = 200;
@ -175,13 +176,15 @@ export function cron (options = {}) {
cron: true,
});
// Apply damage from a boss, less damage for Trivial priority (difficulty)
user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1);
// NB: Medium and Hard priorities do not increase damage from boss. This was by accident
// initially, and when we realised, we could not fix it because users are used to
// their Medium and Hard Dailies doing an Easy amount of damage from boss.
// Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future
// setting between Trivial and Easy.
if (!CRON_SEMI_SAFE_MODE) {
// Apply damage from a boss, less damage for Trivial priority (difficulty)
user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1);
// NB: Medium and Hard priorities do not increase damage from boss. This was by accident
// initially, and when we realised, we could not fix it because users are used to
// their Medium and Hard Dailies doing an Easy amount of damage from boss.
// Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future
// setting between Trivial and Easy.
}
}
}
}

View file

@ -517,7 +517,8 @@ schema.statics.bossQuest = async function bossQuest (user, progress) {
group.quest.progress.hp -= progress.up;
// TODO Create a party preferred language option so emits like this can be localized. Suggestion: Always display the English version too. Or, if English is not displayed to the players, at least include it in a new field in the chat object that's visible in the database - essential for admins when troubleshooting quests!
let playerAttack = `${user.profile.name} attacks ${quest.boss.name('en')} for ${progress.up.toFixed(1)} damage.`;
let bossAttack = nconf.get('CRON_SAFE_MODE') === 'true' ? `${quest.boss.name('en')} did not attack the party because it was asleep while maintenance was happening.` : `${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.`;
let bossAttack = nconf.get('CRON_SAFE_MODE') === 'true' || nconf.get('CRON_SEMI_SAFE_MODE') === 'true' ? `${quest.boss.name('en')} does not attack, because it respects the fact that there are some bugs\` \`post-maintenance and it doesn't want to hurt anyone unfairly. It will continue its rampage soon!` : `${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.`;
// TODO Consider putting the safe mode boss attack message in an ENV var
group.sendChat(`\`${playerAttack}\` \`${bossAttack}\``);
// If boss has Rage, increment Rage as well

View file

@ -1,58 +0,0 @@
var nconf = require('nconf');
var express = require('express');
var router = express.Router();
var _ = require('lodash');
var locals = require('../middlewares/api-v2/locals');
var i18n = require('../libs/api-v2/i18n');
var md = require('markdown-it')({
html: true,
});
const TOTAL_USER_COUNT = '1,100,000';
// -------- App --------
router.get('/', i18n.getUserLanguage, locals, function(req, res) {
if (!req.headers['x-api-user'] && !req.headers['x-api-key'] && !(req.session && req.session.userId))
return res.redirect('/static/front');
return res.render('index', {
title: 'Habitica | Your Life The Role Playing Game',
env: res.locals.habitrpg
});
});
// -------- Static Pages --------
var pages = ['front', 'privacy', 'terms', 'api', 'features', 'videos', 'contact', 'plans', 'new-stuff', 'community-guidelines', 'old-news', 'press-kit', 'faq', 'overview', 'apps', 'clear-browser-data', 'merch', 'maintenance-info'];
_.each(pages, function(name){
router.get('/static/' + name, i18n.getUserLanguage, locals, function(req, res) {
res.render( 'static/' + name, {
env: res.locals.habitrpg,
md: md,
userCount: TOTAL_USER_COUNT
});
});
});
// -------- Social Media Sharing --------
var shareables = ['level-up','hatch-pet','raise-pet','unlock-quest','won-challenge','achievement'];
_.each(shareables, function(name){
router.get('/social/' + name, i18n.getUserLanguage, locals, function(req, res) {
res.render( 'social/' + name, {
env: res.locals.habitrpg,
md: md,
userCount: TOTAL_USER_COUNT
});
});
});
// --------- Redirects --------
router.get('/static/extensions', function(req, res) {
res.redirect('http://habitica.wikia.com/wiki/App_and_Extension_Integrations');
});
module.exports = router;

View file

@ -88,7 +88,7 @@ script(type='text/ng-template', id='partials/options.social.hall.heroes.html')
span(ng-class='userAdminGlyphiconStyle(hero)')
span(ng-if='!hero.contributor.admin')
a.label.label-default(ng-class='userLevelStyle(hero)', ng-click='clickMember(hero._id, true)') {{hero.profile.name}}
td(ng-if='user.contributor.admin', ng-click='populateContributorInput(hero._id)').btn-link {{hero._id}}
td(ng-if='user.contributor.admin', ng-click='populateContributorInput(hero._id, $index)').btn-link {{hero._id}}
td {{hero.contributor.level}}
td {{hero.contributor.text}}
td

View file

@ -98,8 +98,7 @@ footer.footer(ng-controller='FooterCtrl')
a.btn.btn-default(ng-click='addLevelsAndGold()') +Exp +GP +MP
a.btn.btn-default(ng-click='addOneLevel()') +1 Level
a.btn.btn-default(ng-click='addQuestProgress()' tooltip="+1000 to boss quests. 300 items to collection quests") Quest Progress Up
// TODO Re-enable after v3 prod testing
// a.btn.btn-default(ng-click='makeAdmin()') Make Admin
a.btn.btn-default(ng-click='makeAdmin()') Make Admin
a.btn.btn-default(ng-click='openModifyInventoryModal()') Modify Inventory
div(ng-init='deferredScripts()')