mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Merged in develop
This commit is contained in:
@@ -228,6 +228,12 @@ api.createChallenge = {
|
||||
let challengeValidationErrors = challenge.validateSync();
|
||||
if (challengeValidationErrors) throw challengeValidationErrors;
|
||||
|
||||
// Add achievement if user's first challenge
|
||||
if (!user.achievements.joinedChallenge) {
|
||||
user.achievements.joinedChallenge = true;
|
||||
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
|
||||
}
|
||||
|
||||
let results = await Bluebird.all([challenge.save({
|
||||
validateBeforeSave: false, // already validate
|
||||
}), group.save()]);
|
||||
@@ -286,6 +292,12 @@ api.joinChallenge = {
|
||||
|
||||
challenge.memberCount += 1;
|
||||
|
||||
// Add achievement if user's first challenge
|
||||
if (!user.achievements.joinedChallenge) {
|
||||
user.achievements.joinedChallenge = true;
|
||||
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
|
||||
}
|
||||
|
||||
// Add all challenge's tasks to user's tasks and save the challenge
|
||||
let results = await Bluebird.all([challenge.syncToUser(user), challenge.save()]);
|
||||
|
||||
|
||||
@@ -117,8 +117,6 @@ function textContainsBannedWords (message) {
|
||||
* @apiParam (Body) {String} message Message The message to post
|
||||
* @apiParam (Query) {UUID} previousMsg The previous chat message's UUID which will force a return of the full group chat
|
||||
*
|
||||
* @apiSuccess data An array of <a href='https://github.com/HabitRPG/habitica/blob/develop/website/server/models/group.js#L51' target='_blank'>chat messages</a> if a new message was posted after previousMsg, otherwise the posted message
|
||||
*
|
||||
* @apiUse GroupNotFound
|
||||
* @apiUse GroupIdRequired
|
||||
* @apiError (400) {NotFound} ChatPriviledgesRevoked Your chat privileges have been revoked
|
||||
@@ -143,7 +141,7 @@ api.postChat = {
|
||||
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.privacy !== 'private' && user.flags.chatRevoked) {
|
||||
throw new NotFound('Your chat privileges have been revoked.');
|
||||
throw new NotAuthorized(res.t('chatPrivilegesRevoked'));
|
||||
}
|
||||
|
||||
if (group._id === TAVERN_ID && textContainsBannedWords(req.body.message)) {
|
||||
|
||||
@@ -396,7 +396,7 @@ api.getGroup = {
|
||||
* @apiUse groupIdRequired
|
||||
* @apiUse GroupNotFound
|
||||
*
|
||||
* @apiPermission GroupLeader
|
||||
* @apiPermission GroupLeader, Admin
|
||||
*/
|
||||
api.updateGroup = {
|
||||
method: 'PUT',
|
||||
@@ -409,11 +409,13 @@ api.updateGroup = {
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
let optionalMembership = Boolean(user.contributor.admin);
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId, optionalMembership});
|
||||
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
|
||||
if (group.leader !== user._id && group.type === 'party') throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
|
||||
else if (group.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
|
||||
|
||||
if (req.body.leader !== user._id && group.hasNotCancelled()) throw new NotAuthorized(res.t('cannotChangeLeaderWithActiveGroupPlan'));
|
||||
|
||||
@@ -472,7 +474,7 @@ api.joinGroup = {
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
// Works even if the user is not yet a member of the group
|
||||
// Works even if the user is not yet a member of the group
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId, optionalMembership: true}); // Do not fetch chat and work even if the user is not yet a member of the group
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
@@ -760,7 +762,7 @@ function _sendMessageToRemoved (group, removedUser, message, isInGroup) {
|
||||
*
|
||||
* @apiSuccess {Object} data An empty object
|
||||
*
|
||||
* @apiPermission GroupLeader
|
||||
* @apiPermission GroupLeader, Admin
|
||||
*
|
||||
* @apiUse groupIdRequired
|
||||
* @apiUse GroupNotFound
|
||||
@@ -777,13 +779,18 @@ api.removeGroupMember = {
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
let optionalMembership = Boolean(user.contributor.admin);
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId, optionalMembership, fields: '-chat'}); // Do not fetch chat
|
||||
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId, fields: '-chat'}); // Do not fetch chat
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
let uuid = req.params.memberId;
|
||||
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyLeaderCanRemoveMember'));
|
||||
if (group.leader !== user._id && group.type === 'party') throw new NotAuthorized(res.t('onlyLeaderCanRemoveMember'));
|
||||
if (group.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderCanRemoveMember'));
|
||||
|
||||
if (group.leader === uuid && user.contributor.admin) throw new NotAuthorized(res.t('cannotRemoveCurrentLeader'));
|
||||
|
||||
if (user._id === uuid) throw new NotAuthorized(res.t('memberCannotRemoveYourself'));
|
||||
|
||||
let member = await User.findOne({_id: uuid}).exec();
|
||||
@@ -946,12 +953,12 @@ async function _inviteByEmail (invite, group, inviter, req, res) {
|
||||
if (!invite.email) throw new BadRequest(res.t('inviteMissingEmail'));
|
||||
|
||||
let userToContact = await User.findOne({$or: [
|
||||
{'auth.local.email': invite.email},
|
||||
{'auth.facebook.emails.value': invite.email},
|
||||
{'auth.google.emails.value': invite.email},
|
||||
{'auth.local.email': invite.email},
|
||||
{'auth.facebook.emails.value': invite.email},
|
||||
{'auth.google.emails.value': invite.email},
|
||||
]})
|
||||
.select({_id: true, 'preferences.emailNotifications': true})
|
||||
.exec();
|
||||
.select({_id: true, 'preferences.emailNotifications': true})
|
||||
.exec();
|
||||
|
||||
if (userToContact) {
|
||||
userReturnInfo = await _inviteByUUID(userToContact._id, group, inviter, req, res);
|
||||
|
||||
@@ -6,22 +6,56 @@ import {
|
||||
} from '../../libs/errors';
|
||||
import _ from 'lodash';
|
||||
|
||||
/**
|
||||
* @apiDefine Admin Moderators
|
||||
* Contributors of tier 8 or higher can use this route.
|
||||
*/
|
||||
|
||||
let api = {};
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/hall/patrons Get all patrons
|
||||
* @apiDescription Only the first 50 patrons are returned. More can be accessed passing ?page=n
|
||||
* @apiDescription Returns an array of objects containing the patrons who backed Habitica's
|
||||
* original kickstarter. The array is sorted by the backer tier in descending order.
|
||||
* By default, only the first 50 patrons are returned. More can be accessed by passing ?page=n
|
||||
* @apiName GetPatrons
|
||||
* @apiGroup Hall
|
||||
*
|
||||
* @apiParam {Number} page Query Parameter - The result page. Default is 0
|
||||
*
|
||||
* @apiParam (Query) {Number} [page=0] The result page.
|
||||
* @apiSuccess {Array} data An array of patrons
|
||||
*
|
||||
* @apiSuccessExample {json} Example response
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": [
|
||||
* {
|
||||
* "_id": "3adb52a9-0dfb-4752-81f2-a62d911d1bf5",
|
||||
* "profile": {
|
||||
* "name": "mattboch"
|
||||
* },
|
||||
* "contributor": {},
|
||||
* "backer": {
|
||||
* "tier": 800,
|
||||
* "npc": "Beast Master"
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* "_id": "9da65443-ed43-4c21-804f-d260c1361596",
|
||||
* "profile": {
|
||||
* "name": "ʎǝlᴉɐq s,┴I"
|
||||
* },
|
||||
* "contributor": {
|
||||
* "text": "Pollen Purveyor",
|
||||
* "admin": true,
|
||||
* "level": 8
|
||||
* },
|
||||
* "backer": {
|
||||
* "npc": "Town Crier",
|
||||
* "tier": 800,
|
||||
* "tokensApplied": true
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
*
|
||||
* @apiUse NoAuthHeaders
|
||||
* @apiUse NoAccount
|
||||
*/
|
||||
api.getPatrons = {
|
||||
method: 'GET',
|
||||
@@ -56,7 +90,32 @@ api.getPatrons = {
|
||||
* @apiName GetHeroes
|
||||
* @apiGroup Hall
|
||||
*
|
||||
* @apiSuccess {Array} data An array of heroes
|
||||
* @apiDescription Returns an array of objects containing the heroes who have
|
||||
* contributed for Habitica. The array is sorted by the contribution level in descending order.
|
||||
*
|
||||
* @apiSuccess {Array} heroes An array of heroes
|
||||
*
|
||||
* @apiSuccessExample {json} Example response:
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": [
|
||||
* {
|
||||
* "_id": "e6e01d2a-c2fa-4b9f-9c0f-7865b777e7b5",
|
||||
* "profile": {
|
||||
* "name": "test2"
|
||||
* },
|
||||
* "contributor": {
|
||||
* "admin": false,
|
||||
* "level": 2,
|
||||
* "text": "Linguist"
|
||||
* },
|
||||
* "backer": {}
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* @apiUse NoAuthHeaders
|
||||
* @apiUse NoAccount
|
||||
*/
|
||||
api.getHeroes = {
|
||||
method: 'GET',
|
||||
@@ -83,14 +142,19 @@ const heroAdminFields = 'contributor balance profile.name purchased items auth f
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/hall/heroes/:heroId Get any user ("hero") given the UUID
|
||||
* @apiParam {UUID} heroId user ID
|
||||
* @apiName GetHero
|
||||
* @apiGroup Hall
|
||||
* @apiPermission Admin
|
||||
*
|
||||
* @apiDescription Returns the profile of the given user
|
||||
*
|
||||
* @apiSuccess {Object} data The user object
|
||||
*
|
||||
* @apiPermission Admin
|
||||
*
|
||||
* @apiUse UserNotFound
|
||||
* @apiUse NoAuthHeaders
|
||||
* @apiUse NoAccount
|
||||
* @apiUse NoUser
|
||||
* @apiUse NotAdmin
|
||||
*/
|
||||
api.getHero = {
|
||||
method: 'GET',
|
||||
@@ -123,15 +187,35 @@ const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
|
||||
|
||||
/**
|
||||
* @api {put} /api/v3/hall/heroes/:heroId Update any user ("hero")
|
||||
* @apiDescription Must be an admin to make this request.
|
||||
* @apiParam {UUID} heroId user ID
|
||||
* @apiName UpdateHero
|
||||
* @apiGroup Hall
|
||||
* @apiPermission Admin
|
||||
*
|
||||
* @apiDescription Update user's gem balance, contributions & contribution tier and admin status. Grant items, block / unblock user's account and revoke / unrevoke chat privileges.
|
||||
*
|
||||
* @apiExample Example Body:
|
||||
* {
|
||||
* "balance": 1000,
|
||||
* "auth": {"blocked": false},
|
||||
* "flags": {"chatRevoked": true},
|
||||
* "purchased": {"ads": true},
|
||||
* "contributor": {
|
||||
* "admin": true,
|
||||
* "contributions": "Improving API documentation",
|
||||
* "level": 5,
|
||||
* "text": "Scribe, Blacksmith"
|
||||
* },
|
||||
* "itemPath": "items.pets.BearCub-Skeleton",
|
||||
* "itemVal": 1
|
||||
* }
|
||||
*
|
||||
* @apiSuccess {Object} data The updated user object
|
||||
*
|
||||
* @apiPermission Admin
|
||||
*
|
||||
* @apiUse UserNotFound
|
||||
* @apiUse NoAuthHeaders
|
||||
* @apiUse NoAccount
|
||||
* @apiUse NoUser
|
||||
* @apiUse NotAdmin
|
||||
*/
|
||||
api.updateHero = {
|
||||
method: 'PUT',
|
||||
|
||||
@@ -4,6 +4,9 @@ import {
|
||||
publicFields as memberFields,
|
||||
nameFields,
|
||||
} from '../../models/user';
|
||||
import {
|
||||
KNOWN_INTERACTIONS,
|
||||
} from '../../models/user/methods';
|
||||
import { model as Group } from '../../models/group';
|
||||
import { model as Challenge } from '../../models/challenge';
|
||||
import {
|
||||
@@ -385,6 +388,39 @@ api.getChallengeMemberProgress = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/members/:toUserId/objections/:interaction Get any objections that would occur if the given interaction was attempted - BETA
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName GetObjectionsToInteraction
|
||||
* @apiGroup Member
|
||||
*
|
||||
* @apiParam {UUID} toUserId The user to interact with
|
||||
* @apiParam {String="send-private-message","transfer-gems"} interaction Name of the interaction to query
|
||||
*
|
||||
* @apiSuccess {Array} data Return an array of objections, if the interaction would be blocked; otherwise an empty array
|
||||
*/
|
||||
api.getObjectionsToInteraction = {
|
||||
method: 'GET',
|
||||
url: '/members/:toUserId/objections/:interaction',
|
||||
middlewares: [authWithHeaders()],
|
||||
async handler (req, res) {
|
||||
req.checkParams('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID();
|
||||
req.checkParams('interaction', res.t('interactionRequired')).notEmpty().isIn(KNOWN_INTERACTIONS);
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
let sender = res.locals.user;
|
||||
let receiver = await User.findById(req.params.toUserId).exec();
|
||||
if (!receiver) throw new NotFound(res.t('userWithIDNotFound', {userId: req.params.toUserId}));
|
||||
|
||||
let interaction = req.params.interaction;
|
||||
let response = sender.getObjectionsToInteraction(interaction, receiver);
|
||||
|
||||
res.respond(200, response.map(res.t));
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {posts} /api/v3/members/send-private-message Send a private message to a member
|
||||
* @apiName SendPrivateMessage
|
||||
@@ -410,17 +446,11 @@ api.sendPrivateMessage = {
|
||||
|
||||
let sender = res.locals.user;
|
||||
let message = req.body.message;
|
||||
|
||||
let receiver = await User.findById(req.body.toUserId).exec();
|
||||
if (!receiver) throw new NotFound(res.t('userNotFound'));
|
||||
|
||||
let userBlockedSender = receiver.inbox.blocks.indexOf(sender._id) !== -1;
|
||||
let userIsBlockBySender = sender.inbox.blocks.indexOf(receiver._id) !== -1;
|
||||
let userOptedOutOfMessaging = receiver.inbox.optOut;
|
||||
|
||||
if (userBlockedSender || userIsBlockBySender || userOptedOutOfMessaging) {
|
||||
throw new NotAuthorized(res.t('notAuthorizedToSendMessageToThisUser'));
|
||||
}
|
||||
let objections = sender.getObjectionsToInteraction('send-private-message', receiver);
|
||||
if (objections.length > 0) throw new NotAuthorized(res.t(objections[0]));
|
||||
|
||||
await sender.sendMessage(receiver, { receiverMsg: message });
|
||||
|
||||
@@ -472,13 +502,11 @@ api.transferGems = {
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
let sender = res.locals.user;
|
||||
|
||||
let receiver = await User.findById(req.body.toUserId).exec();
|
||||
if (!receiver) throw new NotFound(res.t('userNotFound'));
|
||||
|
||||
if (receiver._id === sender._id) {
|
||||
throw new NotAuthorized(res.t('cannotSendGemsToYourself'));
|
||||
}
|
||||
let objections = sender.getObjectionsToInteraction('transfer-gems', receiver);
|
||||
if (objections.length > 0) throw new NotAuthorized(res.t(objections[0]));
|
||||
|
||||
let gemAmount = req.body.gemAmount;
|
||||
let amount = gemAmount / 4;
|
||||
|
||||
@@ -39,7 +39,7 @@ function canStartQuestAutomatically (group) {
|
||||
let api = {};
|
||||
|
||||
/**
|
||||
* @api {post} /api/v3/groups/:groupId/quests/invite Invite users to a quest
|
||||
* @api {post} /api/v3/groups/:groupId/quests/invite/:questKey Invite users to a quest
|
||||
* @apiName InviteToQuest
|
||||
* @apiGroup Quest
|
||||
*
|
||||
|
||||
@@ -107,8 +107,8 @@ api.getSeasonalShopItems = {
|
||||
let resObject = {
|
||||
identifier: 'seasonalShop',
|
||||
text: res.t('seasonalShop'),
|
||||
notes: res.t('seasonalShopClosedText'),
|
||||
imageName: 'seasonalshop_closed',
|
||||
notes: res.t('seasonalShopSummerText'),
|
||||
imageName: 'seasonalshop_open',
|
||||
categories: shops.getSeasonalShopCategories(user, req.language),
|
||||
};
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ api.deleteUser = {
|
||||
await user.remove();
|
||||
|
||||
if (feedback) {
|
||||
txnEmail(TECH_ASSISTANCE_EMAIL, 'admin-feedback', [
|
||||
txnEmail({email: TECH_ASSISTANCE_EMAIL}, 'admin-feedback', [
|
||||
{name: 'PROFILE_NAME', content: user.profile.name},
|
||||
{name: 'UUID', content: user._id},
|
||||
{name: 'EMAIL', content: getUserInfo(user, ['email']).email},
|
||||
@@ -1037,8 +1037,8 @@ api.buySpecialSpell = {
|
||||
*
|
||||
* @apiParam {String} egg The egg to use
|
||||
* @apiParam {String} hatchingPotion The hatching potion to use
|
||||
* @apiParamExample {URL}
|
||||
* /api/v3/user/hatch/Dragon/CottonCandyPink
|
||||
* @apiParamExample {URL} Example-URL
|
||||
* https://habitica.com/api/v3/user/hatch/Dragon/CottonCandyPink
|
||||
*
|
||||
* @apiSuccess {Object} data user.items
|
||||
* @apiSuccess {String} message
|
||||
@@ -1081,8 +1081,8 @@ api.hatch = {
|
||||
* @apiParam {String="mount","pet","costume","equipped"} type The type of item to equip
|
||||
* @apiParam {String} key The item to equip
|
||||
*
|
||||
* @apiParamExample {URL}
|
||||
* /api/v3/user/equip/equipped/weapon_warrior_2
|
||||
* @apiParamExample {URL} Example-URL
|
||||
* https://habitica.com/api/v3/user/equip/equipped/weapon_warrior_2
|
||||
*
|
||||
* @apiSuccess {Object} data user.items
|
||||
* @apiSuccess {String} message Optional success message for unequipping an items
|
||||
@@ -1122,7 +1122,7 @@ api.equip = {
|
||||
* @apiParam {String} pet
|
||||
* @apiParam {String} food
|
||||
*
|
||||
* @apiParamExample {url}
|
||||
* @apiParamExample {url} Example-URL
|
||||
* https://habitica.com/api/v3/user/feed/Armadillo-Shade/Chocolate
|
||||
*
|
||||
* @apiSuccess {Number} data The pet value
|
||||
@@ -1206,12 +1206,20 @@ api.disableClasses = {
|
||||
* @apiName UserPurchase
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam {String} type Type of item to purchase. Must be one of: gems, eggs, hatchingPotions, food, quests, or gear
|
||||
* @apiParam {String="gems","eggs","hatchingPotions","premiumHatchingPotions",food","quests","gear"} type Type of item to purchase.
|
||||
* @apiParam {String} key Item's key (use "gem" for purchasing gems)
|
||||
*
|
||||
* @apiSuccess {Object} data.items user.items
|
||||
* @apiSuccess {Number} data.balance user.balance
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiError {NotAuthorized} NotAvailable Item is not available to be purchased (not unlocked for the user).
|
||||
* @apiError {NotAuthorized} Gems Not enough gems
|
||||
* @apiError {NotFound} Key Key not found for Content type.
|
||||
* @apiError {NotFound} Type Type invalid.
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"This item is not currently available for purchase."}
|
||||
*/
|
||||
api.purchase = {
|
||||
method: 'POST',
|
||||
@@ -1230,12 +1238,19 @@ api.purchase = {
|
||||
* @apiName UserPurchaseHourglass
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam {String} type The type of item to purchase (pets or mounts)
|
||||
* @apiParam {String} key Ex: {MantisShrimp-Base}. The key for the mount/pet
|
||||
* @apiParam {String="pets","mounts"} type The type of item to purchase
|
||||
* @apiParam {String} key Ex: {Phoenix-Base}. The key for the mount/pet
|
||||
*
|
||||
* @apiSuccess {Object} data.items user.items
|
||||
* @apiSuccess {Object} data.purchasedPlanConsecutive user.purchased.plan.consecutive
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiError {NotAuthorized} NotAvailable Item is not available to be purchased or is not valid.
|
||||
* @apiError {NotAuthorized} Hourglasses User does not have enough Mystic Hourglasses.
|
||||
* @apiError {NotFound} Type Type invalid.
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"You don't have enough Mystic Hourglasses."}
|
||||
*/
|
||||
api.userPurchaseHourglass = {
|
||||
method: 'POST',
|
||||
@@ -1254,11 +1269,40 @@ api.userPurchaseHourglass = {
|
||||
* @apiName UserReadCard
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam {String} cardType Type of card to read
|
||||
* @apiParam {String} cardType Type of card to read (e.g. - birthday, greeting, nye, thankyou, valentine)
|
||||
*
|
||||
* @apiSuccess {Object} data.specialItems user.items.special
|
||||
* @apiSuccess {Boolean} data.cardReceived user.flags.cardReceived
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {
|
||||
* "specialItems": {
|
||||
* "snowball": 0,
|
||||
* "spookySparkles": 0,
|
||||
* "shinySeed": 0,
|
||||
* "seafoam": 0,
|
||||
* "valentine": 0,
|
||||
* "valentineReceived": [],
|
||||
* "nye": 0,
|
||||
* "nyeReceived": [],
|
||||
* "greeting": 0,
|
||||
* "greetingReceived": [
|
||||
* "MadPink"
|
||||
* ],
|
||||
* "thankyou": 0,
|
||||
* "thankyouReceived": [],
|
||||
* "birthday": 0,
|
||||
* "birthdayReceived": []
|
||||
* },
|
||||
* "cardReceived": false
|
||||
* },
|
||||
* "message": "valentine has been read"
|
||||
* }
|
||||
*
|
||||
* @apiError {NotAuthorized} CardType Unknown card type.
|
||||
*/
|
||||
api.readCard = {
|
||||
method: 'POST',
|
||||
@@ -1279,6 +1323,28 @@ api.readCard = {
|
||||
*
|
||||
* @apiSuccess {Object} data The item obtained
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* { "success": true,
|
||||
* "data": {
|
||||
* "mystery": "201612",
|
||||
* "value": 0,
|
||||
* "type": "armor",
|
||||
* "key": "armor_mystery_201612",
|
||||
* "set": "mystery-201612",
|
||||
* "klass": "mystery",
|
||||
* "index": "201612",
|
||||
* "str": 0,
|
||||
* "int": 0,
|
||||
* "per": 0,
|
||||
* "con": 0
|
||||
* },
|
||||
* "message": "Mystery item opened."
|
||||
*
|
||||
* @apiError {BadRequest} Empty No mystery items to open.
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"BadRequest","message":"Mystery items are empty"}
|
||||
*/
|
||||
api.userOpenMysteryItem = {
|
||||
method: 'POST',
|
||||
@@ -1298,6 +1364,19 @@ api.userOpenMysteryItem = {
|
||||
*
|
||||
* @apiSuccess {Object} data.items `user.items.pets`
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {
|
||||
* },
|
||||
* "message": "Pets released"
|
||||
* }
|
||||
*
|
||||
* @apiError {NotAuthorized} Not enough gems
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"Not enough Gems"}
|
||||
*/
|
||||
api.userReleasePets = {
|
||||
method: 'POST',
|
||||
@@ -1315,11 +1394,38 @@ api.userReleasePets = {
|
||||
* @api {post} /api/v3/user/release-both Release pets and mounts and grants Triad Bingo
|
||||
* @apiName UserReleaseBoth
|
||||
* @apiGroup User
|
||||
|
||||
*
|
||||
* @apiSuccess {Object} data.achievements
|
||||
* @apiSuccess {Object} data.items
|
||||
* @apiSuccess {Number} data.balance
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {
|
||||
* "achievements": {
|
||||
* "ultimateGearSets": {},
|
||||
* "challenges": [],
|
||||
* "quests": {},
|
||||
* "perfect": 0,
|
||||
* "beastMaster": true,
|
||||
* "beastMasterCount": 1,
|
||||
* "mountMasterCount": 1,
|
||||
* "triadBingoCount": 1,
|
||||
* "mountMaster": true,
|
||||
* "triadBingo": true
|
||||
* },
|
||||
* "items": {}
|
||||
* },
|
||||
* "message": "Mounts and pets released"
|
||||
* }
|
||||
*
|
||||
* @apiError {NotAuthorized} Not enough gems
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"Not enough Gems"}
|
||||
|
||||
*/
|
||||
api.userReleaseBoth = {
|
||||
method: 'POST',
|
||||
@@ -1340,6 +1446,22 @@ api.userReleaseBoth = {
|
||||
*
|
||||
* @apiSuccess {Object} data user.items.mounts
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {
|
||||
* },
|
||||
* "items": {}
|
||||
* },
|
||||
* "message": "Mounts released"
|
||||
* }
|
||||
*
|
||||
* @apiError {NotAuthorized} Not enough gems
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"Not enough Gems"}
|
||||
*
|
||||
*/
|
||||
api.userReleaseMounts = {
|
||||
method: 'POST',
|
||||
@@ -1358,12 +1480,17 @@ api.userReleaseMounts = {
|
||||
* @apiName UserSell
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam {String} type The type of item to sell. Must be one of: eggs, hatchingPotions, or food
|
||||
* @apiParam {String="eggs","hatchingPotions","food"} type The type of item to sell.
|
||||
* @apiParam {String} key The key of the item
|
||||
*
|
||||
* @apiSuccess {Object} data.stats
|
||||
* @apiSuccess {Object} data.items
|
||||
* @apiSuccess {String} message Success message
|
||||
*
|
||||
* @apiError {NotFound} InvalidKey Key not found for user.items eggs (either the key does not exist or the user has none in inventory)
|
||||
* @apiError {NotAuthorized} InvalidType Type is not a valid type.
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"NotAuthorized","message":"Type is not sellable. Must be one of the following eggs, hatchingPotions, food"}
|
||||
*/
|
||||
api.userSell = {
|
||||
method: 'POST',
|
||||
@@ -1382,12 +1509,31 @@ api.userSell = {
|
||||
* @apiName UserUnlock
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiParam {String} path Query parameter. The path to unlock
|
||||
* @apiParam {String} path Query parameter. Full path to unlock. See "content" API call for list of items.
|
||||
*
|
||||
* @apiParamExample {curl}
|
||||
* curl -x POST http://habitica.com/api/v3/user/unlock?path=background.midnight_clouds
|
||||
* curl -x POST http://habitica.com/api/v3/user/unlock?path=hair.color.midnight
|
||||
*
|
||||
* @apiSuccess {Object} data.purchased
|
||||
* @apiSuccess {Object} data.items
|
||||
* @apiSuccess {Object} data.preferences
|
||||
* @apiSuccess {String} message
|
||||
* @apiSuccess {String} message "Items have been unlocked"
|
||||
*
|
||||
* @apiSuccessExample {json}
|
||||
* {
|
||||
* "success": true,
|
||||
* "data": {},
|
||||
* "message": "Items have been unlocked"
|
||||
* }
|
||||
*
|
||||
* @apiError {BadRequest} Path Path to unlock not specified
|
||||
* @apiError {NotAuthorized} Gems Not enough gems available.
|
||||
* @apiError {NotAuthorized} Unlocked Full set already unlocked.
|
||||
*
|
||||
* @apiErrorExample {json}
|
||||
* {"success":false,"error":"BadRequest","message":"Path string is required"}
|
||||
8 {"success":false,"error":"NotAuthorized","message":"Full set already unlocked."}
|
||||
*/
|
||||
api.userUnlock = {
|
||||
method: 'POST',
|
||||
@@ -1664,3 +1810,4 @@ api.setCustomDayStart = {
|
||||
};
|
||||
|
||||
module.exports = api;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user