syntax/linting fixes

This commit is contained in:
Aaron Kimbre 2022-03-12 20:09:35 -06:00
parent 70742549b9
commit 5ce9ac85bc
18 changed files with 504 additions and 375 deletions

View File

@ -10,7 +10,7 @@ from app.forms import CustomUserManager
from flask_user import user_registered, current_user, user_logged_in from flask_user import user_registered, current_user, user_logged_in
from flask_wtf.csrf import CSRFProtect from flask_wtf.csrf import CSRFProtect
from flask_apscheduler import APScheduler from flask_apscheduler import APScheduler
from app.luclient import query_cdclient, register_luclient_jinja_helpers from app.luclient import register_luclient_jinja_helpers
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
from app.models import Account, AccountInvitation, AuditLog from app.models import Account, AccountInvitation, AuditLog
@ -46,7 +46,6 @@ def create_app():
else: else:
app.logger.info(f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered") app.logger.info(f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered")
@user_logged_in.connect_via(app) @user_logged_in.connect_via(app)
def _after_login_hook(sender, user, **extra): def _after_login_hook(sender, user, **extra):
app.logger.info(f"{user.username} Logged in") app.logger.info(f"{user.username} Logged in")
@ -246,6 +245,7 @@ def gm_level(gm_level):
return wrapper return wrapper
return decorator return decorator
def log_audit(message): def log_audit(message):
AuditLog( AuditLog(
account_id=current_user.id, account_id=current_user.id,

View File

@ -1,10 +1,8 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, current_app, flash, current_app from flask import render_template, Blueprint, redirect, url_for, request, current_app, flash
from flask_user import login_required, current_user from flask_user import login_required, current_user
import json
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
import datetime import datetime
import time from app.models import Account, db
from app.models import Account, AccountInvitation, db
from app.schemas import AccountSchema from app.schemas import AccountSchema
from app import gm_level, log_audit from app import gm_level, log_audit
from app.forms import EditGMLevelForm from app.forms import EditGMLevelForm
@ -13,6 +11,7 @@ accounts_blueprint = Blueprint('accounts', __name__)
account_schema = AccountSchema() account_schema = AccountSchema()
@accounts_blueprint.route('/', methods=['GET']) @accounts_blueprint.route('/', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -154,13 +153,13 @@ def get():
account["5"] = '''<h2 class="far fa-check-square text-success"></h2>''' account["5"] = '''<h2 class="far fa-check-square text-success"></h2>'''
if account["6"]: if account["6"]:
account["6"] = f'''<h2 class="far fa-times-circle text-danger"></h2>''' account["6"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
else: else:
account["6"] = '''<h2 class="far fa-check-square text-success"></h2>''' account["6"] = '''<h2 class="far fa-check-square text-success"></h2>'''
if current_app.config["USER_ENABLE_EMAIL"]: if current_app.config["USER_ENABLE_EMAIL"]:
if account["8"]: if account["8"]:
account["8"] = f'''<h2 class="far fa-check-square text-success"></h2>''' account["8"] = '''<h2 class="far fa-check-square text-success"></h2>'''
else: else:
account["8"] = '''<h2 class="far fa-times-circle text-danger"></h2>''' account["8"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
else: else:
@ -175,4 +174,3 @@ def get():
del account["8"] del account["8"]
return data return data

View File

@ -1,4 +1,4 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash from flask import render_template, Blueprint, redirect, url_for, request, flash
from flask_user import login_required, current_user from flask_user import login_required, current_user
from app.models import db, BugReport, CharacterInfo from app.models import db, BugReport, CharacterInfo
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
@ -8,6 +8,7 @@ from app.luclient import translate_from_locale
bug_report_blueprint = Blueprint('bug_reports', __name__) bug_report_blueprint = Blueprint('bug_reports', __name__)
@bug_report_blueprint.route('/<status>', methods=['GET']) @bug_report_blueprint.route('/<status>', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -65,9 +66,9 @@ def get(status):
if status == "all": if status == "all":
query = db.session.query().select_from(BugReport) query = db.session.query().select_from(BugReport)
elif status == "resolved": elif status == "resolved":
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time != None) query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time not None)
elif status == "unresolved": elif status == "unresolved":
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time == None) query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time is None)
else: else:
raise Exception("Not a valid filter") raise Exception("Not a valid filter")

View File

@ -1,8 +1,7 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, make_response from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, make_response
from flask_user import login_required, current_user from flask_user import login_required, current_user
import json
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
import datetime, time import time
from app.models import CharacterInfo, CharacterXML, Account, db from app.models import CharacterInfo, CharacterXML, Account, db
from app.schemas import CharacterInfoSchema from app.schemas import CharacterInfoSchema
from app.forms import RescueForm from app.forms import RescueForm
@ -16,6 +15,7 @@ character_blueprint = Blueprint('characters', __name__)
character_schema = CharacterInfoSchema() character_schema = CharacterInfoSchema()
@character_blueprint.route('/', methods=['GET']) @character_blueprint.route('/', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -42,9 +42,12 @@ def approve_name(id, action):
elif action == "rename": elif action == "rename":
character.needs_rename = True character.needs_rename = True
log_audit(f"Marked character ({character.id}){character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename") log_audit(
f"Marked character ({character.id}){character.name} \
(Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename")
flash( flash(
f"Marked character {character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename", f"Marked character {character.name} \
(Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename",
"danger" "danger"
) )
@ -86,7 +89,6 @@ def view(id):
if "i" in inv.keys() and type(inv["i"]) == list: if "i" in inv.keys() and type(inv["i"]) == list:
inv["i"] = sorted(inv["i"], key=lambda i: int(i['attr_s'])) inv["i"] = sorted(inv["i"], key=lambda i: int(i['attr_s']))
return render_template( return render_template(
'character/view.html.j2', 'character/view.html.j2',
character_data=character_data, character_data=character_data,
@ -117,6 +119,7 @@ def view_xml(id):
response.headers.set('Content-Type', 'text/xml') response.headers.set('Content-Type', 'text/xml')
return response return response
@character_blueprint.route('/get_xml/<id>', methods=['GET']) @character_blueprint.route('/get_xml/<id>', methods=['GET'])
@login_required @login_required
def get_xml(id): def get_xml(id):
@ -144,6 +147,7 @@ def get_xml(id):
) )
return response return response
@character_blueprint.route('/restrict/<bit>/<id>', methods=['GET']) @character_blueprint.route('/restrict/<bit>/<id>', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -205,6 +209,7 @@ def rescue(id):
return render_template("character/rescue.html.j2", form=form) return render_template("character/rescue.html.j2", form=form)
@character_blueprint.route('/get/<status>', methods=['GET']) @character_blueprint.route('/get/<status>', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -223,9 +228,9 @@ def get(status):
if status == "all": if status == "all":
query = db.session.query().select_from(CharacterInfo).join(Account) query = db.session.query().select_from(CharacterInfo).join(Account)
elif status == "approved": elif status == "approved":
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name == "") & (CharacterInfo.needs_rename == False)) query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name == "") & (CharacterInfo.needs_rename is False))
elif status == "unapproved": elif status == "unapproved":
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name != "") | (CharacterInfo.needs_rename == True)) query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name != "") | (CharacterInfo.needs_rename is True))
else: else:
raise Exception("Not a valid filter") raise Exception("Not a valid filter")
@ -286,6 +291,4 @@ def get(status):
if perm_map & (1 << 6): if perm_map & (1 << 6):
character["6"] += "Restricted Chat</br>" character["6"] += "Restricted Chat</br>"
return data return data

View File

