Invite system created, mostly done, but timeboxed for now
This commit is contained in:
@@ -48,3 +48,4 @@ aldeed:collection2@3.0.0
|
||||
aldeed:schema-index
|
||||
akryum:vue-component
|
||||
accounts-patreon
|
||||
bozhao:link-accounts
|
||||
|
||||
@@ -21,6 +21,7 @@ binary-heap@1.0.11
|
||||
blaze@2.3.4
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.7.0
|
||||
bozhao:link-accounts@2.1.1
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.1.3
|
||||
callback-hook@1.3.0
|
||||
|
||||
153
app/imports/api/users/Invites.js
Normal file
153
app/imports/api/users/Invites.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
|
||||
let Invites= new Mongo.Collection('invites');
|
||||
|
||||
let InviteSchema = new SimpleSchema({
|
||||
inviter: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
index: 1,
|
||||
},
|
||||
invitee: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
optional: true,
|
||||
index: 1,
|
||||
},
|
||||
inviteToken: {
|
||||
type: String,
|
||||
optional: true,
|
||||
index: 1,
|
||||
unique: 1,
|
||||
},
|
||||
isFunded: {
|
||||
type: Boolean,
|
||||
},
|
||||
isRedundant: {
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
},
|
||||
// The timestamp of when the invitee was confirmed
|
||||
// Older invites have priority over newer ones
|
||||
dateConfirmed: {
|
||||
type: Date,
|
||||
optional: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (Meteor.isServer){
|
||||
Accounts.onLogin(function({user}){
|
||||
alignInvitesWithPatreonTier(user);
|
||||
});
|
||||
}
|
||||
|
||||
function alignInvitesWithPatreonTier(user){
|
||||
const tier = getUserTier(user);
|
||||
let availableInvites = tier.invites;
|
||||
let currentlyFundedInvites = [];
|
||||
let currenltyUnfundedInvites = [];
|
||||
Invites.find({
|
||||
inviter: user._id
|
||||
}).forEach(invite => {
|
||||
if (invite.isFunded){
|
||||
currentlyFundedInvites.push(invite);
|
||||
} else {
|
||||
currenltyUnfundedInvites.push(invite);
|
||||
}
|
||||
});
|
||||
|
||||
// Return early if no work needs doing to skip sorting
|
||||
if (currentlyFundedInvites.length === availableInvites) return;
|
||||
|
||||
// Sort the invites by date forwards and backwards
|
||||
currentlyFundedInvites.sort((a, b) => a.dateConfirmed - b.dateConfirmed);
|
||||
currenltyUnfundedInvites.sort((a, b) => b.dateConfirmed - a.dateConfirmed);
|
||||
|
||||
// Defund or delete excess invites
|
||||
while (currentlyFundedInvites.length > availableInvites){
|
||||
let inviteToDefund = currentlyFundedInvites.pop();
|
||||
if (inviteToDefund.invitee){
|
||||
Invites.update(inviteToDefund._id, {$set: {isFunded: false}});
|
||||
} else {
|
||||
Invites.remove(inviteToDefund._id);
|
||||
}
|
||||
}
|
||||
// Fund unfunded invites or insert new ones
|
||||
while (currentlyFundedInvites.length < availableInvites){
|
||||
if (currenltyUnfundedInvites.length){
|
||||
let inviteToFund = currenltyUnfundedInvites.pop();
|
||||
currentlyFundedInvites.push(inviteToFund);
|
||||
Invites.update(inviteToFund._id, {$set: {isFunded: true}});
|
||||
} else {
|
||||
let inviteId = Invites.insert({inviter: user._id, isFunded: true});
|
||||
currentlyFundedInvites.push({_id: inviteId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getInviteToken = new ValidatedMethod({
|
||||
name: 'Invites.methods.getToken',
|
||||
validate: new SimpleSchema({
|
||||
inviteId: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
},
|
||||
}).validator(),
|
||||
run({inviteId}) {
|
||||
let invite = Invites.findOne(inviteId);
|
||||
if (this.userId !== invite.inviter) {
|
||||
throw new Meteor.Error('Invites.methods.getToken.denied',
|
||||
'You need to be the inviter of the invite to create a token');
|
||||
}
|
||||
if (invite.inviteToken){
|
||||
return invite.inviteToken;
|
||||
} else {
|
||||
let inviteToken = Random.id(5);
|
||||
Invites.update(inviteId, {$set: {inviteToken}})
|
||||
return inviteToken;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const acceptInviteToken = new ValidatedMethod({
|
||||
name: 'Invites.methods.acceptToken',
|
||||
validate: new SimpleSchema({
|
||||
inviteToken: {
|
||||
type: String,
|
||||
},
|
||||
}).validator(),
|
||||
run({inviteToken}) {
|
||||
if (this.userId) {
|
||||
throw new Meteor.Error('Invites.methods.acceptToken.denied',
|
||||
'You need to be the logged in to accept a token');
|
||||
}
|
||||
let invite = Invites.findOne({inviteToken});
|
||||
if (!invite){
|
||||
throw new Meteor.Error('Invites.methods.acceptToken.notFound',
|
||||
'No invite could be found for this token');
|
||||
}
|
||||
// If the invitee is already filled, fix unexpected case by deleting the token
|
||||
if (invite.invitee){
|
||||
Invites.update(invite._id, {
|
||||
$unset: {inviteToken: 1}
|
||||
});
|
||||
throw new Meteor.Error('Invites.methods.acceptToken.alreadyAccepted',
|
||||
'This invite already has an invitee, and shouldn\'t have a token');
|
||||
}
|
||||
if (this.userId === invite.inviter){
|
||||
throw new Meteor.Error('Invites.methods.acceptToken.ownToken',
|
||||
'You can\'t accept your own invite');
|
||||
}
|
||||
Invites.update(invite._id, {
|
||||
$set: {invitee: this.userId},
|
||||
$unset: {inviteToken: 1},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Invites.attachSchema(InviteSchema);
|
||||
|
||||
export default Invites;
|
||||
export { alignInvitesWithPatreonTier, getInviteToken, acceptInviteToken };
|
||||
@@ -1,4 +1,5 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
|
||||
const userSchema = new SimpleSchema({
|
||||
username: {
|
||||
@@ -140,13 +141,3 @@ Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({
|
||||
return user && user._id;
|
||||
}
|
||||
});
|
||||
|
||||
export function getEntitledCentsOfUser(user){
|
||||
if (!user) return 0;
|
||||
const patreon = user.services && user.services.patreon;
|
||||
if (!patreon) return 0;
|
||||
let entitledCents = patreon.entitledCents || 0;
|
||||
let overrideCents = patreon.entitledCentsOverride || 0;
|
||||
if (overrideCents > entitledCents) entitledCents = overrideCents;
|
||||
return entitledCents;
|
||||
}
|
||||
|
||||
20
app/imports/api/users/linkWithPatreon.js
Normal file
20
app/imports/api/users/linkWithPatreon.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// Adds accounts-patreon support to bozhao:link-accounts
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
|
||||
export default function linkWithPatreon(options, callback) {
|
||||
if (!Meteor.userId()) {
|
||||
throw new Meteor.Error(402, 'Please login to an existing account before link.');
|
||||
}
|
||||
if (!Package['patreon-oauth']) {
|
||||
throw new Meteor.Error(403, 'Please include patreon-oauth package');
|
||||
}
|
||||
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
const credentialRequestCompleteCallback = Accounts.oauth.linkCredentialRequestCompleteHandler(callback);
|
||||
Package['patreon-oauth'].Patreon.requestCredential(options, credentialRequestCompleteCallback);
|
||||
}
|
||||
9
app/imports/api/users/patreon/getEntitledCents.js
Normal file
9
app/imports/api/users/patreon/getEntitledCents.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export default function getEntitledCents(user){
|
||||
if (!user) return 0;
|
||||
const patreon = user.services && user.services.patreon;
|
||||
if (!patreon) return 0;
|
||||
let entitledCents = patreon.entitledCents || 0;
|
||||
let overrideCents = patreon.entitledCentsOverride || 0;
|
||||
if (overrideCents > entitledCents) entitledCents = overrideCents;
|
||||
return entitledCents;
|
||||
}
|
||||
137
app/imports/api/users/patreon/patreon.js
Normal file
137
app/imports/api/users/patreon/patreon.js
Normal file
@@ -0,0 +1,137 @@
|
||||
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.tokenExpiryDate < 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: {patreon: 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: {
|
||||
'patreon.accessToken': access_token,
|
||||
'patreon.refreshToken': refresh_token,
|
||||
'patreon.tokenExpiryDate': expiryDate,
|
||||
},
|
||||
$unset: {
|
||||
'patreon.error': 1,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const writeEntitledCents = function(userId, amount){
|
||||
Meteor.users.update(userId, {
|
||||
$set: {
|
||||
'services.patreon.entitledCents': amount,
|
||||
},
|
||||
$unset: {
|
||||
'patreon.error': 1,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { updatePatreonDetails };
|
||||
66
app/imports/api/users/patreon/tiers.js
Normal file
66
app/imports/api/users/patreon/tiers.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { findLast } from 'lodash';
|
||||
import getEntitledCents from '/imports/api/users/patreon/getEntitledCents.js';
|
||||
|
||||
const TIERS = [
|
||||
{
|
||||
//cost per user $0
|
||||
name: 'Commoner',
|
||||
minimumEntitledCents: 0,
|
||||
invites: 0,
|
||||
paidBenefits: false,
|
||||
}, {
|
||||
//cost per user $0
|
||||
name: 'Wanderer',
|
||||
minimumEntitledCents: 300,
|
||||
invites: 0,
|
||||
paidBenefits: false,
|
||||
}, {
|
||||
//cost per user $5
|
||||
name: 'Adventurer',
|
||||
minimumEntitledCents: 500,
|
||||
invites: 0,
|
||||
paidBenefits: true,
|
||||
}, {
|
||||
//cost per user $3.33
|
||||
name: 'Hero',
|
||||
minimumEntitledCents: 1000,
|
||||
invites: 2,
|
||||
paidBenefits: true,
|
||||
}, {
|
||||
//cost per user $3.333
|
||||
name: 'Legend',
|
||||
minimumEntitledCents: 2000,
|
||||
invites: 5,
|
||||
paidBenefits: true,
|
||||
}, {
|
||||
//cost per user $3.125
|
||||
name: 'Paragon',
|
||||
minimumEntitledCents: 5000,
|
||||
invites: 15,
|
||||
paidBenefits: true,
|
||||
},
|
||||
];
|
||||
|
||||
const GUEST_TIER = {
|
||||
name: 'Companion',
|
||||
guest: true,
|
||||
invites: 0,
|
||||
paidBenefits: true,
|
||||
}
|
||||
|
||||
export function getTierByEntitledCents(entitledCents = 0){
|
||||
return findLast(TIERS, tier => entitledCents >= tier.minimumEntitledCents);
|
||||
}
|
||||
|
||||
export function getUserTier(user){
|
||||
if (!user) throw 'user must be provided';
|
||||
if (typeof user === 'string'){
|
||||
user = Meteor.users.findOne(user);
|
||||
if (!user) throw 'User not found';
|
||||
}
|
||||
const entitledCents = getEntitledCents(user);
|
||||
return getTierByEntitledCents(entitledCents);
|
||||
}
|
||||
|
||||
export default TIERS;
|
||||
export { GUEST_TIER };
|
||||
@@ -1,15 +1,24 @@
|
||||
import '/imports/api/users/Users.js';
|
||||
import Invites from '/imports/api/users/Invites.js';
|
||||
|
||||
Meteor.publish('user', function(){
|
||||
return Meteor.users.find(this.userId, {fields: {
|
||||
roles: 1,
|
||||
username: 1,
|
||||
apiKey: 1,
|
||||
darkMode: 1,
|
||||
'services.patreon.id': 1,
|
||||
'services.patreon.entitledCents': 1,
|
||||
'services.patreon.entitledCentsOverride': 1,
|
||||
}});
|
||||
return [
|
||||
Meteor.users.find(this.userId, {fields: {
|
||||
roles: 1,
|
||||
username: 1,
|
||||
apiKey: 1,
|
||||
darkMode: 1,
|
||||
'services.patreon.id': 1,
|
||||
'services.patreon.entitledCents': 1,
|
||||
'services.patreon.entitledCentsOverride': 1,
|
||||
}}),
|
||||
Invites.find({
|
||||
$or: [
|
||||
{inviter: this.userId},
|
||||
{invitee: this.userId}
|
||||
],
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
Meteor.publish('userPublicProfiles', function(ids){
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
dismissible
|
||||
:value="true"
|
||||
>
|
||||
This version of DiceCloud is in beta. Data stored here may be destroyed by
|
||||
future updates. Don't store anything important here yet.
|
||||
This version of DiceCloud is in beta. Some data stored here may be destroyed by
|
||||
future updates.
|
||||
</v-alert>
|
||||
<v-fade-transition
|
||||
mode="out-in"
|
||||
|
||||
@@ -44,109 +44,32 @@
|
||||
<v-list-tile-title>
|
||||
{{ email.address }}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-action>
|
||||
<v-tooltip
|
||||
v-if="email.verified"
|
||||
left
|
||||
>
|
||||
<span>Verified</span>
|
||||
<v-icon slot="activator">
|
||||
assignment_turned_in
|
||||
</v-icon>
|
||||
</v-tooltip>
|
||||
<v-tooltip left>
|
||||
<span>Verify Account</span>
|
||||
<v-btn
|
||||
slot="activator"
|
||||
flat
|
||||
icon
|
||||
@click="verifyEmail(email.address)"
|
||||
>
|
||||
<v-icon>assignment_late</v-icon>
|
||||
</v-btn>
|
||||
</v-tooltip>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
|
||||
<v-list-tile>
|
||||
<v-list-tile-action>
|
||||
<v-tooltip right>
|
||||
<span>Add email address</span>
|
||||
<v-btn
|
||||
slot="activator"
|
||||
flat
|
||||
icon
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
</v-btn>
|
||||
</v-tooltip>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
|
||||
<v-subheader>
|
||||
Patreon reward tier
|
||||
Patreon
|
||||
</v-subheader>
|
||||
<v-list-tile>
|
||||
<v-list-tile-title>
|
||||
${{ entitledCents/100 }}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
|
||||
<v-subheader>
|
||||
API Key
|
||||
</v-subheader>
|
||||
<v-list-tile v-if="user && user.apiKey">
|
||||
<v-list-tile v-if="showApiKey">
|
||||
{{ user.apiKey }}
|
||||
</v-list-tile>
|
||||
<v-list-tile-title>
|
||||
{{ "•".repeat(user.apiKey.length) }}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-action>
|
||||
<v-btn
|
||||
flat
|
||||
icon
|
||||
@click="showApiKey=!showApiKey"
|
||||
>
|
||||
<v-icon>{{ showApiKey ? 'visibility_off' : 'visibility' }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
<v-list-tile v-else>
|
||||
<v-btn
|
||||
flat
|
||||
color="accent"
|
||||
@click="generateKey"
|
||||
>
|
||||
Generate API Key
|
||||
</v-btn>
|
||||
</v-list-tile>
|
||||
<!--
|
||||
<v-subheader>
|
||||
Google Account
|
||||
</v-subheader>
|
||||
<v-list-tile v-if="googleAccount">
|
||||
<v-list-tile-avatar>
|
||||
<img src="googleAccount.picture">
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<template v-if="user.services.patreon">
|
||||
<v-list-tile>
|
||||
<v-list-tile-title>
|
||||
{{ googleAccount.name }}
|
||||
Pledged amount: ${{ entitledCents/100 }}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-sub-title>
|
||||
{{ googleAccount.email }}
|
||||
</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile v-else="googleAccount">
|
||||
<v-btn
|
||||
flat
|
||||
color="accent"
|
||||
>
|
||||
Connect Google
|
||||
<v-list-tile-action>
|
||||
<v-btn icon>
|
||||
<v-icon>refresh</v-icon>
|
||||
</v-btn>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
<v-list-tile>
|
||||
<v-list-tile-title>
|
||||
Tier: {{ tier.name }}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
<v-list-tile v-else>
|
||||
<v-btn @click="linkWithPatreon">
|
||||
Link Patreon
|
||||
</v-btn>
|
||||
</v-list-tile>
|
||||
-->
|
||||
</v-list>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
@@ -164,7 +87,10 @@
|
||||
|
||||
<script>
|
||||
import router from '/imports/ui/router.js';
|
||||
import {getEntitledCentsOfUser} from '/imports/api/users/Users.js';
|
||||
import getEntitledCents from '/imports/api/users/patreon/getEntitledCents.js';
|
||||
import Invites from '/imports/api/users/Invites.js';
|
||||
import linkWithPatreon from '/imports/api/users/linkWithPatreon.js'
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
|
||||
export default {
|
||||
meteor: {
|
||||
@@ -194,7 +120,10 @@
|
||||
}},
|
||||
computed: {
|
||||
entitledCents(){
|
||||
return getEntitledCentsOfUser(this.user);
|
||||
return getEntitledCents(this.user);
|
||||
},
|
||||
tier(){
|
||||
return getUserTier(this.user);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -216,6 +145,7 @@
|
||||
if(error) this.emailVerificationError = error.reason;
|
||||
});
|
||||
},
|
||||
linkWithPatreon,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
},
|
||||
methods: {
|
||||
getEffectIcon,
|
||||
log: console.log,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
|
||||
import { getEntitledCentsOfUser } from '/imports/api/users/Users.js';
|
||||
import getEntitledCents from '/imports/api/users/patreon/getEntitledCents.js';
|
||||
|
||||
// Components
|
||||
import Home from '/imports/ui/pages/Home.vue';
|
||||
@@ -49,7 +49,7 @@ function ensurePatronTier5(to, from, next){
|
||||
next('/sign-in');
|
||||
return;
|
||||
}
|
||||
let entitledCents = getEntitledCentsOfUser(user);
|
||||
let entitledCents = getEntitledCents(user);
|
||||
if (entitledCents < 500){
|
||||
next('/patreon-level-too-low');
|
||||
} else {
|
||||
@@ -143,6 +143,7 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Account',
|
||||
},
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
path: '/feedback',
|
||||
components: {
|
||||
|
||||
@@ -12,6 +12,7 @@ OAuth.registerService('patreon', 2, null, query => {
|
||||
email: identity.data.attributes.email,
|
||||
entitledCents: identity.included[0] &&
|
||||
identity.included[0].attributes.currently_entitled_amount_cents || 0,
|
||||
lastUpdatedIdentity: new Date(),
|
||||
accessToken,
|
||||
refreshToken,
|
||||
scope,
|
||||
|
||||
Reference in New Issue
Block a user