API v3 [WIP] (#6144)

* Fixed more tests

* Added tags into user service

* Added api-v3 auth urls

* v3: fix package.json

* v3: fix package.json

* Fixed auth tests. Updated Authctrl response

* v3: remove newrelic config file in favour of env variables

* v3: upgrade some deps

* switch from Q to Bluebird

* v3 fix tests with deferred

* Removed extra consoles.log. Changed data.data to res.data

* v3 fix tests and use coroutines instead of regenerator

* v3: fix tests

* v3: do not await a non promise

* v3: q -> bluebird

* Changed id param for registration response

* Updated party query and create

* Ensured login callback happens after user sync

* Add challenges to groups. Fixed isMemberOfGuild check

* Updated party and group tests

* Fixed cron test

* return user.id and send analytics event before changing page

* fix trailing spaces

* disable redirects

* Api v3 party tavern fixes (#7191)

* Added check if user is in party before query

* Cached party query. Prevented party request when user is not in party. Updated Party create with no invites

* Update tavern ctrl to use new promise

* v3: misc fixes

* Api v3 task fixes (#7193)

* Update task view to use _id

* Added try catch to user service ops calls

* v3 client: saving after syncing is complete

* Fixed test broken by part sync change (#7195)

* v3: fix todo scoring and try to fix production testing problem

* revert changes to mongoose config

* mongoose: increase keepAlive

* test mongoose fix

* fix: Only apply captureStackTrace if it exists on the error object

* v3: fix reminders with no startDate

* mongoose: use options

* chore(): rename website/src -> website/server and website/public -> website/client (#7199)

* v3 fix GET /groups: return an error only if an invalid type is supplied not when there are 0 results (#7203)

* [API v3] Fix calls to user.ops and deleting tags (#7204)

* v3: fixes calls to user.ops from views and deleting tags

* v3: fix tests that use user._statsComputed

* Api v3 fixes continued (#7205)

* Added timzeone offset back

* Added APIToken back to settings page

* Fixed fetch recent messages for party

* Fixed returning group description

* Fixed check if user is member of challenge

* Fixed party members appearing in header

* Updated get myGroups param to include public groups. Fixed isMemberOf group

* Fixed hourglass purchase

* Fixed challenge addding tasks on first creating

* Updated tests to accomidate new changes

* fix: Correct checklist on client

Closes #7207

* fix: Pin eslint to 2.9

* minor improvements to cron code for clarity; fix inaccurate comments; add TODOs for rest-in-inn actions

* fix: Add missing type param to equip call

closes #7212

* rename and reword pubChalsMinPrize to reflect that it's only for Tavern challenges

* allows players to send gems to each other; other minor related changes - fixes https://github.com/HabitRPG/habitrpg/issues/7227

* fix tests for /members/transfer-gems

* fix: Set gems sent notification as translatable string

* chore: Remove unusued variable

* fix: Remove requirement on message paramter in transfer-gems

* add a missing variable declaration

* chore: clarify comments on cron code

* fix: Correct client request from habitrpg -> tavern

* update apidoc URL in package.json

Closes #7222

* Fixed start party by invites

* Updated spell casting to v3

* Fixed adding and removing tags on tasks

* Fixed page reload on settings change

* Fixed battle monsters with friends button

* Loaded completed todos when done is clicked

* chore: Reinstate floating version number for eslint

babel-eslint regression fixed

* Fixed reload tests

* change "an user" to "a user" in comments and text (no code changes) (#7257)

* fix: Alert user that drops were recieved

* remove userServices.js from karma.conf - it's been moved to website/client/js/services

* feat: Create debug update user route

* fix: Correct set cron debug function

* feat: Add make admin button to debug menu

* lint: Add missing semicolons in test

* fix: Temporarilly comment out udpate user debug route

* v3: fix _tmp for crit and streakBonus

* v3: execute all actions when leaving a solo party

* v3 client: fix group not found when leaving party

* v3 migration: fix challenge prize

* v3 cron: only save modified tasks

* v3: add CHALLENGE_TASK_NOT_FOUND to valid broken reasons

* v3: fix tasks chart

* v3 client: fix ability to leave challenge

* v3 client: fix filtering by tag and correctly show tag tooltip

* v3 common: fix tags tests

* v3 client: support unlinking not found challenges tasks

* v3: disable Bluebird warning for missing return, fixes #7269

* feat: Separate out update-user into set-cron and make-admin debug routes

* chore: Disable make admin debug route for v3 prod testing

* v3: misc fixes

* v3: misc fixes

* v3: fix adding multiple tasks

* Fixed join/leave button updates

* Queried only user groups to be available when creating challenges

* Fixed bulk add tasks to challenge

* Synced challenge tasks after leave and join.

* Fixed default selected group

* Fixed challenge member info. Fixed challenge winner selection

* Fixed deleting challenge tasks

* Fixed particiapting filter

* v3 client: fix casting spells

* v3: do not log sensitive data

* v3: always save user when casting spell

* v3: always save user when casting spell

* v3: more fixes for spells

* fix typos and missing information in apidocs - fixes https://github.com/HabitRPG/habitrpg/issues/7277 (#7282)

* v3: add TODO for client side spells

* feat: Add modify inventory debug menu

* Fixed viewing user progress on challenge

* Updated tests

* fix: Fix quest progress button

* fix incorrect Armoire test; remove unneeded param details from apidocs; disambiguate health potion

* v3: fix stealth casting

* v3: fix tasks saving and selection for rebirth reroll and reset (server-only)

* v3: fix auto allocation

* v3 client: misc fixes

* rename buyPotion and buy-potion to buyHealthPotion and buy-health-potion; fix apidoc param error

* Added delete for saved challenge task

* Fixed member modal on front page

* adjust text in apidocs for errors / clarity / consistency / standard terminology (no code changes) (#7298)

* fix bug in Rebirth test, add new tests, adjust apidocs (#7293)

* Updated task model to allow setting streak (#7306)

* fix: Correct missing * in apidoc comments

* Api v3 challenge fixes (#7287)

* Fixed join/leave button updates

* Queried only user groups to be available when creating challenges

* Fixed bulk add tasks to challenge

* Synced challenge tasks after leave and join.

* Fixed default selected group

* Fixed challenge member info. Fixed challenge winner selection

* Fixed deleting challenge tasks

* Fixed particiapting filter

* Fixed viewing user progress on challenge

* Updated tests

* Added delete for saved challenge task

* v3: fix sorting

* [API v3] add CRON_SAFE_MODE (#7286)

* add CRON_SAFE_MODE to example config file, fix some bugs, add an unrelated low-priority TODO

* create CRON_SAFE_MODE to disable parts of cron for use after extended outage - fixes https://github.com/HabitRPG/habitrpg/issues/7161

* fix a bug with CRON_SAFE_MODE, remove duplicated code, remove completed TODO comment

* fix check for CRON_SAFE_MODE

* v3 client: fix typo

* adjust debug menu Modify Inventory: hungrier pets, fewer Special items, "Hide" buttons

* completed To-Dos: return the 30 most recent instead of 30 oldest (#7318)

* v3 migration: fix createdAt date

* adjust locales text, key names, and files for Rebirth, Reset, and Fortify / ReRoll for consistency with existing strings (#7321)

* v3: fix unlinking multiple tasks

* v3 fix releasing pets

* v3: fix authenticating with apiUrl

* v3: fix typo

* v3 fix client tests for unlinking

* v3 client: do not show start quest button when quest is active

* v3 client: fix ability to send cards

* v3 client: fix misc challenge issues

* v3: fix notifications

* v3 client: more user friendly errors

* v3 client: only load completed todos once

* v3 client: fix tests

* v3: move TAVERN_ID to common code

* fix: Provide default type and text for new task creation in score route

* fix: Provide default history [] for habit in score route

* fix: Add _legacyId prop to tasks to support non-uuid identifiers

* chore: Change v3 migration to use _legacyId instead of legacyId

* fix: check for _legacyId in tasks if id does not exist

* refactor: Extract out finding task by id or _legacyId into a function

* Api v3 party quest fixes (#7341)

* Fix display of add challenge message when group challenges are empty

* Fixed forced quest start to update quest without reload

* Fixed needing to reload when accepting party invite

* Fix group leave and join reload

* Fixed leave current party and join another

* Updated party tests

* v3 client: remove console.log statement

* v3: misc fixes

* v3 client: fix predicatbale random

* v3: info about API v3

* v3: update footer with links to developer resources

* v3: support party invitation from email

* v3 client: fix chat flagging

* fix: Correct get tasks route to properly get todos (#7349)

* move locales strings from api-v3.json to other locales files (#7347)

* move locales strings from api-v3.json: authentication strings -> front.json

* move locales strings from api-v3.json: authentication strings -> tasks.json

* move locales strings from api-v3.json: authentication strings -> groups.json

* move locales strings from api-v3.json: authentication strings -> challenge.json

* move locales strings from api-v3.json: authentication strings -> groups.json (again)

* move locales strings from api-v3.json: authentication strings -> quests.json

* move locales strings from api-v3.json: authentication strings -> subscriber.json

* move locales strings from api-v3.json: authentication strings -> spells.json

* move locales strings from api-v3.json: authentication strings -> character.json

* move locales strings from api-v3.json: authentication strings -> groups.json (PMs)

* move locales strings from api-v3.json: authentication strings -> npc.json

* move locales strings from api-v3.json: authentication strings -> pets.json

* move locales strings from api-v3.json: authentication strings -> miscellaneous

* move locales strings from api-v3.json: authentication strings -> contrib.json and settings.json

* move locales strings from api-v3.json: delete unused string (invalidTasksOwner), delete api-v3.json, whitespace cleanup

* v3 client: fix sticky header

* v3: remove unused code

* v3 client: correctly redirect after inviting

* Removed v2 calls from views (#7351)

* v3: fix tests for challenge export

* v3: fallbackto authWithHeaders if wuthWithSession or authWithUrl fails

* Added force cache update when fetching new messages (#7360)

* v3: fetch whole user when booting from group tto avoid issues with pre save hook expecting all data

* v3: misc fixes for payments

* v3: limit fields of challenge tasks that can be updated

* fix(tests): never connect to NODE_DB_URI for tests

* Added new route for setting last cron and updated front end

* v3: fix iap url

* v3: fix build and ios IAP

* Changed route to user set custom day start

* v3: iap accessible under /api/v3, fixes to spells and groups invitations

* v3: correctly use v3 routes in client

* remove XP, GP when unticking a Daily with a completed checklist - fixes https://github.com/HabitRPG/habitrpg/issues/7246

* use natural language for error message about skills on challenge tasks (#7336), fix other gramatical error

* Updated ui when user rejects a guild invite (#7368)

* feat: complete custom day start route

Closes #7363

* fix: Correct spelling of healAll skill

fix: Correct sprite name of healAll skill

* fix: Change all instances of spookDust -> spookySparkles

* add dateCreated to all tasks; add empty challenge object to tasks that don't have one (#7386)

* add plumilla to artists for Tangle Tree in Bailey message

* Fixed quest drop modal (#7377)

* Fixed quest drop modal

* Fixed broken party test

* [API v3] Maintenance Mode (#7367)

* WIP(maintenance): maintenance

* WIP(maintenance): working locale features

* fix(maintenance): don't translate info page target

* WIP(maintenance): start adding info page

* fix(maintenance): linting

* feat: Add container to maintenance info page

* fix(maintenance): add config.json edits
Also DRY variables for main vs info pages

* fix(maintenance): linting

* refactor(maintenance): further slim down variables

* refactor: Remove unnecessary variables

* fix: Correct string interpolation in maintenace view

* feat: Dynamically add time to maintenance pages

* maintenance mode: do not connect to mongodb

* fix(maintenance): clean up timezones etc.

* fix(maintenance): remove unneeded sprite

* Tavern party challenges invites fix (#7394)

* Added challenges and invitations to party

* Loaded tavern challenges

* Updated group and quest services tests

* v3: implement automatic syncing if user is not up to date

* Removed unnecessary fields when updating groups and challenges (#7395)

* v3: do not saved populated user

* v3: correctly return user subset

* Chained party promises together (#7396)

* v3: $w -> splitWhitespace

* use bluebird

* use babel polyfill

* migration: fix items

* update links for v3

* Updated shortname validation to support multiple browsers

* Docs changes (#7401)

* chore: Clarify transfer-gems documentation

* chore: Clarify api status route documentation

* chore: Mark webhooks as BETA

* Added tags update route. Added sort to user service (#7381)

* Added tags update route. Added sort to user service

* Change update tasks route to reorder tasks

* Fixed linting issue

* Changed params for reorder tags route

* Fixed not found tag and added test

* Added password confirmation when deleteing account (#7402)

* fix production logging

* feat(commit): push

* empty commit

* feat(maintenance): post-downtime news & awards (#7406)

* fix exporting avatar

* second attempt at fixing exporting avatar

* fix production logging

* s3: convert moment to date instance

* fix avatar sharing and caching (30 minutes)

* fix: Correct missing parameter

Closes #7433

* fix: Validate challenge shortname on server

* adjust text strings - fixes https://github.com/HabitRPG/habitrpg/issues/5631 and also Short Name -> Tag Name
This commit is contained in:
Matteo Pagliazzi
2016-05-23 13:58:31 +02:00
parent ef3a2fc286
commit 28f2e9c356
993 changed files with 44888 additions and 12883 deletions

View File

@@ -0,0 +1,21 @@
var auth = require('../../controllers/api-v2/auth');
var express = require('express');
var i18n = require('../../libs/api-v2/i18n');
var router = express.Router();
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
/* auth.auth*/
// auth.setupPassport(router); //TODO make this consistent with the others
router.post('/register', getUserLanguage, auth.registerUser);
router.post('/user/auth/local', getUserLanguage, auth.loginLocal);
router.post('/user/auth/social', getUserLanguage, auth.loginSocial);
router.delete('/user/auth/social', getUserLanguage, auth.auth, auth.deleteSocial);
router.post('/user/reset-password', getUserLanguage, auth.resetPassword);
router.post('/user/change-password', getUserLanguage, auth.auth, auth.changePassword);
router.post('/user/change-username', getUserLanguage, auth.auth, auth.changeUsername);
router.post('/user/change-email', getUserLanguage, auth.auth, auth.changeEmail);
// router.post('/user/auth/firebase', i18n.getUserLanguage, auth.auth, auth.getFirebaseToken);
module.exports = router;

View File

@@ -0,0 +1,15 @@
var nconf = require('nconf');
var express = require('express');
var router = express.Router();
var auth = require('../../controllers/api-v2/auth');
var coupon = require('../../controllers/api-v2/coupon');
var i18n = require('../../libs/api-v2/i18n');
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
router.get('/coupons', auth.authWithUrl, getUserLanguage, coupon.ensureAdmin, coupon.getCoupons);
router.post('/coupons/generate/:event', auth.auth, getUserLanguage, coupon.ensureAdmin, coupon.generateCoupons);
router.post('/user/coupon/:code', auth.auth, getUserLanguage, coupon.enterCode);
module.exports = router;

View File

@@ -0,0 +1,778 @@
/*
---------- /api/v2 API ------------
see https://github.com/wordnik/swagger-node-express
Every url added to router is prefaced by /api/v2
Note: Many user-route ops exist in ../../common/script/index.js#user.ops, so that they can (1) be called both
client and server.
v1 user. Requires x-api-user (user id) and x-api-key (api key) headers, Test with:
*/
var user = require("../../controllers/api-v2/user");
var groups = require("../../controllers/api-v2/groups");
var members = require("../../controllers/api-v2/members");
var auth = require("../../controllers/api-v2/auth");
var hall = require("../../controllers/api-v2/hall");
var challenges = require("../../controllers/api-v2/challenges");
var dataexport = require("../../controllers/api-v2/dataexport");
var nconf = require("nconf");
var cron = user.cron;
var _ = require('lodash');
var content = require('../../../../common').content;
var i18n = require('../../libs/api-v2/i18n');
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
var forceRefresh = require('../../middlewares/forceRefresh').middleware;
module.exports = function(swagger, v2) {
var path = swagger.pathParam;
var body = swagger.bodyParam;
var query = swagger.queryParam;
swagger.setAppHandler(v2);
swagger.setErrorHandler("next");
swagger.setHeaders = function() {};
swagger.configureSwaggerPaths("", "/api-docs", "");
var api = {
'/status': {
spec: {
description: "Returns the status of the server (up or down). Does not require authentication."
},
action: function(req, res) {
return res.json({
status: "up"
});
}
},
'/content': {
spec: {
description: "Get all available content objects. This is essential, since Habit often depends on item keys (eg, when purchasing a weapon). Does not require authentication.",
parameters: [query("language", "Optional language to use for content's strings. Default is english.", "string")]
},
action: user.getContent
},
'/content/paths': {
spec: {
description: "Show user model tree. Does not require authentication."
},
action: user.getModelPaths
},
"/export/history": {
spec: {
description: "Export user history",
method: 'GET'
},
middleware: [auth.auth, getUserLanguage],
action: dataexport.history
},
"/user/tasks/{id}/{direction}": {
spec: {
description: "Simple scoring of a task (Habit, Daily, To-Do, or Reward). This is most-likely the only API route you'll be using as a 3rd-party developer. The most common operation is for the user to gain or lose points based on some action (browsing Reddit, running a mile, 1 Pomodor, etc). Call this route, if the task you're trying to score doesn't exist, it will be created for you. When random events occur, the <b>user._tmp</b> variable will be filled. Critical hits can be accessed through <b>user._tmp.crit</b>. The Streakbonus can be accessed through <b>user._tmp.streakBonus</b>. Both will contain the multiplier value. When random drops occur, the following values are available: <b>user._tmp.drop = {text,type,dialog,value,key,notes}</b>",
parameters: [path("id", "ID of the task to score. If this task doesn't exist, a task will be created automatically", "string"), path("direction", "Either 'up' or 'down'", "string"), body('', "If you're creating a 3rd-party task, pass up any task attributes in the body (see TaskSchema).", 'object')],
method: 'POST'
},
action: user.score
},
"/user/tasks:GET": {
spec: {
path: '/user/tasks',
description: "Get all user's tasks"
},
action: user.getTasks
},
"/user/tasks:POST": {
spec: {
path: '/user/tasks',
description: "Create a task",
method: 'POST',
parameters: [body("", "Send up the whole task (see TaskSchema)", "object")]
},
action: user.addTask
},
"/user/tasks/{id}:GET": {
spec: {
path: '/user/tasks/{id}',
description: "Get an individual task",
parameters: [path("id", "Task ID", "string")]
},
action: user.getTask
},
"/user/tasks/{id}:PUT": {
spec: {
path: '/user/tasks/{id}',
description: "Update a user's task",
method: 'PUT',
parameters: [path("id", "Task ID", "string"), body("", "Send up the whole task (see TaskSchema)", "object")]
},
action: user.updateTask
},
"/user/tasks/{id}:DELETE": {
spec: {
path: '/user/tasks/{id}',
description: "Delete a task",
method: 'DELETE',
parameters: [path("id", "Task ID", "string")]
},
action: user.deleteTask
},
"/user/tasks/{id}/sort": {
spec: {
method: 'POST',
description: 'Sort tasks',
parameters: [path("id", "Task ID", "string"), query("from", "Index where you're sorting from (0-based)", "integer"), query("to", "Index where you're sorting to (0-based)", "integer")]
},
action: user.sortTask
},
"/user/tasks/clear-completed": {
spec: {
method: 'POST',
description: "Clears competed To-Dos (needed periodically for performance)."
},
action: user.clearCompleted
},
"/user/tasks/{id}/unlink": {
spec: {
method: 'POST',
description: 'Unlink a task from its challenge',
parameters: [path("id", "Task ID", "string"), query('keep', "When unlinking a challenge task, how to handle the orphans?", 'string', ['keep', 'keep-all', 'remove', 'remove-all'])]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.unlink
},
"/user/inventory/buy": {
spec: {
description: "Get a list of buyable gear"
},
action: user.getBuyList
},
"/user/inventory/buy/{key}": {
spec: {
method: 'POST',
description: "Buy a gear piece and equip it automatically",
parameters: [path('key', "The key of the item to buy (call /content route for available keys)", 'string', _.keys(content.gear.flat))]
},
action: user.buy
},
"/user/inventory/sell/{type}/{key}": {
spec: {
method: 'POST',
description: "Sell inventory items back to Alexander",
parameters: [path('type', "The type of object you're selling back.", 'string', ['eggs', 'hatchingPotions', 'food']), path('key', "The object key you're selling back (call /content route for available keys)", 'string')]
},
action: user.sell
},
"/user/inventory/purchase/{type}/{key}": {
spec: {
method: 'POST',
description: "Purchase a Gem-purchasable item from Alexander",
parameters: [path('type', "The type of object you're purchasing.", 'string', ['eggs', 'hatchingPotions', 'food', 'quests', 'special']), path('key', "The object key you're purchasing (call /content route for available keys)", 'string')]
},
action: user.purchase
},
"/user/inventory/hourglass/{type}/{key}": {
spec: {
method: 'POST',
description: "Purchase a pet or mount using a Mystic Hourglass",
parameters: [path('type', "The type of object you're purchasing.", 'string', ['pets', 'mounts']), path('key', "The object key you're purchasing (call /content route for available keys)", 'string')]
},
action: user.hourglassPurchase
},
"/user/inventory/mystery/{key}": {
spec: {
method: 'POST',
description: "Purchase a Mystery Item Set using a Mystic Hourglass",
parameters: [path('key', "The key for the Mystery Set you're purchasing (call /content route for available keys)", 'string')]
},
action: user.buyMysterySet
},
"/user/inventory/feed/{pet}/{food}": {
spec: {
method: 'POST',
description: "Feed your pet some food",
parameters: [path('pet', "The key of the pet you're feeding", 'string', _.keys(content.pets)), path('food', "The key of the food to feed your pet", 'string', _.keys(content.food))]
},
action: user.feed
},
"/user/inventory/equip/{type}/{key}": {
spec: {
method: 'POST',
description: "Equip an item (either pet, mount, equipped or costume)",
parameters: [path('type', "Type to equip", 'string', ['pet', 'mount', 'equipped', 'costume']), path('key', "The object key you're equipping (call /content route for available keys)", 'string')]
},
action: user.equip
},
"/user/inventory/hatch/{egg}/{hatchingPotion}": {
spec: {
method: 'POST',
description: "Pour a hatching potion on an egg",
parameters: [path('egg', "The egg key to hatch", 'string', _.keys(content.eggs)), path('hatchingPotion', "The hatching potion to pour", 'string', _.keys(content.hatchingPotions))]
},
action: user.hatch
},
"/user:GET": {
spec: {
path: '/user',
description: "Get the full user object"
},
action: user.getUser
},
"/user/anonymized": {
spec: {
description: "Get the user object without any personal data"
},
action: user.getUserAnonymized
},
"/user:PUT": {
spec: {
path: '/user',
method: 'PUT',
description: "Update the user object (only certain attributes are supported)",
parameters: [body('', 'The user object (see UserSchema)', 'object')]
},
action: user.update
},
"/user:DELETE": {
spec: {
path: '/user',
method: 'DELETE',
description: "Delete a user object entirely, USE WITH CAUTION!"
},
middleware: [auth.auth, getUserLanguage],
action: user["delete"]
},
"/user/revive": {
spec: {
method: 'POST',
description: "Revive your dead user"
},
action: user.revive
},
"/user/reroll": {
spec: {
method: 'POST',
description: 'Drink the Fortify Potion (Note, it used to be called re-roll)'
},
action: user.reroll
},
"/user/reset": {
spec: {
method: 'POST',
description: "Completely reset your account"
},
action: user.reset
},
"/user/sleep": {
spec: {
method: 'POST',
description: "Toggle whether you're resting in the inn"
},
action: user.sleep
},
"/user/rebirth": {
spec: {
method: 'POST',
description: "Rebirth your avatar"
},
action: user.rebirth
},
"/user/class/change": {
spec: {
method: 'POST',
description: "Either remove your avatar's class, or change it to something new",
parameters: [query('class', "The key of the class to change to. If not provided, user's class is removed.", 'string', ['warrior', 'healer', 'rogue', 'wizard', ''])]
},
action: user.changeClass
},
"/user/class/allocate": {
spec: {
method: 'POST',
description: "Allocate one point towards an attribute",
parameters: [query('stat', 'The stat to allocate towards', 'string', ['str', 'per', 'int', 'con'])]
},
action: user.allocate
},
"/user/class/cast/{spell}": {
spec: {
method: 'POST',
description: "Casts a spell on a target.",
parameters: [path('spell', "The key of the spell to cast (see ../../common#content/index.js)", 'string'), query('targetType', "The type of object you're targeting", 'string', ['party', 'self', 'user', 'task']), query('targetId', "The ID of the object you're targeting", 'string')]
},
action: user.cast
},
"/user/unlock": {
spec: {
method: 'POST',
description: "Unlock a certain gem-purchaseable path (or multiple paths)",
parameters: [query('path', "The path to unlock, such as hair.green or shirts.red,shirts.blue", 'string')]
},
action: user.unlock
},
"/user/batch-update": {
spec: {
method: 'POST',
description: "This is an advanced route which is useful for apps which might for example need offline support. You can send a whole batch of user-based operations, which allows you to queue them up offline and send them all at once. The format is {op:'nameOfOperation',parameters:{},body:{},query:{}}",
parameters: [body('', 'The array of batch-operations to perform', 'object')]
},
middleware: [forceRefresh, auth.auth, getUserLanguage, cron, user.sessionPartyInvite],
action: user.batchUpdate
},
"/user/tags/{id}:GET": {
spec: {
path: '/user/tags/{id}',
method: 'GET',
description: "Get a tag",
parameters: [path('id', 'The id of the tag to get', 'string')]
},
action: user.getTag
},
"/user/tags:POST": {
spec: {
path: "/user/tags",
method: 'POST',
description: 'Create a new tag',
parameters: [body('', 'New tag (see UserSchema.tags)', 'object')]
},
action: user.addTag
},
"/user/tags:GET": {
spec: {
path: "/user/tags",
method: 'GET',
description: 'List all of a user\'s tags'
},
action: user.getTags
},
"/user/tags/sort": {
spec: {
method: 'POST',
description: 'Sort tags',
parameters: [query("from", "Index where you're sorting from (0-based)", "integer"), query("to", "Index where you're sorting to (0-based)", "integer")]
},
action: user.sortTag
},
"/user/tags/{id}:PUT": {
spec: {
path: '/user/tags/{id}',
method: 'PUT',
description: "Edit a tag",
parameters: [path('id', 'The id of the tag to edit', 'string'), body('', 'Tag edits (see UserSchema.tags)', 'object')]
},
action: user.updateTag
},
"/user/tags/{id}:DELETE": {
spec: {
path: '/user/tags/{id}',
method: 'DELETE',
description: 'Delete a tag',
parameters: [path('id', 'Id of tag to delete', 'string')]
},
action: user.deleteTag
},
"/user/webhooks": {
spec: {
method: 'POST',
description: 'Create a new webhook',
parameters: [body('', 'New Webhook {url:"webhook endpoint (required)", id:"id of webhook (shared.uuid(), optional)", enabled:"whether webhook is enabled (true by default, optional)"}', 'object')]
},
action: user.addWebhook
},
"/user/webhooks/{id}:PUT": {
spec: {
path: '/user/webhooks/{id}',
method: 'PUT',
description: "Edit a webhook",
parameters: [path('id', 'The id of the webhook to edit', 'string'), body('', 'New Webhook {url:"webhook endpoint (required)", id:"id of webhook (shared.uuid(), optional)", enabled:"whether webhook is enabled (true by default, optional)"}', 'object')]
},
action: user.updateWebhook
},
"/user/webhooks/{id}:DELETE": {
spec: {
path: '/user/webhooks/{id}',
method: 'DELETE',
description: 'Delete a webhook',
parameters: [path('id', 'Id of webhook to delete', 'string')]
},
action: user.deleteWebhook
},
"/user/pushDevice": {
spec: {
method: 'POST',
description: 'Add a new push devices registration ID',
parameters: [body('', 'New push registration { regId: "123123", type: "android"}', 'object')]
},
action: user.addPushDevice
},
"/groups:GET": {
spec: {
path: '/groups',
description: "Get a list of groups",
parameters: [query('type', "Comma-separated types of groups to return, eg 'party,guilds,public,tavern'", 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: groups.list
},
"/groups:POST": {
spec: {
path: '/groups',
method: 'POST',
description: 'Create a group',
parameters: [body('', 'Group object (see GroupSchema)', 'object')]
},
middleware: [auth.auth, getUserLanguage],
action: groups.create
},
"/groups/{gid}:GET": {
spec: {
path: '/groups/{gid}',
description: "Get a group. The party the user currently is in can be accessed with the gid 'party'.",
parameters: [path('gid', 'Group ID', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: groups.get
},
"/groups/{gid}:POST": {
spec: {
path: '/groups/{gid}',
method: 'POST',
description: "Edit a group",
parameters: [body('', 'Group object (see GroupSchema)', 'object')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.update
},
"/groups/{gid}/join": {
spec: {
method: 'POST',
description: 'Join a group',
parameters: [path('gid', 'Id of the group to join', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.join
},
"/groups/{gid}/leave": {
spec: {
method: 'POST',
description: 'Leave a group',
parameters: [path('gid', 'ID of the group to leave', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.leave
},
"/groups/{gid}/invite": {
spec: {
method: 'POST',
description: "Invite a user to a group",
parameters: [path('gid', 'Group id', 'string'), body('', 'a payload of invites either under body.uuids or body.emails, only one of them!', 'object')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.invite
},
"/groups/{gid}/removeMember": {
spec: {
method: 'POST',
description: "Remove / boot a member from a group",
parameters: [path('gid', 'Group id', 'string'), query('uuid', 'User id to boot', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.removeMember
},
"/groups/{gid}/questAccept": {
spec: {
method: 'POST',
description: "Accept a quest invitation",
parameters: [path('gid', "Group id", 'string'), query('key', "optional. if provided, trigger new invite, if not, accept existing invite", 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questAccept
},
"/groups/{gid}/questReject": {
spec: {
method: 'POST',
description: 'Reject quest invitation',
parameters: [path('gid', 'Group id', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questReject
},
"/groups/{gid}/questCancel": {
spec: {
method: 'POST',
description: 'Cancel quest before it starts (in invitation stage)',
parameters: [path('gid', 'Group to cancel quest in', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questCancel
},
"/groups/{gid}/questAbort": {
spec: {
method: 'POST',
description: 'Abort quest after it has started (all progress will be lost)',
parameters: [path('gid', 'Group to abort quest in', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questAbort
},
"/groups/{gid}/questLeave": {
spec: {
method: 'POST',
description: 'Leave an active quest (Quest leaders cannot leave active quests. They must abort the quest to leave)',
parameters: [path('gid', 'Group to leave quest in', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.questLeave
},
"/groups/{gid}/chat:GET": {
spec: {
path: "/groups/{gid}/chat",
description: "Get all chat messages",
parameters: [path('gid', 'Group to return the chat from ', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.getChat
},
"/groups/{gid}/chat:POST": {
spec: {
method: 'POST',
path: "/groups/{gid}/chat",
description: "Send a chat message",
parameters: [query('message', 'Chat message', 'string'), path('gid', 'Group id', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.postChat
},
"/groups/{gid}/chat/seen": {
spec: {
method: 'POST',
description: "Flag chat messages for a particular group as seen",
parameters: [path('gid', 'Group id', 'string')]
},
action: groups.seenMessage
},
"/groups/{gid}/chat/{messageId}": {
spec: {
method: 'DELETE',
description: 'Delete a chat message in a given group',
parameters: [path('gid', 'ID of the group containing the message to be deleted', 'string'), path('messageId', 'ID of message to be deleted', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.deleteChatMessage
},
"/groups/{gid}/chat/{mid}/like": {
spec: {
method: 'POST',
description: "Like a chat message",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.likeChatMessage
},
"/groups/{gid}/chat/{mid}/flag": {
spec: {
method: 'POST',
description: "Flag a chat message",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.flagChatMessage
},
"/groups/{gid}/chat/{mid}/clearflags": {
spec: {
method: 'POST',
description: "Clear flag count from message and unhide it",
parameters: [path('gid', 'Group id', 'string'), path('mid', 'Message id', 'string')]
},
middleware: [auth.auth, getUserLanguage, groups.attachGroup],
action: groups.clearFlagCount
},
"/members/{uuid}:GET": {
spec: {
path: '/members/{uuid}',
description: "Get a member.",
parameters: [path('uuid', 'Member ID', 'string')]
},
middleware: [getUserLanguage],
action: members.getMember
},
"/members/{uuid}/message": {
spec: {
method: 'POST',
description: 'Send a private message to a member',
parameters: [path('uuid', 'The UUID of the member to message', 'string'), body('', '{"message": "The private message to send"}', 'object')]
},
middleware: [auth.auth],
action: members.sendPrivateMessage
},
"/members/{uuid}/block": {
spec: {
method: 'POST',
description: 'Block a member from sending private messages',
parameters: [path('uuid', 'The UUID of the member to message', 'string')]
},
middleware: [auth.auth],
action: user.blockUser
},
"/members/{uuid}/gift": {
spec: {
method: 'POST',
description: 'Send a gift to a member',
parameters: [path('uuid', 'The UUID of the member', 'string'), body('', '{"type": "gems or subscription", "gems":{"amount":Number, "fromBalance":Boolean}, "subscription":{"months":Number}}', 'object')]
},
middleware: [auth.auth],
action: members.sendGift
},
"/hall/heroes": {
spec: {},
middleware: [auth.auth, getUserLanguage],
action: hall.getHeroes
},
"/hall/heroes/{uid}:GET": {
spec: {
path: "/hall/heroes/{uid}"
},
middleware: [auth.auth, getUserLanguage, hall.ensureAdmin],
action: hall.getHero
},
"/hall/heroes/{uid}:POST": {
spec: {
method: 'POST',
path: "/hall/heroes/{uid}"
},
middleware: [auth.auth, getUserLanguage, hall.ensureAdmin],
action: hall.updateHero
},
"/hall/patrons": {
spec: {
parameters: [query('page', 'Page number to fetch (this list is long)', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: hall.getPatrons
},
"/challenges:GET": {
spec: {
path: '/challenges',
description: "Get a list of challenges"
},
middleware: [auth.auth, getUserLanguage],
action: challenges.list
},
"/challenges:POST": {
spec: {
path: '/challenges',
method: 'POST',
description: "Create a challenge",
parameters: [body('', 'Challenge object (see ChallengeSchema)', 'object')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.create
},
"/challenges/{cid}:GET": {
spec: {
path: '/challenges/{cid}',
description: 'Get a challenge',
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.get
},
"/challenges/{cid}/csv": {
spec: {
description: 'Get a challenge (csv format)',
parameters: [path('cid', 'Challenge id', 'string')]
},
action: challenges.csv
},
"/challenges/{cid}:POST": {
spec: {
path: '/challenges/{cid}',
method: 'POST',
description: "Update a challenge",
parameters: [path('cid', 'Challenge id', 'string'), body('', 'Challenge object (see ChallengeSchema)', 'object')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.update
},
"/challenges/{cid}:DELETE": {
spec: {
path: '/challenges/{cid}',
method: 'DELETE',
description: "Delete a challenge",
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges["delete"]
},
"/challenges/{cid}/close": {
spec: {
method: 'POST',
description: 'Close a challenge',
parameters: [path('cid', 'Challenge id', 'string'), query('uid', 'User ID of the winner', 'string', true)]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.selectWinner
},
"/challenges/{cid}/join": {
spec: {
method: 'POST',
description: "Join a challenge",
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.join
},
"/challenges/{cid}/leave": {
spec: {
method: 'POST',
description: 'Leave a challenge',
parameters: [path('cid', 'Challenge id', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.leave
},
"/challenges/{cid}/member/{uid}": {
spec: {
description: "Get a member's progress in a particular challenge",
parameters: [path('cid', 'Challenge id', 'string'), path('uid', 'User id', 'string')]
},
middleware: [auth.auth, getUserLanguage],
action: challenges.getMember
}
};
if (nconf.get("NODE_ENV") === "development") {
api["/user/addTenGems"] = {
spec: {
method: 'POST'
},
action: user.addTenGems
};
api["/user/addHourglass"] = {
spec: {
method: 'POST'
},
action: user.addHourglass
};
};
_.each(api, function(route, path) {
var base;
if ((base = route.spec).description == null) {
base.description = '';
}
_.defaults(route.spec, {
path: path,
nickname: path,
notes: route.spec.description,
summary: route.spec.description,
parameters: [],
errorResponses: [],
method: 'GET'
});
if (route.middleware == null) {
route.middleware = path.indexOf('/user') === 0 ? [auth.auth, getUserLanguage, cron] : [i18n.getUserLanguage];
}
swagger["add" + route.spec.method](route);
return true;
});
return swagger.configure((nconf.get('BASE_URL')) + "/api/v2", "2");
};

View File

@@ -0,0 +1,11 @@
var express = require('express');
var router = express.Router();
var i18n = require('../../libs/api-v2/i18n');
var unsubscription = require('../../controllers/api-v2/unsubscription');
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
router.get('/unsubscribe', getUserLanguage, unsubscription.unsubscribe);
module.exports = router;