setting up subscrption management for creators

revamp
lza_menace 2 years ago
parent 856490cf50
commit 3da8c9951d

@ -15,10 +15,9 @@ SERVER_NAME = getenv('SERVER_NAME', 'localhost:5000')
PLATFORM_WALLET = getenv('PLATFORM_WALLET')
# Constants - here for easy template references
CREATOR_SUBSCRIPTION_TERM = 60 # term of how long creator subscriptions are valid for
CREATOR_SUBSCRIPTION_GRACE = 10 # grace period after expiration of creator subscriptions until content is hidden
CREATOR_SUBSCRIPTION_DELETE = 20 # time after grace period until content is deleted
CREATOR_SUBSCRIPTION_FEE_XMR = .15 # default flat rate fee in XMR for creator subscriptions
CREATOR_SUBSCRIPTION_TERM = 60 # 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_FEE_XMR = .3 # XMR flat rate fee for creator subscriptions
# Crypto RPC
XMR_WALLET_PASS = getenv('XMR_WALLET_PASS')

@ -1,7 +1,7 @@
from datetime import datetime
import arrow
import monero
from monero import numbers
from quart import Blueprint, current_app
@ -22,4 +22,4 @@ def xmr_block_explorer(v):
@bp.app_template_filter('from_atomic')
def from_atomic(amt):
return monero.numbers.from_atomic(amt)
return numbers.as_monero(numbers.from_atomic(amt))

@ -1,5 +1,5 @@
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import StringField, FloatField
from wtforms.validators import DataRequired, ValidationError
from monero.address import address
@ -35,3 +35,8 @@ class UserChallenge(FlaskForm):
class ConfirmSubscription(FlaskForm):
tx_id = StringField('TX ID:', validators=[DataRequired()], render_kw={"placeholder": "TX ID", "class": "form-control", "type": "text"})
tx_key = StringField('TX Key:', validators=[DataRequired()], render_kw={"placeholder": "TX Key", "class": "form-control", "type": "text"})
class CreateSubscription(FlaskForm):
price_xmr = FloatField('Price (XMR):', validators=[DataRequired()], render_kw={'placeholder': '.5', 'class': 'form-control', 'type': 'text'})
number_days = FloatField('Length (Days)', validators=[DataRequired()], render_kw={'placeholder': '30', 'class': 'form-control', 'type': 'text'})

@ -1,4 +1,4 @@
from datetime import datetime
from datetime import datetime, timedelta
from enum import IntEnum, unique
from typing import List
from secrets import token_urlsafe
@ -116,7 +116,29 @@ class CreatorSubscription(pw.Model):
atomic_xmr = pw.BigIntegerField()
term_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_TERM * 24)
grace_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_GRACE * 24)
delete_hours = pw.IntegerField(default=config.CREATOR_SUBSCRIPTION_DELETE * 24)
delete_hours = pw.IntegerField(default=0) # delete me
@property
def grace_start_date(self):
# Hide content after this date if no new valid platform subscription
return self.create_date + timedelta(hours=self.term_hours)
@property
def delete_start_date(self):
# Archive content after this date if no new valid platform subscription
return self.grace_start_date + timedelta(hours=self.grace_hours)
@property
def hours_until_content_hidden(self):
return self.grace_start_date - datetime.utcnow()
@property
def hours_until_content_archived(self):
return self.delete_start_date - datetime.utcnow()
@property
def is_active(self):
return self.grace_start_date > datetime.utcnow()
class Meta:
database = db
@ -136,9 +158,10 @@ class SubscriptionMeta(pw.Model):
number_hours = pw.IntegerField()
wallet_address = pw.CharField()
def get_end_date(self) -> datetime:
# some timedelta shiz
pass
def get_active_subscriptions(self):
return Subscription.select().where(
Subscription.meta == self
)
class Meta:
database = db

@ -122,6 +122,43 @@ async def show(handle):
)
@bp.route('/creator/subscriptions/manage', methods=['GET', 'POST'])
@login_required
async def manage_subscriptions():
form = forms.CreateSubscription()
if UserRole.creator not in current_user.roles:
await flash('You are not a creator!', 'warning')
return redirect(url_for('main.index'))
platform_subs = CreatorSubscription.select().where(
CreatorSubscription.user == current_user
).order_by(CreatorSubscription.create_date.desc())
content_subs = SubscriptionMeta.select().where(
SubscriptionMeta.user == current_user
).order_by(SubscriptionMeta.create_date.desc())
subscribers = Subscription.select().where(
Subscription.meta.in_(content_subs)
).order_by(Subscription.subscribe_date.desc())
if form.validate_on_submit():
s = SubscriptionMeta(
user=current_user,
atomic_xmr=to_atomic(form.price_xmr.data),
number_hours=form.number_days.data * 24.0,
wallet_address=current_user.wallet_address
)
s.save()
await flash('posting form data', 'success')
return await render_template(
'creator/manage_subscriptions.html',
platform_subs=platform_subs,
content_subs=content_subs,
subscribers=subscribers,
form=form
)
# @bp.route('/creator/<username>/subscription')
# async def subscription(username):
# user = User.select().where(User.username == username)

