Merge branch 'develop' into api-v3

This commit is contained in:
Blade Barringer
2015-11-04 20:25:05 -06:00
11 changed files with 211 additions and 41 deletions

View File

@@ -179,5 +179,8 @@
"businessInquiries": "Business Inquiries",
"merchandiseInquiries": "Merchandise Inquiries",
"marketingInquiries": "Marketing/Social Media Inquiries",
"tweet": "Tweet"
"tweet": "Tweet",
"apps": "Apps",
"notifyAndroidApp": "Want us to notify you when the Android app is ready? Sign up for this mailing list!",
"checkOutIOSApp": "Check out our new iOS App!"
}

View File

@@ -3,7 +3,8 @@ import {
requester,
translate as t,
} from '../../../helpers/api-integration.helper';
import {v4 as generateRandomUserName} from 'uuid';
import { v4 as generateRandomUserName } from 'uuid';
import { each } from 'lodash';
describe('POST /register', () => {
@@ -137,4 +138,106 @@ describe('POST /register', () => {
});
});
});
context('successful login via api', () => {
let api, username, email, password;
beforeEach(() => {
api = requester();
username = generateRandomUserName();
email = `${username}@example.com`;
password = 'password';
});
it('sets all site tour values to -2 (already seen)', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.flags.tour).to.not.be.empty;
each(user.flags.tour, (value, attribute) => {
expect(value).to.eql(-2);
});
});
});
it('populates user with default todos, not no other task types', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.todos).to.not.be.empty;
expect(user.dailys).to.be.empty;
expect(user.habits).to.be.empty;
expect(user.rewards).to.be.empty;
});
});
it('populates user with default tags', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.tags).to.not.be.empty;
});
});
});
context('successful login with habitica-web header', () => {
let api, username, email, password;
beforeEach(() => {
api = requester({}, {'x-client': 'habitica-web'});
username = generateRandomUserName();
email = `${username}@example.com`;
password = 'password';
});
it('sets all common tutorial flags to true', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.flags.tour).to.not.be.empty;
each(user.flags.tutorial.common, (value, attribute) => {
expect(value).to.eql(true);
});
});
});
it('populates user with default todos, habits, and rewards', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.todos).to.not.be.empty;
expect(user.dailys).to.be.empty;
expect(user.habits).to.not.be.empty;
expect(user.rewards).to.not.be.empty;
});
});
it('populates user with default tags', () => {
return api.post('/register', {
username: username,
email: email,
password: password,
confirmPassword: password,
}).then((user) => {
expect(user.tags).to.not.be.empty;
});
});
});
});

View File

