mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
Merge branch 'develop' into api-v3
This commit is contained in:
@@ -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!"
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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')
|
||||
|
||||
23
website/views/static/apps.jade
Normal file
23
website/views/static/apps.jade
Normal 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");
|
||||
|
||||
Reference in New Issue
Block a user