dynamic subscription fees

revamp
lza_menace 2 years ago
parent 680dc5aff5
commit ad6bad9b5e

@ -18,6 +18,8 @@ PLATFORM_WALLET = getenv('PLATFORM_WALLET')
CREATOR_SUBSCRIPTION_TERM = 30 # days term of how long creator subscriptions are valid for until content is hidden CREATOR_SUBSCRIPTION_TERM = 30 # days term of how long creator subscriptions are valid for until content is hidden
CREATOR_SUBSCRIPTION_GRACE = 21 # days grace period after expiration of creator subscriptions until content is archived CREATOR_SUBSCRIPTION_GRACE = 21 # days grace period after expiration of creator subscriptions until content is archived
CREATOR_SUBSCRIPTION_FEE_XMR = .15 # XMR flat rate fee for creator subscriptions CREATOR_SUBSCRIPTION_FEE_XMR = .15 # XMR flat rate fee for creator subscriptions
CREATOR_CONTENT_FEE_PERCENT = 5 # percentage of base fee to charge for content/posts
CREATOR_ACTIVE_SUBSCRIBER_FEE_PERCENT = 10 # percentage of received subscriber fees to charge creator for platform reup
# Crypto RPC # Crypto RPC
XMR_WALLET_PASS = getenv('XMR_WALLET_PASS') XMR_WALLET_PASS = getenv('XMR_WALLET_PASS')

@ -4,6 +4,7 @@ from typing import List
from secrets import token_urlsafe from secrets import token_urlsafe
import peewee as pw import peewee as pw
from monero.numbers import to_atomic, from_atomic
from xmrbackers import config from xmrbackers import config
from xmrbackers.helpers import EnumArrayField, EnumIntField from xmrbackers.helpers import EnumArrayField, EnumIntField
@ -28,12 +29,20 @@ class UserRole(IntEnum):
@unique @unique
class ContentType(IntEnum): class PostType(IntEnum):
text = 0 text = 0
gallery = 1 gallery = 1
stream = 2 stream = 2
@unique
class ContentType(IntEnum):
text = 0
image = 1
video = 2
stream = 3
class User(pw.Model): class User(pw.Model):
""" """
User model is for base user management and reporting. User model is for base user management and reporting.
@ -78,6 +87,29 @@ class User(pw.Model):
return True return True
return False return False
def derive_subscription_fees(self):
base_fee_atomic = to_atomic(config.CREATOR_SUBSCRIPTION_FEE_XMR)
posts = Post.select().where(Post.creator == self)
content = Content.select().join(Post).where(Post.creator == self)
content_base_fee_atomic = base_fee_atomic * config.CREATOR_CONTENT_FEE_PERCENT
content_fee_atomic = (posts.count() + content.count()) * content_base_fee_atomic
active_subs = Subscription.select().where(
Subscription.creator == self,
Subscription.is_active == True
)
received_sub_xmr_atomic = 0
for sub in active_subs:
received_sub_xmr_atomic += sub.meta.atomic_xmr
print('User can expect to pay the following fees on their next reup:\nBase Fee: {} XMR\nContent Fees: {} ({} posts, {} uploads)\nSubscriber Fees: {}'.format(
config.CREATOR_SUBSCRIPTION_FEE_XMR,
from_atomic(content_fee_atomic),
posts.count(),
content.count(),
from_atomic(received_sub_xmr_atomic)
))
class Meta: class Meta:
database = db database = db
@ -127,7 +159,6 @@ class CreatorSubscription(pw.Model):
atomic_xmr = pw.BigIntegerField() atomic_xmr = pw.BigIntegerField()
term_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_TERM * 24) term_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_TERM * 24)
grace_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_GRACE * 24) grace_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_GRACE * 24)
delete_hours = pw.IntegerField(default=0) # delete me
@property @property
def grace_start_date(self): def grace_start_date(self):
@ -188,19 +219,23 @@ class Subscription(pw.Model):
id = pw.AutoField() id = pw.AutoField()
subscribe_date = pw.DateTimeField(default=datetime.utcnow) subscribe_date = pw.DateTimeField(default=datetime.utcnow)
tx = pw.ForeignKeyField(Transaction) tx = pw.ForeignKeyField(Transaction)
active = pw.BooleanField(default=True)
creator = pw.ForeignKeyField(User) creator = pw.ForeignKeyField(User)
backer = pw.ForeignKeyField(User) backer = pw.ForeignKeyField(User)
meta = pw.ForeignKeyField(SubscriptionMeta) meta = pw.ForeignKeyField(SubscriptionMeta)
@property
def is_active(self):
end_date = self.subscribe_date + timedelta(hours=self.meta.number_hours)
return end_date > datetime.utcnow()
class Meta: class Meta:
database = db database = db
class Content(pw.Model): class Post(pw.Model):
""" """
Content model represents any uploaded content from a creator which is only Post model represents a post from a creator consisting of Content objects
viewable by backers with an active subscription. which is only viewable by backers with an active subscription.
""" """
id = pw.AutoField() id = pw.AutoField()
post_date = pw.DateTimeField(default=datetime.utcnow) post_date = pw.DateTimeField(default=datetime.utcnow)
@ -210,6 +245,21 @@ class Content(pw.Model):
last_edit_date = pw.DateTimeField(default=datetime.utcnow) last_edit_date = pw.DateTimeField(default=datetime.utcnow)
creator = pw.ForeignKeyField(User) creator = pw.ForeignKeyField(User)
type: List[PostType] = EnumIntField(enum_class=PostType, default=PostType.text)
class Meta:
database = db
class Content(pw.Model):
"""
Content model is any uploaded content from a creator.
"""
id = pw.AutoField()
location = pw.CharField()
upload_date = pw.DateTimeField(default=datetime.utcnow)
post = pw.ForeignKeyField(Post)
type: List[ContentType] = EnumIntField(enum_class=ContentType, default=ContentType.text) type: List[ContentType] = EnumIntField(enum_class=ContentType, default=ContentType.text)
class Meta: class Meta:

