文件
jw-beauty/cloud/functions/subscription/index.js
T

139 行
4.2 KiB
JavaScript

var db = require('../../common/db')
var auth = require('../../common/auth')
var log = require('../../common/log')
var RESPONSE = require('../../common/response').RESPONSE
var ERROR_CODES = require('../../common/response').ERROR_CODES
exports.main_handler = async function (event) {
try {
var method = event.httpMethod || 'GET'
var path = event.path || ''
var body = parseBody(event)
if (method === 'GET' && path === '/api/v1/subscription') {
return await getSubscription(event)
}
if (method === 'POST' && path === '/api/v1/subscription/purchase') {
return await purchaseSubscription(event, body)
}
if (method === 'POST' && path === '/api/v1/subscription/verify') {
return await verifyPayment(event, body)
}
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'unknown route')
} catch (err) {
console.error('subscription error:', err)
return RESPONSE.error(ERROR_CODES.SERVER_ERROR.code, err.message)
}
}
async function getSubscription(event) {
var user = auth.extractUser(event)
if (!user) return RESPONSE.error(ERROR_CODES.INVALID_TOKEN.code, ERROR_CODES.INVALID_TOKEN.message)
var subs = await db.query(
'SELECT id, type, plan, status, trial_used, started_at AS start_time, expired_at AS expire_time ' +
'FROM subscriptions ' +
'WHERE user_id = ? AND status = 1 AND expired_at > NOW() ' +
'ORDER BY expired_at DESC LIMIT 1',
[user.user_id]
)
if (subs.length === 0) {
return RESPONSE.success({
status: 0,
plan: null,
start_time: null,
expire_time: null,
remaining_days: 0
})
}
var sub = subs[0]
var remainingMs = new Date(sub.expire_time) - new Date()
var remainingDays = Math.ceil(remainingMs / 86400000)
return RESPONSE.success({
status: sub.type === 1 ? 1 : 2,
plan: sub.plan,
start_time: sub.start_time,
expire_time: sub.expire_time,
remaining_days: remainingDays
})
}
async function purchaseSubscription(event, body) {
var user = auth.extractUser(event)
if (!user) return RESPONSE.error(ERROR_CODES.INVALID_TOKEN.code, ERROR_CODES.INVALID_TOKEN.message)
if (!body.plan) {
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'missing plan')
}
var planDays = { monthly: 30, quarterly: 90, yearly: 365 }
var days = planDays[body.plan] || 30
var orderId = 'ORD' + Date.now() + Math.random().toString(36).substring(2, 8)
return RESPONSE.success({
order_id: orderId,
payment_params: {
plan: body.plan,
days: days,
amount: 0,
channel: body.payment_method || 'wechat'
}
})
}
async function verifyPayment(event, body) {
var user = auth.extractUser(event)
if (!user) return RESPONSE.error(ERROR_CODES.INVALID_TOKEN.code, ERROR_CODES.INVALID_TOKEN.message)
if (!body.order_id) {
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'missing order_id')
}
var planDays = { monthly: 30, quarterly: 90, yearly: 365 }
var currentSub = await db.query(
'SELECT id, expired_at FROM subscriptions WHERE user_id = ? AND status = 1 AND expired_at > NOW() ORDER BY expired_at DESC LIMIT 1',
[user.user_id]
)
var startDate = new Date()
if (currentSub.length > 0 && new Date(currentSub[0].expired_at) > startDate) {
startDate = new Date(currentSub[0].expired_at)
}
var plan = body.plan || 'monthly'
var days = planDays[plan] || 30
var expiredAt = new Date(startDate.getTime() + days * 86400000)
await db.insert(
'INSERT INTO subscriptions (user_id, type, plan, status, started_at, expired_at, source, source_id) VALUES (?, 2, ?, 1, ?, ?, ?, ?)',
[user.user_id, plan, startDate.toISOString().slice(0, 19).replace('T', ' '), expiredAt.toISOString().slice(0, 19).replace('T', ' '), 'purchase', body.order_id]
)
await log.writeLog({
operator_type: 2,
operator_id: user.user_id,
target_type: 'subscription',
target_id: body.order_id,
action: 'purchase',
remark: 'plan=' + plan + ',days=' + days
})
return RESPONSE.success({
status: 2,
plan: plan,
expire_time: expiredAt.toISOString().slice(0, 19).replace('T', ' ')
})
}
function parseBody(event) {
if (event.body) {
try { return JSON.parse(event.body) } catch (e) { return {} }
}
return event.queryStringParameters || {}
}