@@ -8,7 +8,14 @@ describe('GET /user/tasks/', () => {
let api, user;
beforeEach(() => {
return generateUser().then((_user) => {
return generateUser({
dailys: [
{text: 'daily', type: 'daily'},
{text: 'daily', type: 'daily'},
{text: 'daily', type: 'daily'},
{text: 'daily', type: 'daily'},
],
}).then((_user) => {
user = _user;
api = requester(user);
});
@@ -17,7 +24,7 @@ describe('GET /user/tasks/', () => {
it('gets all tasks', () => {
return api.get(`/user/tasks/`).then((tasks) => {
expect(tasks).to.be.an('array');
expect(tasks.length).to.be.greaterThan(4);
expect(tasks.length).to.be.greaterThan(3);
let task = tasks[0];
expect(task.id).to.exist;

View File

@@ -16,12 +16,12 @@ const API_TEST_SERVER_PORT = 3003;
// Sets up an abject that can make all REST requests
// If a user is passed in, the uuid and api token of
// the user are used to make the requests
export function requester(user={}) {
export function requester(user={}, additionalSets) {
return {
get: _requestMaker(user, 'get'),
post: _requestMaker(user, 'post'),
put: _requestMaker(user, 'put'),
del: _requestMaker(user, 'del'),
get: _requestMaker(user, 'get', additionalSets),
post: _requestMaker(user, 'post', additionalSets),
put: _requestMaker(user, 'put', additionalSets),
del: _requestMaker(user, 'del', additionalSets),
}
};
@@ -207,18 +207,22 @@ export function resetHabiticaDB() {
});
}
function _requestMaker(user, method) {
function _requestMaker(user, method, additionalSets) {
return (route, send, query) => {
return new Promise((resolve, reject) => {
let request = superagent[method](`http://localhost:${API_TEST_SERVER_PORT}/api/v2${route}`)
.accept('application/json');
if (user._id && user.apiToken) {
if (user && user._id && user.apiToken) {
request
.set('x-api-user', user._id)
.set('x-api-key', user.apiToken);
}
if (additionalSets) {
request.set(additionalSets);
}
request
.query(query)
.send(send)

View File

@@ -9,6 +9,8 @@ angular.module('habitrpg')
function($scope, $rootScope, User, $http, $location, $window, ApiUrl, $modal, Analytics) {
$scope.Analytics = Analytics;
$http.defaults.headers.common['x-client'] = 'habitica-web';
$scope.logout = function() {
localStorage.clear();
window.location.href = '/logout';

View File

@@ -36,6 +36,8 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
$rootScope.toJson = angular.toJson;
$rootScope.Payments = Payments;
$http.defaults.headers.common['x-client'] = 'habitica-web';
// Angular UI Router
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;

View File

@@ -123,6 +123,8 @@ api.registerUser = function(req, res, next) {
};
analytics.track('register', analyticsData)
user.registeredThrough = req.headers['x-client']
user.save(function(err, savedUser){
// Clean previous email preferences
// TODO when emails added to EmailUnsubcription they should use lowercase version

View File

@@ -481,34 +481,7 @@ UserSchema.pre('save', function(next) {
// Populate new users with default content
if (this.isNew){
//TODO for some reason this doesn't work here: `_.merge(this, shared.content.userDefaults);`
var self = this;
_.each(['habits', 'dailys', 'todos', 'rewards', 'tags'], function(taskType){
self[taskType] = _.map(shared.content.userDefaults[taskType], function(task){
var newTask = _.cloneDeep(task);
// Render task's text and notes in user's language
if(taskType === 'tags'){
// tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here
newTask.id = shared.uuid();
newTask.name = newTask.name(self.preferences.language);
}else{
newTask.text = newTask.text(self.preferences.language);
if(newTask.notes) {
newTask.notes = newTask.notes(self.preferences.language);
}
if(newTask.checklist){
newTask.checklist = _.map(newTask.checklist, function(checklistItem){
checklistItem.text = checklistItem.text(self.preferences.language);
return checklistItem;
});
}
}
return newTask;
});
});
_populateDefaultsForNewUser(this);
}
//this.markModified('tasks');
@@ -601,6 +574,57 @@ UserSchema.methods.unlink = function(options, cb) {
self.save(cb);
}
function _populateDefaultsForNewUser(user) {
var taskTypes;
if (user.registeredThrough === "habitica-web") {
taskTypes = ['habits', 'dailys', 'todos', 'rewards', 'tags'];
_.each(user.flags.tutorial.common, function(value, section) {
user.flags.tutorial.common[section] = true;
});
} else {
taskTypes = ['todos', 'tags']
user.flags.showTour = false;
_.each(user.flags.tour, function(value, section) {
user.flags.tour[section] = -2;
});
}
_populateDefaultTasks(user, taskTypes);
}
function _populateDefaultTasks (user, taskTypes) {
_.each(taskTypes, function(taskType){
user[taskType] = _.map(shared.content.userDefaults[taskType], function(task){
var newTask = _.cloneDeep(task);
// Render task's text and notes in user's language
if(taskType === 'tags'){
// tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here
newTask.id = shared.uuid();
newTask.name = newTask.name(user.preferences.language);
}else{
newTask.text = newTask.text(user.preferences.language);
if(newTask.notes) {
newTask.notes = newTask.notes(user.preferences.language);
}
if(newTask.checklist){
newTask.checklist = _.map(newTask.checklist, function(checklistItem){
checklistItem.text = checklistItem.text(user.preferences.language);
return checklistItem;
});
}
}
return newTask;
});
});
}
module.exports.schema = UserSchema;
module.exports.model = mongoose.model("User", UserSchema);
// Initially export an empty object so external requires will get

View File

@@ -18,7 +18,7 @@ router.get('/', i18n.getUserLanguage, locals, function(req, res) {
// -------- Marketing --------
var pages = ['front', 'privacy', 'terms', 'api', 'features', 'videos', 'contact', 'plans', 'new-stuff', 'community-guidelines', 'old-news', 'press-kit', 'faq'];
var pages = ['front', 'privacy', 'terms', 'api', 'features', 'videos', 'contact', 'plans', 'new-stuff', 'community-guidelines', 'old-news', 'press-kit', 'faq', 'apps'];
_.each(pages, function(name){
router.get('/static/' + name, i18n.getUserLanguage, locals, function(req, res) {

View File

@@ -8,7 +8,7 @@ footer.footer(ng-controller='FooterCtrl')
li
a(href='https://itunes.apple.com/us/app/habitica/id994882113?ls=1&mt=8', target='_blank')=env.t('mobileIOS')
li
a(href='https://play.google.com/store/apps/details?id=com.ocdevel.habitrpg', target='_blank')=env.t('mobileAndroid')
a(href='/static/apps')=env.t('mobileAndroid')
if env.isStaticPage
h4=env.t('language')
select(ng-change='changeLang()', ng-model='selectedLanguage', ng-options='language.name for language in languages')

View File

@@ -0,0 +1,23 @@
extends ./layout
block vars
- var layoutEnv = env
block title
title Habitica | 
=env.t('apps')
block content
.lead
=env.t('checkOutIOSApp')
.row.text-center
#ibb-widget-root-994882113
script.
(function(t,e,i,d){var o=t.getElementById(i),n=t.createElement(e);o.style.height=250;o.style.width=300;o.style.display='inline-block';n.id='ibb-widget',n.setAttribute('src',('https:'===t.location.protocol?'https://':'http://')+d),n.setAttribute('width','300'),n.setAttribute('height','250'),n.setAttribute('frameborder','0'),n.setAttribute('scrolling','no'),o.appendChild(n)})(document,'iframe','ibb-widget-root-994882113',"banners.itunes.apple.com/banner.html?partnerId=&aId=&bt=catalog&t=catalog_white&id=994882113&c=us&l=en-US&w=300&h=250&store=apps");
.lead
=env.t('notifyAndroidApp')
.row.text-center
.sendgrid-subscription-widget(data-token='WEc2mXZw9YqemYAJp3a%2FO%2FxyvSWuFCFS2x88bbdMa%2FJjEH%2FlDdpc%2Flbz4PPZZRZMnTmr8kNOzI6ypw%2Br3r55wQ%3D%3D')
script.
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?"http":"https";if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://s3.amazonaws.com/subscription-cdn/0.2/widget.min.js";fjs.parentNode.insertBefore(js,fjs);}}(document, "script", "sendgrid-subscription-widget-js");