import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '../../lib/constants' import { datePivot } from '../../lib/time' export default { Query: { imageFees: async (parent, { s3Keys }, { models, me }) => { const [, fees] = await imageFees(s3Keys, { models, me }) return fees } } } export async function imageFeesFromText (text, { models, me }) { // no text means no image fees if (!text) return [itemId => [], 0] // parse all s3 keys (= image ids) from text const textS3Keys = [...text.matchAll(AWS_S3_URL_REGEXP)].map(m => Number(m[1])) if (!textS3Keys.length) return [itemId => [], 0] return imageFees(textS3Keys, { models, me }) } export async function imageFees (s3Keys, { models, me }) { // To apply image fees, we return queries which need to be run, preferably in the same transaction as creating or updating an item. function queries (userId, imgIds, imgFees) { return itemId => { return [ // pay fees models.$queryRawUnsafe('SELECT * FROM user_fee($1::INTEGER, $2::INTEGER, $3::BIGINT)', userId, itemId, imgFees), // mark images as paid models.upload.updateMany({ where: { id: { in: imgIds } }, data: { paid: true } }) ] } } // we want to ignore image ids for which someone already paid during fee calculation // to make sure that every image is only paid once const unpaidS3Keys = (await models.upload.findMany({ select: { id: true }, where: { id: { in: s3Keys }, paid: false } })).map(({ id }) => id) const unpaid = unpaidS3Keys.length if (!unpaid) return [itemId => [], 0] if (!me) { // anons pay for every new image 100 sats const fees = unpaid * 100 return [queries(ANON_USER_ID, unpaidS3Keys, fees), fees] } // check how much stacker uploaded in last 24 hours const { _sum: { size: size24h } } = await models.upload.aggregate({ _sum: { size: true }, where: { userId: me.id, createdAt: { gt: datePivot(new Date(), { days: -1 }) }, paid: true } }) // check how much stacker uploaded now in size const { _sum: { size: sizeNow } } = await models.upload.aggregate({ _count: { id: true }, _sum: { size: true }, where: { id: { in: unpaidS3Keys } } }) // total size that we consider to calculate fees includes size of images within last 24 hours and size of incoming images const size = size24h + sizeNow const MB = 1024 * 1024 // factor for bytes -> megabytes // 10 MB per 24 hours are free. fee is also 0 if there are no incoming images (obviously) let fees if (!sizeNow || size <= 1 * MB) { fees = 0 } else if (size <= 25 * MB) { fees = 10 * unpaid } else if (size <= 50 * MB) { fees = 100 * unpaid } else if (size <= 100 * MB) { fees = 1000 * unpaid } else { fees = 10000 * unpaid } return [queries(me.id, unpaidS3Keys, fees), fees] }