diff --git a/rpg-docs/.meteor/.finished-upgraders b/rpg-docs/.meteor/.finished-upgraders index aa607041..910574ce 100644 --- a/rpg-docs/.meteor/.finished-upgraders +++ b/rpg-docs/.meteor/.finished-upgraders @@ -13,3 +13,5 @@ notices-for-facebook-graph-api-2 1.3.0-split-minifiers-package 1.4.0-remove-old-dev-bundle-link 1.4.1-add-shell-server-package +1.4.3-split-account-service-packages +1.5-add-dynamic-import-package diff --git a/rpg-docs/.meteor/packages b/rpg-docs/.meteor/packages index d3dffb6f..ba641bc6 100644 --- a/rpg-docs/.meteor/packages +++ b/rpg-docs/.meteor/packages @@ -3,13 +3,12 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -iron:router -accounts-password@1.3.3 +accounts-password@1.4.0 accounts-ui@1.1.9 random@1.0.10 dburles:collection-helpers reactive-var@1.0.11 -underscore@1.0.10 +underscore aldeed:collection2 matb33:collection-hooks zimme:collection-softremovable @@ -18,35 +17,40 @@ dburles:mongo-collection-instances percolate:migrations ecwyne:mathjs useraccounts:polymer -accounts-google@1.0.11 +accounts-google@1.2.0 splendido:accounts-meld -email@1.1.18 +email@1.2.3 meteorhacks:subs-manager chuangbo:marked reywood:iron-router-ga -meteor-base@1.0.4 +meteor-base@1.1.0 mobile-experience@1.0.4 -mongo@1.1.14 +mongo@1.2.0 blaze-html-templates session@1.1.7 jquery@1.11.10 -tracker@1.1.1 -logging@1.1.16 +tracker@1.1.3 +logging@1.1.17 reload@1.1.11 -ejson@1.0.13 +ejson@1.0.14 spacebars -check@1.2.4 +check@1.2.5 useraccounts:iron-routing wizonesolutions:canonical -standard-minifier-js@1.2.1 -shell-server@0.2.1 +standard-minifier-js@2.1.1 +shell-server@0.2.4 seba:minifiers-autoprefixer nikogosovd:multiple-uihooks templates:array -ecmascript@0.6.1 +ecmascript@0.8.2 es5-shim@4.6.15 differential:vulcanize -reactive-dict +reactive-dict@1.1.9 percolate:synced-cron ongoworks:speakingurl -service-configuration +service-configuration@1.0.11 +google-config-ui +dynamic-import +ddp-rate-limiter +rate-limit +iron:router diff --git a/rpg-docs/.meteor/release b/rpg-docs/.meteor/release index b7694ea3..0fa8d22d 100644 --- a/rpg-docs/.meteor/release +++ b/rpg-docs/.meteor/release @@ -1 +1 @@ -METEOR@1.4.2.6 +METEOR@1.6 diff --git a/rpg-docs/.meteor/versions b/rpg-docs/.meteor/versions index c2254df9..1d932436 100644 --- a/rpg-docs/.meteor/versions +++ b/rpg-docs/.meteor/versions @@ -1,53 +1,56 @@ -accounts-base@1.2.14 -accounts-google@1.0.11 +accounts-base@1.4.0 +accounts-google@1.3.0 accounts-oauth@1.1.15 -accounts-password@1.3.3 -accounts-ui@1.1.9 -accounts-ui-unstyled@1.1.13 +accounts-password@1.5.0 +accounts-ui@1.2.0 +accounts-ui-unstyled@1.3.0 aldeed:collection2@2.10.0 aldeed:collection2-core@1.2.0 aldeed:schema-deny@1.1.0 aldeed:schema-index@1.1.1 aldeed:simple-schema@1.5.3 -allow-deny@1.0.5 +allow-deny@1.1.0 autoupdate@1.3.12 -babel-compiler@6.13.0 -babel-runtime@1.0.1 +babel-compiler@6.24.7 +babel-runtime@1.1.1 base64@1.0.10 binary-heap@1.0.10 -blaze@2.3.0 -blaze-html-templates@1.1.0 +blaze@2.3.2 +blaze-html-templates@1.1.2 blaze-tools@1.0.10 -boilerplate-generator@1.0.11 +boilerplate-generator@1.3.1 caching-compiler@1.1.9 -caching-html-compiler@1.1.0 +caching-html-compiler@1.1.2 callback-hook@1.0.10 -check@1.2.4 +check@1.2.5 chuangbo:marked@0.3.5_1 coffeescript@1.11.1_4 dburles:collection-helpers@1.1.0 dburles:mongo-collection-instances@0.3.5 -ddp@1.2.5 -ddp-client@1.3.2 -ddp-common@1.2.8 -ddp-rate-limiter@1.0.6 -ddp-server@1.3.12 +ddp@1.4.0 +ddp-client@2.2.0 +ddp-common@1.3.0 +ddp-rate-limiter@1.0.7 +ddp-server@2.1.1 deps@1.0.12 diff-sequence@1.0.7 differential:vulcanize@3.0.0 -ecmascript@0.6.1 -ecmascript-runtime@0.3.15 +dynamic-import@0.2.1 +ecmascript@0.9.0 +ecmascript-runtime@0.5.0 +ecmascript-runtime-client@0.5.0 +ecmascript-runtime-server@0.5.0 ecwyne:mathjs@0.25.0 -ejson@1.0.13 -email@1.1.18 +ejson@1.1.0 +email@1.2.3 es5-shim@4.6.15 -fastclick@1.0.13 geojson-utils@1.0.10 -google@1.1.15 +google-config-ui@1.0.0 +google-oauth@1.2.4 hot-code-push@1.0.4 html-tools@1.0.11 htmljs@1.0.11 -http@1.2.10 +http@1.3.0 id-map@1.0.9 iron:controller@1.0.12 iron:core@1.0.11 @@ -55,45 +58,46 @@ iron:dynamic-template@1.0.12 iron:layout@1.0.12 iron:location@1.0.11 iron:middleware-stack@1.1.0 -iron:router@1.1.1 -iron:url@1.0.11 +iron:router@1.1.2 +iron:url@1.1.0 jquery@1.11.10 lai:collection-extensions@0.2.1_1 -launch-screen@1.1.0 -less@2.7.9 +launch-screen@1.1.1 +less@2.7.11 livedata@1.0.18 -localstorage@1.0.12 -logging@1.1.16 +localstorage@1.2.0 +logging@1.1.19 matb33:collection-hooks@0.8.4 mdg:validation-error@0.5.1 -meteor@1.6.0 -meteor-base@1.0.4 +meteor@1.8.2 +meteor-base@1.2.0 meteorhacks:subs-manager@1.6.4 minifier-css@1.2.16 -minifier-js@1.2.17 -minimongo@1.0.19 -mobile-experience@1.0.4 -mobile-status-bar@1.0.13 -modules@0.7.7 -modules-runtime@0.7.8 -momentjs:moment@2.17.1 -mongo@1.1.14 +minifier-js@2.2.2 +minimongo@1.4.2 +mobile-experience@1.0.5 +mobile-status-bar@1.0.14 +modules@0.11.0 +modules-runtime@0.9.1 +momentjs:moment@2.19.2 +mongo@1.3.0 +mongo-dev-server@1.1.0 mongo-id@1.0.6 nikogosovd:multiple-uihooks@0.1.8 -npm-bcrypt@0.9.2 -npm-mongo@2.2.16_1 -oauth@1.1.12 -oauth2@1.1.11 -observe-sequence@1.0.14 +npm-bcrypt@0.9.3 +npm-mongo@2.2.33 +oauth@1.2.0 +oauth2@1.2.0 +observe-sequence@1.0.16 ongoworks:speakingurl@9.0.0 ordered-dict@1.0.9 percolate:migrations@0.9.8 percolate:synced-cron@1.3.2 -promise@0.8.8 +promise@0.10.0 raix:eventemitter@0.1.3 random@1.0.10 -rate-limit@1.0.6 -reactive-dict@1.1.8 +rate-limit@1.0.8 +reactive-dict@1.2.0 reactive-var@1.0.11 reload@1.1.11 retry@1.0.9 @@ -103,27 +107,27 @@ seba:minifiers-autoprefixer@1.0.1 service-configuration@1.0.11 session@1.1.7 sha@1.0.9 -shell-server@0.2.1 -softwarerero:accounts-t9n@1.3.7 -spacebars@1.0.13 -spacebars-compiler@1.1.0 +shell-server@0.3.0 +softwarerero:accounts-t9n@1.3.11 +spacebars@1.0.15 +spacebars-compiler@1.1.3 splendido:accounts-emails-field@1.2.0 splendido:accounts-meld@1.3.1 srp@1.0.10 -standard-minifier-js@1.2.2 +standard-minifier-js@2.2.2 templates:array@1.0.3 -templating@1.3.0 -templating-compiler@1.3.0 -templating-runtime@1.3.0 -templating-tools@1.1.0 -tracker@1.1.1 -ui@1.0.12 +templating@1.3.2 +templating-compiler@1.3.3 +templating-runtime@1.3.2 +templating-tools@1.1.2 +tracker@1.1.3 +ui@1.0.13 underscore@1.0.10 -url@1.0.11 +url@1.1.0 useraccounts:core@1.14.2 useraccounts:iron-routing@1.14.2 useraccounts:polymer@1.14.2 -webapp@1.3.12 +webapp@1.4.0 webapp-hashing@1.0.9 wizonesolutions:canonical@0.0.5 zimme:collection-behaviours@1.1.3 diff --git a/rpg-docs/Model/Character/Characters.js b/rpg-docs/Model/Character/Characters.js index e950409a..7ba2ac97 100644 --- a/rpg-docs/Model/Character/Characters.js +++ b/rpg-docs/Model/Character/Characters.js @@ -164,9 +164,9 @@ Schemas.Character = new SimpleSchema({ //permissions party: {type: String, regEx: SimpleSchema.RegEx.Id, optional: true}, - owner: {type: String, regEx: SimpleSchema.RegEx.Id}, - readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []}, - writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []}, + owner: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, + readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [], index: 1}, + writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [], index: 1}, color: { type: String, allowedValues: _.pluck(colorOptions, "key"), @@ -185,11 +185,13 @@ Schemas.Character = new SimpleSchema({ type: String, defaultValue: "whitelist", allowedValues: ["whitelist", "public"], + index: 1, }, "settings.swapStatAndModifier": {type: Boolean, defaultValue: false}, "settings.exportFeatures": {type: Boolean, defaultValue: true}, "settings.exportAttacks": {type: Boolean, defaultValue: true}, "settings.exportDescription": {type: Boolean, defaultValue: true}, + "settings.newUserExperience": {type: Boolean, optional: true}, }); Characters.attachSchema(Schemas.Character); @@ -283,6 +285,7 @@ if (Meteor.isClient) { //create a local memoize with a argument concatenating hash function var memoize = function(f) { + if (Meteor.isServer) return f; return Tracker.memoize(f, function() { return _.reduce(arguments, function(memo, arg) { return memo + arg; @@ -296,6 +299,7 @@ Characters.calculate = { var fieldSelector = {}; fieldSelector[fieldName] = 1; var char = Characters.findOne(charId, {fields: fieldSelector}); + if (!char) return; var field = char[fieldName]; if (field === undefined){ throw new Meteor.Error( @@ -329,6 +333,7 @@ Characters.calculate = { }, attributeValue: memoize(function(charId, attributeName){ var attribute = Characters.calculate.getField(charId, attributeName); + if (!attribute) return; //base value var value = Characters.calculate.attributeBase(charId, attributeName); //plus adjustment @@ -340,6 +345,7 @@ Characters.calculate = { }), skillMod: memoize(preventLoop(function(charId, skillName){ var skill = Characters.calculate.getField(charId, skillName); + if (!skill) return; //get the final value of the ability score var ability = Characters.calculate.attributeValue(charId, skill.ability); @@ -391,7 +397,6 @@ Characters.calculate = { return prof && prof.value || 0; }), passiveSkill: memoize(function(charId, skillName){ - var skill = Characters.calculate.getField(charId, skillName); var mod = +Characters.calculate.skillMod(charId, skillName); var value = 10 + mod; Effects.find( @@ -552,6 +557,10 @@ if (Meteor.isServer){ }); Characters.before.insert(function(userId, doc) { doc.urlName = getSlug(doc.name, {maintainCase: true}) || "-"; + // The first character a user creates should have the new user experience + if (!Characters.find({owner: userId}).count()){ + doc.settings.newUserExperience = true; + } }); } diff --git a/rpg-docs/Model/Users/Users.js b/rpg-docs/Model/Users/Users.js index f9011409..bdbbdda4 100644 --- a/rpg-docs/Model/Users/Users.js +++ b/rpg-docs/Model/Users/Users.js @@ -1,3 +1,75 @@ +Schemas.UserProfile = new SimpleSchema({ + username: { + type: String, + optional: true, + }, +}); + +Schemas.User = new SimpleSchema({ + username: { + type: String, + optional: true, + }, + profile: { + type: Schemas.UserProfile, + optional: true, + }, + emails: { + type: Array, + optional: true, + }, + "emails.$": { + type: Object, + }, + "emails.$.address": { + type: String, + regEx: SimpleSchema.RegEx.Email, + }, + "emails.$.verified": { + type: Boolean, + }, + registered_emails: { + type: Array, + optional: true, + }, + "registered_emails.$": { + type: Object, + blackbox: true, + }, + createdAt: { + type: Date + }, + services: { + type: Object, + optional: true, + blackbox: true, + }, + roles: { + type: Object, + optional: true, + blackbox: true, + }, + roles: { + type: Array, + optional: true, + }, + "roles.$": { + type: String + }, + // In order to avoid an 'Exception in setInterval callback' from Meteor + heartbeat: { + type: Date, + optional: true, + }, + apiKey: { + type: String, + index: 1, + optional: true, + }, +}); + +Meteor.users.attachSchema(Schemas.User); + Meteor.users.allow({ update: function(userId, doc, fields, modifier) { if ( @@ -21,3 +93,13 @@ Meteor.users.allow({ } } }); + +if (Meteor.isServer) Meteor.methods({ + generateMyApiKey() { + var user = Meteor.users.findOne(this.userId); + if (!user) return; + if (user && user.apiKey) return; + var apiKey = Random.id(30); + Meteor.users.update(this.userId, {$set: {apiKey}}); + }, +}); diff --git a/rpg-docs/Routes/API.js b/rpg-docs/Routes/API.js new file mode 100644 index 00000000..451ac2ee --- /dev/null +++ b/rpg-docs/Routes/API.js @@ -0,0 +1,53 @@ +Router.map(function() { + this.route("vmixCharacter", { + path: "/vmix-character/:_id/", + where: "server", + action: function() { + this.response.setHeader("Content-Type", "application/json"); + var query = this.params.query; + var key = query && query.key; + ifKeyValid(key, this.response, () => + this.response.end(vMixCharacter(this.params._id)) + ); + }, + }); + this.route("vmixParty", { + path: "/vmix-party/:_id/", + where: "server", + action: function() { + this.response.setHeader("Content-Type", "application/json"); + var query = this.params.query; + var key = query && query.key; + ifKeyValid(key, this.response, () => + this.response.end(vMixParty(this.params._id)) + ); + }, + }); +}); + +var ifKeyValid = function(apiKey, response, callback){ + if (!apiKey){ + response.writeHead(403, "You must use an api key to access this api"); + response.end(); + } else if (!isKeyValid(apiKey)){ + response.writeHead(403, "API key is invalid"); + response.end(); + } else if (isRateLimited(apiKey)){ + response.writeHead(429, "Too many requests"); + response.end(); + } else { + rateLimiter.increment({apiKey}) + callback(); + } +}; + +var isKeyValid = function(apiKey){ + return !!Meteor.users.findOne({apiKey}); +}; + +var rateLimiter = new RateLimiter(); +rateLimiter.addRule({apiKey: String}, 2, 10000); + +var isRateLimited = function(apiKey){ + return !rateLimiter.check({apiKey}).allowed; +}; diff --git a/rpg-docs/client/globalHelpers/canEditCharacter.js b/rpg-docs/client/globalHelpers/canEditCharacter.js index 2de1b6d6..57d0ce6f 100644 --- a/rpg-docs/client/globalHelpers/canEditCharacter.js +++ b/rpg-docs/client/globalHelpers/canEditCharacter.js @@ -3,7 +3,8 @@ Template.registerHelper("canEditCharacter", function(charId) { }); canEditCharacter = function(charId) { - var char = Characters.findOne(charId) + var char = Characters.findOne(charId); + if (!char) return false; var userId = Meteor.userId(); return char.owner === userId || _.contains(char.writers, userId); diff --git a/rpg-docs/client/style/bounce.css b/rpg-docs/client/style/bounce.css new file mode 100644 index 00000000..481754d5 --- /dev/null +++ b/rpg-docs/client/style/bounce.css @@ -0,0 +1,17 @@ +@keyframes bounce { + from { + transform: translate(0px,0px); + } + to { + transform: translate(0px,-16px); + } +} + +.bounce{ + animation-name: bounce; + animation-duration: 0.3s; + animation-direction: alternate; + animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); + animation-delay: 0s; + animation-iteration-count: infinite; +} diff --git a/rpg-docs/client/views/character/characterSettings/deleteCharacterConfirmation.js b/rpg-docs/client/views/character/characterSettings/deleteCharacterConfirmation.js index af8a64c2..fda5ba5c 100644 --- a/rpg-docs/client/views/character/characterSettings/deleteCharacterConfirmation.js +++ b/rpg-docs/client/views/character/characterSettings/deleteCharacterConfirmation.js @@ -10,7 +10,7 @@ Template.deleteCharacterConfirmation.helpers({ if (Template.instance().canDelete.get()) { return "background: #d23f31; color: white;"; } - } + }, }); Template.deleteCharacterConfirmation.events({ @@ -20,9 +20,7 @@ Template.deleteCharacterConfirmation.events({ }, "click #deleteButton": function(event, instance) { if (instance.find("#nameInput").value === this.name) { - popDialogStack(); - Router.go("/characterList"); - Characters.remove(this._id); + popDialogStack(true); } }, "click .cancelButton": function(event, instance){ diff --git a/rpg-docs/client/views/character/characterSheet.html b/rpg-docs/client/views/character/characterSheet.html index 5573ee4b..5048856f 100644 --- a/rpg-docs/client/views/character/characterSheet.html +++ b/rpg-docs/client/views/character/characterSheet.html @@ -4,7 +4,7 @@ {{/if}}
- +
@@ -47,17 +47,18 @@
- Stats - Features + Stats + Features Inventory {{#unless hideSpellcasting}} Spells {{/unless}} Persona - Journal + Journal
+ {{#if newUserExperience}}{{> newUserStepper}}{{/if}}
diff --git a/rpg-docs/client/views/character/characterSheet.js b/rpg-docs/client/views/character/characterSheet.js index 655863df..f2984779 100644 --- a/rpg-docs/client/views/character/characterSheet.js +++ b/rpg-docs/client/views/character/characterSheet.js @@ -29,7 +29,7 @@ Template.characterSheet.onRendered(function() { tabFabMenus = _.times(6, (n) => tabPages[n].find(".mini-holder") ); - }) + }); //watch this character and make sure their encumbrance is updated //trackEncumbranceConditions(this.data._id, this); @@ -175,6 +175,18 @@ Template.characterSheet.helpers({ var char = Characters.findOne(this._id); return char && char.settings.hideSpellcasting; }, + newUserExperience: function(){ + var char = Characters.findOne(this._id); + return char && char.settings.newUserExperience; + }, + shouldBounce: function(tab){ + const selected = Session.get(this._id + ".selectedTab") + const step = Session.get("newUserExperienceStep"); + if (selected == tab) return false; + return (tab === 1 && step === 0) || + (tab === 5 && step === 1) || + (tab === 0 && step === 2); + }, }); Template.characterSheet.events({ @@ -190,6 +202,12 @@ Template.characterSheet.events({ data: this, template: "deleteCharacterConfirmation", element: event.currentTarget.parentElement.parentElement, + callback: (result) => { + if (result === true){ + Router.go("/characterList"); + Tracker.afterFlush(() => Characters.remove(this._id)); + } + }, }); }, "click #shareCharacter": function(event, instance){ diff --git a/rpg-docs/client/views/character/features/featureDialog/featureDialog.html b/rpg-docs/client/views/character/features/featureDialog/featureDialog.html index c73a988c..187e2216 100644 --- a/rpg-docs/client/views/character/features/featureDialog/featureDialog.html +++ b/rpg-docs/client/views/character/features/featureDialog/featureDialog.html @@ -42,9 +42,20 @@ diff --git a/rpg-docs/client/views/character/features/features.js b/rpg-docs/client/views/character/features/features.js index ad08dec6..17873a2f 100644 --- a/rpg-docs/client/views/character/features/features.js +++ b/rpg-docs/client/views/character/features/features.js @@ -59,6 +59,10 @@ Template.features.helpers({ hasCharacters: function(string){ return string && string.match(/\S/); }, + shouldFloatyButtonBounce: function(){ + const step = Session.get("newUserExperienceStep"); + return step === 0 && Features.find({charId: this._id}).count() <= 1; + }, }); Template.features.events({ diff --git a/rpg-docs/client/views/character/inventory/inventory.html b/rpg-docs/client/views/character/inventory/inventory.html index cf823d5f..c135c6ec 100644 --- a/rpg-docs/client/views/character/inventory/inventory.html +++ b/rpg-docs/client/views/character/inventory/inventory.html @@ -110,12 +110,12 @@
{{round totalWeight}} lbs
-
+
- Container carried + {{#simpleTooltip}} Container carried{{/simpleTooltip}}
@@ -136,21 +136,21 @@ class="addContainer" mini> - New container + {{#simpleTooltip class="always"}} Container {{/simpleTooltip}}
- Library item + {{#simpleTooltip class="always"}} Item from library {{/simpleTooltip}}
- New item + {{#simpleTooltip class="always"}} Item {{/simpleTooltip}}
{{/fabMenu}} {{/if}} diff --git a/rpg-docs/client/views/character/journal/journal.html b/rpg-docs/client/views/character/journal/journal.html index ca5c1c14..8632954c 100644 --- a/rpg-docs/client/views/character/journal/journal.html +++ b/rpg-docs/client/views/character/journal/journal.html @@ -53,7 +53,7 @@
-
+
{{race}}
@@ -83,9 +83,12 @@
{{#if canEditCharacter _id}} - +
+ + + {{#simpleTooltip}}Add Note{{/simpleTooltip}} +
{{/if}} diff --git a/rpg-docs/client/views/character/journal/journal.js b/rpg-docs/client/views/character/journal/journal.js index 959b0d15..a1cbef98 100644 --- a/rpg-docs/client/views/character/journal/journal.js +++ b/rpg-docs/client/views/character/journal/journal.js @@ -50,6 +50,9 @@ Template.journal.helpers({ var char = Characters.findOne(this._id, {fields: {race: 1}}); return char && char.race; }, + shouldRaceBounce: function(){ + return Session.get("newUserExperienceStep") === 1; + }, }); Template.journal.events({ diff --git a/rpg-docs/client/views/character/journal/raceDialog/raceDialog.html b/rpg-docs/client/views/character/journal/raceDialog/raceDialog.html index ab4c73c5..190e539c 100644 --- a/rpg-docs/client/views/character/journal/raceDialog/raceDialog.html +++ b/rpg-docs/client/views/character/journal/raceDialog/raceDialog.html @@ -1,11 +1,34 @@