@ -1,19 +1,20 @@
import click import click
import json
from flask.cli import with_appcontext from flask.cli import with_appcontext
import random, string, datetime import random
import string
import datetime
from flask_user import current_app from flask_user import current_app
from app import db from app import db
from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC
import pathlib import pathlib
import zlib import zlib
import os
from wand import image from wand import image
from wand.exceptions import BlobError as BE from wand.exceptions import BlobError as BE
import app.pylddlib as ldd import app.pylddlib as ldd
from multiprocessing import Pool from multiprocessing import Pool
from functools import partial from functools import partial
@click.command("init_db") @click.command("init_db")
@click.argument('drop_tables', nargs=1) @click.argument('drop_tables', nargs=1)
@with_appcontext @with_appcontext
@ -45,6 +46,7 @@ def init_accounts():
return return
@click.command("load_property") @click.command("load_property")
@click.argument('zone') @click.argument('zone')
@click.argument('player') @click.argument('player')
@ -95,6 +97,7 @@ def load_property(zone, player):
) )
new_prop_content.save() new_prop_content.save()
@click.command("gen_image_cache") @click.command("gen_image_cache")
def gen_image_cache(): def gen_image_cache():
"""generates image cache""" """generates image cache"""
@ -113,6 +116,7 @@ def gen_image_cache():
except BE: except BE:
return print(f"Error on {file}") return print(f"Error on {file}")
@click.command("gen_model_cache") @click.command("gen_model_cache")
def gen_model_cache(): def gen_model_cache():
"""generate model obj cache""" """generate model obj cache"""
@ -123,6 +127,7 @@ def gen_model_cache():
pool.map(partial(convert_lxfml_to_obj, lod=1), files) pool.map(partial(convert_lxfml_to_obj, lod=1), files)
pool.map(partial(convert_lxfml_to_obj, lod=2), files) pool.map(partial(convert_lxfml_to_obj, lod=2), files)
def convert_lxfml_to_obj(file, lod): def convert_lxfml_to_obj(file, lod):
mtl = get_cache_file(file).with_suffix(f".lod{lod}.mtl") mtl = get_cache_file(file).with_suffix(f".lod{lod}.mtl")
if not mtl.exists(): if not mtl.exists():
@ -136,6 +141,7 @@ def convert_lxfml_to_obj(file, lod):
# print(f"Already Exists: {file} with LOD {lod}") # print(f"Already Exists: {file} with LOD {lod}")
return return
def get_cache_file(path): def get_cache_file(path):
"""helper""" """helper"""
# convert to list so that we can change elements # convert to list so that we can change elements
@ -147,6 +153,7 @@ def get_cache_file(path):
return pathlib.Path(*parts) return pathlib.Path(*parts)
def find_or_create_account(name, email, password, gm_level=9): def find_or_create_account(name, email, password, gm_level=9):
""" Find existing account or create new account """ """ Find existing account or create new account """
account = Account.query.filter(Account.email == email).first() account = Account.query.filter(Account.email == email).first()
@ -164,7 +171,8 @@ def find_or_create_account(name, email, password, gm_level=9):
db.session.commit() db.session.commit()
play_key = PlayKey.query.filter(PlayKey.key_string == key).first() play_key = PlayKey.query.filter(PlayKey.key_string == key).first()
account = Account(email=email, account = Account(
email=email,
username=name, username=name,
password=current_app.user_manager.password_manager.hash_password(password), password=current_app.user_manager.password_manager.hash_password(password),
play_key_id=play_key.id, play_key_id=play_key.id,

View File

@ -16,13 +16,13 @@ from wtforms import (
SubmitField, SubmitField,
validators, validators,
IntegerField, IntegerField,
StringField,
SelectField SelectField
) )
from wtforms.validators import DataRequired, Optional from wtforms.validators import DataRequired, Optional
from app.models import PlayKey from app.models import PlayKey
def validate_play_key(form, field): def validate_play_key(form, field):
"""Validates a field for a valid phone number """Validates a field for a valid phone number
Args: Args:
@ -85,6 +85,7 @@ class CustomRegisterForm(FlaskForm):
submit = SubmitField('Register') submit = SubmitField('Register')
class CreatePlayKeyForm(FlaskForm): class CreatePlayKeyForm(FlaskForm):
count = IntegerField( count = IntegerField(
@ -97,6 +98,7 @@ class CreatePlayKeyForm(FlaskForm):
) )
submit = SubmitField('Create!') submit = SubmitField('Create!')
class EditPlayKeyForm(FlaskForm): class EditPlayKeyForm(FlaskForm):
active = BooleanField( active = BooleanField(

View File

@ -1,5 +1,5 @@
from flask import render_template, Blueprint, request, url_for from flask import render_template, Blueprint, request, url_for
from flask_user import login_required, current_user from flask_user import login_required
from app.models import CommandLog, ActivityLog, db, Account, CharacterInfo, AuditLog from app.models import CommandLog, ActivityLog, db, Account, CharacterInfo, AuditLog
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
import time import time
@ -7,6 +7,7 @@ from app import gm_level
log_blueprint = Blueprint('log', __name__) log_blueprint = Blueprint('log', __name__)
@log_blueprint.route('/activities', methods=['GET']) @log_blueprint.route('/activities', methods=['GET'])
@login_required @login_required
@gm_level(8) @gm_level(8)

View File

@ -19,6 +19,7 @@ import xml.etree.ElementTree as ET
luclient_blueprint = Blueprint('luclient', __name__) luclient_blueprint = Blueprint('luclient', __name__)
locale = {} locale = {}
@luclient_blueprint.route('/get_dds_as_png/<filename>') @luclient_blueprint.route('/get_dds_as_png/<filename>')
@login_required @login_required
def get_dds_as_png(filename): def get_dds_as_png(filename):
@ -69,7 +70,8 @@ def get_icon_lot(id):
)[0] )[0]
# find the asset from rendercomponent given the component id # find the asset from rendercomponent given the component id
filename = query_cdclient('select icon_asset from RenderComponent where id = ?', filename = query_cdclient(
'select icon_asset from RenderComponent where id = ?',
[render_component_id], [render_component_id],
one=True one=True
)[0] )[0]
@ -117,6 +119,7 @@ def get_icon_iconid(id):
return send_file(pathlib.Path(cache).resolve()) return send_file(pathlib.Path(cache).resolve())
@luclient_blueprint.route('/unknown') @luclient_blueprint.route('/unknown')
@login_required @login_required
def unknown(): def unknown():
@ -195,6 +198,7 @@ def translate_from_locale(trans_string):
else: else:
return trans_string return trans_string
def register_luclient_jinja_helpers(app): def register_luclient_jinja_helpers(app):
@app.template_filter('get_zone_name') @app.template_filter('get_zone_name')
@ -203,7 +207,9 @@ def register_luclient_jinja_helpers(app):
@app.template_filter('get_skill_desc') @app.template_filter('get_skill_desc')
def get_skill_desc(skill_id): def get_skill_desc(skill_id):
return translate_from_locale(f'SkillBehavior_{skill_id}_descriptionUI').replace( return translate_from_locale(
f'SkillBehavior_{skill_id}_descriptionUI'
).replace(
"%(DamageCombo)", "Damage Combo: " "%(DamageCombo)", "Damage Combo: "
).replace( ).replace(
"%(AltCombo)", "<br/>Skeleton Combo: " "%(AltCombo)", "<br/>Skeleton Combo: "
@ -240,7 +246,7 @@ def register_luclient_jinja_helpers(app):
one=True one=True
) )
if intermed: if intermed:
name = intermed[7] if (intermed[7] != "None" and intermed[7] !="" and intermed[7] != None) else intermed[1] name = intermed[7] if (intermed[7] != "None" and intermed[7] != "" and intermed[7] is None) else intermed[1]
return name return name
@app.template_filter('get_lot_rarity') @app.template_filter('get_lot_rarity')
@ -252,7 +258,8 @@ def register_luclient_jinja_helpers(app):
one=True one=True
)[0] )[0]
rarity = query_cdclient('select rarity from ItemComponent where id = ?', rarity = query_cdclient(
'select rarity from ItemComponent where id = ?',
[render_component_id], [render_component_id],
one=True one=True
) )
@ -302,7 +309,6 @@ def register_luclient_jinja_helpers(app):
return consolidate_stats(stats) return consolidate_stats(stats)
@app.template_filter('get_set_stats') @app.template_filter('get_set_stats')
def get_set_stats(lot_id): def get_set_stats(lot_id):
stats = query_cdclient( stats = query_cdclient(
@ -342,7 +348,6 @@ def consolidate_stats(stats):
if stat[3]: if stat[3]:
consolidated_stats["skill"].append([stat[3], stat[4]]) consolidated_stats["skill"].append([stat[3], stat[4]])
stats = consolidated_stats stats = consolidated_stats
elif len(stats) == 1: elif len(stats) == 1:
stats = { stats = {

View File

@ -1,7 +1,6 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, request from flask import render_template, Blueprint, redirect, url_for, flash, request
from flask_user import login_required, current_user from flask_user import login_required, current_user
from app.models import db, Mail, CharacterInfo from app.models import Mail, CharacterInfo
from datatables import ColumnDT, DataTables
from app.forms import SendMailForm from app.forms import SendMailForm
from app import gm_level, log_audit from app import gm_level, log_audit
from app.luclient import translate_from_locale, query_cdclient from app.luclient import translate_from_locale, query_cdclient
@ -42,7 +41,9 @@ def send():
attachment_lot=form.attachment.data, attachment_lot=form.attachment.data,
attachment_count=form.attachment_count.data attachment_count=form.attachment_count.data
).save() ).save()
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({character.id}){character.name} with {form.attachment_count.data} of item {form.attachment.data}") log_audit(f"Sent {form.subject.data}: \
{form.body.data} to ({character.id}){character.name} \
with {form.attachment_count.data} of item {form.attachment.data}")
else: else:
Mail( Mail(
sender_id=0, sender_id=0,
@ -56,12 +57,13 @@ def send():
attachment_lot=form.attachment.data, attachment_lot=form.attachment.data,
attachment_count=form.attachment_count.data attachment_count=form.attachment_count.data
).save() ).save()
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({form.recipient.data}){CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name} with {form.attachment_count.data} of item {form.attachment.data}") log_audit(f"Sent {form.subject.data}: \
{form.body.data} to ({form.recipient.data}){CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name} \
with {form.attachment_count.data} of item {form.attachment.data}")
flash("Sent Mail", "success") flash("Sent Mail", "success")
return redirect(url_for('mail.send')) return redirect(url_for('mail.send'))
recipients = CharacterInfo.query.all() recipients = CharacterInfo.query.all()
for character in recipients: for character in recipients:
form.recipient.choices.append((character.id, character.name)) form.recipient.choices.append((character.id, character.name))
@ -74,7 +76,7 @@ def send():
for item in items: for item in items:
name = translate_from_locale(f'Objects_{item[0]}_name') name = translate_from_locale(f'Objects_{item[0]}_name')
if name == f'Objects_{item[0]}_name': if name == f'Objects_{item[0]}_name':
name = (item[2] if (item[2] != "None" and item[2] !="" and item[2] != None) else item[1]) name = (item[2] if (item[2] != "None" and item[2] != "" and item[2] not None) else item[1])
form.attachment.choices.append( form.attachment.choices.append(
( (
item[0], item[0],

View File

@ -1,18 +1,15 @@
from flask import render_template, Blueprint, redirect, request, send_from_directory, make_response, send_file, current_app from flask import render_template, Blueprint, send_from_directory
from flask_user import login_required, current_user from flask_user import current_user
import json, glob, os
from wand import image
from app.models import Account, AccountInvitation, CharacterInfo from app.models import Account
from app.schemas import AccountSchema, CharacterInfoSchema from app.schemas import AccountSchema, CharacterInfoSchema
from app.luclient import query_cdclient
from app import gm_level
main_blueprint = Blueprint('main', __name__) main_blueprint = Blueprint('main', __name__)
account_schema = AccountSchema() account_schema = AccountSchema()
char_info_schema = CharacterInfoSchema() char_info_schema = CharacterInfoSchema()
@main_blueprint.route('/', methods=['GET']) @main_blueprint.route('/', methods=['GET'])
def index(): def index():
"""Home/Index Page""" """Home/Index Page"""

View File

@ -1,6 +1,6 @@
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_user import UserMixin, current_user from flask_user import UserMixin
from wtforms import ValidationError from wtforms import ValidationError
import logging import logging
@ -12,6 +12,7 @@ from time import sleep
import random import random
import string import string
# retrying query to work around python trash collector # retrying query to work around python trash collector
# killing connections of other gunicorn workers # killing connections of other gunicorn workers
class RetryingQuery(BaseQuery): class RetryingQuery(BaseQuery):
@ -46,9 +47,11 @@ class RetryingQuery(BaseQuery):
raise raise
self.session.rollback() self.session.rollback()
db = SQLAlchemy(query_class=RetryingQuery) db = SQLAlchemy(query_class=RetryingQuery)
migrate = Migrate() migrate = Migrate()
class PlayKey(db.Model): class PlayKey(db.Model):
__tablename__ = 'play_keys' __tablename__ = 'play_keys'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -121,6 +124,7 @@ class PlayKey(db.Model):
db.session.commit() db.session.commit()
db.session.refresh(self) db.session.refresh(self)
class Account(db.Model, UserMixin): class Account(db.Model, UserMixin):
__tablename__ = 'accounts' __tablename__ = 'accounts'
id = db.Column( id = db.Column(
@ -200,7 +204,7 @@ class Account(db.Model, UserMixin):
@staticmethod @staticmethod
def get_user_by_id(*, user_id=None): def get_user_by_id(*, user_id=None):
return User.query.filter(user_id == User.id).first() return Account.query.filter(user_id == Account.id).first()
def save(self): def save(self):
db.session.add(self) db.session.add(self)
@ -211,6 +215,7 @@ class Account(db.Model, UserMixin):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class AccountInvitation(db.Model): class AccountInvitation(db.Model):
__tablename__ = 'account_invites' __tablename__ = 'account_invites'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -245,14 +250,10 @@ class AccountInvitation(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
@staticmethod @staticmethod
def get_user_by_id(*, user_id=None): def get_user_by_id(*, user_id=None):
return User.query.filter(user_id == User.id).first() return Account.query.filter(user_id == Account.id).first()
def delete(self):
db.session.delete(self)
db.session.commit()
# This table is cursed, see prop_clone_id # This table is cursed, see prop_clone_id
class CharacterInfo(db.Model): class CharacterInfo(db.Model):
@ -327,6 +328,7 @@ class CharacterInfo(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class CharacterXML(db.Model): class CharacterXML(db.Model):
__tablename__ = 'charxml' __tablename__ = 'charxml'
id = db.Column( id = db.Column(
@ -348,6 +350,7 @@ class CharacterXML(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class CommandLog(db.Model): class CommandLog(db.Model):
__tablename__ = 'command_log' __tablename__ = 'command_log'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -378,6 +381,7 @@ class CommandLog(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class Friends(db.Model): class Friends(db.Model):
__tablename__ = 'friends' __tablename__ = 'friends'
player_id = db.Column( player_id = db.Column(
@ -423,6 +427,7 @@ class Friends(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class Leaderboard(db.Model): class Leaderboard(db.Model):
__tablename__ = 'leaderboard' __tablename__ = 'leaderboard'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -472,6 +477,7 @@ class Leaderboard(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class Mail(db.Model): class Mail(db.Model):
__tablename__ = 'mail' __tablename__ = 'mail'
id = db.Column( id = db.Column(
@ -560,6 +566,7 @@ class Mail(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class ObjectIDTracker(db.Model): class ObjectIDTracker(db.Model):
__tablename__ = 'object_id_tracker' __tablename__ = 'object_id_tracker'
last_object_id = db.Column( last_object_id = db.Column(
@ -569,6 +576,7 @@ class ObjectIDTracker(db.Model):
server_default='0' server_default='0'
) )
class PetNames(db.Model): class PetNames(db.Model):
__tablename__ = 'pet_names' __tablename__ = 'pet_names'
id = db.Column(mysql.BIGINT, primary_key=True) id = db.Column(mysql.BIGINT, primary_key=True)
@ -763,6 +771,7 @@ class UGC(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class PropertyContent(db.Model): class PropertyContent(db.Model):
__tablename__ = 'properties_contents' __tablename__ = 'properties_contents'
id = db.Column( id = db.Column(
@ -843,6 +852,7 @@ class PropertyContent(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class ActivityLog(db.Model): class ActivityLog(db.Model):
__tablename__ = 'activity_log' __tablename__ = 'activity_log'
id = db.Column(mysql.INTEGER, primary_key=True) id = db.Column(mysql.INTEGER, primary_key=True)
@ -883,6 +893,7 @@ class ActivityLog(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class BugReport(db.Model): class BugReport(db.Model):
__tablename__ = 'bug_reports' __tablename__ = 'bug_reports'
id = db.Column(mysql.INTEGER, primary_key=True) id = db.Column(mysql.INTEGER, primary_key=True)
@ -944,6 +955,7 @@ class BugReport(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class Server(db.Model): class Server(db.Model):
__tablename__ = 'servers' __tablename__ = 'servers'
id = db.Column( id = db.Column(
@ -1016,6 +1028,7 @@ class Reports(db.Model):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
class AuditLog(db.Model): class AuditLog(db.Model):
__tablename__ = 'audit_logs' __tablename__ = 'audit_logs'
id = db.Column( id = db.Column(

View File

@ -2,7 +2,6 @@ from flask import render_template, Blueprint, redirect, url_for, request, flash,
from flask_user import login_required from flask_user import login_required
from app.models import PetNames, db, CharacterXML, CharacterInfo from app.models import PetNames, db, CharacterXML, CharacterInfo
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
from app import gm_level, log_audit, scheduler from app import gm_level, log_audit, scheduler
moderation_blueprint = Blueprint('moderation', __name__) moderation_blueprint = Blueprint('moderation', __name__)
@ -64,7 +63,6 @@ def get_pets(status="all"):
else: else:
raise Exception("Not a valid filter") raise Exception("Not a valid filter")
params = request.args.to_dict() params = request.args.to_dict()
rowTable = DataTables(params, query, columns) rowTable = DataTables(params, query, columns)
@ -116,7 +114,7 @@ def get_pets(status="all"):
{CharacterInfo.query.filter(CharacterInfo.id==pet_data['3']).first().name} {CharacterInfo.query.filter(CharacterInfo.id==pet_data['3']).first().name}
</a> </a>
""" """
except Exception as e: except Exception:
PetNames.query.filter(PetNames.id == id).first().delete() PetNames.query.filter(PetNames.id == id).first().delete()
pet_data["0"] = "<span class='text-danger'>Deleted Refresh to make go away</span>" pet_data["0"] = "<span class='text-danger'>Deleted Refresh to make go away</span>"
pet_data["3"] = "<span class='text-danger'>Character Deleted</span>" pet_data["3"] = "<span class='text-danger'>Character Deleted</span>"
@ -131,7 +129,7 @@ def pet_name_maintenance():
with scheduler.app.app_context(): with scheduler.app.app_context():
# associate pet names to characters # associate pet names to characters
current_app.logger.info("Started Pet Name Maintenance") current_app.logger.info("Started Pet Name Maintenance")
unassociated_pets = PetNames.query.filter(PetNames.owner_id == None).all() unassociated_pets = PetNames.query.filter(PetNames.owner_id is None).all()
if unassociated_pets: if unassociated_pets:
current_app.logger.info("Found un-associated pets") current_app.logger.info("Found un-associated pets")
for pet in unassociated_pets: for pet in unassociated_pets:

View File

@ -1,14 +1,14 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash from flask import render_template, Blueprint, redirect, url_for, request, flash
from flask_user import login_required, current_user from flask_user import login_required
from app.models import Account, AccountInvitation, PlayKey, db from app.models import Account, PlayKey, db
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
from app.forms import CreatePlayKeyForm, EditPlayKeyForm from app.forms import CreatePlayKeyForm, EditPlayKeyForm
from app import gm_level, log_audit from app import gm_level, log_audit
play_keys_blueprint = Blueprint('play_keys', __name__) play_keys_blueprint = Blueprint('play_keys', __name__)
# Key creation page
# Key creation page
@play_keys_blueprint.route('/', methods=['GET']) @play_keys_blueprint.route('/', methods=['GET'])
@login_required @login_required
@gm_level(9) @gm_level(9)
@ -45,7 +45,7 @@ def bulk_create():
@gm_level(9) @gm_level(9)
def delete(id): def delete(id):
key = PlayKey.query.filter(PlayKey.id == id).first() key = PlayKey.query.filter(PlayKey.id == id).first()
associated_accounts = Account.query.filter(Account.play_key_id==id).all() # associated_accounts = Account.query.filter(Account.play_key_id==id).all()
log_audit(f"Deleted Play Key {key.key_string}") log_audit(f"Deleted Play Key {key.key_string}")
flash(f"Deleted Play Key {key.key_string}", "danger") flash(f"Deleted Play Key {key.key_string}", "danger")
key.delete() key.delete()
@ -125,7 +125,12 @@ def get():
Delete Delete
</a> </a>
<div class="modal fade bd-example-modal-lg" id="delete-{play_key["1"]}-modal" tabindex="-1" role="dialog" aria-labelledby="delete-{play_key["1"]}-modalLabel" aria-hidden="true"> <div class="modal
fade bd-example-modal-lg"
id="delete-{play_key["1"]}-modal"
tabindex="-1" role="dialog"
aria-labelledby="delete-{play_key["1"]}-modalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document"> <div class="modal-dialog modal-lg" role="document">
<div class="modal-content bg-dark border-primary"> <div class="modal-content bg-dark border-primary">
<div class="modal-header"> <div class="modal-header">

View File

@ -5,14 +5,11 @@ from flask import (
url_for, url_for,
request, request,
abort, abort,
jsonify,
send_from_directory,
make_response, make_response,
flash, flash,
current_app current_app
) )
from flask_user import login_required, current_user from flask_user import login_required, current_user
import json
from datatables import ColumnDT, DataTables from datatables import ColumnDT, DataTables
import time import time
from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account
@ -21,8 +18,6 @@ from app import gm_level, log_audit
from app.luclient import query_cdclient from app.luclient import query_cdclient
import zlib import zlib
import xmltodict
import os
import app.pylddlib as ldd import app.pylddlib as ldd
import pathlib import pathlib
@ -30,6 +25,7 @@ property_blueprint = Blueprint('properties', __name__)
property_schema = PropertySchema() property_schema = PropertySchema()
@property_blueprint.route('/', methods=['GET']) @property_blueprint.route('/', methods=['GET'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -89,8 +85,6 @@ def approve(id):
else: else:
go_to = url_for('main.index') go_to = url_for('main.index')
return redirect(go_to) return redirect(go_to)
@ -137,13 +131,16 @@ def get(status="all"):
if status == "all": if status == "all":
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id == Property.owner_id).join(Account) query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id == Property.owner_id).join(Account)
elif status == "approved": elif status == "approved":
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id==Property.owner_id).join(Account).filter(Property.mod_approved==True).filter(Property.privacy_option==2) query = db.session.query().select_from(Property).join(
CharacterInfo, CharacterInfo.id == Property.owner_id
).join(Account).filter(Property.mod_approved is True).filter(Property.privacy_option == 2)
elif status == "unapproved": elif status == "unapproved":
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id==Property.owner_id).join(Account).filter(Property.mod_approved==False).filter(Property.privacy_option==2) query = db.session.query().select_from(Property).join(
CharacterInfo, CharacterInfo.id == Property.owner_id
).join(Account).filter(Property.mod_approved is False).filter(Property.privacy_option == 2)
else: else:
raise Exception("Not a valid filter") raise Exception("Not a valid filter")
params = request.args.to_dict() params = request.args.to_dict()
rowTable = DataTables(params, query, columns) rowTable = DataTables(params, query, columns)
@ -242,6 +239,7 @@ def view_model(id, lod):
lod=lod lod=lod
) )
property_center = { property_center = {
1150: "(-17, 432, -60)", 1150: "(-17, 432, -60)",
1151: "(0, 455, -110)", 1151: "(0, 455, -110)",
@ -304,6 +302,7 @@ def view_models(id, lod):
lod=lod lod=lod
) )
@property_blueprint.route('/get_model/<id>/<file_format>/<lod>', methods=['GET']) @property_blueprint.route('/get_model/<id>/<file_format>/<lod>', methods=['GET'])
@login_required @login_required
def get_model(id, file_format, lod): def get_model(id, file_format, lod):
@ -312,14 +311,13 @@ def get_model(id, file_format, lod):
abort(404) abort(404)
if content.lot == 14: # ugc model if content.lot == 14: # ugc model
response = ugc(content)[0] response = ugc(content)[0]
else: # prebuild model else: # prebuilt model
response = prebuilt(content, file_format, lod)[0] response = prebuilt(content, file_format, lod)[0]
response.headers.set('Content-Type', 'text/xml') response.headers.set('Content-Type', 'text/xml')
return response return response
@property_blueprint.route('/download_model/<id>', methods=['GET']) @property_blueprint.route('/download_model/<id>', methods=['GET'])
@login_required @login_required
def download_model(id): def download_model(id):
@ -327,7 +325,7 @@ def download_model(id):
if content.lot == 14: # ugc model if content.lot == 14: # ugc model
response, filename = ugc(content) response, filename = ugc(content)
else: # prebuild model else: # prebuilt model
response, filename = prebuilt(content, "lxfml") response, filename = prebuilt(content, "lxfml")
response.headers.set('Content-Type', 'attachment/xml') response.headers.set('Content-Type', 'attachment/xml')
@ -355,7 +353,8 @@ def prebuilt(content, file_format, lod):
one=True one=True
)[0] )[0]
# find the asset from rendercomponent given the component id # find the asset from rendercomponent given the component id
filename = query_cdclient('select render_asset from RenderComponent where id = ?', filename = query_cdclient(
'select render_asset from RenderComponent where id = ?',
[render_component_id], [render_component_id],
one=True one=True
) )

View File

@ -1,33 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
# pylddlib version 0.4.9.7 # pylddlib version 0.4.9.7
# based on pyldd2obj version 0.4.8 - Copyright (c) 2019 by jonnysp # based on pyldd2obj version 0.4.8 - Copyright (c) 2019 by jonnysp
#
# Updates:
# 0.4.9.8 Make work with LEGO Universe brickdb
# 0.4.9.7 corrected bug of incorrectly parsing the primitive xml file, specifically with comments. Add support LDDLIFTREE envirnment variable to set location of db.lif.
# 0.4.9.6 preliminary Linux support
# 0.4.9.5 corrected bug of incorrectly Bounding / GeometryBounding parsing the primitive xml file.
# 0.4.9.4 improved lif.db checking for crucial files (because of the infamous botched 4.3.12 LDD Windows update).
# 0.4.9.3 improved Windows and Python 3 compatibility
# 0.4.9.2 changed handling of material = 0 for a part. Now a 0 will choose the 1st material (the base material of a part) and not the previous material of the subpart before. This will fix "Chicken Helmet Part 11262". It may break other parts and this change needs further regression.
# 0.4.9.1 improved custom2DField handling, fixed decorations bug, improved material assignments handling
# 0.4.9 updates to support reading extracted db.lif from db folder
#
# License: MIT License
#
import os import os
import platform
import sys import sys
import math import math
import struct import struct
import zipfile import zipfile
from xml.dom import minidom from xml.dom import minidom
import time
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf-8')
PRIMITIVEPATH = '/Primitives/' PRIMITIVEPATH = '/Primitives/'
GEOMETRIEPATH = PRIMITIVEPATH GEOMETRIEPATH = PRIMITIVEPATH
@ -36,6 +15,7 @@ MATERIALNAMESPATH = '/MaterialNames/'
LOGOONSTUDSCONNTYPE = {"0:4", "0:4:1", "0:4:2", "0:4:33", "2:4:1", "2:4:34"} LOGOONSTUDSCONNTYPE = {"0:4", "0:4:1", "0:4:2", "0:4:33", "2:4:1", "2:4:34"}
class Matrix3D: class Matrix3D:
def __init__(self, n11=1, n12=0, n13=0, n14=0, n21=0, n22=1, n23=0, n24=0, n31=0, n32=0, n33=1, n34=0, n41=0, n42=0, n43=0, n44=1): def __init__(self, n11=1, n12=0, n13=0, n14=0, n21=0, n22=1, n23=0, n24=0, n31=0, n32=0, n33=1, n34=0, n41=0, n42=0, n43=0, n44=1):
self.n11 = n11 self.n11 = n11
@ -56,7 +36,24 @@ class Matrix3D:
self.n44 = n44 self.n44 = n44
def __str__(self): def __str__(self):
return '[{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}]'.format(self.n11, self.n12, self.n13,self.n14,self.n21, self.n22, self.n23,self.n24,self.n31, self.n32, self.n33,self.n34,self.n41, self.n42, self.n43,self.n44) return '[{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}]'.format(
self.n11,
self.n12,
self.n13,
self.n14,
self.n21,
self.n22,
self.n23,
self.n24,
self.n31,
self.n32,
self.n33,
self.n34,
self.n41,
self.n42,
self.n43,
self.n44
)
def rotate(self, angle=0, axis=0): def rotate(self, angle=0, axis=0):
c = math.cos(angle) c = math.cos(angle)
@ -111,6 +108,7 @@ class Matrix3D:
self.n14 * other.n41 + self.n24 * other.n42 + self.n34 * other.n43 + self.n44 * other.n44 self.n14 * other.n41 + self.n24 * other.n42 + self.n34 * other.n43 + self.n44 * other.n44
) )
class Point3D: class Point3D:
def __init__(self, x=0, y=0, z=0): def __init__(self, x=0, y=0, z=0):
self.x = x self.x = x
@ -142,40 +140,57 @@ class Point3D:
def copy(self): def copy(self):
return Point3D(x=self.x, y=self.y, z=self.z) return Point3D(x=self.x, y=self.y, z=self.z)
class Point2D: class Point2D:
def __init__(self, x=0, y=0): def __init__(self, x=0, y=0):
self.x = x self.x = x
self.y = y self.y = y
def __str__(self): def __str__(self):
return '[{0},{1}]'.format(self.x, self.y * -1) return '[{0},{1}]'.format(self.x, self.y * -1)
def string(self, prefix="t"): def string(self, prefix="t"):
return '{0} {1:f} {2:f}\n'.format(prefix, self.x, self.y * -1) return '{0} {1:f} {2:f}\n'.format(prefix, self.x, self.y * -1)
def copy(self): def copy(self):
return Point2D(x=self.x, y=self.y) return Point2D(x=self.x, y=self.y)
class Face: class Face:
def __init__(self, a=0, b=0, c=0): def __init__(self, a=0, b=0, c=0):
self.a = a self.a = a
self.b = b self.b = b
self.c = c self.c = c
def string(self, prefix="f", indexOffset=0, textureoffset=0): def string(self, prefix="f", indexOffset=0, textureoffset=0):
if textureoffset == 0: if textureoffset == 0:
return prefix + ' {0}//{0} {1}//{1} {2}//{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset) return prefix + ' {0}//{0} {1}//{1} {2}//{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset)
else: else:
return prefix + ' {0}/{3}/{0} {1}/{4}/{1} {2}/{5}/{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset,self.a + textureoffset, self.b + textureoffset, self.c + textureoffset) return prefix + ' {0}/{3}/{0} {1}/{4}/{1} {2}/{5}/{2}\n'.format(
self.a + indexOffset,
self.b + indexOffset,
self.c + indexOffset,
self.a + textureoffset,
self.b + textureoffset,
self.c + textureoffset
)
def __str__(self): def __str__(self):
return '[{0},{1},{2}]'.format(self.a, self.b, self.c) return '[{0},{1},{2}]'.format(self.a, self.b, self.c)
class Group: class Group:
def __init__(self, node): def __init__(self, node):
self.partRefs = node.getAttribute('partRefs').split(',') self.partRefs = node.getAttribute('partRefs').split(',')
class Bone: class Bone:
def __init__(self, node): def __init__(self, node):
self.refID = node.getAttribute('refID') self.refID = node.getAttribute('refID')
(a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(',')) (a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(','))
self.matrix = Matrix3D(n11=a, n12=b, n13=c, n14=0, n21=d, n22=e, n23=f, n24=0, n31=g, n32=h, n33=i, n34=0, n41=x, n42=y, n43=z, n44=1) self.matrix = Matrix3D(n11=a, n12=b, n13=c, n14=0, n21=d, n22=e, n23=f, n24=0, n31=g, n32=h, n33=i, n34=0, n41=x, n42=y, n43=z, n44=1)
class Part: class Part:
def __init__(self, node): def __init__(self, node):
self.isGrouped = False self.isGrouped = False
@ -185,19 +200,17 @@ class Part:
self.designID = node.getAttribute('designID') self.designID = node.getAttribute('designID')
self.materials = list(map(str, node.getAttribute('materials').split(','))) self.materials = list(map(str, node.getAttribute('materials').split(',')))
lastm = '0'
for i, m in enumerate(self.materials): for i, m in enumerate(self.materials):
if (m == '0'): if (m == '0'):
# self.materials[i] = lastm # self.materials[i] = lastm
self.materials[i] = self.materials[0] # in case of 0 choose the 'base' material self.materials[i] = self.materials[0] # in case of 0 choose the 'base' material
else:
lastm = m
if node.hasAttribute('decoration'): if node.hasAttribute('decoration'):
self.decoration = list(map(str, node.getAttribute('decoration').split(','))) self.decoration = list(map(str, node.getAttribute('decoration').split(',')))
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'Bone': if childnode.nodeName == 'Bone':
self.Bones.append(Bone(node=childnode)) self.Bones.append(Bone(node=childnode))
class Brick: class Brick:
def __init__(self, node): def __init__(self, node):
self.refID = node.getAttribute('refID') self.refID = node.getAttribute('refID')
@ -207,6 +220,7 @@ class Brick:
if childnode.nodeName == 'Part': if childnode.nodeName == 'Part':
self.Parts.append(Part(node=childnode)) self.Parts.append(Part(node=childnode))
class SceneCamera: class SceneCamera:
def __init__(self, node): def __init__(self, node):
self.refID = node.getAttribute('refID') self.refID = node.getAttribute('refID')
@ -215,6 +229,7 @@ class SceneCamera:
self.fieldOfView = float(node.getAttribute('fieldOfView')) self.fieldOfView = float(node.getAttribute('fieldOfView'))
self.distance = float(node.getAttribute('distance')) self.distance = float(node.getAttribute('distance'))
class Scene: class Scene:
def __init__(self, file): def __init__(self, file):
self.Bricks = [] self.Bricks = []
@ -262,6 +277,7 @@ class Scene:
# print('Scene "'+ self.Name + '" Brickversion: ' + str(self.Version)) # print('Scene "'+ self.Name + '" Brickversion: ' + str(self.Version))
class GeometryReader: class GeometryReader:
def __init__(self, data): def __init__(self, data):
self.offset = 0 self.offset = 0
@ -330,6 +346,7 @@ class GeometryReader:
self.offset += 4 self.offset += 4
return ret return ret
class Geometry: class Geometry:
def __init__(self, designID, database): def __init__(self, designID, database):
self.designID = designID self.designID = designID
@ -348,10 +365,14 @@ class Geometry:
self.Partname = primitive.Designname self.Partname = primitive.Designname
self.studsFields2D = primitive.Fields2D self.studsFields2D = primitive.Fields2D
try: try:
geoBoundingList = [abs(float(primitive.Bounding['minX']) - float(primitive.Bounding['maxX'])), abs(float(primitive.Bounding['minY']) - float(primitive.Bounding['maxY'])), abs(float(primitive.Bounding['minZ']) - float(primitive.Bounding['maxZ']))] geoBoundingList = [
abs(float(primitive.Bounding['minX']) - float(primitive.Bounding['maxX'])),
abs(float(primitive.Bounding['minY']) - float(primitive.Bounding['maxY'])),
abs(float(primitive.Bounding['minZ']) - float(primitive.Bounding['maxZ']))
]
geoBoundingList.sort() geoBoundingList.sort()
self.maxGeoBounding = geoBoundingList[-1] self.maxGeoBounding = geoBoundingList[-1]
except KeyError as e: except KeyError:
# print('\nBounding errror in part {0}: {1}\n'.format(designID, e)) # print('\nBounding errror in part {0}: {1}\n'.format(designID, e))
pass pass
@ -386,11 +407,15 @@ class Geometry:
count += self.Parts[part].texCount count += self.Parts[part].texCount
return count return count
class Bone2: class Bone2:
def __init__(self, boneId=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0): def __init__(self, boneId=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
self.boneId = boneId self.boneId = boneId
rotationMatrix = Matrix3D() rotationMatrix = Matrix3D()
rotationMatrix.rotate(angle = -angle * math.pi / 180.0,axis = Point3D(x=ax,y=ay,z=az)) rotationMatrix.rotate(
angle=(-angle * math.pi / 180.0),
axis=Point3D(x=ax, y=ay, z=az)
)
p = Point3D(x=tx, y=ty, z=tz) p = Point3D(x=tx, y=ty, z=tz)
p.transformW(rotationMatrix) p.transformW(rotationMatrix)
rotationMatrix.n41 -= p.x rotationMatrix.n41 -= p.x
@ -398,12 +423,16 @@ class Bone2:
rotationMatrix.n43 -= p.z rotationMatrix.n43 -= p.z
self.matrix = rotationMatrix self.matrix = rotationMatrix
class Field2D: class Field2D:
def __init__(self, type=0, width=0, height=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0, field2DRawData='none'): def __init__(self, type=0, width=0, height=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0, field2DRawData='none'):
self.type = type self.type = type
self.field2DRawData = field2DRawData self.field2DRawData = field2DRawData
rotationMatrix = Matrix3D() rotationMatrix = Matrix3D()
rotationMatrix.rotate(angle = -angle * math.pi / 180.0, axis = Point3D(x=ax,y=ay,z=az)) rotationMatrix.rotate(
angle=(-angle * math.pi / 180.0),
axis=Point3D(x=ax, y=ay, z=az)
)
p = Point3D(x=tx, y=ty, z=tz) p = Point3D(x=tx, y=ty, z=tz)
p.transformW(rotationMatrix) p.transformW(rotationMatrix)
rotationMatrix.n41 -= p.x rotationMatrix.n41 -= p.x
@ -432,11 +461,16 @@ class Field2D:
def __str__(self): def __str__(self):
return '[type="{0}" transform="{1}" custom2DField="{2}"]'.format(self.type, self.matrix, self.custom2DField) return '[type="{0}" transform="{1}" custom2DField="{2}"]'.format(self.type, self.matrix, self.custom2DField)
class CollisionBox: class CollisionBox:
def __init__(self, sX=0, sY=0, sZ=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0): def __init__(self, sX=0, sY=0, sZ=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
rotationMatrix = Matrix3D() rotationMatrix = Matrix3D()
rotationMatrix.rotate(angle = -angle * math.pi / 180.0, axis = Point3D(x=ax,y=ay,z=az)) rotationMatrix.rotate(
p = Point3D(x=tx,y=ty,z=tz) angle=(-angle * math.pi / 180.0),
axis=Point3D(x=ax, y=ay, z=az)
)
p = Point3D(x=tx, y=ty,
z=tz)
p.transformW(rotationMatrix) p.transformW(rotationMatrix)
rotationMatrix.n41 -= p.x rotationMatrix.n41 -= p.x
rotationMatrix.n42 -= p.y rotationMatrix.n42 -= p.y
@ -456,7 +490,10 @@ class CollisionBox:
self.positions.append(Point3D(x=sX, y=sY, z=sZ)) self.positions.append(Point3D(x=sX, y=sY, z=sZ))
def __str__(self): def __str__(self):
return '[0,0,0] [{0},0,0] [0,{1},0] [{0},{1},0] [0,0,{2}] [0,{1},{2}] [{0},0,{2}] [{0},{1},{2}]'.format(self.corner.x, self.corner.y, self.corner.z) return '[0,0,0] [{0},0,0] [0,{1},0] [{0},{1},0] [0,0,{2}] [0,{1},{2}] [{0},0,{2}] [{0},{1},{2}]'.format(
self.corner.x, self.corner.y, self.corner.z
)
class Primitive: class Primitive:
def __init__(self, data): def __init__(self, data):
@ -475,7 +512,18 @@ class Primitive:
if node.nodeName == 'Flex': if node.nodeName == 'Flex':
for node in node.childNodes: for node in node.childNodes:
if node.nodeName == 'Bone': if node.nodeName == 'Bone':
self.Bones.append(Bone2(boneId=int(node.getAttribute('boneId')), angle=float(node.getAttribute('angle')), ax=float(node.getAttribute('ax')), ay=float(node.getAttribute('ay')), az=float(node.getAttribute('az')), tx=float(node.getAttribute('tx')), ty=float(node.getAttribute('ty')), tz=float(node.getAttribute('tz')))) self.Bones.append(
Bone2(
boneId=int(node.getAttribute('boneId')),
angle=float(node.getAttribute('angle')),
ax=float(node.getAttribute('ax')),
ay=float(node.getAttribute('ay')),
az=float(node.getAttribute('az')),
tx=float(node.getAttribute('tx')),
ty=float(node.getAttribute('ty')),
tz=float(node.getAttribute('tz'))
)
)
elif node.nodeName == 'Annotations': elif node.nodeName == 'Annotations':
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'Annotation' and childnode.hasAttribute('designname'): if childnode.nodeName == 'Annotation' and childnode.hasAttribute('designname'):
@ -483,23 +531,73 @@ class Primitive:
elif node.nodeName == 'Collision': elif node.nodeName == 'Collision':
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'Box': if childnode.nodeName == 'Box':
self.CollisionBoxes.append(CollisionBox(sX=float(childnode.getAttribute('sX')), sY=float(childnode.getAttribute('sY')), sZ=float(childnode.getAttribute('sZ')), angle=float(childnode.getAttribute('angle')), ax=float(childnode.getAttribute('ax')), ay=float(childnode.getAttribute('ay')), az=float(childnode.getAttribute('az')), tx=float(childnode.getAttribute('tx')), ty=float(childnode.getAttribute('ty')), tz=float(childnode.getAttribute('tz')))) self.CollisionBoxes.append(
CollisionBox(
sX=float(childnode.getAttribute('sX')),
sY=float(childnode.getAttribute('sY')),
sZ=float(childnode.getAttribute('sZ')),
angle=float(childnode.getAttribute('angle')),
ax=float(childnode.getAttribute('ax')),
ay=float(childnode.getAttribute('ay')),
az=float(childnode.getAttribute('az')),
tx=float(childnode.getAttribute('tx')),
ty=float(childnode.getAttribute('ty')),
tz=float(childnode.getAttribute('tz'))
)
)
elif node.nodeName == 'PhysicsAttributes': elif node.nodeName == 'PhysicsAttributes':
self.PhysicsAttributes = {"inertiaTensor": node.getAttribute('inertiaTensor'),"centerOfMass": node.getAttribute('centerOfMass'),"mass": node.getAttribute('mass'),"frictionType": node.getAttribute('frictionType')} self.PhysicsAttributes = {
"inertiaTensor": node.getAttribute('inertiaTensor'),
"centerOfMass": node.getAttribute('centerOfMass'),
"mass": node.getAttribute('mass'),
"frictionType": node.getAttribute('frictionType')
}
elif node.nodeName == 'Bounding': elif node.nodeName == 'Bounding':
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'AABB': if childnode.nodeName == 'AABB':
self.Bounding = {"minX": childnode.getAttribute('minX'), "minY": childnode.getAttribute('minY'), "minZ": childnode.getAttribute('minZ'), "maxX": childnode.getAttribute('maxX'), "maxY": childnode.getAttribute('maxY'), "maxZ": childnode.getAttribute('maxZ')} self.Bounding = {
"minX": childnode.getAttribute('minX'),
"minY": childnode.getAttribute('minY'),
"minZ": childnode.getAttribute('minZ'),
"maxX": childnode.getAttribute('maxX'),
"maxY": childnode.getAttribute('maxY'),
"maxZ": childnode.getAttribute('maxZ')
}
elif node.nodeName == 'GeometryBounding': elif node.nodeName == 'GeometryBounding':
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'AABB': if childnode.nodeName == 'AABB':
self.GeometryBounding = {"minX": childnode.getAttribute('minX'), "minY": childnode.getAttribute('minY'), "minZ": childnode.getAttribute('minZ'), "maxX": childnode.getAttribute('maxX'), "maxY": childnode.getAttribute('maxY'), "maxZ": childnode.getAttribute('maxZ')} self.GeometryBounding = {
"minX": childnode.getAttribute('minX'),
"minY": childnode.getAttribute('minY'),
"minZ": childnode.getAttribute('minZ'),
"maxX": childnode.getAttribute('maxX'),
"maxY": childnode.getAttribute('maxY'),
"maxZ": childnode.getAttribute('maxZ')
}
elif node.nodeName == 'Connectivity': elif node.nodeName == 'Connectivity':
for childnode in node.childNodes: for childnode in node.childNodes:
if childnode.nodeName == 'Custom2DField': if childnode.nodeName == 'Custom2DField':
self.Fields2D.append(Field2D(type=int(childnode.getAttribute('type')), width=int(childnode.getAttribute('width')), height=int(childnode.getAttribute('height')), angle=float(childnode.getAttribute('angle')), ax=float(childnode.getAttribute('ax')), ay=float(childnode.getAttribute('ay')), az=float(childnode.getAttribute('az')), tx=float(childnode.getAttribute('tx')), ty=float(childnode.getAttribute('ty')), tz=float(childnode.getAttribute('tz')), field2DRawData=str(childnode.firstChild.data))) self.Fields2D.append(
Field2D(
type=int(childnode.getAttribute('type')),
width=int(childnode.getAttribute('width')),
height=int(childnode.getAttribute('height')),
angle=float(childnode.getAttribute('angle')),
ax=float(childnode.getAttribute('ax')),
ay=float(childnode.getAttribute('ay')),
az=float(childnode.getAttribute('az')),
tx=float(childnode.getAttribute('tx')),
ty=float(childnode.getAttribute('ty')),
tz=float(childnode.getAttribute('tz')),
field2DRawData=str(childnode.firstChild.data)
)
)
elif node.nodeName == 'Decoration': elif node.nodeName == 'Decoration':
self.Decoration = {"faces": node.getAttribute('faces'), "subMaterialRedirectLookupTable": node.getAttribute('subMaterialRedirectLookupTable')} self.Decoration = {
"faces": node.getAttribute('faces'),
"subMaterialRedirectLookupTable": node.getAttribute('subMaterialRedirectLookupTable')
}
class Materials: class Materials:
def __init__(self, data): def __init__(self, data):
@ -519,6 +617,7 @@ class Materials:
def getMaterialbyId(self, mid): def getMaterialbyId(self, mid):
return self.Materials[mid] return self.Materials[mid]
class Material: class Material:
def __init__(self, id, r, g, b, a, mtype): def __init__(self, id, r, g, b, a, mtype):
self.id = id self.id = id
@ -528,18 +627,25 @@ class Material:
self.g = float(g) self.g = float(g)
self.b = float(b) self.b = float(b)
self.a = float(a) self.a = float(a)
def string(self): def string(self):
out = 'Kd {0} {1} {2}\nKa 1.600000 1.600000 1.600000\nKs 0.400000 0.400000 0.400000\nNs 3.482202\nTf 1 1 1\n'.format( self.r / 255, self.g / 255,self.b / 255) out = 'Kd {0} {1} {2}\nKa 1.600000 1.600000 1.600000\nKs 0.400000 0.400000 0.400000\nNs 3.482202\nTf 1 1 1\n'.format(
self.r / 255,
self.g / 255,
self.b / 255
)
if self.a < 255: if self.a < 255:
out += 'Ni 1.575\n' + 'd {0}'.format(0.05) + '\n' + 'Tr {0}\n'.format(0.05) out += 'Ni 1.575\n' + 'd {0}'.format(0.05) + '\n' + 'Tr {0}\n'.format(0.05)
return out return out
class DBinfo: class DBinfo:
def __init__(self, data): def __init__(self, data):
xml = minidom.parseString(data) xml = minidom.parseString(data)
self.Version = xml.getElementsByTagName('Bricks')[0].attributes['version'].value self.Version = xml.getElementsByTagName('Bricks')[0].attributes['version'].value
# print('DB Version: ' + str(self.Version)) # print('DB Version: ' + str(self.Version))
class DBFolderFile: class DBFolderFile:
def __init__(self, name, handle): def __init__(self, name, handle):
self.handle = handle self.handle = handle
@ -554,6 +660,7 @@ class DBFolderFile:
finally: finally:
reader.close() reader.close()
class LIFFile: class LIFFile:
def __init__(self, name, offset, size, handle): def __init__(self, name, offset, size, handle):
self.handle = handle self.handle = handle
@ -565,6 +672,7 @@ class LIFFile:
self.handle.seek(self.offset, 0) self.handle.seek(self.offset, 0)
return self.handle.read(self.size) return self.handle.read(self.size)
class DBFolderReader: class DBFolderReader:
def __init__(self, folder): def __init__(self, folder):
self.filelist = {} self.filelist = {}
@ -574,7 +682,7 @@ class DBFolderReader:
try: try:
os.path.isdir(self.location) os.path.isdir(self.location)
except Exception as e: except Exception:
self.initok = False self.initok = False
# print("db folder read FAIL") # print("db folder read FAIL")
return return
@ -593,7 +701,6 @@ class DBFolderReader:
# print(MATERIALNAMESPATH) # print(MATERIALNAMESPATH)
pass pass
def fileexist(self, filename): def fileexist(self, filename):
return filename in self.filelist return filename in self.filelist
@ -603,6 +710,7 @@ class DBFolderReader:
entryName = os.path.join(path, name) entryName = os.path.join(path, name)
self.filelist[entryName] = DBFolderFile(name=entryName, handle=entryName) self.filelist[entryName] = DBFolderFile(name=entryName, handle=entryName)
class LIFReader: class LIFReader:
def __init__(self, file): def __init__(self, file):
self.packedFilesOffset = 84 self.packedFilesOffset = 84
@ -614,7 +722,7 @@ class LIFReader:
try: try:
self.filehandle = open(self.location, "rb") self.filehandle = open(self.location, "rb")
self.filehandle.seek(0, 0) self.filehandle.seek(0, 0)
except Exception as e: except Exception:
self.initok = False self.initok = False
# print("Database FAIL") # print("Database FAIL")
return return
@ -648,7 +756,7 @@ class LIFReader:
entryType = self.readShort(offset=offset) entryType = self.readShort(offset=offset)
offset += 6 offset += 6
entryName = '{0}{1}'.format(prefix,'/'); entryName = '{0}{1}'.format(prefix, '/')
self.filehandle.seek(offset + 1, 0) self.filehandle.seek(offset + 1, 0)
if sys.version_info < (3, 0): if sys.version_info < (3, 0):
t = ord(self.filehandle.read(1)) t = ord(self.filehandle.read(1))
@ -692,17 +800,18 @@ class LIFReader:
else: else:
return int.from_bytes(self.filehandle.read(2), byteorder='big') return int.from_bytes(self.filehandle.read(2), byteorder='big')
class Converter: class Converter:
def LoadDBFolder(self, dbfolderlocation): def LoadDBFolder(self, dbfolderlocation):
self.database = DBFolderReader(folder=dbfolderlocation) self.database = DBFolderReader(folder=dbfolderlocation)
if self.database.initok and self.database.fileexist(os.path.join(dbfolderlocation, 'Materials.xml')): if self.database.initok and self.database.fileexist(os.path.join(dbfolderlocation, 'Materials.xml')):
self.allMaterials = Materials(data=self.database.filelist[os.path.join(dbfolderlocation,'Materials.xml')].read()); self.allMaterials = Materials(data=self.database.filelist[os.path.join(dbfolderlocation, 'Materials.xml')].read())
def LoadDatabase(self, databaselocation): def LoadDatabase(self, databaselocation):
self.database = LIFReader(file=databaselocation) self.database = LIFReader(file=databaselocation)
if self.database.initok and self.database.fileexist('/Materials.xml'): if self.database.initok and self.database.fileexist('/Materials.xml'):
self.allMaterials = Materials(data=self.database.filelist['/Materials.xml'].read()); self.allMaterials = Materials(data=self.database.filelist['/Materials.xml'].read())
def LoadScene(self, filename): def LoadScene(self, filename):
if self.database.initok: if self.database.initok:
@ -717,8 +826,6 @@ class Converter:
usedmaterials = [] usedmaterials = []
geometriecache = {} geometriecache = {}
start_time = time.time()
out = open(filename + ".obj.tmp", "w+") out = open(filename + ".obj.tmp", "w+")
out.truncate(0) out.truncate(0)
out.write("mtllib " + filename + ".mtl" + '\n\n') out.write("mtllib " + filename + ".mtl" + '\n\n')
@ -772,13 +879,12 @@ class Converter:
last_color = 0 last_color = 0
for part in geo.Parts: for part in geo.Parts:
# try catch here for possible problems in materials assignment of various g, g1, g2, .. files in lxf file # try catch here for possible problems in materials assignment of various g, g1, g2, .. files in lxf file
try: try:
materialCurrentPart = pa.materials[part] materialCurrentPart = pa.materials[part]
last_color = pa.materials[part] last_color = pa.materials[part]
except IndexError: except IndexError:
# print('WARNING: {0}.g{1} has NO material assignment in lxf. Replaced with color {2}. Fix {0}.xml faces values.'.format(pa.designID, part, last_color))
materialCurrentPart = last_color materialCurrentPart = last_color
lddmat = self.allMaterials.getMaterialbyId(materialCurrentPart) lddmat = self.allMaterials.getMaterialbyId(materialCurrentPart)
@ -801,7 +907,7 @@ class Converter:
f.write(self.database.filelist[decofilename].read()) f.write(self.database.filelist[decofilename].read())
f.close() f.close()
if not matname in usedmaterials: if matname not in usedmaterials:
usedmaterials.append(matname) usedmaterials.append(matname)
outtext.write("newmtl " + matname + '\n') outtext.write("newmtl " + matname + '\n')
outtext.write(lddmat.string()) outtext.write(lddmat.string())
@ -825,6 +931,7 @@ class Converter:
sys.stdout.write('%s\r' % (' ')) sys.stdout.write('%s\r' % (' '))
# print("--- %s seconds ---" % (time.time() - start_time)) # print("--- %s seconds ---" % (time.time() - start_time))
def setDBFolderVars(dbfolderlocation, lod): def setDBFolderVars(dbfolderlocation, lod):
global PRIMITIVEPATH global PRIMITIVEPATH
global GEOMETRIEPATH global GEOMETRIEPATH
@ -836,42 +943,6 @@ def setDBFolderVars(dbfolderlocation, lod):
MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '') MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '')
# print(MATERIALNAMESPATH) # print(MATERIALNAMESPATH)
def FindDatabase():
lddliftree = os.getenv('LDDLIFTREE')
if lddliftree is not None:
if os.path.isdir(str(lddliftree)): #LDDLIFTREE points to folder
return str(lddliftree)
elif os.path.isfile(str(lddliftree)): #LDDLIFTREE points to file (should be db.lif)
return str(lddliftree)
else: #Env variable LDDLIFTREE not set. Check for default locations per different platform.
if platform.system() == 'Darwin':
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db'))
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db.lif'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db.lif'))
else:
# print("no LDD database found please install LEGO-Digital-Designer")
os._exit()
elif platform.system() == 'Windows':
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db'))
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db.lif'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db.lif'))
else:
# print("no LDD database found please install LEGO-Digital-Designer")
os._exit()
elif platform.system() == 'Linux':
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db'))
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db.lif'))):
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db.lif'))
else:
# print("no LDD database found please install LEGO-Digital-Designer")
os._exit()
else:
# print('Your OS {0} is not supported yet.'.format(platform.system()))
os._exit()
def progress(count, total, status='', suffix=''): def progress(count, total, status='', suffix=''):
bar_len = 40 bar_len = 40
@ -882,6 +953,7 @@ def progress(count, total, status='', suffix = ''):
sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status)) sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status))
sys.stdout.flush() sys.stdout.flush()
def main(lxf_filename, obj_filename, lod="2"): def main(lxf_filename, obj_filename, lod="2"):
# print("- - - pylddlib - - -") # print("- - - pylddlib - - -")
# print(" _ ") # print(" _ ")
@ -901,5 +973,6 @@ def main(lxf_filename, obj_filename, lod="2"):
converter.LoadScene(filename=lxf_filename) converter.LoadScene(filename=lxf_filename)
converter.Export(filename=obj_filename) converter.Export(filename=obj_filename)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,11 +1,13 @@
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, request, current_app from flask import render_template, Blueprint, current_app
from flask_user import login_required, current_user from flask_user import login_required
from app.models import db, CharacterInfo, Account, CharacterXML, Reports from app.models import CharacterInfo, Account, CharacterXML, Reports
from app import gm_level, scheduler from app import gm_level, scheduler
import datetime, xmltodict, json import datetime
import xmltodict
reports_blueprint = Blueprint('reports', __name__) reports_blueprint = Blueprint('reports', __name__)
@reports_blueprint.route('/', methods=['GET', 'POST']) @reports_blueprint.route('/', methods=['GET', 'POST'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -13,6 +15,7 @@ def index():
reports = Reports.query.distinct(Reports.date).group_by(Reports.date).all() reports = Reports.query.distinct(Reports.date).group_by(Reports.date).all()
return render_template('reports/index.html.j2', reports=reports) return render_template('reports/index.html.j2', reports=reports)
@reports_blueprint.route('/items/by_date/<date>', methods=['GET', 'POST']) @reports_blueprint.route('/items/by_date/<date>', methods=['GET', 'POST'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -20,6 +23,7 @@ def items_by_date(date):
data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first().data data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first().data
return render_template('reports/items/by_date.html.j2', data=data, date=date) return render_template('reports/items/by_date.html.j2', data=data, date=date)
@reports_blueprint.route('/currency/by_date/<date>', methods=['GET', 'POST']) @reports_blueprint.route('/currency/by_date/<date>', methods=['GET', 'POST'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -27,6 +31,7 @@ def currency_by_date(date):
data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first().data data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first().data
return render_template('reports/currency/by_date.html.j2', data=data, date=date) return render_template('reports/currency/by_date.html.j2', data=data, date=date)
@reports_blueprint.route('/uscore/by_date/<date>', methods=['GET', 'POST']) @reports_blueprint.route('/uscore/by_date/<date>', methods=['GET', 'POST'])
@login_required @login_required
@gm_level(3) @gm_level(3)
@ -45,7 +50,7 @@ def gen_item_report():
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first() report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first()
# Only one report per day # Only one report per day
if report != None: if report not None:
current_app.logger.info(f"Item Report Already Generated for {date}") current_app.logger.info(f"Item Report Already Generated for {date}")
return return
@ -99,7 +104,7 @@ def gen_currency_report():
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first() report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first()
# Only one report per day # Only one report per day
if report != None: if report not None:
current_app.logger.info(f"Currency Report Already Generated for {date}") current_app.logger.info(f"Currency Report Already Generated for {date}")
return return
@ -147,7 +152,7 @@ def gen_uscore_report():
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "uscore").first() report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "uscore").first()
# Only one report per day # Only one report per day
if report != None: if report not None:
current_app.logger.info(f"U-Score Report Already Generated for {date}") current_app.logger.info(f"U-Score Report Already Generated for {date}")
return return

View File

@ -1,7 +1,21 @@
from flask_marshmallow import Marshmallow from flask_marshmallow import Marshmallow
from app.models import * from app.models import (
PlayKey
PetNames
Mail
UGC
PropertyContent
Property
CharacterXML
CharacterInfo
Account
AccountInvitation
ActivityLog
CommandLog
)
ma = Marshmallow() ma = Marshmallow()
class PlayKeySchema(ma.SQLAlchemyAutoSchema): class PlayKeySchema(ma.SQLAlchemyAutoSchema):
class Meta: class Meta:
model = PlayKey model = PlayKey
@ -44,7 +58,6 @@ class PropertyContentSchema(ma.SQLAlchemyAutoSchema):
ugc = ma.Nested(UGCSchema) ugc = ma.Nested(UGCSchema)
class PropertySchema(ma.SQLAlchemyAutoSchema): class PropertySchema(ma.SQLAlchemyAutoSchema):
class Meta: class Meta:
model = Property model = Property

6
pylama.ini Normal file
View File

@ -0,0 +1,6 @@
[pylama]
ignore = D203, D212, D213, D406, D407, D408, D409, D100, D104, D401, F722
max_line_length = 160
[pylama:mccabe]
max-complexity = 35