mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
APIv2: add paths /api/v2/* and /api/v1/*. v1 has limited deprecated routes (only the things I know currently work), and we'll notify 3rd-partyists to migrate to apiv2 once it's documented and tested
This commit is contained in:
4
API.md
Normal file
4
API.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
## APIv2
|
||||||
|
|
||||||
|
## APIv1 (Deprecated)
|
||||||
|
Make sure to send `PUT /api/v1/user` request bodies as `{'set.this.path':value}` instead of `{set:{this:{path:value}}}`
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'API_URL', '$resource',
|
habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'API_URL', '$resource',
|
||||||
function($scope, $rootScope, User, Notification, API_URL, $resource) {
|
function($scope, $rootScope, User, Notification, API_URL, $resource) {
|
||||||
var Contributor = $resource(API_URL + '/api/v1/admin/members/:uid', {uid:'@_id'});
|
var Contributor = $resource(API_URL + '/api/v2/admin/members/:uid', {uid:'@_id'});
|
||||||
|
|
||||||
$scope.profile = undefined;
|
$scope.profile = undefined;
|
||||||
$scope.loadUser = function(uuid){
|
$scope.loadUser = function(uuid){
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ habitrpg.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$loca
|
|||||||
if ($scope.registrationForm.$invalid) {
|
if ($scope.registrationForm.$invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$http.post(API_URL + "/api/v1/register", $scope.registerVals).success(function(data, status, headers, config) {
|
$http.post(API_URL + "/api/v2/register", $scope.registerVals).success(function(data, status, headers, config) {
|
||||||
runAuth(data.id, data.apiToken);
|
runAuth(data.id, data.apiToken);
|
||||||
}).error(function(data, status, headers, config) {
|
}).error(function(data, status, headers, config) {
|
||||||
if (status === 0) {
|
if (status === 0) {
|
||||||
@@ -68,7 +68,7 @@ habitrpg.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$loca
|
|||||||
if ($scope.useUUID) {
|
if ($scope.useUUID) {
|
||||||
runAuth($scope.loginUsername, $scope.loginPassword);
|
runAuth($scope.loginUsername, $scope.loginPassword);
|
||||||
} else {
|
} else {
|
||||||
$http.post(API_URL + "/api/v1/user/auth/local", data)
|
$http.post(API_URL + "/api/v2/user/auth/local", data)
|
||||||
.success(function(data, status, headers, config) {
|
.success(function(data, status, headers, config) {
|
||||||
runAuth(data.id, data.token);
|
runAuth(data.id, data.token);
|
||||||
}).error(errorAlert);
|
}).error(errorAlert);
|
||||||
@@ -84,7 +84,7 @@ habitrpg.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$loca
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope.passwordReset = function(email){
|
$scope.passwordReset = function(email){
|
||||||
$http.post(API_URL + '/api/v1/user/reset-password', {email:email})
|
$http.post(API_URL + '/api/v2/user/reset-password', {email:email})
|
||||||
.success(function(){
|
.success(function(){
|
||||||
alert('New password sent.');
|
alert('New password sent.');
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not
|
|||||||
Notification.text('-1 day, remember to refresh');
|
Notification.text('-1 day, remember to refresh');
|
||||||
}
|
}
|
||||||
$scope.addTenGems = function(){
|
$scope.addTenGems = function(){
|
||||||
$http.post(API_URL + '/api/v1/user/addTenGems').success(function(){
|
$http.post(API_URL + '/api/v2/user/addTenGems').success(function(){
|
||||||
User.log({});
|
User.log({});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
|||||||
panelLabel: "Checkout",
|
panelLabel: "Checkout",
|
||||||
token: function(data) {
|
token: function(data) {
|
||||||
$scope.$apply(function(){
|
$scope.$apply(function(){
|
||||||
$http.post("/api/v1/user/buy-gems", data)
|
$http.post("/api/v2/user/buy-gems", data)
|
||||||
.success(function() {
|
.success(function() {
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
}).error(function(err) {
|
}).error(function(err) {
|
||||||
@@ -158,7 +158,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
|||||||
$scope.castEnd = function(target, type, $event){
|
$scope.castEnd = function(target, type, $event){
|
||||||
if ($scope.spell.target != type) return Notification.text("Invalid target");
|
if ($scope.spell.target != type) return Notification.text("Invalid target");
|
||||||
$scope.spell.cast(User.user, target);
|
$scope.spell.cast(User.user, target);
|
||||||
$http.post('/api/v1/user/cast/' + $scope.spell.name, {target:target, type:type}).success(function(){
|
$http.post('/api/v2/user/cast/' + $scope.spell.name, {target:target, type:type}).success(function(){
|
||||||
var msg = "You cast " + $scope.spell.text;
|
var msg = "You cast " + $scope.spell.text;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'task': msg += ' on ' + target.text;break;
|
case 'task': msg += ' on ' + target.text;break;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ habitrpg.controller('SettingsCtrl',
|
|||||||
if (!changePass.oldPassword || !changePass.newPassword || !changePass.confirmNewPassword) {
|
if (!changePass.oldPassword || !changePass.newPassword || !changePass.confirmNewPassword) {
|
||||||
return alert("Please fill out all fields");
|
return alert("Please fill out all fields");
|
||||||
}
|
}
|
||||||
$http.post(API_URL + '/api/v1/user/change-password', changePass)
|
$http.post(API_URL + '/api/v2/user/change-password', changePass)
|
||||||
.success(function(){
|
.success(function(){
|
||||||
alert("Password successfully changed");
|
alert("Password successfully changed");
|
||||||
$scope.changePass = {};
|
$scope.changePass = {};
|
||||||
@@ -92,7 +92,7 @@ habitrpg.controller('SettingsCtrl',
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope['delete'] = function(){
|
$scope['delete'] = function(){
|
||||||
$http['delete'](API_URL + '/api/v1/user')
|
$http['delete'](API_URL + '/api/v2/user')
|
||||||
.success(function(){
|
.success(function(){
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
window.location.href = '/logout';
|
window.location.href = '/logout';
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||||||
|
|
||||||
$scope.unlink = function(task, keep) {
|
$scope.unlink = function(task, keep) {
|
||||||
// TODO move this to userServices, turn userSerivces.user into ng-resource
|
// TODO move this to userServices, turn userSerivces.user into ng-resource
|
||||||
$http.post(API_URL + '/api/v1/user/tasks/' + task.id + '/unlink?keep=' + keep)
|
$http.post(API_URL + '/api/v2/user/tasks/' + task.id + '/unlink?keep=' + keep)
|
||||||
.success(function(){
|
.success(function(){
|
||||||
User.log({});
|
User.log({});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ factory('Facebook',
|
|||||||
email: response.email
|
email: response.email
|
||||||
}
|
}
|
||||||
|
|
||||||
$http.post(API_URL + '/api/v1/user/auth/facebook', data).success(function(data, status, headers, config) {
|
$http.post(API_URL + '/api/v2/user/auth/facebook', data).success(function(data, status, headers, config) {
|
||||||
User.authenticate(data.id, data.token, function(err) {
|
User.authenticate(data.id, data.token, function(err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
alert('Login successful!');
|
alert('Login successful!');
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
angular.module('challengeServices', ['ngResource']).
|
angular.module('challengeServices', ['ngResource']).
|
||||||
factory('Challenges', ['API_URL', '$resource', 'User', '$q', 'Members',
|
factory('Challenges', ['API_URL', '$resource', 'User', '$q', 'Members',
|
||||||
function(API_URL, $resource, User, $q, Members) {
|
function(API_URL, $resource, User, $q, Members) {
|
||||||
var Challenge = $resource(API_URL + '/api/v1/challenges/:cid',
|
var Challenge = $resource(API_URL + '/api/v2/challenges/:cid',
|
||||||
{cid:'@_id'},
|
{cid:'@_id'},
|
||||||
{
|
{
|
||||||
//'query': {method: "GET", isArray:false}
|
//'query': {method: "GET", isArray:false}
|
||||||
join: {method: "POST", url: API_URL + '/api/v1/challenges/:cid/join'},
|
join: {method: "POST", url: API_URL + '/api/v2/challenges/:cid/join'},
|
||||||
leave: {method: "POST", url: API_URL + '/api/v1/challenges/:cid/leave'},
|
leave: {method: "POST", url: API_URL + '/api/v2/challenges/:cid/leave'},
|
||||||
close: {method: "POST", params: {uid:''}, url: API_URL + '/api/v1/challenges/:cid/close'},
|
close: {method: "POST", params: {uid:''}, url: API_URL + '/api/v2/challenges/:cid/close'},
|
||||||
getMember: {method: "GET", url: API_URL + '/api/v1/challenges/:cid/member/:uid'}
|
getMember: {method: "GET", url: API_URL + '/api/v2/challenges/:cid/member/:uid'}
|
||||||
});
|
});
|
||||||
|
|
||||||
//var challenges = [];
|
//var challenges = [];
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
angular.module('groupServices', ['ngResource']).
|
angular.module('groupServices', ['ngResource']).
|
||||||
factory('Groups', ['API_URL', '$resource', '$q',
|
factory('Groups', ['API_URL', '$resource', '$q',
|
||||||
function(API_URL, $resource, $q) {
|
function(API_URL, $resource, $q) {
|
||||||
var Group = $resource(API_URL + '/api/v1/groups/:gid',
|
var Group = $resource(API_URL + '/api/v2/groups/:gid',
|
||||||
{gid:'@_id', messageId: '@_messageId'},
|
{gid:'@_id', messageId: '@_messageId'},
|
||||||
{
|
{
|
||||||
//query: {method: "GET", isArray:false},
|
//query: {method: "GET", isArray:false},
|
||||||
postChat: {method: "POST", url: API_URL + '/api/v1/groups/:gid/chat'},
|
postChat: {method: "POST", url: API_URL + '/api/v2/groups/:gid/chat'},
|
||||||
deleteChatMessage: {method: "DELETE", url: API_URL + '/api/v1/groups/:gid/chat/:messageId'},
|
deleteChatMessage: {method: "DELETE", url: API_URL + '/api/v2/groups/:gid/chat/:messageId'},
|
||||||
join: {method: "POST", url: API_URL + '/api/v1/groups/:gid/join'},
|
join: {method: "POST", url: API_URL + '/api/v2/groups/:gid/join'},
|
||||||
leave: {method: "POST", url: API_URL + '/api/v1/groups/:gid/leave'},
|
leave: {method: "POST", url: API_URL + '/api/v2/groups/:gid/leave'},
|
||||||
invite: {method: "POST", url: API_URL + '/api/v1/groups/:gid/invite'},
|
invite: {method: "POST", url: API_URL + '/api/v2/groups/:gid/invite'},
|
||||||
removeMember: {method: "POST", url: API_URL + '/api/v1/groups/:gid/removeMember'}
|
removeMember: {method: "POST", url: API_URL + '/api/v2/groups/:gid/removeMember'}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Defer loading everything until they're requested
|
// Defer loading everything until they're requested
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ angular.module('memberServices', ['ngResource']).
|
|||||||
factory('Members', ['$rootScope', 'API_URL', '$resource',
|
factory('Members', ['$rootScope', 'API_URL', '$resource',
|
||||||
function($rootScope, API_URL, $resource) {
|
function($rootScope, API_URL, $resource) {
|
||||||
var members = {};
|
var members = {};
|
||||||
var Member = $resource(API_URL + '/api/v1/members/:uid', {uid:'@_id'});
|
var Member = $resource(API_URL + '/api/v2/members/:uid', {uid:'@_id'});
|
||||||
var memberServices = {
|
var memberServices = {
|
||||||
|
|
||||||
Member: Member,
|
Member: Member,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ angular.module('userServices', []).
|
|||||||
sent.push(queue.shift());
|
sent.push(queue.shift());
|
||||||
});
|
});
|
||||||
|
|
||||||
$http.post(API_URL + '/api/v1/user/batch-update', sent, {params: {data:+new Date, _v:user._v, siteVersion: $window.env && $window.env.siteVersion}})
|
$http.post(API_URL + '/api/v2/user/batch-update', sent, {params: {data:+new Date, _v:user._v, siteVersion: $window.env && $window.env.siteVersion}})
|
||||||
.success(function (data, status, heacreatingders, config) {
|
.success(function (data, status, heacreatingders, config) {
|
||||||
//make sure there are no pending actions to sync. If there are any it is not safe to apply model from server as we may overwrite user data.
|
//make sure there are no pending actions to sync. If there are any it is not safe to apply model from server as we may overwrite user data.
|
||||||
if (!queue.length) {
|
if (!queue.length) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
window.habitrpg = angular.module('habitrpg', ['userServices', 'chieffancypants.loadingBar'])
|
window.habitrpg = angular.module('habitrpg', ['notificationServices', 'userServices', 'chieffancypants.loadingBar'])
|
||||||
.constant("API_URL", "")
|
.constant("API_URL", "")
|
||||||
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
||||||
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
|
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
|
|
||||||
"bower_components/angular-loading-bar/build/loading-bar.js",
|
"bower_components/angular-loading-bar/build/loading-bar.js",
|
||||||
"js/static.js",
|
"js/static.js",
|
||||||
"js/services/userServices.js",
|
|
||||||
"js/services/notificationServices.js",
|
"js/services/notificationServices.js",
|
||||||
|
"js/services/userServices.js",
|
||||||
"js/controllers/authCtrl.js"
|
"js/controllers/authCtrl.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
var express = require('express');
|
|
||||||
var router = new express.Router();
|
|
||||||
var _ = require('lodash');
|
|
||||||
var icalendar = require('icalendar');
|
|
||||||
var api = require('./user');
|
|
||||||
var auth = require('./auth');
|
|
||||||
|
|
||||||
/* ---------- Deprecated Paths ------------*/
|
|
||||||
|
|
||||||
|
|
||||||
var deprecatedMessage = 'This API is no longer supported, see https://github.com/lefnire/habitrpg/wiki/API for new protocol';
|
|
||||||
|
|
||||||
router.get('/:uid/up/:score?', function(req, res) {
|
|
||||||
return res.send(500, deprecatedMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/:uid/down/:score?', function(req, res) {
|
|
||||||
return res.send(500, deprecatedMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/users/:uid/tasks/:taskId/:direction', function(req, res) {
|
|
||||||
return res.send(500, deprecatedMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Redirect to new API*/
|
|
||||||
|
|
||||||
|
|
||||||
var initDeprecated = function(req, res, next) {
|
|
||||||
req.headers['x-api-user'] = req.params.uid;
|
|
||||||
req.headers['x-api-key'] = req.body.apiToken;
|
|
||||||
return next();
|
|
||||||
};
|
|
||||||
|
|
||||||
router.post('/v1/users/:uid/tasks/:taskId/:direction', initDeprecated, auth.auth, api.score);
|
|
||||||
|
|
||||||
router.get('/v1/users/:uid/calendar.ics', function(req, res, next) {
|
|
||||||
return next() //disable for now
|
|
||||||
|
|
||||||
var apiToken, model, query, uid;
|
|
||||||
uid = req.params.uid;
|
|
||||||
apiToken = req.query.apiToken;
|
|
||||||
model = req.getModel();
|
|
||||||
query = model.query('users').withIdAndToken(uid, apiToken);
|
|
||||||
return query.fetch(function(err, result) {
|
|
||||||
var formattedIcal, ical, tasks, tasksWithDates;
|
|
||||||
if (err) {
|
|
||||||
return res.send(500, err);
|
|
||||||
}
|
|
||||||
tasks = result.get('tasks');
|
|
||||||
/* tasks = result[0].tasks*/
|
|
||||||
|
|
||||||
tasksWithDates = _.filter(tasks, function(task) {
|
|
||||||
return !!task.date;
|
|
||||||
});
|
|
||||||
if (_.isEmpty(tasksWithDates)) {
|
|
||||||
return res.send(500, "No events found");
|
|
||||||
}
|
|
||||||
ical = new icalendar.iCalendar();
|
|
||||||
ical.addProperty('NAME', 'HabitRPG');
|
|
||||||
_.each(tasksWithDates, function(task) {
|
|
||||||
var d, event;
|
|
||||||
event = new icalendar.VEvent(task.id);
|
|
||||||
event.setSummary(task.text);
|
|
||||||
d = new Date(task.date);
|
|
||||||
d.date_only = true;
|
|
||||||
event.setDate(d);
|
|
||||||
ical.addComponent(event);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
res.type('text/calendar');
|
|
||||||
formattedIcal = ical.toString().replace(/DTSTART\:/g, 'DTSTART;VALUE=DATE:');
|
|
||||||
return res.send(200, formattedIcal);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -43,19 +43,16 @@ findTask = function(req, res) {
|
|||||||
Export it also so we can call it from deprecated.coffee
|
Export it also so we can call it from deprecated.coffee
|
||||||
*/
|
*/
|
||||||
api.score = function(req, res, next) {
|
api.score = function(req, res, next) {
|
||||||
var task = findTask(req,res);
|
|
||||||
if (!task) return res.json(404, {err: "No task found."});
|
|
||||||
|
|
||||||
var id = req.params.id,
|
var id = req.params.id,
|
||||||
direction = req.params.direction,
|
direction = req.params.direction,
|
||||||
user = res.locals.user,
|
user = res.locals.user,
|
||||||
task;
|
task;
|
||||||
|
|
||||||
// Send error responses for improper API call
|
// Send error responses for improper API call
|
||||||
if (!id) return res.json(500, {err: ':id required'});
|
if (!id) return res.json(400, {err: ':id required'});
|
||||||
if (direction !== 'up' && direction !== 'down') {
|
if (direction !== 'up' && direction !== 'down') {
|
||||||
if (direction == 'unlink') return next();
|
if (direction == 'unlink') return next();
|
||||||
return res.json(500, {err: ":direction must be 'up' or 'down'"});
|
return res.json(400, {err: ":direction must be 'up' or 'down'"});
|
||||||
}
|
}
|
||||||
// If exists already, score it
|
// If exists already, score it
|
||||||
if (task = user.tasks[id]) {
|
if (task = user.tasks[id]) {
|
||||||
@@ -181,7 +178,7 @@ api.update = function(req, res, next) {
|
|||||||
if (acceptablePUTPaths[k])
|
if (acceptablePUTPaths[k])
|
||||||
user.fns.dotSet(k, v);
|
user.fns.dotSet(k, v);
|
||||||
else
|
else
|
||||||
errors.push("path `" + k + "` was not saved, as it's a protected path. Make sure to send `PUT /api/v1/user` request bodies as `{'set.this.path':value}` instead of `{set:{this:{path:value}}}`");
|
errors.push("path `" + k + "` was not saved, as it's a protected path. See https://github.com/HabitRPG/habitrpg/blob/develop/API.md for PUT /api/v2/user.");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
|
|||||||
171
src/routes/apiv1.js
Normal file
171
src/routes/apiv1.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var _ = require('lodash');
|
||||||
|
var async = require('async');
|
||||||
|
var icalendar = require('icalendar');
|
||||||
|
var api = require('./../controllers/user');
|
||||||
|
var auth = require('./../controllers/auth');
|
||||||
|
var middleware = require('../middleware');
|
||||||
|
|
||||||
|
/* ---------- Deprecated API ------------*/
|
||||||
|
|
||||||
|
var initDeprecated = function(req, res, next) {
|
||||||
|
req.headers['x-api-user'] = req.params.uid;
|
||||||
|
req.headers['x-api-key'] = req.body.apiToken;
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
|
||||||
|
router.post('/v1/users/:uid/tasks/:taskId/:direction', initDeprecated, auth.auth, api.score);
|
||||||
|
|
||||||
|
// FIXME add this back in
|
||||||
|
router.get('/v1/users/:uid/calendar.ics', function(req, res, next) {
|
||||||
|
return next() //disable for now
|
||||||
|
|
||||||
|
var apiToken, model, query, uid;
|
||||||
|
uid = req.params.uid;
|
||||||
|
apiToken = req.query.apiToken;
|
||||||
|
model = req.getModel();
|
||||||
|
query = model.query('users').withIdAndToken(uid, apiToken);
|
||||||
|
return query.fetch(function(err, result) {
|
||||||
|
var formattedIcal, ical, tasks, tasksWithDates;
|
||||||
|
if (err) {
|
||||||
|
return res.send(500, err);
|
||||||
|
}
|
||||||
|
tasks = result.get('tasks');
|
||||||
|
/* tasks = result[0].tasks*/
|
||||||
|
|
||||||
|
tasksWithDates = _.filter(tasks, function(task) {
|
||||||
|
return !!task.date;
|
||||||
|
});
|
||||||
|
if (_.isEmpty(tasksWithDates)) {
|
||||||
|
return res.send(500, "No events found");
|
||||||
|
}
|
||||||
|
ical = new icalendar.iCalendar();
|
||||||
|
ical.addProperty('NAME', 'HabitRPG');
|
||||||
|
_.each(tasksWithDates, function(task) {
|
||||||
|
var d, event;
|
||||||
|
event = new icalendar.VEvent(task.id);
|
||||||
|
event.setSummary(task.text);
|
||||||
|
d = new Date(task.date);
|
||||||
|
d.date_only = true;
|
||||||
|
event.setDate(d);
|
||||||
|
ical.addComponent(event);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
res.type('text/calendar');
|
||||||
|
formattedIcal = ical.toString().replace(/DTSTART\:/g, 'DTSTART;VALUE=DATE:');
|
||||||
|
return res.send(200, formattedIcal);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Batch Update
|
||||||
|
This is super-deprecated, and will be removed once apiv2 is running against mobile for a while
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
var batchUpdate = function(req, res, next) {
|
||||||
|
var user = res.locals.user;
|
||||||
|
var oldSend = res.send;
|
||||||
|
var oldJson = res.json;
|
||||||
|
var performAction = function(action, cb) {
|
||||||
|
|
||||||
|
// req.body=action.data; delete action.data; _.defaults(req.params, action)
|
||||||
|
// Would require changing action.dir on mobile app
|
||||||
|
req.params.id = action.data && action.data.id;
|
||||||
|
req.params.direction = action.dir;
|
||||||
|
req.params.type = action.type;
|
||||||
|
req.body = action.data;
|
||||||
|
res.send = res.json = function(code, data) {
|
||||||
|
if (_.isNumber(code) && code >= 400) {
|
||||||
|
console.error({
|
||||||
|
code: code,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//FIXME send error messages down
|
||||||
|
return cb();
|
||||||
|
};
|
||||||
|
switch (action.op) {
|
||||||
|
case "score":
|
||||||
|
api.score(req, res);
|
||||||
|
break;
|
||||||
|
case "addTask":
|
||||||
|
api.addTask(req, res);
|
||||||
|
break;
|
||||||
|
case "delTask":
|
||||||
|
api.deleteTask(req, res);
|
||||||
|
break;
|
||||||
|
case "revive":
|
||||||
|
api.revive(req, res);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cb();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup the array of functions we're going to call in parallel with async
|
||||||
|
var actions = _.transform(req.body || [], function(result, action) {
|
||||||
|
if (!_.isEmpty(action)) {
|
||||||
|
result.push(function(cb) {
|
||||||
|
performAction(action, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// call all the operations, then return the user object to the requester
|
||||||
|
async.series(actions, function(err) {
|
||||||
|
res.json = oldJson;
|
||||||
|
res.send = oldSend;
|
||||||
|
if (err) return res.json(500, {err: err});
|
||||||
|
var response = user.toJSON();
|
||||||
|
response.wasModified = res.locals.wasModified;
|
||||||
|
if (response._tmp && response._tmp.drop){
|
||||||
|
res.json(200, {_tmp: {drop: response._tmp.drop}, _v: response._v});
|
||||||
|
}else if(response.wasModified){
|
||||||
|
res.json(200, response);
|
||||||
|
}else{
|
||||||
|
res.json(200, {_v: response._v});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
API v1 Routes
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var cron = api.cron;
|
||||||
|
|
||||||
|
router.get('/status', function(req, res) {
|
||||||
|
return res.json({
|
||||||
|
status: 'up'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scoring
|
||||||
|
router.post('/user/task/:id/:direction', auth.auth, cron, api.score);
|
||||||
|
router.post('/user/tasks/:id/:direction', auth.auth, cron, api.score);
|
||||||
|
|
||||||
|
// Tasks
|
||||||
|
router.get('/user/tasks', auth.auth, cron, api.getTasks);
|
||||||
|
router.get('/user/task/:id', auth.auth, cron, api.getTask);
|
||||||
|
router["delete"]('/user/task/:id', auth.auth, cron, api.deleteTask);
|
||||||
|
router.post('/user/task', auth.auth, cron, api.addTask);
|
||||||
|
|
||||||
|
// User
|
||||||
|
router.get('/user', auth.auth, cron, api.getUser);
|
||||||
|
router.post('/user/revive', auth.auth, cron, api.revive);
|
||||||
|
router.post('/user/batch-update', middleware.forceRefresh, auth.auth, cron, batchUpdate);
|
||||||
|
|
||||||
|
function deprecated(req, res) {
|
||||||
|
res.json(404, {err:'API v1 is no longer supported, please use API v2 instead (https://github.com/HabitRPG/habitrpg/blob/develop/API.md)'});
|
||||||
|
}
|
||||||
|
router.get('*', deprecated);
|
||||||
|
router.post('*', deprecated);
|
||||||
|
router.put('*', deprecated);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -4,10 +4,10 @@ var router = new express.Router();
|
|||||||
|
|
||||||
/* auth.auth*/
|
/* auth.auth*/
|
||||||
auth.setupPassport(router); //FIXME make this consistent with the others
|
auth.setupPassport(router); //FIXME make this consistent with the others
|
||||||
router.post('/api/v1/register', auth.registerUser);
|
router.post('/api/v2/register', auth.registerUser);
|
||||||
router.post('/api/v1/user/auth/local', auth.loginLocal);
|
router.post('/api/v2/user/auth/local', auth.loginLocal);
|
||||||
router.post('/api/v1/user/auth/facebook', auth.loginFacebook);
|
router.post('/api/v2/user/auth/facebook', auth.loginFacebook);
|
||||||
router.post('/api/v1/user/reset-password', auth.resetPassword);
|
router.post('/api/v2/user/reset-password', auth.resetPassword);
|
||||||
router.post('/api/v1/user/change-password', auth.auth, auth.changePassword);
|
router.post('/api/v2/user/change-password', auth.auth, auth.changePassword);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -113,9 +113,9 @@ if ("development" === app.get("env")) {
|
|||||||
// Custom Directives
|
// Custom Directives
|
||||||
app.use(require('./routes/pages').middleware);
|
app.use(require('./routes/pages').middleware);
|
||||||
app.use(require('./routes/auth').middleware);
|
app.use(require('./routes/auth').middleware);
|
||||||
app.use('/api/v1', require('./routes/api').middleware);
|
app.use('/api/v2', require('./routes/apiv2').middleware);
|
||||||
|
app.use('/api/v1', require('./routes/apiv1').middleware);
|
||||||
app.use('/export', require('./routes/dataexport').middleware);
|
app.use('/export', require('./routes/dataexport').middleware);
|
||||||
app.use(require('./controllers/deprecated').middleware);
|
|
||||||
server = http.createServer(app).listen(app.get("port"), function() {
|
server = http.createServer(app).listen(app.get("port"), function() {
|
||||||
return console.log("Express server listening on port " + app.get("port"));
|
return console.log("Express server listening on port " + app.get("port"));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ div(modal='modals.buyGems')
|
|||||||
.btn.btn-primary(ng-click='showStripe()') Pay with Card
|
.btn.btn-primary(ng-click='showStripe()') Pay with Card
|
||||||
.span6.well
|
.span6.well
|
||||||
h3 Pay with PayPal
|
h3 Pay with PayPal
|
||||||
script(src='/bower_components/JavaScriptButtons/dist/paypal-button.min.js?merchant=#{env.PAYPAL_MERCHANT}', data-button='buynow', data-name='20 Gems, Disable Ads, Donation to the Developers', data-quantity='1', data-amount='5', data-currency='USD', data-tax='0', data-callback='#{env.BASE_URL}/api/v1/user/buy-gems/paypal-ipn', data-env="#{env.NODE_ENV == 'production' ? '' : 'sandbox'}", data-custom='?uid={{user._id}}&apiToken={{user.apiToken}}', data-return='#{env.BASE_URL}', data-rm='1', data-no_shipping='1')
|
script(src='/bower_components/JavaScriptButtons/dist/paypal-button.min.js?merchant=#{env.PAYPAL_MERCHANT}', data-button='buynow', data-name='20 Gems, Disable Ads, Donation to the Developers', data-quantity='1', data-amount='5', data-currency='USD', data-tax='0', data-callback='#{env.BASE_URL}/api/v2/user/buy-gems/paypal-ipn', data-env="#{env.NODE_ENV == 'production' ? '' : 'sandbox'}", data-custom='?uid={{user._id}}&apiToken={{user.apiToken}}', data-return='#{env.BASE_URL}', data-rm='1', data-no_shipping='1')
|
||||||
|
|
||||||
.modal-footer
|
.modal-footer
|
||||||
button.btn.btn-default.cancel(ng-click='modals.buyGems = false') Cancel
|
button.btn.btn-default.cancel(ng-click='modals.buyGems = false') Cancel
|
||||||
Reference in New Issue
Block a user