@wepublish/api
Version:
API core for we.publish.
646 lines • 38.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GraphQLPublicMutation = void 0;
const tslib_1 = require("tslib");
const client_1 = require("@prisma/client");
const api_1 = require("../../../settings-api/src");
const api_2 = require("../../../user-api/src");
const crypto = tslib_1.__importStar(require("crypto"));
const graphql_1 = require("graphql");
const error_1 = require("../error");
const api_3 = require("../../../utils-api/src");
const utility_1 = require("../utility");
const validator_1 = require("../validator");
const comment_rating_public_mutation_1 = require("./comment-rating/comment-rating.public-mutation");
const comment_1 = require("./comment/comment");
const comment_public_mutation_1 = require("./comment/comment.public-mutation");
const common_1 = require("./common");
const image_1 = require("./image");
const memberPlan_1 = require("./memberPlan");
const payment_1 = require("./payment");
const poll_1 = require("./poll/poll");
const poll_public_mutation_1 = require("./poll/poll.public-mutation");
const session_1 = require("./session");
const session_mutation_1 = require("./session/session.mutation");
const slug_1 = require("./slug");
const subscription_public_1 = require("./subscription-public");
const subscription_public_mutation_1 = require("./subscription/subscription.public-mutation");
const user_1 = require("./user");
const user_mutation_1 = require("./user/user.mutation");
const user_public_mutation_1 = require("./user/user.public-mutation");
const api_4 = require("../../../mail-api/src");
const date_fns_1 = require("date-fns");
exports.GraphQLPublicMutation = new graphql_1.GraphQLObjectType({
name: 'Mutation',
fields: {
// Session
// =======
createSession: {
type: new graphql_1.GraphQLNonNull(session_1.GraphQLPublicSessionWithToken),
args: {
email: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
password: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) }
},
resolve: (root, { email, password }, { sessionTTL, prisma }) => (0, session_mutation_1.createSession)(email, password, sessionTTL, prisma.session, prisma.user, prisma.userRole)
},
createSessionWithJWT: {
type: new graphql_1.GraphQLNonNull(session_1.GraphQLPublicSessionWithToken),
args: {
jwt: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) }
},
resolve: (root, { jwt }, { sessionTTL, prisma, verifyJWT }) => (0, session_mutation_1.createJWTSession)(jwt, sessionTTL, verifyJWT, prisma.session, prisma.user, prisma.userRole)
},
createSessionWithOAuth2Code: {
type: new graphql_1.GraphQLNonNull(session_1.GraphQLPublicSessionWithToken),
args: {
name: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
code: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
redirectUri: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) }
},
resolve: (root, { name, code, redirectUri }, { sessionTTL, prisma, oauth2Providers }) => (0, session_mutation_1.createOAuth2Session)(name, code, redirectUri, sessionTTL, oauth2Providers, prisma.session, prisma.user, prisma.userRole)
},
revokeActiveSession: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLBoolean),
args: {},
description: 'This mutation revokes and deletes the active session.',
resolve: (root, _, { authenticateUser, prisma: { session } }) => (0, session_mutation_1.revokeSessionByToken)(authenticateUser, session)
},
// Comment
// =======
addComment: {
type: new graphql_1.GraphQLNonNull(comment_1.GraphQLPublicComment),
args: { input: { type: new graphql_1.GraphQLNonNull(comment_1.GraphQLPublicCommentInput) } },
description: 'This mutation allows to add a comment. The input is of type CommentInput.',
resolve: (_, { input }, { optionalAuthenticateUser, prisma: { comment, setting }, challenge }) => (0, comment_public_mutation_1.addPublicComment)(input, optionalAuthenticateUser, challenge, setting, comment)
},
updateComment: {
type: new graphql_1.GraphQLNonNull(comment_1.GraphQLPublicComment),
args: {
input: { type: new graphql_1.GraphQLNonNull(comment_1.GraphQLPublicCommentUpdateInput) }
},
description: 'This mutation allows to update a comment. The input is of type CommentUpdateInput which contains the ID of the comment you want to update and the new text.',
resolve: (_, { input }, { prisma: { comment, setting }, authenticateUser }) => (0, comment_public_mutation_1.updatePublicComment)(input, authenticateUser, comment, setting)
},
rateComment: {
type: new graphql_1.GraphQLNonNull(comment_1.GraphQLPublicComment),
args: {
commentId: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) },
answerId: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) },
value: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLInt) }
},
description: 'This mutation allows to rate a comment. Supports logged in and anonymous',
resolve: (root, { commentId, answerId, value }, { optionalAuthenticateUser, prisma: { comment, commentRating, commentRatingSystemAnswer, setting } }) => (0, comment_rating_public_mutation_1.rateComment)(commentId, answerId, value, undefined, optionalAuthenticateUser, commentRatingSystemAnswer, commentRating, comment, setting)
},
registerMember: {
type: new graphql_1.GraphQLNonNull(user_1.GraphQLMemberRegistration),
args: {
name: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
firstName: { type: graphql_1.GraphQLString },
preferredName: { type: graphql_1.GraphQLString },
email: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
address: { type: user_1.GraphQLUserAddressInput },
password: { type: graphql_1.GraphQLString },
challengeAnswer: {
type: new graphql_1.GraphQLNonNull(comment_1.GraphQLChallengeInput)
}
},
description: 'This mutation allows to register a new member,',
resolve(root, { name, firstName, preferredName, email, address, password, challengeAnswer }, { sessionTTL, hashCostFactor, prisma, challenge, mailContext }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
email = email.toLowerCase();
yield validator_1.Validator.createUser().parse({ name, email, firstName, preferredName });
const challengeValidationResult = yield challenge.validateChallenge({
challengeID: challengeAnswer.challengeID,
solution: challengeAnswer.challengeSolution
});
if (!challengeValidationResult.valid) {
throw new error_1.CommentAuthenticationError(challengeValidationResult.message);
}
const userExists = yield prisma.user.findUnique({
where: {
email
},
select: api_2.unselectPassword
});
if (userExists) {
throw new error_1.EmailAlreadyInUseError();
}
if (!password) {
password = crypto.randomBytes(48).toString('base64');
}
const user = yield (0, user_mutation_1.createUser)({
name,
firstName,
preferredName,
email,
address,
emailVerifiedAt: null,
active: true,
roleIDs: [],
password
}, hashCostFactor, prisma, mailContext);
if (!user) {
(0, api_3.logger)('mutation.public').error('Could not create new user for email "%s"', email);
throw new error_1.InternalError();
}
const session = yield (0, session_mutation_1.createUserSession)(user, sessionTTL, prisma.session, prisma.userRole);
return {
user,
session
};
});
}
},
registerMemberAndReceivePayment: {
type: new graphql_1.GraphQLNonNull(user_1.GraphQLMemberRegistrationAndPayment),
args: {
name: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
firstName: { type: graphql_1.GraphQLString },
preferredName: { type: graphql_1.GraphQLString },
email: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
address: { type: user_1.GraphQLUserAddressInput },
password: { type: graphql_1.GraphQLString },
memberPlanID: { type: graphql_1.GraphQLID },
memberPlanSlug: { type: slug_1.GraphQLSlug },
autoRenew: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLBoolean) },
paymentPeriodicity: { type: new graphql_1.GraphQLNonNull(memberPlan_1.GraphQLPaymentPeriodicity) },
monthlyAmount: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLInt) },
paymentMethodID: { type: graphql_1.GraphQLID },
paymentMethodSlug: { type: slug_1.GraphQLSlug },
subscriptionProperties: {
type: new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(common_1.GraphQLMetadataPropertyPublicInput))
},
successURL: { type: graphql_1.GraphQLString },
failureURL: { type: graphql_1.GraphQLString },
challengeAnswer: {
type: new graphql_1.GraphQLNonNull(comment_1.GraphQLChallengeInput)
}
},
description: 'This mutation allows to register a new member, select a member plan, payment method and create an invoice. ',
resolve(root, { name, firstName, preferredName, email, address, password, memberPlanID, memberPlanSlug, autoRenew, paymentPeriodicity, monthlyAmount, paymentMethodID, paymentMethodSlug, subscriptionProperties, successURL, failureURL, challengeAnswer }, { sessionTTL, hashCostFactor, prisma, loaders, memberContext, challenge, createPaymentWithProvider, mailContext }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
email = email.toLowerCase();
yield validator_1.Validator.createUser().parse({ name, email, firstName, preferredName });
const challengeValidationResult = yield challenge.validateChallenge({
challengeID: challengeAnswer.challengeID,
solution: challengeAnswer.challengeSolution
});
if (!challengeValidationResult.valid)
throw new error_1.CommentAuthenticationError(challengeValidationResult.message);
yield memberContext.validateInputParamsCreateSubscription(memberPlanID, memberPlanSlug, paymentMethodID, paymentMethodSlug);
const memberPlan = yield memberContext.getMemberPlanByIDOrSlug(loaders, memberPlanSlug, memberPlanID);
const paymentMethod = yield memberContext.getPaymentMethodByIDOrSlug(loaders, paymentMethodSlug, paymentMethodID);
// Check that monthly amount not
if (monthlyAmount < memberPlan.amountPerMonthMin)
throw new error_1.MonthlyAmountNotEnough();
yield memberContext.validateSubscriptionPaymentConfiguration(memberPlan, autoRenew, paymentPeriodicity, paymentMethod);
const userExists = yield prisma.user.findUnique({
where: {
email
},
select: api_2.unselectPassword
});
if (userExists)
throw new error_1.EmailAlreadyInUseError();
if (!password)
password = crypto.randomBytes(48).toString('base64');
const user = yield (0, user_mutation_1.createUser)({
name,
firstName,
preferredName,
email,
address,
emailVerifiedAt: null,
active: true,
roleIDs: [],
password
}, hashCostFactor, prisma, mailContext);
if (!user) {
(0, api_3.logger)('mutation.public').error('Could not create new user for email "%s"', email);
throw new error_1.InternalError();
}
const session = yield (0, session_mutation_1.createUserSession)(user, sessionTTL, prisma.session, prisma.userRole);
const properties = yield memberContext.processSubscriptionProperties(subscriptionProperties);
const { subscription, invoice } = yield memberContext.createSubscription(prisma.subscription, user.id, paymentMethod.id, paymentPeriodicity, monthlyAmount, memberPlan.id, properties, autoRenew);
if (!invoice) {
(0, api_3.logger)('mutation.public').error('Could not create new invoice for subscription with ID "%s"', subscription.id);
throw new error_1.InternalError();
}
return {
payment: yield createPaymentWithProvider({
invoice,
saveCustomer: true,
paymentMethodID: paymentMethod.id,
successURL,
failureURL
}),
user,
session
};
});
}
},
createSubscription: {
type: new graphql_1.GraphQLNonNull(payment_1.GraphQLPublicPayment),
args: {
memberPlanID: { type: graphql_1.GraphQLID },
memberPlanSlug: { type: slug_1.GraphQLSlug },
autoRenew: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLBoolean) },
paymentPeriodicity: { type: new graphql_1.GraphQLNonNull(memberPlan_1.GraphQLPaymentPeriodicity) },
monthlyAmount: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLInt) },
paymentMethodID: { type: graphql_1.GraphQLID },
paymentMethodSlug: { type: slug_1.GraphQLSlug },
subscriptionProperties: {
type: new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(common_1.GraphQLMetadataPropertyPublicInput))
},
successURL: { type: graphql_1.GraphQLString },
failureURL: { type: graphql_1.GraphQLString }
},
description: 'Allows authenticated users to create additional subscriptions',
resolve(root, { memberPlanID, memberPlanSlug, autoRenew, paymentPeriodicity, monthlyAmount, paymentMethodID, paymentMethodSlug, subscriptionProperties, successURL, failureURL }, { prisma, loaders, memberContext, createPaymentWithProvider, authenticateUser }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// authenticate user
const { user } = authenticateUser();
yield memberContext.validateInputParamsCreateSubscription(memberPlanID, memberPlanSlug, paymentMethodID, paymentMethodSlug);
const memberPlan = yield memberContext.getMemberPlanByIDOrSlug(loaders, memberPlanSlug, memberPlanID);
const paymentMethod = yield memberContext.getPaymentMethodByIDOrSlug(loaders, paymentMethodSlug, paymentMethodID);
if (monthlyAmount < memberPlan.amountPerMonthMin)
throw new error_1.MonthlyAmountNotEnough();
yield memberContext.validateSubscriptionPaymentConfiguration(memberPlan, autoRenew, paymentPeriodicity, paymentMethod);
const properties = yield memberContext.processSubscriptionProperties(subscriptionProperties);
const { subscription, invoice } = yield memberContext.createSubscription(prisma.subscription, user.id, paymentMethod.id, paymentPeriodicity, monthlyAmount, memberPlan.id, properties, autoRenew);
if (!invoice) {
(0, api_3.logger)('mutation.public').error('Could not create new invoice for subscription with ID "%s"', subscription.id);
throw new error_1.InternalError();
}
return yield createPaymentWithProvider({
invoice,
saveCustomer: true,
paymentMethodID: paymentMethod.id,
successURL,
failureURL,
user
});
});
}
},
extendSubscription: {
type: new graphql_1.GraphQLNonNull(payment_1.GraphQLPublicPayment),
args: {
subscriptionId: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) },
successURL: { type: graphql_1.GraphQLString },
failureURL: { type: graphql_1.GraphQLString }
},
description: 'This mutation extends an subscription early',
resolve(root, { subscriptionId, successURL, failureURL }, { prisma, authenticateUser, memberContext, createPaymentWithProvider, paymentProviders, loaders }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// authenticate user
const { user } = authenticateUser();
const subscription = (yield prisma.subscription.findUnique({
where: {
id: subscriptionId
}
}));
// Allow only valid and subscription belonging to the user to early extend
if (!subscription || subscription.userID !== user.id) {
(0, api_3.logger)('extendSubscription').error('Could not find subscription with ID "%s" or subscription does not belong to user "%s"', subscriptionId, user.id);
throw new error_1.SubscriptionNotFound();
}
// Throw for unsupported payment providers
const paymentMethod = yield prisma.paymentMethod.findUnique({
where: {
id: subscription.paymentMethodID
}
});
if (!paymentMethod) {
(0, api_3.logger)('extendSubscription').error('Could not find paymentMethod with ID "%s"', subscription.paymentMethodID);
throw new error_1.InternalError();
}
const paymentProvider = paymentProviders.find(obj => obj.id === paymentMethod.paymentProviderID);
// Prevent user from creating new invoice while having unpaid invoices
const unpaidInvoices = yield prisma.invoice.findMany({
where: {
subscriptionID: subscription.id,
paidAt: null
}
});
if (unpaidInvoices.length > 0) {
throw new error_1.AlreadyUnpaidInvoices();
}
const invoice = yield memberContext.renewSubscriptionForUser({
subscription
});
if (!invoice) {
(0, api_3.logger)('extendSubscription').error('Could not create new invoice for subscription with ID "%s"', subscription.id);
throw new error_1.InternalError();
}
// If payment provider supports off session payment try to charge
if (!paymentProvider || paymentProvider.offSessionPayments) {
const paymentMethod = yield loaders.paymentMethodsByID.load(subscription.paymentMethodID);
if (!paymentMethod) {
(0, api_3.logger)('extendSubscription').warn('paymentMethod %s not found', subscription.paymentMethodID);
throw new error_1.InternalError();
}
const fullUser = yield prisma.user.findUnique({
where: { id: subscription.userID },
select: api_2.unselectPassword
});
if (!fullUser) {
(0, api_3.logger)('extendSubscription').warn('user %s not found', subscription.userID);
throw new error_1.InternalError();
}
const customer = fullUser.paymentProviderCustomers.find(ppc => ppc.paymentProviderID === paymentMethod.paymentProviderID);
if (!customer) {
(0, api_3.logger)('extendSubscription').warn('customer %s not found', paymentMethod.paymentProviderID);
}
else {
// Charge customer
try {
const payment = yield memberContext.chargeInvoice({
user,
invoice,
paymentMethodID: subscription.paymentMethodID,
customer
});
if (payment) {
return payment;
}
}
catch (e) {
(0, api_3.logger)('extendSubscription').warn('Invoice off session charge for subscription %s failed: %s', subscription.id, e);
}
}
}
return yield createPaymentWithProvider({
invoice,
saveCustomer: true,
paymentMethodID: subscription.paymentMethodID,
successURL,
failureURL
});
});
}
},
sendWebsiteLogin: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
args: {
email: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) }
},
description: 'This mutation sends a login link to the email if the user exists. Method will always return email address',
resolve(root, { email }, { prisma, generateJWT, mailContext, urlAdapter }) {
var _a, _b;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
email = email.toLowerCase();
yield validator_1.Validator.login().parse({ email });
const user = yield prisma.user.findUnique({
where: { email },
select: api_2.unselectPassword
});
if (!user)
return email;
const lastSendTimeStamp = user.properties.find(property => (property === null || property === void 0 ? void 0 : property.key) === utility_1.USER_PROPERTY_LAST_LOGIN_LINK_SEND);
if (lastSendTimeStamp &&
parseInt(lastSendTimeStamp.value) > Date.now() - utility_1.FIFTEEN_MINUTES_IN_MILLISECONDS) {
(0, api_3.logger)('mutation.public').warn('User with ID %s requested Login Link multiple times in 15 min time window', user.id);
return email;
}
const resetPwdSetting = yield prisma.setting.findUnique({
where: { name: api_1.SettingName.RESET_PASSWORD_JWT_EXPIRES_MIN }
});
const resetPwd = (_a = resetPwdSetting === null || resetPwdSetting === void 0 ? void 0 : resetPwdSetting.value) !== null && _a !== void 0 ? _a : parseInt((_b = process.env.RESET_PASSWORD_JWT_EXPIRES_MIN) !== null && _b !== void 0 ? _b : '');
if (!resetPwd) {
throw new Error('No value set for RESET_PASSWORD_JWT_EXPIRES_MIN');
}
const remoteTemplate = yield mailContext.getUserTemplateName(client_1.UserEvent.LOGIN_LINK);
yield mailContext.sendMail({
externalMailTemplateId: remoteTemplate,
recipient: user,
optionalData: {},
mailType: api_4.mailLogType.UserFlow
});
try {
yield prisma.user.update({
where: { id: user.id },
data: {
properties: {
deleteMany: {
key: utility_1.USER_PROPERTY_LAST_LOGIN_LINK_SEND
},
create: {
key: utility_1.USER_PROPERTY_LAST_LOGIN_LINK_SEND,
public: false,
value: `${Date.now()}`
}
}
}
});
}
catch (error) {
(0, api_3.logger)('mutation.public').warn(error, 'Updating User with ID %s failed', user.id);
}
return email;
});
}
},
updateUser: {
type: user_1.GraphQLPublicUser,
args: {
input: { type: new graphql_1.GraphQLNonNull(user_1.GraphQLPublicUserInput) }
},
description: "This mutation allows to update the user's data by taking an input of type UserInput.",
resolve: (root, { input }, { authenticateUser, mediaAdapter, prisma: { user, image } }) => (0, user_public_mutation_1.updatePublicUser)(input, authenticateUser, mediaAdapter, user, image)
},
uploadUserProfileImage: {
type: user_1.GraphQLPublicUser,
args: {
uploadImageInput: { type: image_1.GraphQLUploadImageInput }
},
description: "This mutation allows to upload and update the user's profile image.",
resolve: (root, { uploadImageInput }, { authenticateUser, mediaAdapter, prisma: { image, user } }) => (0, user_public_mutation_1.uploadPublicUserProfileImage)(uploadImageInput, authenticateUser, mediaAdapter, image, user)
},
updatePassword: {
type: user_1.GraphQLPublicUser,
args: {
password: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) },
passwordRepeated: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) }
},
description: "This mutation allows to update the user's password by entering the new password. The repeated new password gives an error if the passwords don't match or if the user is not authenticated.",
resolve: (root, { password, passwordRepeated }, { authenticateUser, prisma: { user }, hashCostFactor }) => (0, user_public_mutation_1.updateUserPassword)(password, passwordRepeated, hashCostFactor, authenticateUser, user)
},
updateUserSubscription: {
type: subscription_public_1.GraphQLPublicSubscription,
args: {
id: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) },
input: { type: new graphql_1.GraphQLNonNull(subscription_public_1.GraphQLPublicSubscriptionInput) }
},
description: "This mutation allows to update the user's subscription by taking an input of type UserSubscription and throws an error if the user doesn't already have a subscription. Updating user subscriptions will set deactivation to null",
resolve: (root, { id, input }, { authenticateUser, prisma: { subscription }, loaders, memberContext, paymentProviders }) => (0, subscription_public_mutation_1.updatePublicSubscription)(id, input, authenticateUser, memberContext, loaders.activeMemberPlansByID, loaders.activePaymentMethodsByID, subscription, paymentProviders)
},
cancelUserSubscription: {
type: subscription_public_1.GraphQLPublicSubscription,
args: {
id: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) }
},
description: 'This mutation allows to cancel the users subscriptions. The deactivation date will be either paidUntil or now',
resolve(root, { id }, { authenticateUser, prisma, memberContext }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const { user } = authenticateUser();
if (!user)
throw new error_1.NotAuthenticatedError();
const subscription = yield prisma.subscription.findUnique({
where: { id },
include: {
deactivation: true,
periods: true,
properties: true
}
});
if (!subscription || subscription.userID !== user.id)
throw new error_1.NotFound('subscription', id);
if (subscription.deactivation)
throw new error_1.UserSubscriptionAlreadyDeactivated(subscription.deactivation.date);
yield memberContext.deactivateSubscription({
subscription,
deactivationReason: client_1.SubscriptionDeactivationReason.userSelfDeactivated
});
const updatedSubscription = yield prisma.subscription.findUnique({
where: { id },
include: {
deactivation: true,
periods: true,
properties: true
}
});
if (!updatedSubscription)
throw new error_1.NotFound('subscription', id);
return updatedSubscription;
});
}
},
updatePaymentProviderCustomers: {
type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(user_1.GraphQLPaymentProviderCustomer))),
args: {
input: {
type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(user_1.GraphQLPaymentProviderCustomerInput)))
}
},
description: 'This mutation allows to update the Payment Provider Customers',
resolve: (root, { input }, { authenticateUser, prisma: { user } }) => (0, user_public_mutation_1.updatePaymentProviderCustomers)(input, authenticateUser, user)
},
createPaymentFromInvoice: {
type: payment_1.GraphQLPublicPayment,
args: {
input: { type: new graphql_1.GraphQLNonNull(payment_1.GraphQLPaymentFromInvoiceInput) }
},
description: 'This mutation allows to create payment by taking an input of type PaymentFromInvoiceInput.',
resolve(root, { input }, { authenticateUser, createPaymentWithProvider, loaders, prisma }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const { user } = authenticateUser();
const { invoiceID, paymentMethodID, paymentMethodSlug, successURL, failureURL } = input;
if ((paymentMethodID == null && paymentMethodSlug == null) ||
(paymentMethodID != null && paymentMethodSlug != null)) {
throw new error_1.UserInputError('You must provide either `paymentMethodID` or `paymentMethodSlug`.');
}
const paymentMethod = paymentMethodID
? yield loaders.activePaymentMethodsByID.load(paymentMethodID)
: yield loaders.activePaymentMethodsBySlug.load(paymentMethodSlug);
if (!paymentMethod)
throw new error_1.NotFound('PaymentMethod', paymentMethodID || paymentMethodSlug);
const invoice = yield prisma.invoice.findUnique({
where: {
id: invoiceID
},
include: {
items: true
}
});
if (!invoice || !invoice.subscriptionID)
throw new error_1.NotFound('Invoice', invoiceID);
if (invoice.paidAt || invoice.canceledAt)
throw new error_1.InvoiceAlreadyPaidOrCanceled(invoiceID);
const subscription = yield prisma.subscription.findUnique({
where: {
id: invoice.subscriptionID
},
include: {
deactivation: true,
periods: true,
properties: true
}
});
if (!subscription || subscription.userID !== user.id)
throw new error_1.NotFound('Invoice', invoiceID);
// Prevent multiple payment of same invoice!
const blockingPaymnet = yield prisma.payment.findFirst({
where: {
invoiceID,
state: {
in: [client_1.PaymentState.created, client_1.PaymentState.submitted, client_1.PaymentState.processing]
},
createdAt: {
gte: (0, date_fns_1.sub)(new Date(), { minutes: 1 })
}
}
});
if (blockingPaymnet)
throw new error_1.PaymentAlreadyRunning(blockingPaymnet.id);
return yield createPaymentWithProvider({
paymentMethodID: paymentMethod.id,
invoice,
saveCustomer: false,
successURL,
failureURL,
user
});
});
}
},
createPaymentFromSubscription: {
type: payment_1.GraphQLPublicPayment,
args: {
subscriptionId: { type: graphql_1.GraphQLID },
successURL: { type: graphql_1.GraphQLString },
failureURL: { type: graphql_1.GraphQLString }
},
description: 'This mutation allows to create payment by referencing a subscription.',
resolve(root, { subscriptionId, successURL, failureURL }, { authenticateUser, createPaymentWithProvider, prisma }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const { user } = authenticateUser();
const invoice = yield prisma.invoice.findFirst({
where: {
subscriptionID: subscriptionId,
paidAt: null,
canceledAt: null
},
include: {
items: true,
subscription: true
}
});
if (!invoice) {
throw new error_1.NotFound('Unpaid Invoice', subscriptionId);
}
if (invoice.subscription.userID !== user.id) {
throw new error_1.NotFound('Subscription', subscriptionId);
}
return yield createPaymentWithProvider({
paymentMethodID: invoice.subscription.paymentMethodID,
invoice,
saveCustomer: false,
successURL,
failureURL
});
});
}
},
voteOnPoll: {
type: poll_1.GraphQLPollVote,
args: {
answerId: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID) }
},
description: "This mutation allows to vote on a poll (or update one's decision). Supports logged in and anonymous",
resolve: (root, { answerId }, { optionalAuthenticateUser, prisma: { pollAnswer, pollVote, setting } }) => (0, poll_public_mutation_1.voteOnPoll)(answerId, undefined, optionalAuthenticateUser, pollAnswer, pollVote, setting)
}
}
});
//# sourceMappingURL=mutation.public.js.map