Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ce1b6aff8 | ||
|
|
41731212ef |
34
README.md
34
README.md
@@ -37,7 +37,7 @@ changes on the fly. Let's look at a hypothetical example.
|
|||||||
Getting started
|
Getting started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Running DiceCloud locally, either to host it yourself away from an internet
|
Running DiceCloud locally, either to run it locally, away from an internet
|
||||||
connection, or to contribute to developing it further, is fairly
|
connection, or to contribute to developing it further, is fairly
|
||||||
straightforward and it should work on Linux, Windows, and Mac.
|
straightforward and it should work on Linux, Windows, and Mac.
|
||||||
|
|
||||||
@@ -45,18 +45,29 @@ You'll need to have installed:
|
|||||||
|
|
||||||
- [git](https://www.atlassian.com/git/tutorials/install-git)
|
- [git](https://www.atlassian.com/git/tutorials/install-git)
|
||||||
- [Meteor](https://www.meteor.com/install)
|
- [Meteor](https://www.meteor.com/install)
|
||||||
- [Bower](https://bower.io/)
|
|
||||||
|
|
||||||
Then, it's just a matter of cloning this repository into a folder, installing the bower dependencies and running
|
Then, it's just a matter of cloning this repository into a folder, installing the dependencies and running
|
||||||
`meteor` in the app directory.
|
`meteor` in the app directory:
|
||||||
|
|
||||||
`git clone https://github.com/ThaumRystra/DiceCloud dicecloud`
|
`git clone https://github.com/ThaumRystra/DiceCloud dicecloud`
|
||||||
`cd dicecloud`
|
`cd dicecloud`
|
||||||
`cd app`
|
`cd app`
|
||||||
`bower install`
|
`meteor npm install`
|
||||||
`meteor`
|
`meteor`
|
||||||
|
|
||||||
You should see this:
|
If you edit the source code at this point, Meteor will rebuild the server with
|
||||||
|
your changes.
|
||||||
|
|
||||||
|
If you want to simulate a production environment, run `meteor --production`
|
||||||
|
|
||||||
|
This will minimize all the files served to your browser, and load a lot faster,
|
||||||
|
in exchange for not watching the source code for changes.
|
||||||
|
|
||||||
|
Note that this is not how you should deploy Meteor to your own web server, that
|
||||||
|
is documented here: https://guide.meteor.com/deployment.html
|
||||||
|
|
||||||
|
After running `meteor` or `meteor --production`, you should see this, possibly
|
||||||
|
mixed with other logged text:
|
||||||
|
|
||||||
```
|
```
|
||||||
=> Started proxy.
|
=> Started proxy.
|
||||||
@@ -69,3 +80,14 @@ You should see this:
|
|||||||
Now, visiting http://localhost:3000/ should show you an empty instance of
|
Now, visiting http://localhost:3000/ should show you an empty instance of
|
||||||
DiceCloud running.
|
DiceCloud running.
|
||||||
|
|
||||||
|
To stop the process when you are done (or if it gets stuck) press `ctrl-c`
|
||||||
|
|
||||||
|
## Adding default documents
|
||||||
|
|
||||||
|
Navigate to `/dataSources/srd/srdimport.js`, and follow the steps under
|
||||||
|
'First Setup', running the code in your browser's console, while logged in to
|
||||||
|
your own instance of DiceCloud.
|
||||||
|
|
||||||
|
Do not run code in your browser console on the live version of DiceCloud hosted
|
||||||
|
at dicecloud.com, as doing so could result in a large number of denied requests
|
||||||
|
to the server, and may get your account permanently banned.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ meteor-base@1.4.0
|
|||||||
mobile-experience@1.0.5
|
mobile-experience@1.0.5
|
||||||
mongo@1.6.0
|
mongo@1.6.0
|
||||||
blaze-html-templates
|
blaze-html-templates
|
||||||
session@1.1.8
|
session@1.2.0
|
||||||
jquery@1.11.10
|
jquery@1.11.10
|
||||||
tracker@1.2.0
|
tracker@1.2.0
|
||||||
logging@1.1.20
|
logging@1.1.20
|
||||||
@@ -36,13 +36,11 @@ ejson@1.1.0
|
|||||||
spacebars
|
spacebars
|
||||||
check@1.3.1
|
check@1.3.1
|
||||||
useraccounts:iron-routing
|
useraccounts:iron-routing
|
||||||
wizonesolutions:canonical
|
|
||||||
standard-minifier-js@2.4.0
|
|
||||||
shell-server@0.4.0
|
shell-server@0.4.0
|
||||||
seba:minifiers-autoprefixer
|
seba:minifiers-autoprefixer
|
||||||
nikogosovd:multiple-uihooks
|
nikogosovd:multiple-uihooks
|
||||||
templates:array
|
templates:array
|
||||||
ecmascript@0.12.0
|
ecmascript@0.12.4
|
||||||
es5-shim@4.8.0
|
es5-shim@4.8.0
|
||||||
differential:vulcanize
|
differential:vulcanize
|
||||||
reactive-dict@1.2.1
|
reactive-dict@1.2.1
|
||||||
@@ -54,3 +52,5 @@ ddp-rate-limiter@1.0.7
|
|||||||
rate-limit@1.0.9
|
rate-limit@1.0.9
|
||||||
iron:router
|
iron:router
|
||||||
littledata:synced-cron
|
littledata:synced-cron
|
||||||
|
montiapm:agent
|
||||||
|
zodern:standard-minifier-js
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
METEOR@1.8
|
METEOR@1.8.0.2
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ accounts-google@1.3.2
|
|||||||
accounts-oauth@1.1.16
|
accounts-oauth@1.1.16
|
||||||
accounts-password@1.5.1
|
accounts-password@1.5.1
|
||||||
accounts-ui@1.3.1
|
accounts-ui@1.3.1
|
||||||
accounts-ui-unstyled@1.4.1
|
accounts-ui-unstyled@1.4.2
|
||||||
aldeed:collection2@2.10.0
|
aldeed:collection2@2.10.0
|
||||||
aldeed:collection2-core@1.2.0
|
aldeed:collection2-core@1.2.0
|
||||||
aldeed:schema-deny@1.1.0
|
aldeed:schema-deny@1.1.0
|
||||||
aldeed:schema-index@1.1.1
|
aldeed:schema-index@1.1.1
|
||||||
aldeed:simple-schema@1.5.4
|
aldeed:simple-schema@1.5.4
|
||||||
allow-deny@1.1.0
|
allow-deny@1.1.0
|
||||||
autoupdate@1.5.0
|
autoupdate@1.5.1
|
||||||
babel-compiler@7.2.0
|
babel-compiler@7.2.4
|
||||||
babel-runtime@1.3.0
|
babel-runtime@1.3.0
|
||||||
base64@1.0.11
|
base64@1.0.11
|
||||||
binary-heap@1.0.11
|
binary-heap@1.0.11
|
||||||
@@ -19,7 +19,7 @@ blaze@2.3.3
|
|||||||
blaze-html-templates@1.1.2
|
blaze-html-templates@1.1.2
|
||||||
blaze-tools@1.0.10
|
blaze-tools@1.0.10
|
||||||
boilerplate-generator@1.6.0
|
boilerplate-generator@1.6.0
|
||||||
caching-compiler@1.2.0
|
caching-compiler@1.2.1
|
||||||
caching-html-compiler@1.1.3
|
caching-html-compiler@1.1.3
|
||||||
callback-hook@1.1.0
|
callback-hook@1.1.0
|
||||||
check@1.3.1
|
check@1.3.1
|
||||||
@@ -33,10 +33,10 @@ ddp-common@1.4.0
|
|||||||
ddp-rate-limiter@1.0.7
|
ddp-rate-limiter@1.0.7
|
||||||
ddp-server@2.2.0
|
ddp-server@2.2.0
|
||||||
deps@1.0.12
|
deps@1.0.12
|
||||||
diff-sequence@1.1.0
|
diff-sequence@1.1.1
|
||||||
differential:vulcanize@3.0.0
|
differential:vulcanize@3.0.0
|
||||||
dynamic-import@0.5.0
|
dynamic-import@0.5.1
|
||||||
ecmascript@0.12.0
|
ecmascript@0.12.6
|
||||||
ecmascript-runtime@0.7.0
|
ecmascript-runtime@0.7.0
|
||||||
ecmascript-runtime-client@0.8.0
|
ecmascript-runtime-client@0.8.0
|
||||||
ecmascript-runtime-server@0.7.1
|
ecmascript-runtime-server@0.7.1
|
||||||
@@ -44,14 +44,14 @@ ecwyne:mathjs@0.25.0
|
|||||||
ejson@1.1.0
|
ejson@1.1.0
|
||||||
email@1.2.3
|
email@1.2.3
|
||||||
es5-shim@4.8.0
|
es5-shim@4.8.0
|
||||||
fetch@0.1.0
|
fetch@0.1.1
|
||||||
geojson-utils@1.0.10
|
geojson-utils@1.0.10
|
||||||
google-config-ui@1.0.1
|
google-config-ui@1.0.1
|
||||||
google-oauth@1.2.6
|
google-oauth@1.2.6
|
||||||
hot-code-push@1.0.4
|
hot-code-push@1.0.4
|
||||||
html-tools@1.0.11
|
html-tools@1.0.11
|
||||||
htmljs@1.0.11
|
htmljs@1.0.11
|
||||||
http@1.4.1
|
http@1.4.2
|
||||||
id-map@1.1.0
|
id-map@1.1.0
|
||||||
inter-process-messaging@0.1.0
|
inter-process-messaging@0.1.0
|
||||||
iron:controller@1.0.12
|
iron:controller@1.0.12
|
||||||
@@ -64,6 +64,7 @@ iron:router@1.1.2
|
|||||||
iron:url@1.1.0
|
iron:url@1.1.0
|
||||||
jquery@1.11.11
|
jquery@1.11.11
|
||||||
lai:collection-extensions@0.2.1_1
|
lai:collection-extensions@0.2.1_1
|
||||||
|
lamhieu:meteorx@2.0.1
|
||||||
launch-screen@1.1.1
|
launch-screen@1.1.1
|
||||||
less@2.8.0
|
less@2.8.0
|
||||||
littledata:synced-cron@1.5.1
|
littledata:synced-cron@1.5.1
|
||||||
@@ -72,32 +73,33 @@ localstorage@1.2.0
|
|||||||
logging@1.1.20
|
logging@1.1.20
|
||||||
matb33:collection-hooks@0.8.4
|
matb33:collection-hooks@0.8.4
|
||||||
mdg:validation-error@0.5.1
|
mdg:validation-error@0.5.1
|
||||||
meteor@1.9.2
|
meteor@1.9.3
|
||||||
meteor-base@1.4.0
|
meteor-base@1.4.0
|
||||||
meteorhacks:subs-manager@1.6.4
|
meteorhacks:subs-manager@1.6.4
|
||||||
minifier-css@1.4.0
|
minifier-css@1.4.2
|
||||||
minifier-js@2.4.0
|
|
||||||
minimongo@1.4.5
|
minimongo@1.4.5
|
||||||
mobile-experience@1.0.5
|
mobile-experience@1.0.5
|
||||||
mobile-status-bar@1.0.14
|
mobile-status-bar@1.0.14
|
||||||
modern-browsers@0.1.2
|
modern-browsers@0.1.4
|
||||||
modules@0.13.0
|
modules@0.13.0
|
||||||
modules-runtime@0.10.2
|
modules-runtime@0.10.3
|
||||||
momentjs:moment@2.22.2
|
momentjs:moment@2.24.0
|
||||||
mongo@1.6.0
|
mongo@1.6.2
|
||||||
mongo-decimal@0.1.0
|
mongo-decimal@0.1.1
|
||||||
mongo-dev-server@1.1.0
|
mongo-dev-server@1.1.0
|
||||||
mongo-id@1.0.7
|
mongo-id@1.0.7
|
||||||
|
mongo-livedata@1.0.12
|
||||||
|
montiapm:agent@2.35.0
|
||||||
nikogosovd:multiple-uihooks@0.1.8
|
nikogosovd:multiple-uihooks@0.1.8
|
||||||
npm-bcrypt@0.9.3
|
npm-bcrypt@0.9.3
|
||||||
npm-mongo@3.1.1
|
npm-mongo@3.1.2
|
||||||
oauth@1.2.3
|
oauth@1.2.8
|
||||||
oauth2@1.2.1
|
oauth2@1.2.1
|
||||||
observe-sequence@1.0.16
|
observe-sequence@1.0.16
|
||||||
ongoworks:speakingurl@9.0.0
|
ongoworks:speakingurl@9.0.0
|
||||||
ordered-dict@1.1.0
|
ordered-dict@1.1.0
|
||||||
percolate:migrations@0.9.8
|
percolate:migrations@0.9.8
|
||||||
promise@0.11.1
|
promise@0.11.2
|
||||||
raix:eventemitter@0.1.3
|
raix:eventemitter@0.1.3
|
||||||
random@1.1.0
|
random@1.1.0
|
||||||
rate-limit@1.0.9
|
rate-limit@1.0.9
|
||||||
@@ -107,9 +109,9 @@ reload@1.2.0
|
|||||||
retry@1.1.0
|
retry@1.1.0
|
||||||
reywood:iron-router-ga@0.7.1
|
reywood:iron-router-ga@0.7.1
|
||||||
routepolicy@1.1.0
|
routepolicy@1.1.0
|
||||||
seba:minifiers-autoprefixer@1.1.1
|
seba:minifiers-autoprefixer@1.1.2
|
||||||
service-configuration@1.0.11
|
service-configuration@1.0.11
|
||||||
session@1.1.8
|
session@1.2.0
|
||||||
sha@1.0.9
|
sha@1.0.9
|
||||||
shell-server@0.4.0
|
shell-server@0.4.0
|
||||||
socket-stream-client@0.2.2
|
socket-stream-client@0.2.2
|
||||||
@@ -119,7 +121,6 @@ spacebars-compiler@1.1.3
|
|||||||
splendido:accounts-emails-field@1.2.0
|
splendido:accounts-emails-field@1.2.0
|
||||||
splendido:accounts-meld@1.3.1
|
splendido:accounts-meld@1.3.1
|
||||||
srp@1.0.12
|
srp@1.0.12
|
||||||
standard-minifier-js@2.4.0
|
|
||||||
templates:array@1.0.3
|
templates:array@1.0.3
|
||||||
templating@1.3.2
|
templating@1.3.2
|
||||||
templating-compiler@1.3.3
|
templating-compiler@1.3.3
|
||||||
@@ -132,8 +133,9 @@ url@1.2.0
|
|||||||
useraccounts:core@1.14.2
|
useraccounts:core@1.14.2
|
||||||
useraccounts:iron-routing@1.14.2
|
useraccounts:iron-routing@1.14.2
|
||||||
useraccounts:polymer@1.14.2
|
useraccounts:polymer@1.14.2
|
||||||
webapp@1.7.0
|
webapp@1.7.3
|
||||||
webapp-hashing@1.0.9
|
webapp-hashing@1.0.9
|
||||||
wizonesolutions:canonical@0.0.5
|
|
||||||
zimme:collection-behaviours@1.1.3
|
zimme:collection-behaviours@1.1.3
|
||||||
zimme:collection-softremovable@1.0.5
|
zimme:collection-softremovable@1.0.5
|
||||||
|
zodern:minifier-js@3.0.0
|
||||||
|
zodern:standard-minifier-js@3.0.0
|
||||||
|
|||||||
68
app/package-lock.json
generated
68
app/package-lock.json
generated
@@ -100,9 +100,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bower": {
|
"bower": {
|
||||||
"version": "1.8.4",
|
"version": "1.8.8",
|
||||||
"resolved": "https://registry.npmjs.org/bower/-/bower-1.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/bower/-/bower-1.8.8.tgz",
|
||||||
"integrity": "sha1-54dqB23rgTf30GUl3F6MZtuC8oo="
|
"integrity": "sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A=="
|
||||||
},
|
},
|
||||||
"buffer-from": {
|
"buffer-from": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
@@ -1126,37 +1126,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"inherits": "~2.0.1",
|
"inherits": "~2.0.1",
|
||||||
"readable-stream": "^2.0.2"
|
"readable-stream": "^2.0.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"readable-stream": {
|
|
||||||
"version": "2.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
|
||||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
|
||||||
"requires": {
|
|
||||||
"core-util-is": "~1.0.0",
|
|
||||||
"inherits": "~2.0.3",
|
|
||||||
"isarray": "~1.0.0",
|
|
||||||
"process-nextick-args": "~2.0.0",
|
|
||||||
"safe-buffer": "~5.1.1",
|
|
||||||
"string_decoder": "~1.1.1",
|
|
||||||
"util-deprecate": "~1.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string_decoder": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "~5.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stream-http": {
|
"stream-http": {
|
||||||
@@ -1169,37 +1138,6 @@
|
|||||||
"readable-stream": "^2.3.3",
|
"readable-stream": "^2.3.3",
|
||||||
"to-arraybuffer": "^1.0.0",
|
"to-arraybuffer": "^1.0.0",
|
||||||
"xtend": "^4.0.0"
|
"xtend": "^4.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"readable-stream": {
|
|
||||||
"version": "2.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
|
||||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
|
||||||
"requires": {
|
|
||||||
"core-util-is": "~1.0.0",
|
|
||||||
"inherits": "~2.0.3",
|
|
||||||
"isarray": "~1.0.0",
|
|
||||||
"process-nextick-args": "~2.0.0",
|
|
||||||
"safe-buffer": "~5.1.1",
|
|
||||||
"string_decoder": "~1.1.1",
|
|
||||||
"util-deprecate": "~1.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string_decoder": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "~5.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"@babel/runtime": "^7.1.2",
|
"@babel/runtime": "^7.1.2",
|
||||||
"@polymer/polymer": "^1.2.5-npm-test.2",
|
"@polymer/polymer": "^1.2.5-npm-test.2",
|
||||||
"bcrypt": "^1.0.3",
|
"bcrypt": "^1.0.3",
|
||||||
"bower": "^1.7.9",
|
"bower": "^1.8.8",
|
||||||
"core-js": "^2.5.7",
|
"core-js": "^2.5.7",
|
||||||
"fibers": "^2.0.2",
|
"fibers": "^2.0.2",
|
||||||
"file-saver": "^2.0.1",
|
"file-saver": "^2.0.1",
|
||||||
|
|||||||
@@ -1,256 +1,262 @@
|
|||||||
import request from 'request';
|
import request from 'request';
|
||||||
|
|
||||||
const CLIENT_ID = Meteor.settings.public.patreon.clientId;
|
if (
|
||||||
const CLIENT_SECRET = Meteor.settings.patreon.clientSecret;
|
Meteor.settings &&
|
||||||
const CREATOR_ACCESS_TOKEN = Meteor.settings.patreon.creatorAccessToken;
|
Meteor.settings.public &&
|
||||||
const CAMPAIGN_ID = Meteor.settings.public.patreon.campaignId;
|
Meteor.settings.public.patreon
|
||||||
|
) {
|
||||||
|
const CLIENT_ID = Meteor.settings.public.patreon.clientId;
|
||||||
|
const CLIENT_SECRET = Meteor.settings.patreon.clientSecret;
|
||||||
|
const CREATOR_ACCESS_TOKEN = Meteor.settings.patreon.creatorAccessToken;
|
||||||
|
const CAMPAIGN_ID = Meteor.settings.public.patreon.campaignId;
|
||||||
|
|
||||||
// Handle redirects from patreon
|
// Handle redirects from patreon
|
||||||
Router.map(function () {
|
Router.map(function () {
|
||||||
this.route("patreon-redirect", {
|
this.route("patreon-redirect", {
|
||||||
path: "/patreon-redirect",
|
path: "/patreon-redirect",
|
||||||
where: "server",
|
where: "server",
|
||||||
action: function () {
|
action: function () {
|
||||||
let route = this;
|
let route = this;
|
||||||
let userId = route.params.query.state;
|
let userId = route.params.query.state;
|
||||||
let singleUseCode = route.params.query.code;
|
let singleUseCode = route.params.query.code;
|
||||||
requestToken(singleUseCode, Meteor.bindEnvironment((error, response, body) => {
|
requestToken(singleUseCode, Meteor.bindEnvironment((error, response, body) => {
|
||||||
// Should return an access token, valid for 1 month, which needs to be
|
// Should return an access token, valid for 1 month, which needs to be
|
||||||
// stored and used to make requests on behalf of the user
|
// stored and used to make requests on behalf of the user
|
||||||
if (error){
|
if (error){
|
||||||
writePatreonError(userId, error);
|
writePatreonError(userId, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let token;
|
let token;
|
||||||
try {
|
try {
|
||||||
token = JSON.parse(body);
|
token = JSON.parse(body);
|
||||||
writePatreonToken(userId, token);
|
writePatreonToken(userId, token);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
writePatreonError(userId, error);
|
writePatreonError(userId, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateIdentity(token.access_token, userId);
|
updateIdentity(token.access_token, userId);
|
||||||
}));
|
}));
|
||||||
route.response.writeHead(302, {
|
route.response.writeHead(302, {
|
||||||
'Location': Meteor.absoluteUrl() + "account",
|
'Location': Meteor.absoluteUrl() + "account",
|
||||||
});
|
});
|
||||||
route.response.end();
|
route.response.end();
|
||||||
},
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const requestToken = function(singleUseCode, callback){
|
const requestToken = function(singleUseCode, callback){
|
||||||
request({
|
request({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
uri: "https://www.patreon.com/api/oauth2/token",
|
uri: "https://www.patreon.com/api/oauth2/token",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
qs: {
|
qs: {
|
||||||
code: singleUseCode,
|
code: singleUseCode,
|
||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
client_id: CLIENT_ID,
|
client_id: CLIENT_ID,
|
||||||
client_secret: CLIENT_SECRET,
|
client_secret: CLIENT_SECRET,
|
||||||
redirect_uri: Meteor.absoluteUrl() + 'patreon-redirect',
|
redirect_uri: Meteor.absoluteUrl() + 'patreon-redirect',
|
||||||
},
|
},
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getIdentity = function(accessToken, callback){
|
const getIdentity = function(accessToken, callback){
|
||||||
request({
|
request({
|
||||||
uri: "https://www.patreon.com/api/oauth2/v2/identity",
|
uri: "https://www.patreon.com/api/oauth2/v2/identity",
|
||||||
headers:{
|
headers:{
|
||||||
Authorization: "Bearer " + accessToken,
|
Authorization: "Bearer " + accessToken,
|
||||||
},
|
},
|
||||||
qs: {
|
qs: {
|
||||||
"include": "memberships",
|
"include": "memberships",
|
||||||
"fields[member]": "currently_entitled_amount_cents",
|
"fields[member]": "currently_entitled_amount_cents",
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should return a new access token for the user
|
// Should return a new access token for the user
|
||||||
// callback is called with (error, response, body)
|
// callback is called with (error, response, body)
|
||||||
const refreshAccessToken = Meteor.wrapAsync(function(refreshToken, userId, callback){
|
const refreshAccessToken = Meteor.wrapAsync(function(refreshToken, userId, callback){
|
||||||
request({
|
request({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
uri: "https://www.patreon.com/api/oauth2/token",
|
uri: "https://www.patreon.com/api/oauth2/token",
|
||||||
qs: {
|
qs: {
|
||||||
grant_type: "refresh_token",
|
grant_type: "refresh_token",
|
||||||
refresh_token: refreshToken,
|
refresh_token: refreshToken,
|
||||||
client_id: CLIENT_ID,
|
client_id: CLIENT_ID,
|
||||||
client_secret: CLIENT_SECRET,
|
client_secret: CLIENT_SECRET,
|
||||||
}
|
}
|
||||||
}, Meteor.bindEnvironment((error, response, body) => {
|
}, Meteor.bindEnvironment((error, response, body) => {
|
||||||
// Should return an access token, valid for 1 month, which needs to be
|
// Should return an access token, valid for 1 month, which needs to be
|
||||||
// stored and used to make requests on behalf of the user
|
// stored and used to make requests on behalf of the user
|
||||||
if (error){
|
if (error){
|
||||||
callback(error)
|
callback(error)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let token;
|
let token;
|
||||||
try {
|
try {
|
||||||
token = JSON.parse(body);
|
token = JSON.parse(body);
|
||||||
writePatreonToken(userId, token);
|
writePatreonToken(userId, token);
|
||||||
callback(undefined, token.access_token);
|
callback(undefined, token.access_token);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateIdentity = Meteor.wrapAsync(function(accessToken, userId, callback){
|
|
||||||
getIdentity(accessToken, Meteor.bindEnvironment((error, response, body) => {
|
|
||||||
if (error){
|
|
||||||
writePatreonError(userId, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let identity = JSON.parse(body);
|
|
||||||
let membership = identity.included[0];
|
|
||||||
let entitledAmount = membership && membership.attributes
|
|
||||||
.currently_entitled_amount_cents || 0;
|
|
||||||
let patreonUserId = identity.data.id;
|
|
||||||
writeEntitledCentsAndId(userId, entitledAmount, patreonUserId);
|
|
||||||
if (callback) callback();
|
|
||||||
} catch(error) {
|
|
||||||
writePatreonError(userId, error);
|
|
||||||
if(callback) callback(error);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
Meteor.methods({
|
|
||||||
updateMyPatreonDetails(){
|
|
||||||
const userId = this.userId;
|
|
||||||
if (!userId) throw new Meteor.Error("not-logged-in", "You must be logged in to update Patreon details");
|
|
||||||
const user = Meteor.users.findOne(userId, {fields: {patreon: 1}});
|
|
||||||
Meteor.users.update(userId, {$unset: {"patreon.entitledCents": 1}});
|
|
||||||
if (!user.patreon || !user.patreon.accessToken){
|
|
||||||
throw new Meteor.Error("no-patreon-access", "Patreon access token not found for this user");
|
|
||||||
}
|
|
||||||
let accessToken = user.patreon.accessToken;
|
|
||||||
if (user.patreon.tokenExpiryDate < new Date()){
|
|
||||||
// Token expired, refresh it before continuing
|
|
||||||
accessToken = refreshAccessToken(user.patreon.refreshToken, userId);
|
|
||||||
}
|
|
||||||
updateIdentity(accessToken, userId);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const writePatreonToken = function(userId, {
|
|
||||||
access_token, refresh_token, expires_in
|
|
||||||
}){
|
|
||||||
// The expiry date is now plus `expires_in` seconds
|
|
||||||
let expiryDate = new Date();
|
|
||||||
expiryDate.setSeconds(expiryDate.getSeconds() + expires_in);
|
|
||||||
// Expire a day early so we don't accidentally miss it
|
|
||||||
expiryDate.setDate(expiryDate.getDate() - 1);
|
|
||||||
|
|
||||||
// Write
|
|
||||||
Meteor.users.update(userId, {
|
|
||||||
$set: {
|
|
||||||
"patreon.accessToken": access_token,
|
|
||||||
"patreon.refreshToken": refresh_token,
|
|
||||||
"patreon.tokenExpiryDate": expiryDate,
|
|
||||||
},
|
|
||||||
$unset: {
|
|
||||||
"patreon.error": 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeEntitledCentsAndId = function(userId, amount, patreonUserId){
|
|
||||||
Meteor.users.update(userId, {
|
|
||||||
$set: {
|
|
||||||
"patreon.entitledCents": amount,
|
|
||||||
"patreon.userId": patreonUserId,
|
|
||||||
},
|
|
||||||
$unset: {
|
|
||||||
"patreon.error": 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const writePatreonError = function(userId, error){
|
|
||||||
console.error({patreonError: error});
|
|
||||||
Meteor.users.update(userId, {
|
|
||||||
$set: {
|
|
||||||
"patreon.error": error.toString(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const requestMembers = Meteor.wrapAsync(function(cursor, members, callback){
|
|
||||||
request({
|
|
||||||
uri: `https://www.patreon.com/api/oauth2/v2/campaigns/${CAMPAIGN_ID}/members`,
|
|
||||||
headers:{
|
|
||||||
Authorization: "Bearer " + CREATOR_ACCESS_TOKEN,
|
|
||||||
},
|
|
||||||
qs: {
|
|
||||||
"include": "user",
|
|
||||||
"fields[member]": "currently_entitled_amount_cents",
|
|
||||||
"page[cursor]": cursor,
|
|
||||||
}
|
|
||||||
}, (error, reponse, body) => {
|
|
||||||
if (error){
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let json = JSON.parse(body);
|
|
||||||
if (json.errors) {
|
|
||||||
callback(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let newMembers = json.data.map(member => ({
|
|
||||||
id: member.relationships.user.data.id,
|
|
||||||
entitledCents: member.attributes.currently_entitled_amount_cents,
|
|
||||||
}));
|
}));
|
||||||
members.push(...newMembers);
|
|
||||||
let next = json.meta.pagination.cursors && json.meta.pagination.cursors.next;
|
|
||||||
if (next){
|
|
||||||
callback(undefined, next);
|
|
||||||
} else {
|
|
||||||
callback(undefined);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const updatePatreonMembersEntitledCents = function(){
|
const updateIdentity = Meteor.wrapAsync(function(accessToken, userId, callback){
|
||||||
let next = "";
|
getIdentity(accessToken, Meteor.bindEnvironment((error, response, body) => {
|
||||||
let members = [];
|
if (error){
|
||||||
do {
|
writePatreonError(userId, error);
|
||||||
next = requestMembers(next, members);
|
return;
|
||||||
} while (next)
|
}
|
||||||
members.forEach(({id, entitledCents}) => {
|
try {
|
||||||
Meteor.users.update({
|
let identity = JSON.parse(body);
|
||||||
"patreon.userId": id
|
let membership = identity.included[0];
|
||||||
}, {$set: {
|
let entitledAmount = membership && membership.attributes
|
||||||
"patreon.entitledCents":entitledCents,
|
.currently_entitled_amount_cents || 0;
|
||||||
}});
|
let patreonUserId = identity.data.id;
|
||||||
|
writeEntitledCentsAndId(userId, entitledAmount, patreonUserId);
|
||||||
|
if (callback) callback();
|
||||||
|
} catch(error) {
|
||||||
|
writePatreonError(userId, error);
|
||||||
|
if(callback) callback(error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
return members;
|
|
||||||
|
Meteor.methods({
|
||||||
|
updateMyPatreonDetails(){
|
||||||
|
const userId = this.userId;
|
||||||
|
if (!userId) throw new Meteor.Error("not-logged-in", "You must be logged in to update Patreon details");
|
||||||
|
const user = Meteor.users.findOne(userId, {fields: {patreon: 1}});
|
||||||
|
Meteor.users.update(userId, {$unset: {"patreon.entitledCents": 1}});
|
||||||
|
if (!user.patreon || !user.patreon.accessToken){
|
||||||
|
throw new Meteor.Error("no-patreon-access", "Patreon access token not found for this user");
|
||||||
|
}
|
||||||
|
let accessToken = user.patreon.accessToken;
|
||||||
|
if (user.patreon.tokenExpiryDate < new Date()){
|
||||||
|
// Token expired, refresh it before continuing
|
||||||
|
accessToken = refreshAccessToken(user.patreon.refreshToken, userId);
|
||||||
|
}
|
||||||
|
updateIdentity(accessToken, userId);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const writePatreonToken = function(userId, {
|
||||||
|
access_token, refresh_token, expires_in
|
||||||
|
}){
|
||||||
|
// The expiry date is now plus `expires_in` seconds
|
||||||
|
let expiryDate = new Date();
|
||||||
|
expiryDate.setSeconds(expiryDate.getSeconds() + expires_in);
|
||||||
|
// Expire a day early so we don't accidentally miss it
|
||||||
|
expiryDate.setDate(expiryDate.getDate() - 1);
|
||||||
|
|
||||||
|
// Write
|
||||||
|
Meteor.users.update(userId, {
|
||||||
|
$set: {
|
||||||
|
"patreon.accessToken": access_token,
|
||||||
|
"patreon.refreshToken": refresh_token,
|
||||||
|
"patreon.tokenExpiryDate": expiryDate,
|
||||||
|
},
|
||||||
|
$unset: {
|
||||||
|
"patreon.error": 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeEntitledCentsAndId = function(userId, amount, patreonUserId){
|
||||||
|
Meteor.users.update(userId, {
|
||||||
|
$set: {
|
||||||
|
"patreon.entitledCents": amount,
|
||||||
|
"patreon.userId": patreonUserId,
|
||||||
|
},
|
||||||
|
$unset: {
|
||||||
|
"patreon.error": 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const writePatreonError = function(userId, error){
|
||||||
|
console.error({patreonError: error});
|
||||||
|
Meteor.users.update(userId, {
|
||||||
|
$set: {
|
||||||
|
"patreon.error": error.toString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const requestMembers = Meteor.wrapAsync(function(cursor, members, callback){
|
||||||
|
request({
|
||||||
|
uri: `https://www.patreon.com/api/oauth2/v2/campaigns/${CAMPAIGN_ID}/members`,
|
||||||
|
headers:{
|
||||||
|
Authorization: "Bearer " + CREATOR_ACCESS_TOKEN,
|
||||||
|
},
|
||||||
|
qs: {
|
||||||
|
"include": "user",
|
||||||
|
"fields[member]": "currently_entitled_amount_cents",
|
||||||
|
"page[cursor]": cursor,
|
||||||
|
}
|
||||||
|
}, (error, reponse, body) => {
|
||||||
|
if (error){
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let json = JSON.parse(body);
|
||||||
|
if (json.errors) {
|
||||||
|
callback(json.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let newMembers = json.data.map(member => ({
|
||||||
|
id: member.relationships.user.data.id,
|
||||||
|
entitledCents: member.attributes.currently_entitled_amount_cents,
|
||||||
|
}));
|
||||||
|
members.push(...newMembers);
|
||||||
|
let next = json.meta.pagination.cursors && json.meta.pagination.cursors.next;
|
||||||
|
if (next){
|
||||||
|
callback(undefined, next);
|
||||||
|
} else {
|
||||||
|
callback(undefined);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatePatreonMembersEntitledCents = function(){
|
||||||
|
let next = "";
|
||||||
|
let members = [];
|
||||||
|
do {
|
||||||
|
next = requestMembers(next, members);
|
||||||
|
} while (next)
|
||||||
|
members.forEach(({id, entitledCents}) => {
|
||||||
|
Meteor.users.update({
|
||||||
|
"patreon.userId": id
|
||||||
|
}, {$set: {
|
||||||
|
"patreon.entitledCents":entitledCents,
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to run a manual update
|
||||||
|
Meteor.methods({
|
||||||
|
updatePatreonMembersEntitledCents(){
|
||||||
|
const user = Meteor.users.findOne(this.userId);
|
||||||
|
if (!user || !_.contains(user.roles, "admin")) throw new Meteor.Error(
|
||||||
|
"permission-error", "You need to be logged in as an admin to run this method"
|
||||||
|
);
|
||||||
|
return updatePatreonMembersEntitledCents();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cron job to run the update automatically
|
||||||
|
Meteor.startup(() => {
|
||||||
|
SyncedCron.add({
|
||||||
|
name: "updatePatreonMembersEntitledCents",
|
||||||
|
schedule: function(parser) {
|
||||||
|
return parser.text('every 4 hours');
|
||||||
|
},
|
||||||
|
job: updatePatreonMembersEntitledCents,
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to run a manual update
|
|
||||||
Meteor.methods({
|
|
||||||
updatePatreonMembersEntitledCents(){
|
|
||||||
const user = Meteor.users.findOne(this.userId);
|
|
||||||
if (!user || !_.contains(user.roles, "admin")) throw new Meteor.Error(
|
|
||||||
"permission-error", "You need to be logged in as an admin to run this method"
|
|
||||||
);
|
|
||||||
return updatePatreonMembersEntitledCents();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cron job to run the update automatically
|
|
||||||
Meteor.startup(() => {
|
|
||||||
SyncedCron.add({
|
|
||||||
name: "updatePatreonMembersEntitledCents",
|
|
||||||
schedule: function(parser) {
|
|
||||||
return parser.text('every 4 hours');
|
|
||||||
},
|
|
||||||
job: updatePatreonMembersEntitledCents,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// This all gets run in the console by an admin.
|
// This all gets run in the console by an admin.
|
||||||
// Probably a good idea to reset the server after running big updates
|
|
||||||
// Only do if the library doesn't exist yet
|
// First Setup
|
||||||
|
// -----------
|
||||||
|
|
||||||
|
// Add the SRD library with the correct static ID:
|
||||||
id = Libraries.insert({
|
id = Libraries.insert({
|
||||||
_id: "SRDLibraryGA3XWsd",
|
_id: "SRDLibraryGA3XWsd",
|
||||||
owner: Meteor.userId(),
|
owner: Meteor.userId(),
|
||||||
@@ -8,19 +11,23 @@ id = Libraries.insert({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// First copy-paste the JSON into your console like `items = <pasted JSON>`
|
// First copy-paste the JSON into your console like `items = <pasted JSON>`
|
||||||
// First import, don't do this if the library is already populated
|
|
||||||
_.each(items, (item) => {
|
_.each(items, (item) => {
|
||||||
item.settings = {category: }; // "adventuringGear", "armor", "weapons", "tools"
|
// replace "adventuringGear" with appropriate category: "armor", "weapons", "tools"
|
||||||
|
// if needed
|
||||||
|
item.settings = {category: "adventuringGear"};
|
||||||
item.library = "SRDLibraryGA3XWsd"
|
item.library = "SRDLibraryGA3XWsd"
|
||||||
LibraryItems.insert(item)
|
LibraryItems.insert(item)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// First copy-paste the JSON into your console like `spells = <pasted JSON>`
|
||||||
_.each(spells, (spell) => {
|
_.each(spells, (spell) => {
|
||||||
spell.library = "SRDLibraryGA3XWsd"
|
spell.library = "SRDLibraryGA3XWsd"
|
||||||
LibrarySpells.insert(spell)
|
LibrarySpells.insert(spell)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the library using names as keys
|
// Updating the Libary
|
||||||
|
// -------------------
|
||||||
|
|
||||||
// Make sure you're subscribed to all item categories
|
// Make sure you're subscribed to all item categories
|
||||||
handles = _.map(["weapons", "armor", "adventuringGear", "tools"],
|
handles = _.map(["weapons", "armor", "adventuringGear", "tools"],
|
||||||
category => Meteor.subscribe("standardLibraryItems", category)
|
category => Meteor.subscribe("standardLibraryItems", category)
|
||||||
|
|||||||
Reference in New Issue
Block a user