Files
DiceCloud/app/imports/api/users/patreon/updatePatreonDetails.js
2020-09-18 20:37:16 +02:00

138 lines
3.9 KiB
JavaScript

import request from 'request';
if (!Meteor.isServer) throw 'Server only, do not import this code in the client';
const config = ServiceConfiguration.configurations.findOne({service: 'patreon'});
const getIdentity = function(accessToken, callback){
request({
uri: 'https://www.patreon.com/api/oauth2/v2/identity',
headers:{
Authorization: 'Bearer ' + accessToken,
},
qs: {
'include': 'memberships',
'fields[member]': 'currently_entitled_amount_cents',
}
}, callback);
};
// Should return a new access token for the user
// callback is called with (error, response, body)
const refreshAccessToken = Meteor.wrapAsync(function(refreshToken, userId, callback){
request({
method: 'POST',
uri: 'https://www.patreon.com/api/oauth2/token',
qs: {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: config.clientId,
client_secret: config.secret,
}
}, Meteor.bindEnvironment((error, response, body) => {
// Should return an access token, valid for 1 month, which needs to be
// stored and used to make requests on behalf of the user
if (error){
if (callback){
callback(error);
return;
} else {
throw error;
}
}
let token;
try {
token = JSON.parse(body);
writePatreonToken(userId, token);
callback(undefined, token.access_token);
} catch(error) {
if (callback){
callback(error);
return;
} else {
throw error;
}
}
}));
});
const updateIdentity = Meteor.wrapAsync(function(accessToken, userId, callback){
getIdentity(accessToken, Meteor.bindEnvironment((error, response, body) => {
if (error){
throw error;
}
try {
let identity = JSON.parse(body);
let membership = identity.included[0];
let entitledAmount = membership && membership.attributes
.currently_entitled_amount_cents || 0;
writeEntitledCents(userId, entitledAmount);
if (callback) callback();
} catch(error) {
if(callback) {
callback(error);
} else {
throw error;
}
}
}));
});
const updatePatreonDetails = function(user){
if (!user) {
throw new Meteor.Error('no-user', 'User must be provided to update patreon details');
}
if (!user.services.patreon || !user.services.patreon.accessToken){
throw new Meteor.Error('no-patreon-access', 'Patreon access token not found for this user');
}
let accessToken = user.services.patreon.accessToken;
if (user.services.patreon.expiresAt < new Date()){
// Token expired, refresh it before continuing
accessToken = refreshAccessToken(user.services.patreon.refreshToken, user._id);
}
updateIdentity(accessToken, user._id);
}
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: {services: 1}});
updatePatreonDetails(user);
},
});
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: {
'services.patreon.accessToken': access_token,
'services.patreon.refreshToken': refresh_token,
'services.patreon.expiresAt': expiryDate,
},
$unset: {
'patreon.error': 1,
},
});
};
const writeEntitledCents = function(userId, amount){
Meteor.users.update(userId, {
$set: {
'services.patreon.entitledCents': amount,
'services.patreon.lastUpdatedIdentity': new Date(),
},
$unset: {
'patreon.error': 1,
},
});
};
export default updatePatreonDetails;