mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 06:07:21 +01:00
Add Bulk Feed via query parameter (#12384)
* Update feed.js New Tests for bulk feeding * Update POST-user_feed_pet_food.test.js Added test for bulk-feeding * Update user.js Added 'query paramter' for bulk feeding * Update pets.json Added "tooMuchFood" for bulk feeding pets * Update feed.js Added query parameter option for bulk feeding pets. * Update feed.js fixing lint (bulk feeding) * Update POST-user_feed_pet_food.test.js adjustments for testing bulk feeding * Update feed.js Bulk feeding amount as integer * Update pets.json added invalidAmount for bulk feeding * Update feed.js Bulk feeding Error handling * Update feed.js Bulk - feed no hardcoded values * Update pets.json Get rid of my german accent.
This commit is contained in:
@@ -41,6 +41,29 @@ describe('POST /user/feed/:pet/:food', () => {
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(7);
|
||||
});
|
||||
|
||||
it('bulk feeding pet with non-preferred food', async () => {
|
||||
await user.update({
|
||||
'items.pets.Wolf-Base': 5,
|
||||
'items.food.Milk': 3,
|
||||
});
|
||||
|
||||
const food = content.food.Milk;
|
||||
const pet = content.petInfo['Wolf-Base'];
|
||||
|
||||
const res = await user.post('/user/feed/Wolf-Base/Milk?amount=2');
|
||||
await user.sync();
|
||||
expect(res).to.eql({
|
||||
data: user.items.pets['Wolf-Base'],
|
||||
message: t('messageDontEnjoyFood', {
|
||||
egg: pet.text(),
|
||||
foodText: food.textThe(),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(user.items.food.Milk).to.eql(1);
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(9);
|
||||
});
|
||||
|
||||
context('sending user activity webhooks', () => {
|
||||
before(async () => {
|
||||
await server.start();
|
||||
@@ -77,5 +100,33 @@ describe('POST /user/feed/:pet/:food', () => {
|
||||
expect(body.pet).to.eql('Wolf-Base');
|
||||
expect(body.message).to.eql(res.message);
|
||||
});
|
||||
|
||||
it('sends user activity webhook (mount raised after full bulk feeding)', async () => {
|
||||
const uuid = generateUUID();
|
||||
|
||||
await user.post('/user/webhook', {
|
||||
url: `http://localhost:${server.port}/webhooks/${uuid}`,
|
||||
type: 'userActivity',
|
||||
enabled: true,
|
||||
options: {
|
||||
mountRaised: true,
|
||||
},
|
||||
});
|
||||
|
||||
await user.update({
|
||||
'items.pets.Wolf-Base': 47,
|
||||
'items.food.Milk': 3,
|
||||
});
|
||||
const res = await user.post('/user/feed/Wolf-Base/Milk?amount=2');
|
||||
|
||||
await sleep();
|
||||
|
||||
const body = server.getWebhookData(uuid);
|
||||
|
||||
expect(user.achievements.allYourBase).to.not.equal(true);
|
||||
expect(body.type).to.eql('mountRaised');
|
||||
expect(body.pet).to.eql('Wolf-Base');
|
||||
expect(body.message).to.eql(res.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,6 +113,30 @@ describe('shared.ops.feed', () => {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('does not allow bulk-feeding query amount above food owned', done => {
|
||||
user.items.pets['Wolf-Base'] = 5;
|
||||
user.items.food.Meat = 6;
|
||||
try {
|
||||
feed(user, { params: { pet: 'Wolf-Base', food: 'Meat' }, query: { amount: 8 } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('notEnoughFood'));
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('does not allow bulk-over-feeding pet', done => {
|
||||
user.items.pets['Wolf-Base'] = 45;
|
||||
user.items.food.Meat = 3;
|
||||
try {
|
||||
feed(user, { params: { pet: 'Wolf-Base', food: 'Meat' }, query: { amount: 2 } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('tooMuchFood'));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
context('successful feeding', () => {
|
||||
@@ -188,6 +212,61 @@ describe('shared.ops.feed', () => {
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(7);
|
||||
});
|
||||
|
||||
it('evolves the pet into a mount when feeding user.items.pets[pet] >= 50 preferred food (bulk)', () => {
|
||||
user.items.pets['Wolf-Base'] = 5;
|
||||
user.items.food.Meat = 10;
|
||||
user.items.currentPet = 'Wolf-Base';
|
||||
|
||||
const pet = content.petInfo['Wolf-Base'];
|
||||
|
||||
const [data, message] = feed(user, { params: { pet: 'Wolf-Base', food: 'Meat' }, query: { amount: 9 } });
|
||||
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
||||
expect(message).to.eql(i18n.t('messageEvolve', {
|
||||
egg: pet.text(),
|
||||
}));
|
||||
|
||||
expect(user.items.food.Meat).to.equal(1);
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(-1);
|
||||
expect(user.items.mounts['Wolf-Base']).to.equal(true);
|
||||
expect(user.items.currentPet).to.equal('');
|
||||
});
|
||||
|
||||
it('evolves the pet into a mount when feeding user.items.pets[pet] >= 50 wrong food (bulk)', () => {
|
||||
user.items.pets['Wolf-Base'] = 5;
|
||||
user.items.food.Milk = 25;
|
||||
user.items.currentPet = 'Wolf-Base';
|
||||
|
||||
const pet = content.petInfo['Wolf-Base'];
|
||||
|
||||
const [data, message] = feed(user, { params: { pet: 'Wolf-Base', food: 'Milk' }, query: { amount: 23 } });
|
||||
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
||||
expect(message).to.eql(i18n.t('messageEvolve', {
|
||||
egg: pet.text(),
|
||||
}));
|
||||
expect(user.items.food.Milk).to.equal(2);
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(-1);
|
||||
expect(user.items.mounts['Wolf-Base']).to.equal(true);
|
||||
expect(user.items.currentPet).to.equal('');
|
||||
});
|
||||
|
||||
it('does not like the food (bulk low food) ', () => {
|
||||
user.items.pets['Wolf-Base'] = 5;
|
||||
user.items.food.Milk = 5;
|
||||
|
||||
const food = content.food.Milk;
|
||||
const pet = content.petInfo['Wolf-Base'];
|
||||
|
||||
const [data, message] = feed(user, { params: { pet: 'Wolf-Base', food: 'Milk' }, query: { amount: 5 } });
|
||||
expect(data).to.eql(user.items.pets['Wolf-Base']);
|
||||
expect(message).to.eql(i18n.t('messageDontEnjoyFood', {
|
||||
egg: pet.text(),
|
||||
foodText: food.textThe(),
|
||||
}));
|
||||
|
||||
expect(user.items.food.Milk).to.equal(0);
|
||||
expect(user.items.pets['Wolf-Base']).to.equal(15);
|
||||
});
|
||||
|
||||
it('awards All Your Base achievement', () => {
|
||||
user.items.pets['Wolf-Spooky'] = 5;
|
||||
user.items.food.Milk = 2;
|
||||
|
||||
@@ -141,5 +141,8 @@
|
||||
"clickOnPotionToHatch": "Click on a hatching potion to use it on your <%= eggName %> and hatch a new pet!",
|
||||
"notEnoughPets": "You have not collected enough pets",
|
||||
"notEnoughMounts": "You have not collected enough mounts",
|
||||
"notEnoughPetsMounts": "You have not collected enough pets and mounts"
|
||||
"notEnoughPetsMounts": "You have not collected enough pets and mounts",
|
||||
"notEnoughFood": "You don't have enough food",
|
||||
"tooMuchFood": "You're trying to feed too much food to your pet, action cancelled",
|
||||
"invalidAmount": "Invalid amount of food, must be a positive integer"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ function evolve (user, pet, req) {
|
||||
export default function feed (user, req = {}, analytics) {
|
||||
let pet = get(req, 'params.pet');
|
||||
const foodK = get(req, 'params.food');
|
||||
let amount = Number(get(req.query, 'amount', 1));
|
||||
let foodFactor;
|
||||
|
||||
if (!pet || !foodK) throw new BadRequest(errorMessage('missingPetFoodFeed'));
|
||||
|
||||
@@ -68,9 +70,28 @@ export default function feed (user, req = {}, analytics) {
|
||||
throw new NotAuthorized(i18n.t('messageAlreadyMount', req.language));
|
||||
}
|
||||
|
||||
if (!Number.isInteger(amount) || amount < 0) {
|
||||
throw new BadRequest(i18n.t('invalidAmount', req.language));
|
||||
}
|
||||
|
||||
if (amount > user.items.food[food.key]) {
|
||||
throw new NotAuthorized(i18n.t('notEnoughFood', req.language));
|
||||
}
|
||||
|
||||
if (food.target === pet.potion || pet.type === 'premium') {
|
||||
foodFactor = 5;
|
||||
} else {
|
||||
foodFactor = 2;
|
||||
}
|
||||
|
||||
if ((user.items.pets[pet.key] + (amount * foodFactor)) >= (50 + foodFactor)) {
|
||||
throw new NotAuthorized(i18n.t('tooMuchFood', req.language));
|
||||
}
|
||||
|
||||
let message;
|
||||
|
||||
if (food.key === 'Saddle') {
|
||||
amount = 1;
|
||||
message = evolve(user, pet, req);
|
||||
} else {
|
||||
const messageParams = {
|
||||
@@ -79,10 +100,10 @@ export default function feed (user, req = {}, analytics) {
|
||||
};
|
||||
|
||||
if (food.target === pet.potion || pet.type === 'premium') {
|
||||
user.items.pets[pet.key] += 5;
|
||||
user.items.pets[pet.key] += foodFactor * amount;
|
||||
message = i18n.t('messageLikesFood', messageParams, req.language);
|
||||
} else {
|
||||
user.items.pets[pet.key] += 2;
|
||||
user.items.pets[pet.key] += foodFactor * amount;
|
||||
message = i18n.t('messageDontEnjoyFood', messageParams, req.language);
|
||||
}
|
||||
|
||||
@@ -98,7 +119,7 @@ export default function feed (user, req = {}, analytics) {
|
||||
}
|
||||
}
|
||||
|
||||
user.items.food[food.key] -= 1;
|
||||
user.items.food[food.key] -= 1 * amount;
|
||||
if (user.markModified) user.markModified('items.food');
|
||||
|
||||
forEach(content.animalColorAchievements, achievement => {
|
||||
|
||||
@@ -862,9 +862,14 @@ api.equip = {
|
||||
*
|
||||
* @apiParam (Path) {String} pet
|
||||
* @apiParam (Path) {String} food
|
||||
* @apiParam (Query) {Number} [amount] The amount of food to feed.
|
||||
* Note: Pet can eat 50 units.
|
||||
* Preferred food offers 5 units per food,
|
||||
* other food 2 units.
|
||||
*
|
||||
* @apiParamExample {url} Example-URL
|
||||
* https://habitica.com/api/v3/user/feed/Armadillo-Shade/Chocolate
|
||||
* https://habitica.com/api/v3/user/feed/Armadillo-Shade/Chocolate?amount=9
|
||||
*
|
||||
* @apiSuccess {Number} data The pet value
|
||||
* @apiSuccess {String} message Success message
|
||||
@@ -877,6 +882,8 @@ api.equip = {
|
||||
* @apiError {BadRequest} InvalidPet Invalid pet name supplied.
|
||||
* @apiError {NotFound} FoodNotOwned :food not found in user.items.food
|
||||
* Note: also sent if food name is invalid.
|
||||
* @apiError {NotAuthorized} notEnoughFood :Not enough food to feed the pet as requested.
|
||||
* @apiError {NotAuthorized} tooMuchFood :You try to feed too much food. Action ancelled.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user