@ -114,10 +114,12 @@ async def show(handle):
await flash('That creator does not exist.', 'warning') await flash('That creator does not exist.', 'warning')
return redirect(url_for('main.index')) return redirect(url_for('main.index'))
posts = Content.select().where( creator.derive_subscription_fees()
Content.creator == creator,
Content.hidden == False posts = Post.select().where(
).order_by(Content.post_date.desc()) Post.creator == creator,
Post.hidden == False
).order_by(Post.post_date.desc())
subscriptions = SubscriptionMeta.select().where( subscriptions = SubscriptionMeta.select().where(
SubscriptionMeta.user == creator SubscriptionMeta.user == creator
).order_by(SubscriptionMeta.create_date.desc()) ).order_by(SubscriptionMeta.create_date.desc())

@ -1,7 +1,7 @@
from quart import Blueprint, render_template from quart import Blueprint, render_template
from flask_login import current_user from flask_login import current_user
from xmrbackers.models import User, Profile, Subscription, Content, UserRole from xmrbackers.models import *
bp = Blueprint('main', 'main') bp = Blueprint('main', 'main')
@ -15,14 +15,14 @@ async def index():
feed['new_creators'] = new_creators feed['new_creators'] = new_creators
if current_user.is_authenticated: if current_user.is_authenticated:
active_subscriptions = Subscription.select().where( active_subscriptions = Subscription.select().where(
Subscription.active == True, Subscription.is_active == True,
Subscription.backer == current_user Subscription.backer == current_user
).order_by(Subscription.subscribe_date.desc()).execute() ).order_by(Subscription.subscribe_date.desc()).execute()
feed['active_subscriptions'] = active_subscriptions feed['active_subscriptions'] = active_subscriptions
new_posts = Content.select().where( new_posts = Post.select().where(
Content.hidden == False, Post.hidden == False,
Content.creator in [c.creator for c in active_subscriptions] Post.creator in [c.creator for c in active_subscriptions]
).order_by(Content.post_date.desc()).execute() ).order_by(Post.post_date.desc()).execute()
feed['new_posts'] = new_posts feed['new_posts'] = new_posts
return await render_template( return await render_template(
'index.html', 'index.html',

Loading…
Cancel
Save