@ -8,26 +8,23 @@ bp = Blueprint('main', 'main')
@bp.route('/')
async def index():
feed = None
if current_user.is_authenticated:
feed = dict()
new_creators = User.select().where(
User.roles.contains_any(UserRole.creator)
).order_by(User.register_date.desc()).execute()
feed['new_creators'] = new_creators
if current_user.is_authenticated:
active_subscriptions = Subscription.select().where(
Subscription.active == True,
Subscription.backer == current_user
).order_by(Subscription.subscribe_date.desc()).execute()
feed['active_subscriptions'] = active_subscriptions
new_posts = Content.select().where(
Content.hidden == False,
Content.creator in [c.creator for c in active_subscriptions]
).order_by(Content.post_date.desc()).execute()
feed = {
'new_creators': new_creators,
'new_posts': new_posts,
'active_subscriptions': active_subscriptions
}
feed['new_posts'] = new_posts
return await render_template(
'index.html',
feed=feed
)

@ -8,23 +8,6 @@
</p>
<p>Platform Wallet: {{ config.PLATFORM_WALLET }}</p>
<form method="POST" action="">
{% for f in form %}
{% if f.name == 'csrf_token' %}
{{ f }}
{% else %}
<div class="form-group">
{{ f.label }}
{{ f }}
</div>
{% endif %}
{% endfor %}
<ul>
{% for field, errors in form.errors.items() %}
<li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %}
</ul>
<input type="submit" value="Confirm" class="btn btn-link btn-outline btn-xl">
</form>
{% include 'includes/form.html' %}
{% endblock %}

@ -0,0 +1,49 @@
{% extends 'includes/base.html' %}
{% block content %}
<h2>Platform Subscriptions</h2>
<ul>
{% for s in platform_subs %}
<li>
Platform Subscription ID: {{ s.id }} <br>
Created: {{ s.create_date }} <br>
TX ID: {{ s.tx.tx_id }} <br>
Paid: {{ s.tx.atomic_xmr | from_atomic }} XMR <br>
Term Length: {{ s.term_hours }} hours ({{ s.hours_until_content_hidden }} hours) <br>
Hide Content: {{ s.hours_until_content_hidden }} hours <br>
Archive Content: {{ s.hours_until_content_archived }} hours <br>
Active Subscription: <strong>{{ s.is_active }}</strong> <br>
<br>
</li>
{% endfor %}
</ul>
<h2>Content Subscriptions</h2>
{% if not content_subs %}
<p>No subscriptions to your content yet.</p>
{% include 'includes/form.html' %}
{% else %}
<ul>
{% for s in content_subs %}
<li>
Content Subscription ID: {{ s.id }} <br>
Created: {{ s.create_date }} <br>
Price: {{ s.atomic_xmr | from_atomic }} XMR <br>
Term Length: {{ s.number_hours }} hours <br>
Active Subscriptions: {{ s.get_active_subscriptions().count() }} <br>
</li>
{% endfor %}
</ul>
{% endif %}
<h2>Subscribers</h2>
{% if not subscribers %}
<p>No subscribers yet.</p>
{% else %}
{% for subscriber in subscribers %}
{{ subscriber }}
{% endfor %}
{% endif %}
{% endblock %}

@ -4,7 +4,7 @@
<body>
{% include 'includes/header.html' %}
{% block content %}{% endblock %}
{% include 'includes/footer.html' %}
{% include 'includes/debug.html' %}
{% include 'includes/scripts.html' %}
</body>
</html>

@ -0,0 +1,11 @@
<hr>
{% if config.DEBUG and current_user.is_authenticated %}
<h2>Debug</h2>
<p>
Authenticated: {{ current_user.is_authenticated }} <br>
Username: {{ current_user.handle }} <br>
Email: {{ current_user.email }} <br>
Wallet Address: {{ current_user.wallet_address }} <br>
</p>
{% endif %}

@ -0,0 +1,18 @@
<form method="POST" action="">
{% for f in form %}
{% if f.name == 'csrf_token' %}
{{ f }}
{% else %}
<div class="form-group">
{{ f.label }}
{{ f }}
</div>
{% endif %}
{% endfor %}
<ul>
{% for field, errors in form.errors.items() %}
<li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %}
</ul>
<input type="submit" value="Confirm" class="btn btn-link btn-outline btn-xl">
</form>

@ -7,16 +7,8 @@
<li><a href="{{ url_for('auth.logout') }}">Logout</a></li>
</ul>
</nav>
{% if current_user.is_authenticated %}
<p>Authenticated: {{ current_user.is_authenticated }}</p>
<p>Username: {{ current_user.handle }}</p>
<p>Email: {{ current_user.email }}</p>
<p>Wallet Address: {{ current_user.wallet_address }}</p>
{% endif %}
</header>
<hr>
<script src="/static/js/noty.js"></script>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}

@ -1,20 +1,17 @@
<!DOCTYPE HTML>
<html>
{% extends 'includes/base.html' %}
{% include 'includes/head.html' %}
{% block content %}
<body class="is-preload landing">
<div id="page-wrapper">
{% include 'includes/header.html' %}
{% if current_user.is_authenticated %}
{% if current_user.is_authenticated %}
{% if 2 not in current_user.roles %}
<a href="{{ url_for('creator.join') }}">Become a Creator</a>
{% else %}
<a href="{{ url_for('creator.manage_subscriptions') }}">Manage Subscriptions</a>
{% endif %}
{% endif %}
{% endif %}
{% if feed %}
{% if feed %}
<h1>Feed</h1>
{% if feed['new_creators'] %}
<h2>New Creators</h2>
{% for c in feed['new_creators'] %}
@ -33,13 +30,6 @@
<p>{{ s.id }}</p>
{% endfor %}
{% endif %}
{% endif %}
{% include 'includes/footer.html' %}
</div>
{% include 'includes/scripts.html' %}
{% endif %}
</body>
</html>
{% endblock %}

Loading…
Cancel
Save