Compare commits

...

2 Commits

@ -12,7 +12,7 @@ if not wallet.connected:
print('Wallet not connected')
exit()
all_posts = Post.select()
all_posts = Post.select().order_by(Post.timestamp.desc())
all_mods = Moderator.select()
all_profiles = Profile.select()
all_bans = Ban.select()
@ -27,7 +27,7 @@ all_data = {
for post in all_posts:
all_data['posts'].append({
post_data = {
'id': post.id,
'title': post.title,
'text': post.text,
@ -43,7 +43,9 @@ for post in all_posts:
'to_discord': post.to_discord,
'approved': post.approved,
'txes': wallet.transfers(post.account_index)
})
}
all_data['posts'].append(post_data)
print(post_data['txes'])
for mod in all_mods:
all_data['moderators'].append(mod.username)

@ -51,11 +51,12 @@ for post in all_data['posts']:
p = Post.get(post['id'])
for tx in post['txes']['in']:
if not TipReceived.select().where(TipReceived.txid == tx['txid']).first():
amount = sum(tx['amounts'])
TipReceived.create(
post=p,
timestamp=datetime.utcfromtimestamp(tx['timestamp']),
txid=tx['txid'],
amount=sum(tx['amounts']),
amount=amount,
fee=tx['fee']
)
print(f'Saving received tip txid {tx["txid"]}')
@ -65,7 +66,8 @@ for post in all_data['posts']:
for tx in post['txes']['out']:
if not TipSent.select().where(TipSent.txid == tx['txid']).first():
TipSent.create(
user=p.user,
from_user=p.user,
to_user=p.user,
txid=tx['txid'],
timestamp=datetime.utcfromtimestamp(tx['timestamp']),
amount=tx['amount'],

@ -32,8 +32,13 @@ class User(Model):
ban_timestamp = DateField(null=True)
login_timestamp = DateTimeField(null=True)
def __repr__(self):
return self.username
def get_wow_received(self):
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:
database = db
@ -74,17 +79,9 @@ class Post(Model):
s = path.splitext(self.image_name)
return s[0] + '.thumbnail' + s[1]
def get_received_wow(self):
try:
w = wownero.Wallet()
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 get_wow_received(self):
tips = TipReceived.select().where(TipReceived.post == self)
return sum(tip.amount for tip in tips)
def hours_elapsed(self):
now = datetime.utcnow()
@ -107,7 +104,7 @@ class Post(Model):
'timestamp': self.timestamp,
'approved': self.approved,
'approved_by': self.approved_by,
'received_wow': self.get_received_wow(),
'received_wow': self.get_wow_received(),
'hours_elapsed': self.hours_elapsed()
}
@ -149,7 +146,8 @@ class TipReceived(Model):
class TipSent(Model):
id = AutoField()
user = ForeignKeyField(User)
from_user = ForeignKeyField(User)
to_user = ForeignKeyField(User)
txid = CharField(unique=True)
timestamp = DateTimeField()
amount = IntegerField()

@ -1,12 +1,9 @@
from os import makedirs
import click
from flask import Blueprint, url_for, current_app
from flask import Blueprint
from suchwow._models import db, User, Post, AuditEvent, TipSent, TipReceived, Vote
from suchwow.utils.helpers import get_latest_tipped_posts
from suchwow.utils.helpers import get_top_posters, get_top_posts
from suchwow.reddit import make_post
from suchwow.models import Post as OldPost
from suchwow import wownero
from suchwow import config
@ -23,6 +20,29 @@ def init():
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")
# @click.argument('last_hours')
# def post_reddit(last_hours):
@ -40,15 +60,6 @@ def init():
# 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")
# def payout_users():
# wallet = wownero.Wallet()

@ -1,13 +1,27 @@
import peewee
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.route("/leaderboards/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)
@bp.route("/leaderboards/top_posts")

@ -2,8 +2,7 @@ from math import ceil
from flask import Blueprint, request, render_template, flash
from suchwow._models import Post, User
from suchwow.utils.helpers import get_latest_tipped_posts
from suchwow._models import Post, User, TipReceived
bp = Blueprint('main', 'main')
@ -16,10 +15,10 @@ def index():
content = request.args.get("content", None)
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(
"index.html",
posts=posts[0:30],
posts=posts,
title="Latest Tipped Memes"
)
@ -29,9 +28,9 @@ def index():
flash("Wow, wtf hackerman. Cool it.", "is-danger")
page = 1
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:
user = Post.select().where(Post.username == submitter).first()
user = User.select().where(User.username == submitter)
if not user:
flash('That user does not exist!', 'is-warning')
else:

@ -11,7 +11,7 @@ from werkzeug.utils import secure_filename
from suchwow import wownero, config
from suchwow._models import User, Post, TipReceived
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.discord import post_discord_webhook

@ -16,19 +16,18 @@
{% if posts %}
{% for row in posts | batch(4) %}
<div class="columns">
{% for p in row %}
{% set post = p.show() %}
{% for post in row %}
<div class="column">
<div class="card">
<div class="card-image">
<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>
<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.
</video>
{% 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 %}
</a>
</div>
@ -38,13 +37,12 @@
<p class="title is-4">
<a href="{{ url_for('post.read', id=post.id) }}">{{ post.title }}</a>
</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 class="content">
{{ 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>
<p>({{ post.timestamp | humanize }})</p>
</div>

@ -5,8 +5,6 @@ from datetime import datetime, timedelta
from flask import session
from suchwow._models import AuditEvent, User
from suchwow.models import Moderator, Post, Profile
from suchwow.wownero import Wallet, from_atomic
from suchwow import config
@ -14,13 +12,6 @@ def allowed_file(filename):
return "." in filename and \
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():
u = User.select().where(User.username == get_session_user()).first()
return u
@ -34,116 +25,3 @@ def get_session_user():
return None
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):
_account = self.make_wallet_rpc('create_account', {'label': label})
self.store()
return _account['account_index']
def addresses(self, account, addr_indices=None):