mirror of
https://git.wownero.com/lza_menace/suchwow.git
synced 2024-08-15 01:03:19 +00:00
updating funcs and queries
This commit is contained in:
parent
df33eaf258
commit
289995cd49
8 changed files with 66 additions and 169 deletions
|
@ -32,8 +32,13 @@ class User(Model):
|
||||||
ban_timestamp = DateField(null=True)
|
ban_timestamp = DateField(null=True)
|
||||||
login_timestamp = DateTimeField(null=True)
|
login_timestamp = DateTimeField(null=True)
|
||||||
|
|
||||||
def __repr__(self):
|
def get_wow_received(self):
|
||||||
return self.username
|
tips = TipReceived.select().join(Post).where(Post.user == self)
|
||||||
|
return sum(tip.amount for tip in tips)
|
||||||
|
|
||||||
|
def get_wow_sent(self):
|
||||||
|
tips = TipSent.select().where(TipSent.from_user == self)
|
||||||
|
return sum(tip.amount for tip in tips)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
database = db
|
database = db
|
||||||
|
@ -74,17 +79,9 @@ class Post(Model):
|
||||||
s = path.splitext(self.image_name)
|
s = path.splitext(self.image_name)
|
||||||
return s[0] + '.thumbnail' + s[1]
|
return s[0] + '.thumbnail' + s[1]
|
||||||
|
|
||||||
def get_received_wow(self):
|
def get_wow_received(self):
|
||||||
try:
|
tips = TipReceived.select().where(TipReceived.post == self)
|
||||||
w = wownero.Wallet()
|
return sum(tip.amount for tip in tips)
|
||||||
it = w.incoming_transfers(self.account_index)
|
|
||||||
if 'transfers' in it:
|
|
||||||
amounts = [amt['amount'] for amt in it['transfers'] if 'transfers' in it]
|
|
||||||
return wownero.as_wownero(wownero.from_atomic(sum(amounts)))
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
except:
|
|
||||||
return '?'
|
|
||||||
|
|
||||||
def hours_elapsed(self):
|
def hours_elapsed(self):
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
|
@ -107,7 +104,7 @@ class Post(Model):
|
||||||
'timestamp': self.timestamp,
|
'timestamp': self.timestamp,
|
||||||
'approved': self.approved,
|
'approved': self.approved,
|
||||||
'approved_by': self.approved_by,
|
'approved_by': self.approved_by,
|
||||||
'received_wow': self.get_received_wow(),
|
'received_wow': self.get_wow_received(),
|
||||||
'hours_elapsed': self.hours_elapsed()
|
'hours_elapsed': self.hours_elapsed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +146,8 @@ class TipReceived(Model):
|
||||||
|
|
||||||
class TipSent(Model):
|
class TipSent(Model):
|
||||||
id = AutoField()
|
id = AutoField()
|
||||||
user = ForeignKeyField(User)
|
from_user = ForeignKeyField(User)
|
||||||
|
to_user = ForeignKeyField(User)
|
||||||
txid = CharField(unique=True)
|
txid = CharField(unique=True)
|
||||||
timestamp = DateTimeField()
|
timestamp = DateTimeField()
|
||||||
amount = IntegerField()
|
amount = IntegerField()
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
from os import makedirs
|
from os import makedirs
|
||||||
|
|
||||||
import click
|
from flask import Blueprint
|
||||||
from flask import Blueprint, url_for, current_app
|
|
||||||
|
|
||||||
from suchwow._models import db, User, Post, AuditEvent, TipSent, TipReceived, Vote
|
from suchwow._models import db, User, Post, AuditEvent, TipSent, TipReceived, Vote
|
||||||
from suchwow.utils.helpers import get_latest_tipped_posts
|
from suchwow.models import Post as OldPost
|
||||||
from suchwow.utils.helpers import get_top_posters, get_top_posts
|
|
||||||
from suchwow.reddit import make_post
|
|
||||||
from suchwow import wownero
|
from suchwow import wownero
|
||||||
from suchwow import config
|
from suchwow import config
|
||||||
|
|
||||||
|
@ -23,6 +20,29 @@ def init():
|
||||||
db.create_tables([User, Post, AuditEvent, TipSent, TipReceived, Vote])
|
db.create_tables([User, Post, AuditEvent, TipSent, TipReceived, Vote])
|
||||||
|
|
||||||
|
|
||||||
|
@bp.cli.command('rescan')
|
||||||
|
def rescan():
|
||||||
|
wallet = wownero.Wallet()
|
||||||
|
wallet.make_wallet_rpc('rescan_blockchain')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.cli.command('save')
|
||||||
|
def rescan():
|
||||||
|
wallet = wownero.Wallet()
|
||||||
|
wallet.make_wallet_rpc('store')
|
||||||
|
print('Saved wallet.')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.cli.command("create_accounts")
|
||||||
|
def create_accounts():
|
||||||
|
wallet = wownero.Wallet()
|
||||||
|
highest_account = OldPost.select().order_by(OldPost.timestamp.desc()).first().account_index
|
||||||
|
print(f'Highest post account index is {highest_account} but highest wallet account is {wallet.accounts()[-1]}. Generating new accounts!')
|
||||||
|
while wallet.accounts()[-1] < highest_account:
|
||||||
|
account = wallet.new_account()
|
||||||
|
print(f"Created account {account}")
|
||||||
|
wallet.make_wallet_rpc('store')
|
||||||
|
|
||||||
# @bp.cli.command("post_reddit")
|
# @bp.cli.command("post_reddit")
|
||||||
# @click.argument('last_hours')
|
# @click.argument('last_hours')
|
||||||
# def post_reddit(last_hours):
|
# def post_reddit(last_hours):
|
||||||
|
@ -40,15 +60,6 @@ def init():
|
||||||
# return
|
# return
|
||||||
|
|
||||||
|
|
||||||
# @bp.cli.command("create_accounts")
|
|
||||||
# def create_accounts():
|
|
||||||
# wallet = wownero.Wallet()
|
|
||||||
# for post in Post.select():
|
|
||||||
# if post.account_index not in wallet.accounts():
|
|
||||||
# account = wallet.new_account()
|
|
||||||
# print(f"Created account {account}")
|
|
||||||
|
|
||||||
|
|
||||||
# @bp.cli.command("payout_users")
|
# @bp.cli.command("payout_users")
|
||||||
# def payout_users():
|
# def payout_users():
|
||||||
# wallet = wownero.Wallet()
|
# wallet = wownero.Wallet()
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
|
import peewee
|
||||||
from flask import render_template, Blueprint, request
|
from flask import render_template, Blueprint, request
|
||||||
|
|
||||||
from suchwow.utils.helpers import get_top_posters, get_top_posts
|
from suchwow._models import Post, TipReceived, User
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint("leaderboard", "leaderboard")
|
bp = Blueprint("leaderboard", "leaderboard")
|
||||||
|
|
||||||
@bp.route("/leaderboards/top_posters")
|
@bp.route("/leaderboards/top_posters")
|
||||||
def top_posters():
|
def top_posters():
|
||||||
top_posters = get_top_posters()
|
top_posters = TipReceived.select(
|
||||||
|
TipReceived.post, peewee.fn.SUM(TipReceived.amount)
|
||||||
|
).join(Post).order_by(
|
||||||
|
peewee.fn.SUM(TipReceived.amount).desc()
|
||||||
|
).group_by(TipReceived.post)
|
||||||
|
# revenue = fn.SUM(Booking.slots * Case(None, (
|
||||||
|
# (Booking.member == 0, Facility.guestcost),
|
||||||
|
# ), Facility.membercost))
|
||||||
|
#
|
||||||
|
# query = (Facility
|
||||||
|
# .select(Facility.name, revenue.alias('revenue'))
|
||||||
|
# .join(Booking)
|
||||||
|
# .group_by(Facility.name)
|
||||||
|
# .order_by(SQL('revenue')))
|
||||||
return render_template("leaderboard.html", posters=top_posters)
|
return render_template("leaderboard.html", posters=top_posters)
|
||||||
|
|
||||||
@bp.route("/leaderboards/top_posts")
|
@bp.route("/leaderboards/top_posts")
|
||||||
|
|
|
@ -2,8 +2,7 @@ from math import ceil
|
||||||
|
|
||||||
from flask import Blueprint, request, render_template, flash
|
from flask import Blueprint, request, render_template, flash
|
||||||
|
|
||||||
from suchwow._models import Post, User
|
from suchwow._models import Post, User, TipReceived
|
||||||
from suchwow.utils.helpers import get_latest_tipped_posts
|
|
||||||
|
|
||||||
bp = Blueprint('main', 'main')
|
bp = Blueprint('main', 'main')
|
||||||
|
|
||||||
|
@ -16,10 +15,10 @@ def index():
|
||||||
content = request.args.get("content", None)
|
content = request.args.get("content", None)
|
||||||
|
|
||||||
if content == 'latest_tipped':
|
if content == 'latest_tipped':
|
||||||
posts = get_latest_tipped_posts()
|
posts = Post.select().join(TipReceived).distinct().order_by(TipReceived.timestamp.desc()).limit(30)
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html",
|
||||||
posts=posts[0:30],
|
posts=posts,
|
||||||
title="Latest Tipped Memes"
|
title="Latest Tipped Memes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ def index():
|
||||||
|
|
||||||
posts = Post.select().where(Post.approved == True).order_by(Post.timestamp.desc())
|
posts = Post.select().where(Post.approved == True).order_by(Post.timestamp.desc())
|
||||||
if submitter:
|
if submitter:
|
||||||
user = Post.select().where(Post.username == submitter).first()
|
user = User.select().where(User.username == submitter)
|
||||||
if not user:
|
if not user:
|
||||||
flash('That user does not exist!', 'is-warning')
|
flash('That user does not exist!', 'is-warning')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -11,7 +11,7 @@ from werkzeug.utils import secure_filename
|
||||||
from suchwow import wownero, config
|
from suchwow import wownero, config
|
||||||
from suchwow._models import User, Post, TipReceived
|
from suchwow._models import User, Post, TipReceived
|
||||||
from suchwow.utils.decorators import login_required, address_required, moderator_required
|
from suchwow.utils.decorators import login_required, address_required, moderator_required
|
||||||
from suchwow.utils.helpers import allowed_file, is_moderator, get_session_user
|
from suchwow.utils.helpers import allowed_file, get_session_user
|
||||||
from suchwow.utils.helpers import audit_event
|
from suchwow.utils.helpers import audit_event
|
||||||
from suchwow.discord import post_discord_webhook
|
from suchwow.discord import post_discord_webhook
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,18 @@
|
||||||
{% if posts %}
|
{% if posts %}
|
||||||
{% for row in posts | batch(4) %}
|
{% for row in posts | batch(4) %}
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
{% for p in row %}
|
{% for post in row %}
|
||||||
{% set post = p.show() %}
|
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-image">
|
<div class="card-image">
|
||||||
<a href="{{ url_for('post.read', id=post.id) }}">
|
<a href="{{ url_for('post.read', id=post.id) }}">
|
||||||
{% if p.get_image_path().endswith('mp4') %}
|
{% if post.get_image_path().endswith('mp4') %}
|
||||||
<video style="max-height: 100vh!important;" controls>
|
<video style="max-height: 100vh!important;" controls>
|
||||||
<source src="{{ url_for('post.uploaded_file', filename=p.image_name) }}" type="video/mp4">
|
<source src="{{ url_for('post.uploaded_file', filename=post.image_name) }}" type="video/mp4">
|
||||||
Your browser does not support the video tag.
|
Your browser does not support the video tag.
|
||||||
</video>
|
</video>
|
||||||
{% else %}
|
{% else %}
|
||||||
<img alt="SuchWow #{{ post.id }} - {{ post.title }} by {{ post.user.username }}" src="{{ url_for('post.uploaded_file', filename=post.thumbnail_name) }}" />
|
<img alt="SuchWow #{{ post.id }} - {{ post.title }} by {{ post.user.username }}" src="{{ url_for('post.uploaded_file', filename=post.get_thumbnail_name()) }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,13 +37,12 @@
|
||||||
<p class="title is-4">
|
<p class="title is-4">
|
||||||
<a href="{{ url_for('post.read', id=post.id) }}">{{ post.title }}</a>
|
<a href="{{ url_for('post.read', id=post.id) }}">{{ post.title }}</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="subtitle is-6"><a href="/?submitter={{ post.submitter }}">{{ post.submitter }}</a></p>
|
<p class="subtitle is-6"><a href="/?submitter={{ post.user.username }}">{{ post.user.username }}</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ post.text | truncate(60) }}
|
{{ post.text | truncate(60) }}
|
||||||
<p><strong>{{ post.received_wow }} WOW received</strong></p>
|
<p><strong>{{ post.get_wow_received() | from_atomic }} WOW received</strong></p>
|
||||||
<time datetime="2016-1-1">{{ post.timestamp.year }}-{{ post.timestamp.month }}-{{ post.timestamp.day }} {{ post.timestamp.hour }}:{{ post.timestamp.minute }} UTC</time>
|
<time datetime="2016-1-1">{{ post.timestamp.year }}-{{ post.timestamp.month }}-{{ post.timestamp.day }} {{ post.timestamp.hour }}:{{ post.timestamp.minute }} UTC</time>
|
||||||
<p>({{ post.timestamp | humanize }})</p>
|
<p>({{ post.timestamp | humanize }})</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,8 +5,6 @@ from datetime import datetime, timedelta
|
||||||
from flask import session
|
from flask import session
|
||||||
|
|
||||||
from suchwow._models import AuditEvent, User
|
from suchwow._models import AuditEvent, User
|
||||||
from suchwow.models import Moderator, Post, Profile
|
|
||||||
from suchwow.wownero import Wallet, from_atomic
|
|
||||||
from suchwow import config
|
from suchwow import config
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,13 +12,6 @@ def allowed_file(filename):
|
||||||
return "." in filename and \
|
return "." in filename and \
|
||||||
filename.rsplit(".", 1)[1].lower() in config.ALLOWED_EXTENSIONS
|
filename.rsplit(".", 1)[1].lower() in config.ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
def is_moderator(username):
|
|
||||||
m = Moderator.filter(username=username)
|
|
||||||
if m:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_current_user():
|
def get_current_user():
|
||||||
u = User.select().where(User.username == get_session_user()).first()
|
u = User.select().where(User.username == get_session_user()).first()
|
||||||
return u
|
return u
|
||||||
|
@ -34,116 +25,3 @@ def get_session_user():
|
||||||
return None
|
return None
|
||||||
return session["auth"]["preferred_username"].strip()
|
return session["auth"]["preferred_username"].strip()
|
||||||
|
|
||||||
def get_latest_tipped_posts():
|
|
||||||
key_name = 'latest_tips'
|
|
||||||
posts = []
|
|
||||||
tipped_posts = rw_cache(key_name)
|
|
||||||
if not tipped_posts:
|
|
||||||
w = Wallet()
|
|
||||||
data = {}
|
|
||||||
for acc in w.accounts():
|
|
||||||
txes = w.transfers(acc)
|
|
||||||
if 'in' in txes:
|
|
||||||
for tx in txes['in']:
|
|
||||||
p = Post.select().where(
|
|
||||||
Post.account_index==acc
|
|
||||||
).first()
|
|
||||||
if p:
|
|
||||||
data[tx['timestamp']] = p
|
|
||||||
|
|
||||||
dates = sorted(data, reverse=True)
|
|
||||||
for d in dates:
|
|
||||||
if not data[d] in posts:
|
|
||||||
posts.append(data[d])
|
|
||||||
|
|
||||||
tipped_posts = rw_cache(key_name, posts)
|
|
||||||
|
|
||||||
return tipped_posts
|
|
||||||
|
|
||||||
def get_top_posters():
|
|
||||||
top_posters = {}
|
|
||||||
posts = rw_cache('top_posters')
|
|
||||||
if not posts:
|
|
||||||
posts = Post.select().where(Post.approved==True)
|
|
||||||
for post in posts:
|
|
||||||
transfers = []
|
|
||||||
incoming = Wallet().incoming_transfers(post.account_index)
|
|
||||||
if "transfers" in incoming:
|
|
||||||
for xfer in incoming["transfers"]:
|
|
||||||
transfers.append(from_atomic(xfer["amount"]))
|
|
||||||
total = sum(transfers)
|
|
||||||
if post.submitter not in top_posters:
|
|
||||||
top_posters[post.submitter] = {"amount": 0, "posts": []}
|
|
||||||
|
|
||||||
top_posters[post.submitter]["amount"] += float(total)
|
|
||||||
top_posters[post.submitter]["posts"].append(post)
|
|
||||||
rw_cache('top_posters', top_posters)
|
|
||||||
else:
|
|
||||||
top_posters = posts
|
|
||||||
return top_posters
|
|
||||||
|
|
||||||
def get_top_posts(days=1):
|
|
||||||
top_posts = []
|
|
||||||
try:
|
|
||||||
days = int(days)
|
|
||||||
except:
|
|
||||||
days = 1
|
|
||||||
|
|
||||||
# stupid magic number bcuz fuck it
|
|
||||||
if days not in [1, 3, 7, 30, 9999]:
|
|
||||||
days = 7
|
|
||||||
|
|
||||||
hours = 24 * days
|
|
||||||
diff = datetime.now() - timedelta(hours=hours)
|
|
||||||
key_name = f'top_posts_{str(hours)}'
|
|
||||||
|
|
||||||
posts = rw_cache(key_name)
|
|
||||||
if not posts:
|
|
||||||
posts = Post.select().where(
|
|
||||||
Post.approved==True,
|
|
||||||
Post.timestamp > diff
|
|
||||||
).order_by(
|
|
||||||
Post.timestamp.desc()
|
|
||||||
)
|
|
||||||
for post in posts:
|
|
||||||
p = post.show()
|
|
||||||
if isinstance(p['received_wow'], float):
|
|
||||||
top_posts.append(p)
|
|
||||||
|
|
||||||
posts = rw_cache(key_name, top_posts)
|
|
||||||
return posts
|
|
||||||
|
|
||||||
# Use hacky filesystem cache since i dont feel like shipping redis
|
|
||||||
def rw_cache(key_name, data=None, diff_seconds=3600):
|
|
||||||
pickle_file = path.join(config.DATA_FOLDER, f'{key_name}.pkl')
|
|
||||||
try:
|
|
||||||
if path.isfile(pickle_file):
|
|
||||||
mtime_ts = path.getmtime(pickle_file)
|
|
||||||
mtime = datetime.fromtimestamp(mtime_ts)
|
|
||||||
now = datetime.now()
|
|
||||||
diff = now - mtime
|
|
||||||
# If pickled data file is less than an hour old, load it and render page
|
|
||||||
# Otherwise, determine balances, build json, store pickled data, and render page
|
|
||||||
if diff.seconds < diff_seconds:
|
|
||||||
print(f'unpickling {key_name}')
|
|
||||||
with open(pickle_file, 'rb') as f:
|
|
||||||
pickled_data = pickle.load(f)
|
|
||||||
return pickled_data
|
|
||||||
else:
|
|
||||||
if data:
|
|
||||||
print(f'pickling {key_name}')
|
|
||||||
with open(pickle_file, 'wb') as f:
|
|
||||||
f.write(pickle.dumps(data))
|
|
||||||
return data
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
if data:
|
|
||||||
print(f'pickling {key_name}')
|
|
||||||
with open(pickle_file, 'wb') as f:
|
|
||||||
f.write(pickle.dumps(data))
|
|
||||||
return data
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ class Wallet(object):
|
||||||
|
|
||||||
def new_account(self, label=None):
|
def new_account(self, label=None):
|
||||||
_account = self.make_wallet_rpc('create_account', {'label': label})
|
_account = self.make_wallet_rpc('create_account', {'label': label})
|
||||||
self.store()
|
|
||||||
return _account['account_index']
|
return _account['account_index']
|
||||||
|
|
||||||
def addresses(self, account, addr_indices=None):
|
def addresses(self, account, addr_indices=None):
|
||||||
|
|
Loading…
Reference in a new issue