From a4ce10c59cd3336ba2bc27b61e24f56b55987b39 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 19 Apr 2019 15:02:21 +0200 Subject: [PATCH 01/22] some work on database implementation for configureable fit classification --- waitlist/storage/database.py | 71 ++++++++++++++++++++++++++++++- waitlist/utility/fitting_utils.py | 27 +++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/waitlist/storage/database.py b/waitlist/storage/database.py index 0e1f1573..795b1ca2 100644 --- a/waitlist/storage/database.py +++ b/waitlist/storage/database.py @@ -388,6 +388,8 @@ class MarketGroup(Base): iconID = Column('icon_id', Integer) hasTypes = Column('has_types', Boolean(name='has_types')) + parent = relationship("MarketGroup", remote_side=[marketGroupID]) + class Account(Base): """ @@ -775,7 +777,6 @@ class Permission(Base): def __repr__(self): return f' str: + check_collection: ShipCheckCollection = db.session.query(ShipCheckCollection).filter( + ShipCheckCollection.waitlistGroupID == waitlist_group_id + ).one() + ship_type: InvType = db.session.query(InvType).get(ship_type_id) + # collect market groups + market_groups = [] + market_group.append(ship_type.marketGroupID) + for check in check_collection.checks: + if check.checkType == SHIP_CHECK_TYPEID: + if check.check_types.any(InvType.typeID == ship_type.typeID): + return check.checkTarget + elif check.checkType == SHIP_CHECK_INVGROUP: + if check.check_groups.any(InvGroup.groupID == ship_type.groupID): + return check.checkTarget + elif check.checkType = SHIP_CHECK_MARKETGROUP: + if check.check_market_groups.any(MarketGroup == ship_type.) + From 2448c76970309392b5523291cba04a0349107d48 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 19 Apr 2019 20:22:24 +0200 Subject: [PATCH 02/22] added more code to use the database supported fit classification --- waitlist/blueprints/xup/submission.py | 8 ++- waitlist/storage/database.py | 25 +++++--- waitlist/utility/fitting_utils.py | 84 +++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/waitlist/blueprints/xup/submission.py b/waitlist/blueprints/xup/submission.py index 99fc62de..a61eeda9 100644 --- a/waitlist/blueprints/xup/submission.py +++ b/waitlist/blueprints/xup/submission.py @@ -16,7 +16,8 @@ from waitlist.utility.history_utils import create_history_object from waitlist.utility.fitting_utils import get_fit_format, parse_dna_fitting,\ parse_eft, is_logi_hull, is_allowed_hull, is_dps_by_group,\ - is_sniper_by_group, get_weapon_type_by_typeid, get_waitlist_type_by_ship_typeid + is_sniper_by_group, get_weapon_type_by_typeid, get_waitlist_type_by_ship_typeid,\ + get_waitlist_type_for_fit from waitlist.base import db from . import bp from flask_babel import gettext, ngettext @@ -252,6 +253,10 @@ def submit(): # split his fits into types for the different waitlist_entries for fit in fits: + wl_type = get_waitlist_type_for_fit(fit, group_id) + fit.wl_type = wl_type + fits_ready.append(fit) + """ mod_list: List[Dict[int, Tuple(int, int)]] try: mod_list = parse_dna_fitting(fit.modules) @@ -298,6 +303,7 @@ def submit(): fit.wl_type = weapon_type fits_ready.append(fit) continue + """ """ #this stuff is needed somewhere else now diff --git a/waitlist/storage/database.py b/waitlist/storage/database.py index 795b1ca2..6e037d5b 100644 --- a/waitlist/storage/database.py +++ b/waitlist/storage/database.py @@ -5,7 +5,7 @@ from esipy import EsiSecurity from esipy.exceptions import APIException from sqlalchemy import Column, Integer, String, SmallInteger, BIGINT, Boolean, DateTime, Index, \ - sql, BigInteger, text, Float, Text + sql, BigInteger, text, Float, Text, Numeric from sqlalchemy import Enum from sqlalchemy.orm import relationship, backref from sqlalchemy.sql.schema import Table, ForeignKey, CheckConstraint, UniqueConstraint @@ -288,6 +288,10 @@ class InvType(Base): 'InvGroup', primaryjoin='foreign(InvType.groupID) == InvGroup.groupID') + market_group: 'MarketGroup' = relationship( + 'MarketGroup' + ) + dogma_attributes = relationship( 'InvTypeDogmaAttribute') @@ -1340,8 +1344,14 @@ class ShipCheckCollection(Base): ondelete='CASCADE', onupdate='CASCADE'), unique=True) - checks = relationship('ShipCheck', back_populates='collection', order_by='asc(ShipCheck.order)') + defaultTargetID: Column = Column('default_target_id', Integer, + ForeignKey(Waitlist.id, + ondelete='CASCADE', + onupdate='CASCADE') + ) + checks = relationship('ShipCheck', back_populates='collection', order_by='asc(ShipCheck.order)') + defaultTarget: Waitlist = relationship('Waitlist') ship_check_invtypes = Table('ship_check_invtypes', Base.metadata, @@ -1361,7 +1371,7 @@ class ShipCheckCollection(Base): ForeignKey('ship_check.check_id', onupdate='CASCADE', ondelete='CASCADE')), Column('group_id', Integer, - ForeignKey('invgroups.group_id', + ForeignKey('invgroup.group_id', onupdate='CASCADE', ondelete='CASCADE')) ) @@ -1378,7 +1388,7 @@ class ShipCheckCollection(Base): ) -class ShipCheck(Base) +class ShipCheck(Base): __tablename__: str = 'ship_check' checkID: Column = Column('check_id', Integer, primary_key=True) collectionID: Column = Column( @@ -1392,8 +1402,7 @@ class ShipCheck(Base) nullable=True) collection = relationship('ShipCheckCollection', back_populates='checks') - check_types = relationship('InvType', secondary='ship_check_invtypes') - check_groups = relationship('InvGroup', secondary='ship_check_groups') - check_market_groups = relationship('MarketGroup', secondary='ship_check_marketgroups') -# TODO: Add marketgroups for module checks + check_types = relationship('InvType', secondary='ship_check_invtypes', lazy='dynamic') + check_groups = relationship('InvGroup', secondary='ship_check_groups', lazy='dynamic') + check_market_groups = relationship('MarketGroup', secondary='ship_check_marketgroups', lazy='dynamic') diff --git a/waitlist/utility/fitting_utils.py b/waitlist/utility/fitting_utils.py index 219bb904..287a6547 100644 --- a/waitlist/utility/fitting_utils.py +++ b/waitlist/utility/fitting_utils.py @@ -1,3 +1,5 @@ +import operator +from sqlalchemy import literal from waitlist.utility.constants import location_flags, effects from typing import List, Dict, Optional from waitlist.storage.database import InvType, Shipfit, FitModule,\ @@ -362,22 +364,84 @@ def get_waitlist_type_by_ship_typeid(type_id: int): SHIP_CHECK_TYPEID = 1 SHIP_CHECK_INVGROUP = 2 SHIP_CHECK_MARKETGROUP = 3 +MODULE_CHECK_TYPEID = 4 +MODULE_CHECK_MARKETGROUP = 5 -def get_waitlist_type_for_ship_type(waitlist_group_id: int, ship_type_id: int) -> str: - check_collection: ShipCheckCollection = db.session.query(ShipCheckCollection).filter( - ShipCheckCollection.waitlistGroupID == waitlist_group_id - ).one() +def get_waitlist_type_for_ship_type(check_collection: ShipCheckCollection, ship_type_id: int) -> Optional[str]: ship_type: InvType = db.session.query(InvType).get(ship_type_id) # collect market groups - market_groups = [] - market_group.append(ship_type.marketGroupID) + market_group_ids = [] + m_group: MarketGroup = ship_type.market_group + while m_group is not None: + market_group_ids.append(m_group.marketGroupID) + m_group = m_group.parent + for check in check_collection.checks: if check.checkType == SHIP_CHECK_TYPEID: - if check.check_types.any(InvType.typeID == ship_type.typeID): + if db.session.query(check.check_types.filter(InvType.typeID == ship_type.typeID).exists()).scalar(): return check.checkTarget elif check.checkType == SHIP_CHECK_INVGROUP: - if check.check_groups.any(InvGroup.groupID == ship_type.groupID): + if db.session.query(check.check_groups.filter(InvGroup.groupID == ship_type.groupID).exists()).scalar(): return check.checkTarget - elif check.checkType = SHIP_CHECK_MARKETGROUP: - if check.check_market_groups.any(MarketGroup == ship_type.) + elif check.checkType == SHIP_CHECK_MARKETGROUP: + if db.session.query(check.check_market_groups.filter(MarketGroup.marketGroupID.in_(market_group_ids)).exists()).scalar(): + return check.checkTarget + + return None + + +def get_waitlist_type_for_modules(check_collection: ShipCheckCollection, fit: Shipfit) -> Optional[str]: + mod_list: List[Dict[int, Tuple(int, int)]] = parse_dna_fitting(fit.modules) + mod_ids = [mod_id in mod_list[location_flags.HIGH_SLOT]] + # prepare marketgroup list for every module, we need it later on + market_groups = dict() + for mod_id in mod_list[HIGH_SLOT]: + if mod_id not in market_group: + invtype: InvType = db.session.query(InvType).get(mod_id) + m_group: MarketGroup = invtype.market_group + while m_group is not None: + market_groups[mod_id].append(m_group.marketGroupID) + m_group = m_group.parent + + # for modules we need to hit every module once or never + result_count_map = dict() + for check in check_collection: + if check.checkType not in result_count_map: + result_count_map[check.checkType] = 0 + modifier = 1 if check.modifier is None else check.modifier + if check.checkType == MODULE_CHECK_TYPEID: + remaining_mods = [] + type_ids = {type_obj.typeID for type_obj in check.check_types} + for mod_id in mod_ids: + if mod_id in type_ids: + result_count_map[check.checkType] += modifier + else: + remaining_mods.append(mod_id) + mod_ids = remaining_mods + elif check.checkType == MODULE_CHECK_MARKETGROUP: + remaining_mods = [] + group_ids = {group_obj.marketGroupID for group_obj in check.check_market_groups} + for mod_id in mod_ids: + mgs_for_mod = set(market_groups[mod_id]) + if mgs_for_mod.intersection(group_ids) > 0: + result_count_map[check.checkType] += modifier + else: + remaining_mods.append(mod_id) + mod_ids = remaining_mods + + return max(result_count_map.items(), key=operator.itemgetter(1), default=(None, None))[0] + + +def get_waitlist_type_for_fit(fit: Shipfit, waitlist_group_id: int) -> str: + # modlist[SLOT_INDEX][TYPE_ID][TYPE_ID][AMOUNT] + check_collection: ShipCheckCollection = db.session.query(ShipCheckCollection).filter( + ShipCheckCollection.waitlistGroupID == waitlist_group_id + ).one() + + ship_wl_type = get_waitlist_type_for_ship_type(check_collection, fit.ship_type) + if ship_wl_type is None: + ship_wl_type = get_waitlist_type_for_modules(check_collection, fit) + if ship_wl_type is None: + return check_collection.defaultTarget.id + return ship_wl_type From 9e35ca0b01390067eca01243b7c8787821006a0e Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 20 Apr 2019 14:57:32 +0200 Subject: [PATCH 03/22] added some basic web ui, not complete yet --- static/js/ship_assignment/collection_list.js | 26 ++++++++ .../ship_assignment/collection_list.html | 56 +++++++++++++++++ .../blueprints/settings/ship_assignment.py | 61 +++++++++++++++++++ waitlist/entry.py | 3 +- 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 static/js/ship_assignment/collection_list.js create mode 100644 templates/settings/ship_assignment/collection_list.html create mode 100644 waitlist/blueprints/settings/ship_assignment.py diff --git a/static/js/ship_assignment/collection_list.js b/static/js/ship_assignment/collection_list.js new file mode 100644 index 00000000..18670c5e --- /dev/null +++ b/static/js/ship_assignment/collection_list.js @@ -0,0 +1,26 @@ +'use strict'; +if (!waitlist) { + var waitlist = {}; +} +if (!waitlist.ship_assignment) { + waitlist.ship_assignment = {}; +} + +waitlist.ship_assignment.collection_list = (function () { + function handleGroupSelected(event) { + const select = $(event.target); + const wl_select = $("#default_target_id"); + let enabled_options = wl_select.find("option:not([disabled])"); + enabled_options.prop("hidden", true); + enabled_options.prop("disabled", true); + let options_for_selection = wl_select.find("option[data-group=\"" + select.val() + "\"]"); + options_for_selection.prop("disabled", false); + options_for_selection.prop("hidden", false); + } + + function init() { + $('#wl_group_id_select').on("change", handleGroupSelected); + } + + $(document).ready(init); +})(); diff --git a/templates/settings/ship_assignment/collection_list.html b/templates/settings/ship_assignment/collection_list.html new file mode 100644 index 00000000..8f6141a2 --- /dev/null +++ b/templates/settings/ship_assignment/collection_list.html @@ -0,0 +1,56 @@ +{% extends "settings/base.html" %} + +{% block title %}{{ _('Settings') }} - {{ _('Ship Assignment Selection') }}{% endblock %} + +{% block head %} +{{ super() }} +{% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", +"js/ship_assignment/collection_list.js" %} + +{% endassets %} +{% endblock %} + +{% block raw_content %} +
+
+ + + +
+
+
+
+ + + + + + +
+
+
+
+ + + +
+
+{% endblock %} diff --git a/waitlist/blueprints/settings/ship_assignment.py b/waitlist/blueprints/settings/ship_assignment.py new file mode 100644 index 00000000..ef25737e --- /dev/null +++ b/waitlist/blueprints/settings/ship_assignment.py @@ -0,0 +1,61 @@ +import logging +import flask +from flask import Blueprint, Response, render_template +from flask_babel import gettext, lazy_gettext +from flask_login import login_required, current_user +from waitlist.base import db +from waitlist.permissions import perm_manager +from waitlist.storage.database import ShipCheckCollection, WaitlistGroup +from waitlist.blueprints.settings import add_menu_entry + +bp = Blueprint('ship_assignment', __name__) +logger = logging.getLogger(__name__) + + +perm_manager.define_permission('ship_assignment_edit') + + +@bp.route('/', methods=['GET']) +@login_required +@perm_manager.require('ship_assignment_edit') +def ship_assignments(): + checks = db.session.query(ShipCheckCollection).all() + wl_groups = db.session.query(WaitlistGroup).all() + # TODO: this site needs the forms for adding a collection + # and removing one, only has edit for now + return render_template('settings/ship_assignment/collection_list.html', + checks=checks, groups=wl_groups) + +@bp.route('/col/edit', methods=['GET']) +@login_required +@perm_manager.require('ship_assignment_edit') +def collection_edit() -> Response: + cid: int = int(request.form['collection_id']) + coll: ShipCheckCollection = db.session.query(ShipCheckCollection).get(cid) + return render_template('settings/ship_assignment/collection_edit.html', coll=coll) + + + +@bp.route('/col/add', methods=['POST']) +@login_required +@perm_manager.require('ship_assignment_edit') +def collection_add(): + # TODO: Add the collection from data of post + return redirect(url_for('.ship_assignments')) + + +@bp.route('/col/remove', methods=['POST']) +@login_required +@perm_manager.require('ship_assignment_edit') +def collection_remove(): + cid: int = request.form['collection_id'] + db.session.query(ShipCheckCollection).get(cid).delete() + return redirect(url_for('.ship_assignments')) + +@bp.route('/col/add_check') +@login_required +@perm_manager.require('ship_assignment_edit') +def add_checks(): + return render_template('settings/ship_assignment/check') + +add_menu_entry('ship_assignment.ship_assignments', lazy_gettext('Ship Classification'), perm_manager.get_permission('ship_assignment_edit').can) diff --git a/waitlist/entry.py b/waitlist/entry.py index d33de687..3a9617a8 100644 --- a/waitlist/entry.py +++ b/waitlist/entry.py @@ -45,7 +45,7 @@ def register_blueprints(): from waitlist.blueprints.fleetview import bp as bp_fleetview from waitlist.blueprints.settings import accounts as settings_accounts, bans, fleet_motd, fleetoptions, inserts, mail, overview,\ - staticdataimport, teamspeak, permissions + staticdataimport, teamspeak, permissions, ship_assignment from waitlist.blueprints import trivia, feedback, swagger_api from waitlist.blueprints.api import permission from waitlist.blueprints import xup @@ -101,6 +101,7 @@ def register_blueprints(): app.register_blueprint(permissions.bp, url_prefix='/settings/permissions') app.register_blueprint(permission.bp, url_prefix='/api/permission') app.register_blueprint(xup.bp, url_prefix='/xup') + app.register_blueprint(ship_assignment.bp, url_prefix='/settings/ship_assignment') # notification app.register_blueprint(notification.bp, url_prefix="/notification") From 314bf19a8855a6820d67bd5710d4cb5d403a2160 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 15:45:43 +0200 Subject: [PATCH 04/22] removed old migration file --- migrations/versions/afa58b54a8fe_.py | 59 ---------------------------- 1 file changed, 59 deletions(-) delete mode 100644 migrations/versions/afa58b54a8fe_.py diff --git a/migrations/versions/afa58b54a8fe_.py b/migrations/versions/afa58b54a8fe_.py deleted file mode 100644 index 2d62c032..00000000 --- a/migrations/versions/afa58b54a8fe_.py +++ /dev/null @@ -1,59 +0,0 @@ -"""empty message - -Revision ID: afa58b54a8fe -Revises: 5d4aee209354 -Create Date: 2019-04-18 17:40:20.275827 - -""" -from alembic import op -import sqlalchemy as sa -from waitlist.utility.sde import update_invtypes -from waitlist.base import db -from waitlist.storage.database import MarketGroup, InvGroup, InvCategory, InvType - -# revision identifiers, used by Alembic. -revision = 'afa58b54a8fe' -down_revision = '5d4aee209354' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint('fk_invmarketgroups_parent_group_id_invmarketgroups', 'invmarketgroups', type_='foreignkey') - # adjust the type for the KF - op.alter_column('invtypes', 'market_group_id', type_=sa.Integer, existing_type=sa.BigInteger) - op.create_foreign_key(op.f('fk_invmarketgroups_parent_group_id_invmarketgroups'), 'invmarketgroups', 'invmarketgroups', ['parent_group_id'], ['market_group_id'], onupdate='CASCADE', ondelete='CASCADE') - - # now we actually need to make sure all of the ones we use FK to are up to date - # this updates market groups and inventory groups+categories - # only do this if there is any inventory data - - market_count = db.session.query(sa.func.count(MarketGroup.marketGroupID)).scalar() - invgroup_count = db.session.query(sa.func.count(InvGroup.groupID)).scalar() - invcat_count = db.session.query(sa.func.count(InvCategory.categoryID)).scalar() - invtype_count = db.session.query(sa.func.count(InvType.typeID)).scalar() - print("Queried counts") - max_count = max(market_count, invgroup_count, invcat_count, invtype_count) - if max_count > 0: - print("We are updating all inventory data now, this can take a while") - update_invtypes() - print("Updating inventory data done") - else: - print("Empty database, no need to upgrade data") - db.session.remove() - - # now we are ready to apply new FKs - op.create_foreign_key(op.f('fk_invtypes_market_group_id_invmarketgroups'), 'invtypes', 'invmarketgroups', ['market_group_id'], ['market_group_id'], onupdate='CASCADE', ondelete='CASCADE') - op.create_foreign_key(op.f('fk_invtypes_group_id_invgroup'), 'invtypes', 'invgroup', ['group_id'], ['group_id'], onupdate='CASCADE', ondelete='CASCADE') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(op.f('fk_invtypes_group_id_invgroup'), 'invtypes', type_='foreignkey') - op.drop_constraint(op.f('fk_invtypes_market_group_id_invmarketgroups'), 'invtypes', type_='foreignkey') - op.drop_constraint(op.f('fk_invmarketgroups_parent_group_id_invmarketgroups'), 'invmarketgroups', type_='foreignkey') - op.alter_column('invtypes', 'market_group_id', _type=sa.BigInteger, existing_type=sa.Integer) - op.create_foreign_key('fk_invmarketgroups_parent_group_id_invmarketgroups', 'invmarketgroups', 'invmarketgroups', ['parent_group_id'], ['market_group_id']) - # ### end Alembic commands ### From 21ea737a371809770c38d6154773409d55b83164 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 19:04:21 +0200 Subject: [PATCH 05/22] finished implementing rule based ship assignment --- migrations/versions/dee8dcee93e4_.py | 150 ++++++++++ static/js/ship_assignment/check_edit.js | 31 ++ static/js/ship_assignment/collection.js | 36 +++ static/js/ship_assignment/collection_edit.js | 29 ++ static/js/ship_assignment/collection_list.js | 16 +- .../settings/ship_assignment/check_edit.html | 68 +++++ .../ship_assignment/collection_edit.html | 128 +++++++++ .../ship_assignment/collection_list.html | 88 +++--- waitlist/blueprints/fittings.py | 179 ++---------- .../blueprints/settings/ship_assignment.py | 188 +++++++++++- waitlist/blueprints/xup/submission.py | 72 +---- waitlist/storage/database.py | 95 +++++- waitlist/storage/modules.py | 4 +- waitlist/utility/constants/check_types.py | 16 ++ waitlist/utility/fitting_utils.py | 271 ++++++++++-------- waitlist/utility/jinja2/__init__.py | 8 +- 16 files changed, 968 insertions(+), 411 deletions(-) create mode 100644 migrations/versions/dee8dcee93e4_.py create mode 100644 static/js/ship_assignment/check_edit.js create mode 100644 static/js/ship_assignment/collection.js create mode 100644 static/js/ship_assignment/collection_edit.js create mode 100644 templates/settings/ship_assignment/check_edit.html create mode 100644 templates/settings/ship_assignment/collection_edit.html create mode 100644 waitlist/utility/constants/check_types.py diff --git a/migrations/versions/dee8dcee93e4_.py b/migrations/versions/dee8dcee93e4_.py new file mode 100644 index 00000000..9cbd029b --- /dev/null +++ b/migrations/versions/dee8dcee93e4_.py @@ -0,0 +1,150 @@ +"""empty message + +Revision ID: dee8dcee93e4 +Revises: 5d4aee209354 +Create Date: 2019-04-26 15:54:00.665467 + +""" +from alembic import op +import sqlalchemy as sa +from waitlist.storage.database import WaitlistGroup, MarketGroup, InvGroup, InvCategory, InvType +from waitlist.base import db +from waitlist.utility.sde import update_invtypes + +# revision identifiers, used by Alembic. +revision = 'dee8dcee93e4' +down_revision = '5d4aee209354' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('ship_check_collection', + sa.Column('collection_id', sa.Integer(), nullable=False), + sa.Column('collection_name', sa.String(length=50), nullable=True), + sa.Column('waitlist_group_id', sa.Integer(), nullable=True), + sa.Column('default_target_id', sa.Integer(), nullable=True), + sa.Column('default_tag', sa.String(length=20), nullable=True), + sa.ForeignKeyConstraint(['default_target_id'], ['waitlists.id'], name=op.f('fk_ship_check_collection_default_target_id_waitlists'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['waitlist_group_id'], ['waitlist_groups.group_id'], name=op.f('fk_ship_check_collection_waitlist_group_id_waitlist_groups'), onupdate='CASCADE', ondelete='CASCADE'), + sa.PrimaryKeyConstraint('collection_id', name=op.f('pk_ship_check_collection')), + sa.UniqueConstraint('waitlist_group_id', name=op.f('uq_ship_check_collection_waitlist_group_id')) + ) + op.create_table('ship_check', + sa.Column('check_id', sa.Integer(), nullable=False), + sa.Column('check_name', sa.String(length=100), nullable=True), + sa.Column('collection_id', sa.Integer(), nullable=True), + sa.Column('check_target_id', sa.Integer(), nullable=False), + sa.Column('check_type', sa.Integer(), nullable=True), + sa.Column('order', sa.Integer(), nullable=True), + sa.Column('modifier', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('tag', sa.String(length=20), nullable=True), + sa.ForeignKeyConstraint(['check_target_id'], ['waitlists.id'], name=op.f('fk_ship_check_check_target_id_waitlists'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['collection_id'], ['ship_check_collection.collection_id'], name=op.f('fk_ship_check_collection_id_ship_check_collection'), onupdate='CASCADE', ondelete='CASCADE'), + sa.PrimaryKeyConstraint('check_id', name=op.f('pk_ship_check')) + ) + op.create_table('ship_check_groups', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('group_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_groups_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['group_id'], ['invgroup.group_id'], name=op.f('fk_ship_check_groups_group_id_invgroup'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.create_table('ship_check_invtypes', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_invtypes_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['type_id'], ['invtypes.type_id'], name=op.f('fk_ship_check_invtypes_type_id_invtypes'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.create_table('ship_check_marketgroups', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('market_group_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_marketgroups_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['market_group_id'], ['invmarketgroups.market_group_id'], name=op.f('fk_ship_check_marketgroups_market_group_id_invmarketgroups'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.create_table('ship_check_rest_groups', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('group_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_rest_groups_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['group_id'], ['invgroup.group_id'], name=op.f('fk_ship_check_rest_groups_group_id_invgroup'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.create_table('ship_check_rest_invtypes', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_rest_invtypes_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['type_id'], ['invtypes.type_id'], name=op.f('fk_ship_check_rest_invtypes_type_id_invtypes'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.create_table('ship_check_rest_marketgroups', + sa.Column('check_id', sa.Integer(), nullable=True), + sa.Column('market_group_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['check_id'], ['ship_check.check_id'], name=op.f('fk_ship_check_rest_marketgroups_check_id_ship_check'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['market_group_id'], ['invmarketgroups.market_group_id'], name=op.f('fk_ship_check_rest_marketgroups_market_group_id_invmarketgroups'), onupdate='CASCADE', ondelete='CASCADE') + ) + op.add_column('fittings', sa.Column('target_waitlist', sa.Integer(), nullable=True)) + op.create_foreign_key(op.f('fk_fittings_target_waitlist_waitlists'), 'fittings', 'waitlists', ['target_waitlist'], ['id'], onupdate='CASCADE', ondelete='CASCADE') + # below here changes the ondelete, onupdate from Restrict to Cascade + op.drop_constraint('fk_invmarketgroups_parent_group_id_invmarketgroups', 'invmarketgroups', type_='foreignkey') + op.create_foreign_key(op.f('fk_invmarketgroups_parent_group_id_invmarketgroups'), 'invmarketgroups', 'invmarketgroups', ['parent_group_id'], ['market_group_id'], onupdate='CASCADE', ondelete='CASCADE') + + # adjust the type for the KF + op.alter_column('invtypes', 'market_group_id', type_=sa.Integer, existing_type=sa.BigInteger) + + # now we actually need to make sure all of the ones we use FK to are up to date + # this updates market groups and inventory groups+categories + # only do this if there is any inventory data + market_count = db.session.query(sa.func.count(MarketGroup.marketGroupID)).scalar() + invgroup_count = db.session.query(sa.func.count(InvGroup.groupID)).scalar() + invcat_count = db.session.query(sa.func.count(InvCategory.categoryID)).scalar() + invtype_count = db.session.query(sa.func.count(InvType.typeID)).scalar() + print("Queried counts") + max_count = max(market_count, invgroup_count, invcat_count, invtype_count) + if max_count > 0: + print("We are updating all inventory data now, this can take a while") + update_invtypes() + print("Updating inventory data done") + else: + print("Empty database, no need to upgrade data") + db.session.remove() + # now we are ready to apply new FKs + op.create_foreign_key(op.f('fk_invtypes_market_group_id_invmarketgroups'), 'invtypes', 'invmarketgroups', ['market_group_id'], ['market_group_id'], onupdate='CASCADE', ondelete='CASCADE') + + op.create_foreign_key(op.f('fk_invtypes_group_id_invgroup'), 'invtypes', 'invgroup', ['group_id'], ['group_id'], onupdate='CASCADE', ondelete='CASCADE') + op.add_column('waitlist_groups', sa.Column('queueID', sa.Integer(), nullable=True)) + wl_groups = db.session.query(WaitlistGroup).all() + for wl_group in wl_groups: + queue_wl = None + for wl in wl_group.waitlists: + if wl.waitlistType == "xup": + queue_wl = wl + break + if queue_wl is None: + print("There is an error with your database, waitlist group", wl_group.groupID, "is missing an xup list") + else: + wl_group.queueID = queue_wl.id + db.session.commit() + # now we can remove the nullable=True + op.alter_column('waitlist_groups', 'queueID', existing_type=sa.Integer(), nullable=False) + op.create_foreign_key(op.f('fk_waitlist_groups_queueID_waitlists'), 'waitlist_groups', 'waitlists', ['queueID'], ['id']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(op.f('fk_waitlist_groups_queueID_waitlists'), 'waitlist_groups', type_='foreignkey') + op.drop_column('waitlist_groups', 'queueID') + op.drop_constraint(op.f('fk_invtypes_group_id_invgroup'), 'invtypes', type_='foreignkey') + op.drop_constraint(op.f('fk_invtypes_market_group_id_invmarketgroups'), 'invtypes', type_='foreignkey') + op.alter_column('invtypes', 'market_group_id', _type=sa.BigInteger, existing_type=sa.Integer) + op.drop_constraint(op.f('fk_invmarketgroups_parent_group_id_invmarketgroups'), 'invmarketgroups', type_='foreignkey') + op.create_foreign_key('fk_invmarketgroups_parent_group_id_invmarketgroups', 'invmarketgroups', 'invmarketgroups', ['parent_group_id'], ['market_group_id']) + op.drop_constraint(op.f('fk_fittings_target_waitlist_waitlists'), 'fittings', type_='foreignkey') + op.drop_column('fittings', 'target_waitlist') + op.drop_table('ship_check_rest_marketgroups') + op.drop_table('ship_check_rest_invtypes') + op.drop_table('ship_check_rest_groups') + op.drop_table('ship_check_marketgroups') + op.drop_table('ship_check_invtypes') + op.drop_table('ship_check_groups') + op.drop_table('ship_check_collection') + op.drop_table('ship_check') + # ### end Alembic commands ### diff --git a/static/js/ship_assignment/check_edit.js b/static/js/ship_assignment/check_edit.js new file mode 100644 index 00000000..f0bff3c4 --- /dev/null +++ b/static/js/ship_assignment/check_edit.js @@ -0,0 +1,31 @@ +'use strict'; +if (!waitlist) { + var waitlist = {}; +} +if (!waitlist.ship_assignment) { + waitlist.ship_assignment = {}; +} + +waitlist.ship_assignment.check_edit = (function () { + + function init() { + let check_select = $("#check_type"); + check_select.on("change", typeSelectHandler); + updateHiddenElements(parseInt(check_select.val(), 10)); + } + + function typeSelectHandler(event) { + updateHiddenElements(parseInt($(event.target).val(), 10)); + } + + function updateHiddenElements(type_id) { + if (isNaN(type_id)) return; + if (type_id > 3) { + $("#check_add_modifier, #check_add_rest_type_ids, #check_add_rest_invgroup_ids, #check_add_rest_mgroup_ids").parent().prop("hidden", false); + } else { + $("#check_add_modifier, #check_add_rest_type_ids, #check_add_rest_invgroup_ids, #check_add_rest_mgroup_ids").parent().prop("hidden", true); + } + } + + $(document).ready(init); +})(); diff --git a/static/js/ship_assignment/collection.js b/static/js/ship_assignment/collection.js new file mode 100644 index 00000000..3730acc8 --- /dev/null +++ b/static/js/ship_assignment/collection.js @@ -0,0 +1,36 @@ +'use strict'; +if (!waitlist) { + var waitlist = {}; +} +if (!waitlist.ship_assignment) { + waitlist.ship_assignment = {}; +} + +waitlist.ship_assignment.collection = (function () { + + function updateListSelect(group_select, waitlist_selector) { + // "#default_target_id" + const wl_select = $(waitlist_selector); + let enabled_options = wl_select.find("option:not([disabled])"); + enabled_options.prop("hidden", true); + enabled_options.prop("disabled", true); + let options_for_selection = wl_select.find("option[data-group=\"" + group_select.val() + "\"]"); + options_for_selection.prop("disabled", false); + options_for_selection.prop("hidden", false); + // now select one of the enabled options + let option = wl_select.find("option:not([disabled])").first(); + option.prop("selected", true); + } + + function addSubwaitlistPopulationHandler(group_selector, waitlist_selector) { + // "#wl_group_id_select" + $(group_selector).on("change", function(event){ updateListSelect($(event.target), waitlist_selector); }); + } + + function doInitialSubwaitlistPopulation(group_selector, waitlist_selector) { + const group_select = $(group_selector); + updateListSelect(group_select, waitlist_selector); + } + + return {'addSubwaitlistPopulationHandler': addSubwaitlistPopulationHandler, 'doInitialSubwaitlistPopulation': doInitialSubwaitlistPopulation}; +})(); diff --git a/static/js/ship_assignment/collection_edit.js b/static/js/ship_assignment/collection_edit.js new file mode 100644 index 00000000..235825fe --- /dev/null +++ b/static/js/ship_assignment/collection_edit.js @@ -0,0 +1,29 @@ +'use strict'; +if (!waitlist) { + var waitlist = {}; +} +if (!waitlist.ship_assignment) { + waitlist.ship_assignment = {}; +} + +waitlist.ship_assignment.collection_edit = (function () { + + let addSubwaitlistPopulationHandler = waitlist.ship_assignment.collection.addSubwaitlistPopulationHandler; + + function init() { + addSubwaitlistPopulationHandler("#wl_group_id_select", "#default_target_id"); + $("#check_type").on("change", typeSelectHandler); + } + + function typeSelectHandler(event) { + let type = parseInt($(event.target).val(), 10); + if (isNaN(type)) return; + if (type > 3) { + $("#check_add_modifier, #check_add_rest_type_ids, #check_add_rest_invgroup_ids, #check_add_rest_mgroup_ids").parent().prop("hidden", false); + } else { + $("#check_add_modifier, #check_add_rest_type_ids, #check_add_rest_invgroup_ids, #check_add_rest_mgroup_ids").parent().prop("hidden", true); + } + } + + $(document).ready(init); +})(); diff --git a/static/js/ship_assignment/collection_list.js b/static/js/ship_assignment/collection_list.js index 18670c5e..fa448540 100644 --- a/static/js/ship_assignment/collection_list.js +++ b/static/js/ship_assignment/collection_list.js @@ -7,19 +7,13 @@ if (!waitlist.ship_assignment) { } waitlist.ship_assignment.collection_list = (function () { - function handleGroupSelected(event) { - const select = $(event.target); - const wl_select = $("#default_target_id"); - let enabled_options = wl_select.find("option:not([disabled])"); - enabled_options.prop("hidden", true); - enabled_options.prop("disabled", true); - let options_for_selection = wl_select.find("option[data-group=\"" + select.val() + "\"]"); - options_for_selection.prop("disabled", false); - options_for_selection.prop("hidden", false); - } + + let addSubwaitlistPopulationHandler = waitlist.ship_assignment.collection.addSubwaitlistPopulationHandler; + let doInitialSubwaitlistPopulation = waitlist.ship_assignment.collection.doInitialSubwaitlistPopulation; function init() { - $('#wl_group_id_select').on("change", handleGroupSelected); + doInitialSubwaitlistPopulation("#wl_group_id_select", "#default_target_id"); + addSubwaitlistPopulation("#wl_group_id_select", "#default_target_id"); } $(document).ready(init); diff --git a/templates/settings/ship_assignment/check_edit.html b/templates/settings/ship_assignment/check_edit.html new file mode 100644 index 00000000..db47b37c --- /dev/null +++ b/templates/settings/ship_assignment/check_edit.html @@ -0,0 +1,68 @@ +{% extends "settings/base.html" %} + +{% block title %}{{ _('Settings') }} - {{ _('Ship Check Edit') }}{% endblock %} + +{% block head %} +{{ super() }} +{% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", + "js/ship_assignment/check_edit.js" %} + +{% endassets %} +{% endblock %} + +{% block raw_content %} +
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+{% endblock %} diff --git a/templates/settings/ship_assignment/collection_edit.html b/templates/settings/ship_assignment/collection_edit.html new file mode 100644 index 00000000..5107d8ec --- /dev/null +++ b/templates/settings/ship_assignment/collection_edit.html @@ -0,0 +1,128 @@ +{% extends "settings/base.html" %} + +{% block title %}{{ _('Settings') }} - {{ _('Ship Classification Selection') }}{% endblock %} + +{% block head %} +{{ super() }} +{% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", +"js/ship_assignment/collection.js", "js/ship_assignment/collection_edit.js" %} + +{% endassets %} +{% endblock %} + +{% block raw_content %} +
+
+ +
+ + +
+
+ + +
+
+ + + +
+
+ + +
+ +
+
+
+
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ + + + + {% for check in coll.checks %} + + + + + + + + + + {% endfor %} + +
{{ _('Name') }}{{ _('Actions') }}{{ _('Target') }}{{ _('Type') }}{{ _('Tag') }}{{ _('Order') }}{{ _('modifier') }}{{ _('TypeIDs') }}{{ _('R by Type') }}{{ _('R by InvGroup') }}{{ _('R by Market Group') }} +
{{ check.checkName }}{{ _('Edit') }}{{ check.checkTargetID }}{{ check_type_map[check.checkType] }}{{ check.checkTag }}{{ check.order }}{{ check.modifier }} + {% for tp in check.ids %}{{ get_pk(tp)[0] }}{% if not loop.last %},{% endif %}{% endfor %}{% for type in check.check_rest_types %}{{ get_pk(type)[0] }}{% if not loop.last %},{% endif %}{% endfor %} + {% for type in check.check_rest_groups %}{{ get_pk(type)[0] }}{% if not loop.last %},{% endif %}{% endfor %} + {% for type in check.check_rest_market_groups %}{{ get_pk(type)[0] }}{% if not loop.last %},{% endif %}{% endfor %} +
+
+ +{% endblock %} diff --git a/templates/settings/ship_assignment/collection_list.html b/templates/settings/ship_assignment/collection_list.html index 8f6141a2..ec8a5c67 100644 --- a/templates/settings/ship_assignment/collection_list.html +++ b/templates/settings/ship_assignment/collection_list.html @@ -1,56 +1,74 @@ {% extends "settings/base.html" %} -{% block title %}{{ _('Settings') }} - {{ _('Ship Assignment Selection') }}{% endblock %} +{% block title %}{{ _('Settings') }} - {{ _('Ship Classification Selection') }}{% endblock %} {% block head %} {{ super() }} {% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", -"js/ship_assignment/collection_list.js" %} +"js/ship_assignment/collection.js", "js/ship_assignment/collection_list.js" %} {% endassets %} {% endblock %} {% block raw_content %} -
-
- - - +
+ +
+ + +
+
-
-
+
+ - - - - +
+
+ + - + +
+
+ + + +
+
+ + +
+
-
-
+
+ - - +
+ + +
+
{% endblock %} diff --git a/waitlist/blueprints/fittings.py b/waitlist/blueprints/fittings.py index de7528f9..923f68f4 100644 --- a/waitlist/blueprints/fittings.py +++ b/waitlist/blueprints/fittings.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Tuple from flask import json from flask.blueprints import Blueprint @@ -42,12 +42,27 @@ perm_comp_unlimited = perm_manager.get_permission('comphistory_unlimited') +def get_waitlist_entry_for_list(wl_id: int, creating_time: datetime, existing_entries: List[WaitlistEntry]) -> Tuple[bool, WaitlistEntry]: + """Gets the corsponding waitlist entry or creates a new one + The first entry of the tuple indicates if the entry was newly created + """ + for entry in existing_entries: + if entry.waitlist_id == wl_id: + return False, entry + entry = WaitlistEntry() + entry.creation = creating_time # for sorting entries + entry.user = entry.user # associate a user with the entry + entry.waitlist_id = wl_id + existing_entries.append(logi_entry) + db.session.add(entry) + return True, entry + @bp_waitlist.route("/move_to_waitlist", methods=["POST"]) @login_required @perm_fleet_manage.require(http_exception=401) def move_to_waitlists(): """ - Move a whole entry to a the corresponding waitlists + Move a whole entry to the corresponding waitlists """ # variables for SSE spawning @@ -75,23 +90,6 @@ def move_to_waitlists(): waitlist_entries = db.session.query(WaitlistEntry) \ .filter((WaitlistEntry.user == entry.user) & WaitlistEntry.waitlist_id.in_(waitlist_ids)).all() - logi_entry = None - sniper_entry = None - dps_entry = None - other_entry = None - if len(waitlist_entries) > 0: # there are actually existing entries - # if there are existing wl entries assign them to appropriate variables - for wl in waitlist_entries: - if wl.waitlist.name == WaitlistNames.logi: - logi_entry = wl - continue - if wl.waitlist.name == WaitlistNames.dps: - dps_entry = wl - continue - if wl.waitlist.name == WaitlistNames.sniper: - sniper_entry = wl - elif wl.waitlist.name == WaitlistNames.other: - other_entry = wl # find out what timestamp a possibly new entry should have # rules are: if no wl entry, take timestamp of x-up @@ -102,125 +100,28 @@ def move_to_waitlists(): if entry_t.creation < new_entry_timedate: new_entry_timedate = entry_t.creation - # sort fittings by ship type - logi = [] - dps = [] - sniper = [] - other = [] h_entry = create_history_object(entry.user, HistoryEntry.EVENT_COMP_MV_XUP_ETR, current_user.id) for fit in entry.fittings: if fit.id not in fit_ids: continue h_entry.fittings.append(fit) - fits_to_remove = [] + fit_list = [fit for fit in entry.fittings] - for fit in entry.fittings: - if fit.id not in fit_ids: - logger.info("Skipping %s because not in %s", fit, fit_ids) - continue - logger.info("Sorting fit %s by type into %s", str(fit), fit.wl_type) - - if fit.wl_type == WaitlistNames.logi: - logi.append(fit) - elif fit.wl_type == WaitlistNames.dps: - dps.append(fit) - elif fit.wl_type == WaitlistNames.sniper: - sniper.append(fit) - elif fit.wl_type == WaitlistNames.other: - other.append(fit) - else: - logger.error("Failed to add %s do a waitlist.", fit) - - fits_to_remove.append(fit) - - for fit in fits_to_remove: + for fit in fit_list: event = FitRemovedSSE(entry.waitlist.group.groupID, entry.waitlist.id, entry.id, fit.id, entry.user) _sseEvents.append(event) entry.fittings.remove(fit) - - # we have a logi fit but no logi wl entry, so create one - if len(logi) and logi_entry is None: - logi_entry = WaitlistEntry() - logi_entry.creation = new_entry_timedate # for sorting entries - logi_entry.user = entry.user # associate a user with the entry - group.logilist.entries.append(logi_entry) - _createdEntriesList.append(logi_entry) - - # same for dps - if len(dps) and dps_entry is None: - dps_entry = WaitlistEntry() - dps_entry.creation = new_entry_timedate # for sorting entries - dps_entry.user = entry.user # associate a user with the entry - group.dpslist.entries.append(dps_entry) - _createdEntriesList.append(dps_entry) - - # and sniper - if len(sniper) and sniper_entry is None: - sniper_entry = WaitlistEntry() - sniper_entry.creation = new_entry_timedate # for sorting entries - sniper_entry.user = entry.user # associate a user with the entry - group.sniperlist.entries.append(sniper_entry) - _createdEntriesList.append(sniper_entry) - - # and other if other exists - if len(other) and other_entry is None and group.otherlist is not None: - other_entry = WaitlistEntry() - other_entry.creation = new_entry_timedate # for sorting entries - other_entry.user = entry.user # associate a user with the entry - group.otherlist.entries.append(other_entry) - _createdEntriesList.append(other_entry) - - # iterate over sorted fits and add them to their entry - for logifit in logi: - logi_entry.fittings.append(logifit) - - if logi_entry not in _createdEntriesList: - for fit in logi: - event = FitAddedSSE(group.groupID, logi_entry.waitlist_id, logi_entry.id, fit, False, logi_entry.user) - _sseEvents.append(event) - - for dpsfit in dps: - dps_entry.fittings.append(dpsfit) - - if dps_entry not in _createdEntriesList: - for fit in dps: - event = FitAddedSSE(group.groupID, dps_entry.waitlist_id, dps_entry.id, fit, False, dps_entry.user) - _sseEvents.append(event) - - for sniperfit in sniper: - sniper_entry.fittings.append(sniperfit) - - if sniper_entry not in _createdEntriesList: - for fit in sniper: - event = FitAddedSSE(group.groupID, sniper_entry.waitlist_id, sniper_entry.id, fit, False, sniper_entry.user) + is_new, new_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, new_entry_timedate, waitlist_entries) + new_entry.fittings.append(fit) + # fits in a created entry will be sent out later a whole entry + if is_new: + _createdEntriesList.append(new_entry) + else: + event = FitAddedSSE(group.grouID, new_entry.waitlist_id, new_entry.id, fit, False, new_entry.user) _sseEvents.append(event) - # if there is no other list sort other fits in dps - if group.otherlist is not None: - for otherfit in other: - other_entry.fittings.append(otherfit) - if other_entry not in _createdEntriesList: - for fit in other: - event = FitAddedSSE(group.groupID, other_entry.waitlist_id, other_entry.id, - fit, False, other_entry.user) - _sseEvents.append(event) - else: - # it fits should go to dps wl make sure it is there - if len(other) > 0 and dps_entry is None: - dps_entry = WaitlistEntry() - dps_entry.creation = new_entry_timedate # for sorting entries - dps_entry.user = entry.user # associate a user with the entry - group.dpslist.entries.append(dps_entry) - _createdEntriesList.append(dps_entry) - for otherfit in other: - dps_entry.fittings.append(otherfit) - - if dps_entry not in _createdEntriesList: - for fit in other: - event = FitAddedSSE(group.groupID, dps_entry.waitlist_id, dps_entry.id, fit, False, dps_entry.user) - _sseEvents.append(event) # add history entry to db db.session.add(h_entry) @@ -264,19 +165,7 @@ def api_move_fit_to_waitlist(): logger.info("%s approved fit %s from %s", current_user.username, fit, entry.user_data.get_eve_name()) - # get the entry for the wl we need - waitlist = None - if fit.wl_type == WaitlistNames.logi: - waitlist = group.logilist - elif fit.wl_type == WaitlistNames.dps: - waitlist = group.dpslist - elif fit.wl_type == WaitlistNames.sniper: - waitlist = group.sniperlist - elif fit.wl_type == WaitlistNames.other: - if group.otherlist is not None: - waitlist = group.otherlist - else: - waitlist = group.dpslist + waitlist = fit.targetWaitlist waitlist_ids: List[int] = [] for wl in group.waitlists: @@ -298,13 +187,7 @@ def api_move_fit_to_waitlist(): if fit.waitlist is not None and wl_entry is not None and fit.waitlist.id == wl_entry.id: flask.abort(409, 'This fit was already moved') - new_entry = False - # if it doesn't exist create it - if wl_entry is None: - wl_entry = WaitlistEntry() - wl_entry.creation = creation_time - wl_entry.user = entry.user - new_entry = True + is_entry_new, wl_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, creation_time, [wl_entry] if wl_entry is not None else []) # remove fit from old entry event = FitRemovedSSE(entry.waitlist.group.groupID, entry.waitlist_id, entry.id, fit.id, entry.user) @@ -313,7 +196,7 @@ def api_move_fit_to_waitlist(): # add the fit to the entry wl_entry.fittings.append(fit) - if not new_entry: + if not is_entry_new: event = FitAddedSSE(wl_entry.waitlist.group.groupID, wl_entry.waitlist_id, wl_entry.id, fit, False, wl_entry.user) send_server_sent_event(event) @@ -322,7 +205,7 @@ def api_move_fit_to_waitlist(): h_entry = create_history_object(entry.user, HistoryEntry.EVENT_COMP_MV_XUP_FIT, current_user.id, [fit]) db.session.add(h_entry) - if new_entry: + if is_entry_new: waitlist.entries.append(wl_entry) db.session.commit() @@ -332,7 +215,7 @@ def api_move_fit_to_waitlist(): db.session.commit() send_server_sent_event(event) - if new_entry: + if is_entry_new: event = EntryAddedSSE(wl_entry, wl_entry.waitlist.group.groupID, wl_entry.waitlist_id, False) send_server_sent_event(event) diff --git a/waitlist/blueprints/settings/ship_assignment.py b/waitlist/blueprints/settings/ship_assignment.py index ef25737e..3d68dda2 100644 --- a/waitlist/blueprints/settings/ship_assignment.py +++ b/waitlist/blueprints/settings/ship_assignment.py @@ -1,12 +1,17 @@ import logging +from typing import Any +from decimal import Decimal import flask -from flask import Blueprint, Response, render_template +from flask import Blueprint, Response, render_template, request,\ + url_for, redirect from flask_babel import gettext, lazy_gettext from flask_login import login_required, current_user from waitlist.base import db from waitlist.permissions import perm_manager -from waitlist.storage.database import ShipCheckCollection, WaitlistGroup +from waitlist.storage.database import ShipCheckCollection, WaitlistGroup, ShipCheck,\ + InvType, InvGroup, MarketGroup from waitlist.blueprints.settings import add_menu_entry +from waitlist.utility.constants import check_types bp = Blueprint('ship_assignment', __name__) logger = logging.getLogger(__name__) @@ -30,17 +35,51 @@ def ship_assignments(): @login_required @perm_manager.require('ship_assignment_edit') def collection_edit() -> Response: - cid: int = int(request.form['collection_id']) + cid: int = int(request.args.get('collection_id')) coll: ShipCheckCollection = db.session.query(ShipCheckCollection).get(cid) - return render_template('settings/ship_assignment/collection_edit.html', coll=coll) + groups: WaitlistGroup = db.session.query(WaitlistGroup).all() + return render_template('settings/ship_assignment/collection_edit.html', coll=coll, groups=groups, check_type_map=check_types.CHECK_NAME_MAP) +@bp.route('/col//change', methods=['POST']) +@login_required +@perm_manager.require('ship_assignment_edit') +def collection_change(coll_id: int) -> Response: + coll_name = request.form['coll_name'] + group_id = request.form['group_id'] + target_id = request.form['target_id'] + tag = request.form['tag'] + collection: ShipCheckCollection = db.session.query(ShipCheckCollection).get(coll_id) + if collection is None: + flask.flash('Invalid Collection ID provided', 'danger') + return redirect(url_for('.ship_assignments')) + + collection.checkCollectionName = coll_name + collection.waitlistGroupID = group_id + collection.defaultTargetID = target_id + collection.defaultTag = tag + db.session.commit() + flask.flash('Collection was updated', 'success') + return redirect(url_for('.collection_edit', collection_id=coll_id)) + @bp.route('/col/add', methods=['POST']) @login_required @perm_manager.require('ship_assignment_edit') def collection_add(): - # TODO: Add the collection from data of post + name: str = request.form['name'] + wl_group_id = int(request.form['group_id']) + def_target_id = int(request.form['target_id']) + tag = request.form['tag'] + + collection = ShipCheckCollection( + checkCollectionName=name, + waitlistGroupID=wl_group_id, + defaultTargetID=def_target_id, + defaultTag=tag + ) + db.session.add(collection) + db.session.commit() return redirect(url_for('.ship_assignments')) @@ -49,13 +88,144 @@ def collection_add(): @perm_manager.require('ship_assignment_edit') def collection_remove(): cid: int = request.form['collection_id'] - db.session.query(ShipCheckCollection).get(cid).delete() + db.session.query(ShipCheckCollection).filter(ShipCheckCollection.checkCollectionID == cid).delete() + db.session.commit() return redirect(url_for('.ship_assignments')) -@bp.route('/col/add_check') + +def get_id_type(check_type: int) -> Any: + type_mapping: Dict[int, Any] = { + check_types.SHIP_CHECK_TYPEID: InvType, + check_types.SHIP_CHECK_INVGROUP: InvGroup, + check_types.SHIP_CHECK_MARKETGROUP: MarketGroup, + check_types.MODULE_CHECK_TYPEID: InvType, + check_types.MODULE_CHECK_MARKETGROUP: MarketGroup + } + return type_mapping[check_type] + + +@bp.route('/col//checks', methods=['POST']) @login_required @perm_manager.require('ship_assignment_edit') -def add_checks(): - return render_template('settings/ship_assignment/check') +def check_add(coll_id: int) -> Response: + collection: ShipCheckCollection = db.session.query(ShipCheckCollection).get(coll_id) + name: str = request.form['check_name'] + check_id: int = int(request.form['check_type'], 10) + target: int = int(request.form['check_target'], 10) + order: int = int(request.form['order'], 10) + modifier: Decimal = Decimal(request.form['modifier']) + check_ids = [int(check_id.strip()) for check_id in request.form['ids'].split(',')] + tag = request.form['tag'] + + check: ShipCheck = ShipCheck( + checkName=name, + collectionID=coll_id, + checkTargetID=target, + checkType=check_id, + order=order, + modifier=modifier, + checkTag=tag + ) + + target_type = get_id_type(check_id) + + for obj_id in check_ids: + obj = db.session.query(target_type).get(obj_id) + check.ids.append(obj) + + # we only have restrictions for specific types of checks + if check_id in [check_types.MODULE_CHECK_MARKETGROUP, check_types.MODULE_CHECK_TYPEID]: + rest_typeids = [int(i.strip()) for i in request.form['rest_typeids'].split(',')] + rest_invgroupids = [int(i.strip()) for i in request.form['rest_invgroupids'].split(',')] + rest_mgroupids = [int(i.strip()) for i in request.form['rest_mgroupids'].split(',')] + + for type_id in rest_typeids: + invtype = db.session.query(InvType).get(type_id) + check.check_rest_types.append(invtype) + for group_id in rest_invgroupids: + check.check_rest_groups.append( + db.session.query(InvGroup).get(group_id) + ) + for mgroup_id in rest_mgroupids: + check.check_rest_market_groups.append( + db.session.query(MarketGroup).get(mgroup_id) + ) + + + db.session.add(check) + db.session.commit() + + return redirect(url_for('.collection_edit', collection_id=coll_id)) + + +@bp.route('/check//edit', methods=['GET']) +@login_required +@perm_manager.require('ship_assignment_edit') +def check_edit(check_id:int) -> Response: + check: ShipCheck = db.session.query(ShipCheck).get(check_id) + return render_template('settings/ship_assignment/check_edit.html', check=check, + check_type_map=check_types.CHECK_NAME_MAP, + waitlists=check.collection.waitlistGroup.waitlists) + + + +@bp.route('/check//', methods=['POST']) +@login_required +@perm_manager.require('ship_assignment_edit') +def check_change(check_id:int) -> Response: + name: str = request.form['check_name'] + order: int = int(request.form['order']) + target_id: int = int(request.form['check_target']) + check_modifier: Decimal = Decimal(request.form['modifier']) + check_type: int = int(request.form['check_type']) + check_ids = [int(check_id.strip()) for check_id in request.form['ids'].split(',')] + tag = request.form['tag'] + + check: ShipCheck = db.session.query(ShipCheck).get(check_id) + # clear old items + # this needs to be done before changing the type + # because otherwise we delete from the wrong relationship + check.ids=[] + + + check.order = order + check.checkTargetID = target_id + check.checkType = check_type + check.checkName = name + check.modifier = check_modifier + check.tag = tag + # add new items + # this needs to be done after changing the type + # because otherwise we add to the wrong relationship + target_type = get_id_type(check_type) + for obj_id in check_ids: + obj = db.session.query(target_type).get(obj_id) + check.ids.append(obj) + + # we only have restrictions for specific types of checks + if check_type in [check_types.MODULE_CHECK_MARKETGROUP, check_types.MODULE_CHECK_TYPEID]: + logger.debug("Adding restrictions to check") + rest_typeids = [int(i.strip()) for i in request.form['rest_typeids'].split(',') if i.strip()] + rest_invgroupids = [int(i.strip()) for i in request.form['rest_invgroupids'].split(',') if i.strip()] + rest_mgroupids = [int(i.strip()) for i in request.form['rest_mgroupids'].split(',') if i.strip()] + logger.debug("types: %r invgroups: %r mgroups: %r", rest_typeids, rest_invgroupids, rest_mgroupids) + check.check_rest_types = [] + check.check_rest_groups = [] + check.check_rest_market_groups = [] + for type_id in rest_typeids: + invtype = db.session.query(InvType).get(type_id) + check.check_rest_types.append(invtype) + for group_id in rest_invgroupids: + check.check_rest_groups.append( + db.session.query(InvGroup).get(group_id) + ) + for mgroup_id in rest_mgroupids: + check.check_rest_market_groups.append( + db.session.query(MarketGroup).get(mgroup_id) + ) + + db.session.commit() + return redirect(url_for('.collection_edit', collection_id=check.collection.checkCollectionID)) + add_menu_entry('ship_assignment.ship_assignments', lazy_gettext('Ship Classification'), perm_manager.get_permission('ship_assignment_edit').can) diff --git a/waitlist/blueprints/xup/submission.py b/waitlist/blueprints/xup/submission.py index a61eeda9..068093f5 100644 --- a/waitlist/blueprints/xup/submission.py +++ b/waitlist/blueprints/xup/submission.py @@ -11,13 +11,10 @@ FitAddedSSE from waitlist.storage.database import WaitlistGroup, WaitlistEntry, Shipfit,\ InvType, FitModule, MarketGroup, HistoryEntry -from waitlist.storage.modules import resist_ships, logi_ships, sniper_ships,\ - sniper_weapons, dps_weapons, weapongroups, dps_ships, t3c_ships +from waitlist.storage.modules import resist_ships, logi_ships from waitlist.utility.history_utils import create_history_object from waitlist.utility.fitting_utils import get_fit_format, parse_dna_fitting,\ - parse_eft, is_logi_hull, is_allowed_hull, is_dps_by_group,\ - is_sniper_by_group, get_weapon_type_by_typeid, get_waitlist_type_by_ship_typeid,\ - get_waitlist_type_for_fit + parse_eft, get_waitlist_type_for_fit from waitlist.base import db from . import bp from flask_babel import gettext, ngettext @@ -240,76 +237,17 @@ def submit(): eve_id = current_user.get_eve_id() - # query to check if sth is a weapon module - ''' - SELECT count(1) FROM invtypes - JOIN invmarketgroups AS weapongroup ON invtypes.marketGroupID = weapongroup.marketGroupID - JOIN invmarketgroups AS wcat ON weapongroup.parentGroupID = wcat.marketGroupID - JOIN invmarketgroups AS mcat ON wcat.parentGroupID = mcat.marketGroupID - WHERE invtypes.typeName = ? AND mcat.parentGroupID = 10;/*10 == Turrets & Bays*/ - ''' - fits_ready = [] # split his fits into types for the different waitlist_entries for fit in fits: - wl_type = get_waitlist_type_for_fit(fit, group_id) - fit.wl_type = wl_type + tag, waitlist_id = get_waitlist_type_for_fit(fit, group_id) + fit.wl_type = tag + fit.targetWaitlistID = waitlist_id fits_ready.append(fit) - """ - mod_list: List[Dict[int, Tuple(int, int)]] - try: - mod_list = parse_dna_fitting(fit.modules) - except ValueError: - abort(400, "Invalid module amounts") - # check that ship is an allowed ship - - # it is a logi put on logi wl - if is_logi_hull(fit.ship_type): - fit.wl_type = WaitlistNames.logi - fits_ready.append(fit) - continue - - is_allowed = is_allowed_hull(fit.ship_type) - - if not is_allowed: # not an allowed ship, push it on other list :P - fit.wl_type = WaitlistNames.other - fits_ready.append(fit) - continue - - possible_weapon_types = dict() - # lets collect all weapons, no matter the amount - # then categorize them - # and choose the category with the most weapons - - high_slot_mod_map = mod_list[location_flags.HIGH_SLOT] - for mod in high_slot_mod_map: - weapon_type = get_weapon_type_by_typeid(mod) - if (weapon_type is not None): - if weapon_type not in possible_weapon_types: - possible_weapon_types[weapon_type] = 0 - - possible_weapon_types[weapon_type] += high_slot_mod_map[mod][1] - - weapon_type = max(possible_weapon_types.items(), key=operator.itemgetter(1), default=(None, None))[0] - if weapon_type is None: - weapon_type = get_waitlist_type_by_ship_typeid(fit.ship_type) - - if weapon_type is None: - fit.wl_type = WaitlistNames.other - fits_ready.append(fit) - continue - else: - fit.wl_type = weapon_type - fits_ready.append(fit) - continue - """ - """ - #this stuff is needed somewhere else now # get the waitlist entries of this user - """ queue = group.xuplist wl_entry = db.session.query(WaitlistEntry).filter( (WaitlistEntry.waitlist_id == queue.id) & (WaitlistEntry.user == eve_id)).first() diff --git a/waitlist/storage/database.py b/waitlist/storage/database.py index 6e037d5b..87e9d82f 100644 --- a/waitlist/storage/database.py +++ b/waitlist/storage/database.py @@ -12,6 +12,7 @@ from waitlist.base import db from waitlist.utility import config +from waitlist.utility.constants import check_types from waitlist.utility.utils import get_random_token from sqlalchemy.types import UnicodeText import json @@ -796,7 +797,7 @@ class Waitlist(Base): groupID = Column('group_id', Integer, ForeignKey("waitlist_groups.group_id"),) displayTitle = Column('display_title', String(100), nullable=False, default="") entries = relationship("WaitlistEntry", back_populates="waitlist", order_by="asc(WaitlistEntry.creation)") - group = relationship("WaitlistGroup", back_populates="waitlists") + group = relationship("WaitlistGroup", foreign_keys=[groupID],back_populates="waitlists") def __repr__(self): return "" % self.name @@ -829,8 +830,10 @@ class WaitlistGroup(Base): constellationID = Column('constellation_id', Integer, ForeignKey(Constellation.constellationID), nullable=True) ordering = Column('ordering', Integer, nullable=False, default=0) influence = Column('influence', Boolean(name='influence'), nullable=False, server_default='0', default=False) + queueID = Column('queueID', Integer, ForeignKey(Waitlist.id), nullable=False) - waitlists = relationship(Waitlist, back_populates="group") + waitlists = relationship(Waitlist, primaryjoin=groupID == Waitlist.groupID, remote_side=Waitlist.groupID, foreign_keys=Waitlist.groupID, back_populates="group") + queue = relationship(Waitlist, foreign_keys=[queueID], uselist=False) def has_wl_of_type(self, wl_type: str): for wl in self.waitlists: @@ -851,11 +854,11 @@ def set_wl_to_type(self, wl: Waitlist, wl_type: str): @property def xuplist(self): - return self.get_wl_for_type('xup') + return self.queue @xuplist.setter def xuplist(self, value: Waitlist): - self.set_wl_to_type(value, 'xup') + self.queue = value @property def logilist(self): @@ -909,21 +912,28 @@ class Shipfit(Base): onupdate='CASCADE')) modules = Column('modules', String(5000)) comment = Column('comment', String(5000)) - wl_type = Column('wl_type', String(10)) + wl_type = Column('wl_type', String(20)) created = Column('created', DateTime, default=datetime.utcnow) + targetWaitlistID = Column('target_waitlist', + ForeignKey('waitlists.id', + ondelete='CASCADE', + onupdate='CASCADE') + ) ship = relationship("InvType") waitlist = relationship("WaitlistEntry", secondary="waitlist_entry_fits", uselist=False) - + # this saves which waitlist we should go to after being approved + targetWaitlist = relationship('Waitlist', uselist=False) moduleslist = relationship("FitModule", back_populates="fit") def get_dna(self): return "{0}:{1}".format(self.ship_type, self.modules) def __repr__(self): - return "".format(self.id, self.ship_type, - self.modules, self.comment, - self.waitlist.id) + return "".\ + format(self.id, self.ship_type, + self.modules, self.comment, + self.waitlist.id if self.waitlist is not None else -1) class WaitlistEntryFit(Base): @@ -1349,9 +1359,11 @@ class ShipCheckCollection(Base): ondelete='CASCADE', onupdate='CASCADE') ) + defaultTag: Column = Column('default_tag', String(20)) checks = relationship('ShipCheck', back_populates='collection', order_by='asc(ShipCheck.order)') defaultTarget: Waitlist = relationship('Waitlist') + waitlistGroup: WaitlistGroup = relationship('WaitlistGroup') ship_check_invtypes = Table('ship_check_invtypes', Base.metadata, @@ -1388,21 +1400,82 @@ class ShipCheckCollection(Base): ) +ship_check_rest_invtypes = Table('ship_check_rest_invtypes', + Base.metadata, + Column('check_id', Integer, + ForeignKey('ship_check.check_id', + onupdate="CASCADE", ondelete="CASCADE")), + Column('type_id', Integer, + ForeignKey('invtypes.type_id', + onupdate="CASCADE", ondelete="CASCADE")) + ) + + +ship_check_rest_groups = Table( + 'ship_check_rest_groups', + Base.metadata, + Column('check_id', Integer, + ForeignKey('ship_check.check_id', + onupdate='CASCADE', ondelete='CASCADE')), + Column('group_id', Integer, + ForeignKey('invgroup.group_id', + onupdate='CASCADE', ondelete='CASCADE')) +) + + +ship_check_rest_marketgroups = Table( + 'ship_check_rest_marketgroups', + Base.metadata, + Column('check_id', Integer, + ForeignKey('ship_check.check_id', + onupdate='CASCADE', ondelete='CASCADE')), + Column('market_group_id', Integer, + ForeignKey('invmarketgroups.market_group_id', + onupdate='CASCADE', ondelete='CASCADE')) +) + + class ShipCheck(Base): __tablename__: str = 'ship_check' checkID: Column = Column('check_id', Integer, primary_key=True) + checkName: Column = Column('check_name', String(100)) collectionID: Column = Column( 'collection_id', Integer, ForeignKey('ship_check_collection.collection_id', - ondelete='SET NULL', onupdate='CASCADE'), nullable=True) - checkTarget = Column('check_target', String(20)) + ondelete='CASCADE', onupdate='CASCADE'), nullable=True) + checkTargetID = Column('check_target_id', Integer, ForeignKey('waitlists.id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False) checkType: Column = Column('check_type', Integer) order: Column = Column('order', Integer) modifier: Column = Column('modifier', Numeric(precision=5, scale=2), nullable=True) + checkTag: Column = Column('tag', String(20)) collection = relationship('ShipCheckCollection', back_populates='checks') check_types = relationship('InvType', secondary='ship_check_invtypes', lazy='dynamic') check_groups = relationship('InvGroup', secondary='ship_check_groups', lazy='dynamic') check_market_groups = relationship('MarketGroup', secondary='ship_check_marketgroups', lazy='dynamic') + checkTarget = relationship('Waitlist') + + check_rest_types = relationship('InvType', secondary='ship_check_rest_invtypes') + check_rest_groups = relationship('InvGroup', secondary='ship_check_rest_groups') + check_rest_market_groups = relationship('MarketGroup', secondary='ship_check_rest_marketgroups') + + @property + def ids(self): + if self.checkType in [check_types.MODULE_CHECK_TYPEID, check_types.SHIP_CHECK_TYPEID]: + return self.check_types + if self.checkType in [check_types.MODULE_CHECK_MARKETGROUP, check_types.SHIP_CHECK_MARKETGROUP]: + return self.check_market_groups + if self.checkType == check_types.SHIP_CHECK_INVGROUP: + return self.check_groups + return None + + @ids.setter + def ids(self, value): + if self.checkType in [check_types.MODULE_CHECK_TYPEID, check_types.SHIP_CHECK_TYPEID]: + self.check_types = value + if self.checkType in [check_types.MODULE_CHECK_MARKETGROUP, check_types.SHIP_CHECK_MARKETGROUP]: + self.check_market_groups = value + if self.checkType == check_types.SHIP_CHECK_INVGROUP: + self.check_groups = value diff --git a/waitlist/storage/modules.py b/waitlist/storage/modules.py index e0ac58e1..91f8e31b 100644 --- a/waitlist/storage/modules.py +++ b/waitlist/storage/modules.py @@ -39,6 +39,6 @@ none_logi_ships.update(resist_ships) none_logi_ships.update(t3c_ships) -weapongroups = {'dps': {"Pulse Lasers": None, "Blasters": None, "Missile Launchers": None, "Autocannons": None, 'Entropic Disintegrators': None}, - 'sniper': {"Beam Lasers": None, "Railguns": None, "Artillery Cannons": None} +weapongroups = {'dps': {"Pulse Lasers": 558, "Blasters": 556, "Missile Launchers": 140, "Autocannons": 559, 'Entropic Disintegrators': 2432}, + 'sniper': {"Beam Lasers": 557, "Railguns": 555, "Artillery Cannons": 560} } diff --git a/waitlist/utility/constants/check_types.py b/waitlist/utility/constants/check_types.py new file mode 100644 index 00000000..bb31a592 --- /dev/null +++ b/waitlist/utility/constants/check_types.py @@ -0,0 +1,16 @@ +from flask_babel import lazy_gettext + +SHIP_CHECK_TYPEID = 1 +SHIP_CHECK_INVGROUP = 2 +SHIP_CHECK_MARKETGROUP = 3 +MODULE_CHECK_TYPEID = 4 +MODULE_CHECK_MARKETGROUP = 5 + +CHECK_NAME_MAP = { + SHIP_CHECK_TYPEID: lazy_gettext('Hull by TypeId'), + SHIP_CHECK_INVGROUP: lazy_gettext('Hull by Inventory Group'), + SHIP_CHECK_MARKETGROUP: lazy_gettext('Hull by Market Group'), + MODULE_CHECK_TYPEID: lazy_gettext('Module by TypeId'), + MODULE_CHECK_MARKETGROUP: lazy_gettext('Module by Market Group') +} + diff --git a/waitlist/utility/fitting_utils.py b/waitlist/utility/fitting_utils.py index 287a6547..478dd8df 100644 --- a/waitlist/utility/fitting_utils.py +++ b/waitlist/utility/fitting_utils.py @@ -1,16 +1,15 @@ import operator +from decimal import Decimal from sqlalchemy import literal -from waitlist.utility.constants import location_flags, effects -from typing import List, Dict, Optional +from waitlist.utility.constants import location_flags, effects, check_types +from typing import List, Dict, Optional, Tuple, AbstractSet from waitlist.storage.database import InvType, Shipfit, FitModule,\ - MarketGroup, ShipCheckCollection, ShipCheck + MarketGroup, ShipCheckCollection, ShipCheck, Waitlist, InvGroup from waitlist.base import db from waitlist.data.names import WaitlistNames import logging import re from waitlist.utility.eve_id_utils import get_item_id -from waitlist.storage.modules import logi_ships, logi_groups, none_logi_ships,\ - dps_groups, sniper_groups, sniper_weapons, dps_weapons, weapongroups logger = logging.getLogger(__name__) @@ -281,93 +280,11 @@ def get_fit_format(line): return "dna" -def is_logi_hull(type_id: int): - if type_id in logi_ships: - return True - inv_type: InvType = db.session.query(InvType).get(type_id) - if inv_type.groupID in logi_groups and type_id not in none_logi_ships: - return True - return False - - -def is_allowed_hull(type_id: int): - if type_id in none_logi_ships or type_id in logi_ships: - return True - inv_type: InvType = db.session.query(InvType).get(type_id) - if inv_type.groupID in logi_groups or ( - inv_type.groupID in dps_groups) or ( - inv_type.groupID in sniper_groups): - return True - return False - - -def is_dps_by_group(type_id: int): - inv_type: InvType = db.session.query(InvType).get(type_id) - if inv_type.groupID in dps_groups: - return True - return False - - -def is_sniper_by_group(type_id: int): - inv_type: InvType = db.session.query(InvType).get(type_id) - if inv_type.groupID in sniper_groups: - return True - return False - -def get_weapon_type_by_typeid(type_id: int): - """Get the weapon_type for the given type_id - Returns: WaitlistNames.dps, WaitlistNames.sniper, WaitlistNames.logi or None +def get_waitlist_type_for_ship_type(checks: List[ShipCheck], ship_type_id: int) -> Optional[Tuple[str, int]]: + """ Get a tag, waitlist id tuple or None if no check applies """ - inv_type: InvType = db.session.query(InvType).get(type_id) - if inv_type is None: - logger.debug('TypeId = %d does not exist', type_id) - return None - - if inv_type.group.groupName == 'Precursor Weapon': - return WaitlistNames.dps - if type_id in sniper_weapons: - return WaitlistNames.sniper - - if type_id in dps_weapons: - return WaitlistNames.dps - - if inv_type.group.groupName in ['Remote Shield Booster', - 'Remote Armor Repairer']: - return WaitlistNames.logi - - # try to decide by market group - market_group = db.session.query(MarketGroup).get( - inv_type.marketGroupID) - if market_group is not None: - parent_group = db.session.query(MarketGroup).get( - market_group.parentGroupID) - if parent_group is not None: - # we have a parent market group - if parent_group.marketGroupName in weapongroups['dps']: - return WaitlistNames.dps - if parent_group.marketGroupName in weapongroups['sniper']: - return WaitlistNames.sniper - - return None - -def get_waitlist_type_by_ship_typeid(type_id: int): - """Get the waitlist type by ship type id - returns WaitlistNames.dps, WaitlistNames.sniper or None - """ - # ships with no valid weapons put on other wl - if is_dps_by_group(type_id): - return WaitlistNames.dps - elif is_sniper_by_group(type_id): - return WaitlistNames.sniper - return None - -SHIP_CHECK_TYPEID = 1 -SHIP_CHECK_INVGROUP = 2 -SHIP_CHECK_MARKETGROUP = 3 -MODULE_CHECK_TYPEID = 4 -MODULE_CHECK_MARKETGROUP = 5 + logger.debug('Got ship_type %d', ship_type_id) -def get_waitlist_type_for_ship_type(check_collection: ShipCheckCollection, ship_type_id: int) -> Optional[str]: ship_type: InvType = db.session.query(InvType).get(ship_type_id) # collect market groups market_group_ids = [] @@ -375,73 +292,173 @@ def get_waitlist_type_for_ship_type(check_collection: ShipCheckCollection, ship_ while m_group is not None: market_group_ids.append(m_group.marketGroupID) m_group = m_group.parent + logger.debug('Found marketgroups: %r', market_group_ids) - for check in check_collection.checks: - if check.checkType == SHIP_CHECK_TYPEID: + for check in checks: + logger.debug('Doing Check %s of type %d', check.checkName, check.checkType) + if check.checkType == check_types.SHIP_CHECK_TYPEID: if db.session.query(check.check_types.filter(InvType.typeID == ship_type.typeID).exists()).scalar(): - return check.checkTarget - elif check.checkType == SHIP_CHECK_INVGROUP: + return check.checkTag, check.checkTargetID + elif check.checkType == check_types.SHIP_CHECK_INVGROUP: if db.session.query(check.check_groups.filter(InvGroup.groupID == ship_type.groupID).exists()).scalar(): - return check.checkTarget - elif check.checkType == SHIP_CHECK_MARKETGROUP: + return check.checkTag, check.checkTargetID + elif check.checkType == check_types.SHIP_CHECK_MARKETGROUP: if db.session.query(check.check_market_groups.filter(MarketGroup.marketGroupID.in_(market_group_ids)).exists()).scalar(): - return check.checkTarget - + return check.checkTag, check.checkTargetID + logger.debug('No match found for ship_type') return None - -def get_waitlist_type_for_modules(check_collection: ShipCheckCollection, fit: Shipfit) -> Optional[str]: +def get_market_groups(inv_type: InvType) -> List[int]: + group_ids: List[int] = [] + m_group: MarketGroup = inv_type.market_group + while m_group is not None: + group_ids.append(m_group.marketGroupID) + m_group = m_group.parent + return group_ids + + +def does_check_apply(check: ShipCheck, ship_type_id: int) -> bool: + invtype: InvType = db.session.query(InvType).get(ship_type_id) + has_restriction = False + if len(check.check_rest_types) > 0: + has_restriction = True + for itype in check.check_rest_types: + if itype.typeID == ship_type_id: + return True + if len(check.check_rest_groups) > 0: + has_restriction = True + for igroup in checks.check_rest_groups: + if igroup.groupID == invtype.groupID: + return True + market_groups = get_market_groups(invtype) + if len(check.check_rest_market_groups) > 0: + has_restriction = True + for mgroup in checks.check_rest_market_groups: + if mgroup.marketGroupID in market_groups: + return True + + return not has_restriction + +def get_waitlist_type_for_modules(checks: List[ShipCheck], fit: Shipfit) -> Optional[Tuple[int, Tuple[Decimal, AbstractSet[str]]]]: + """Get a tuple of module type id, amount, set of tags for the module with the highest value + Or None if no check applied + """ + logger.debug('Doing modules check with checks %r', checks) mod_list: List[Dict[int, Tuple(int, int)]] = parse_dna_fitting(fit.modules) - mod_ids = [mod_id in mod_list[location_flags.HIGH_SLOT]] + high_slot_modules = mod_list[location_flags.HIGH_SLOT] + logger.debug('Module list %r', mod_list) + mod_ids = [mod_id for mod_id in high_slot_modules] + logger.debug('Moudle ids: %r', mod_ids) # prepare marketgroup list for every module, we need it later on market_groups = dict() - for mod_id in mod_list[HIGH_SLOT]: - if mod_id not in market_group: + for mod_id in mod_ids: + if mod_id not in market_groups: invtype: InvType = db.session.query(InvType).get(mod_id) - m_group: MarketGroup = invtype.market_group - while m_group is not None: - market_groups[mod_id].append(m_group.marketGroupID) - m_group = m_group.parent + market_groups[mod_id] = get_market_groups(invtype) + logger.debug('Market groups: %r', market_groups) # for modules we need to hit every module once or never - result_count_map = dict() - for check in check_collection: - if check.checkType not in result_count_map: - result_count_map[check.checkType] = 0 - modifier = 1 if check.modifier is None else check.modifier - if check.checkType == MODULE_CHECK_TYPEID: + # never only if there is no rule for it! + # so after getting a rule hit on a module, remove the module + result_count_map: Dict[int, Tuple(Decimal, Set[str])] = dict() + for check in checks: + # lets see if this check applies to this ship + if not does_check_apply(check, fit.ship_type): + continue + + logger.debug('Doing check %s with type %d and target %s and mods %r', check.checkName, check.checkType, check.checkTarget.waitlistType, mod_ids) + if check.checkTargetID not in result_count_map: + result_count_map[check.checkTargetID] = (Decimal("0.00"), set()) + modifier = Decimal("1.00") if check.modifier is None else check.modifier + if check.checkType == check_types.MODULE_CHECK_TYPEID: remaining_mods = [] type_ids = {type_obj.typeID for type_obj in check.check_types} + logger.debug('Matching TypeIDs: %r', type_ids) for mod_id in mod_ids: if mod_id in type_ids: - result_count_map[check.checkType] += modifier + logger.debug('Match found for %d', mod_id) + result_count_map[check.checkTargetID][0] += Decimal(high_slot_modules[mod_id][1]) * modifier + result_count_map[check.checkTargetID][1].add(check.checkTag) else: remaining_mods.append(mod_id) mod_ids = remaining_mods - elif check.checkType == MODULE_CHECK_MARKETGROUP: + elif check.checkType == check_types.MODULE_CHECK_MARKETGROUP: remaining_mods = [] group_ids = {group_obj.marketGroupID for group_obj in check.check_market_groups} + logger.debug('Market Groups for check: %r', group_ids) for mod_id in mod_ids: mgs_for_mod = set(market_groups[mod_id]) - if mgs_for_mod.intersection(group_ids) > 0: - result_count_map[check.checkType] += modifier + logger.debug('MarketGroups for Mod %d are %r', mod_id, mgs_for_mod) + if len(mgs_for_mod.intersection(group_ids)) > 0: + result_count_map[check.checkTargetID][0] += Decimal(high_slot_modules[mod_id][1]) * modifier + result_count_map[check.checkTargetID][1].add(check.checkTag) else: remaining_mods.append(mod_id) mod_ids = remaining_mods + logger.debug('Result Map: %r', result_count_map) + return max(result_count_map.items(), key=lambda tpl: tpl[1][0], default=None) - return max(result_count_map.items(), key=operator.itemgetter(1), default=(None, None))[0] - - -def get_waitlist_type_for_fit(fit: Shipfit, waitlist_group_id: int) -> str: +def get_waitlist_type_for_fit(fit: Shipfit, waitlist_group_id: int) -> Tuple[str, int]: + """Get a tag, waitlist_id tuple for this fit + """ # modlist[SLOT_INDEX][TYPE_ID][TYPE_ID][AMOUNT] + logger.debug('Check fit %r against rules for group %d', fit, waitlist_group_id) check_collection: ShipCheckCollection = db.session.query(ShipCheckCollection).filter( ShipCheckCollection.waitlistGroupID == waitlist_group_id ).one() - ship_wl_type = get_waitlist_type_for_ship_type(check_collection, fit.ship_type) - if ship_wl_type is None: - ship_wl_type = get_waitlist_type_for_modules(check_collection, fit) - if ship_wl_type is None: - return check_collection.defaultTarget.id - return ship_wl_type + """ + This should work by: + * Checks with same priority for modules are done in 1 go + * For Ship Type and Module checks with same priority the module check is done before the shiptype + """ + # we build a list of checks to execute + # List[Tuple[module_checks, ship_checks]] + checks_list: List[Tuple[List[ShipCheck], List[ShipCheck]]] = [] + current_order = None + module_checks = None + ship_type_checks = None + for check in check_collection.checks: + if current_order is None: + current_order = check.order + module_checks = [] + ship_type_checks = [] + elif current_order < check.order: + current_order = check.order + checks_list.append(( + module_checks, + ship_type_checks + )) + + if check.checkType in [check_types.MODULE_CHECK_MARKETGROUP, check_types.MODULE_CHECK_TYPEID]: + module_checks.append(check) + elif check.checkType in [check_types.SHIP_CHECK_INVGROUP, check_types.SHIP_CHECK_TYPEID, check_types.SHIP_CHECK_MARKETGROUP]: + ship_type_checks.append(check) + + # add the lowest priorty checks those do not get added by the for loop + checks_list.append((module_checks, ship_type_checks)) + + logger.debug("Check Structure: %r", checks_list) + + ship_wl_id = None + tag = None + for check_tuple in checks_list: + module_data: Optional[Tuple[int, Tuple[Decimal, AbstractSet[str]]]] = get_waitlist_type_for_modules(check_tuple[0], fit) + if module_data is not None and module_data[1][0] >= Decimal("4.00"): + ship_wl_id = module_data[0] + if len(module_data[1][1]) > 0: + tag = module_data[1][1][0] + break + ship_data = get_waitlist_type_for_ship_type(check_tuple[1], fit.ship_type) + if ship_data is not None: + tag = ship_data[0] + ship_wl_id = ship_data[1] + break + + if ship_wl_id is None: + ship_wl_id = check_collection.defaultTarget.id + if tag is None: + tag = check_collection.defaultTag + + return tag, ship_wl_id diff --git a/waitlist/utility/jinja2/__init__.py b/waitlist/utility/jinja2/__init__.py index 65576f60..574811c6 100644 --- a/waitlist/utility/jinja2/__init__.py +++ b/waitlist/utility/jinja2/__init__.py @@ -1,5 +1,7 @@ from datetime import datetime +from sqlalchemy.inspection import inspect + from flask import request from flask_login import current_user from typing import Callable, Dict, Any @@ -12,7 +14,6 @@ from waitlist.utility.i18n.locale import get_locale, get_langcode_from_locale from waitlist.utility.mainmenu import main_nav - def eve_image(browser_webp: bool) -> Callable[[str, str], str]: if browser_webp and cdn_eveimg_webp: def _eve_image(path: str, _: str) -> str: @@ -44,3 +45,8 @@ def inject_data() -> Dict[str, Any]: title=title, lang_code=get_langcode_from_locale(get_locale(app)), main_nav=main_nav ) + +def get_pk(obj): + return inspect(obj).identity + +app.jinja_env.globals.update(get_pk=get_pk) From ac95302a39cf09d2fbb9f2a687f95142db9f70bd Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 19:07:52 +0200 Subject: [PATCH 06/22] added script to convert info in modules.py to new rules --- setup_shipclassifications.py | 262 +++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 setup_shipclassifications.py diff --git a/setup_shipclassifications.py b/setup_shipclassifications.py new file mode 100644 index 00000000..8fba1c62 --- /dev/null +++ b/setup_shipclassifications.py @@ -0,0 +1,262 @@ +import logging +from decimal import Decimal +from typing import Optional, List, Tuple +from waitlist.storage.database import Waitlist, ShipCheckCollection, ShipCheck,\ + InvType, InvGroup, MarketGroup, WaitlistGroup +from waitlist.base import db +from waitlist.storage import modules +from waitlist.utility.constants import check_types + + + +def add_default_sorting(collection: ShipCheckCollection, logi_wl, dps_wl, sniper_wl): + + # how old WTM sorting worked was to first sort out T2 logi ships :> + check = ShipCheck( + checkName = 'SortOutLogiHulls', + checkTargetID = logi_wl.id, + checkType = check_types.SHIP_CHECK_TYPEID, + order = 0, + modifier = Decimal('1.00'), + checkTag = 'logi' + ) + + collection.checks.append(check) + + for k, v in modules.logi_ships.items(): + inv_type: InvType = db.session.query(InvType).get(k) + if inv_type is None: + print('ERROR NONE', inv_type) + + check.ids.append(inv_type) + + # check dps weapons + check = ShipCheck( + checkName = 'SortToDpsByWeapon', + checkTargetID=dps_wl.id, + checkType = check_types.MODULE_CHECK_TYPEID, + order = 1, + modifier = Decimal('1.00'), + checkTag = 'dps' + ) + + collection.checks.append(check) + + for k, v in modules.dps_weapons.items(): + inv_type = db.session.query(InvType).get(k) + if inv_type is None: + print('ERROR NONE', inv_type) + + check.ids.append(inv_type) + + # check sniper weapons + check = ShipCheck( + checkName = 'SortToSniperByWeapon', + checkTargetID = sniper_wl.id, + checkType = check_types.MODULE_CHECK_TYPEID, + order = 1, + modifier = Decimal('1.00'), + checkTag = 'sniper' + ) + collection.checks.append(check) + + for k, v in modules.sniper_weapons.items(): + inv_type = db.session.query(InvType).get(k) + if inv_type is None: + print('ERROR NONE', inv_type) + + check.ids.append(inv_type) + + # check sniper by market group + check = ShipCheck( + checkName = 'SortToSniperByWeaponMarketGroup', + checkTargetID = sniper_wl.id, + checkType = check_types.MODULE_CHECK_MARKETGROUP, + order = 2, + modifier = Decimal('1.00'), + checkTag = 'sniper' + ) + collection.checks.append(check) + + for k, v in modules.weapongroups['sniper'].items(): + grp = db.session.query(MarketGroup).get(v) + if grp is None: + print('ERROR NONE sniper weapon grps', v) + check.ids.append(grp) + + # check dps by market group + check = ShipCheck( + checkName = 'SortToDpsByWeaponMarketGroup', + checkTargetID = dps_wl.id, + checkType = check_types.MODULE_CHECK_MARKETGROUP, + order = 2, + modifier = Decimal('1.00'), + checkTag = 'sniper' + ) + collection.checks.append(check) + + for k, v in modules.weapongroups['dps'].items(): + if v == 2432: # skip Entropic Disintigrators + continue + grp = db.session.query(MarketGroup).get(v) + if grp is None: + print('ERROR NONE dps weapongroups', v) + check.ids.append(grp) + + # special rule for entropic disintigrators because it needs a higher modifier + check = ShipCheck( + checkName = 'SortToSniperEntropicDisintigrators', + checkTargetID = sniper_wl.id, + checkType = check_types.MODULE_CHECK_MARKETGROUP, + order = 2, + modifier = Decimal('4.00'), + checkTag = 'sniper' + ) + collection.checks.append(check) + check.ids.append(db.session.query(MarketGroup).get(2432)) + + # check dps by ship_type + check = ShipCheck( + checkName = 'SortToDpsByShipType', + checkTargetID = dps_wl.id, + checkType = check_types.SHIP_CHECK_TYPEID, + order = 3, + modifier = Decimal('1.00'), + checkTag = 'dps' + ) + collection.checks.append(check) + + for k, v in modules.dps_ships.items(): + inv_type = db.session.query(InvType).get(k) + if inv_type is None: + print('ERROR NONE', inv_type) + check.ids.append(inv_type) + + # sniper ships by typeid + check = ShipCheck( + checkName = 'SortToSniperByShipType', + checkTargetID = sniper_wl.id, + checkType = check_types.SHIP_CHECK_TYPEID, + order = 3, + modifier = Decimal('1.00'), + checkTag = 'sniper' + ) + collection.checks.append(check) + + for k, v in modules.sniper_ships.items(): + inv_type = db.session.query(InvType).get(k) + if inv_type is None: + print('ERROR NONE', inv_type) + check.ids.append(inv_type) + + # dps ships by market group id + check = ShipCheck( + checkName = 'SortToDpsByInvGroup', + checkTargetID = dps_wl.id, + checkType = check_types.SHIP_CHECK_INVGROUP, + order = 4, + modifier = Decimal('1.00'), + checkTag = 'dps' + ) + collection.checks.append(check) + + for k, v in modules.dps_groups.items(): + grp = db.session.query(InvGroup).get(k) + if grp is None: + print('ERROR NONE dps groups', k) + check.ids.append(grp) + + # logiships by marketgroup + check = ShipCheck( + checkName = 'SortToLogiByInvGroup', + checkTargetID = dps_wl.id, + checkType = check_types.SHIP_CHECK_INVGROUP, + order = 4, + modifier = Decimal('1.00'), + checkTag = 'logi' + ) + collection.checks.append(check) + + for k, v in modules.logi_groups.items(): + grp = db.session.query(InvGroup).get(k) + if grp is None: + print('ERROR NONE logi invgroups', k) + check.ids.append(grp) + + + +if __name__ == '__main__': + waitlistGroup = db.session.query(WaitlistGroup).filter(WaitlistGroup.groupName == 'default').one() + + logi_wl = None + dps_wl = None + sniper_wl = None + for wl in waitlistGroup.waitlists: + if wl.waitlistType == 'dps': + dps_wl = wl + if wl.waitlistType == 'logi': + logi_wl = wl + if wl.waitlistType == 'sniper': + sniper_wl = wl + + collection = ShipCheckCollection( + checkCollectionName = 'HQAssignments', + waitlistGroupID = waitlistGroup.groupID, + defaultTargetID = dps_wl.id, + defaultTag = 'other' + ) + + db.session.add(collection) + add_default_sorting(collection, logi_wl, dps_wl, sniper_wl) + db.session.commit() + + + waitlistGroup = db.session.query(WaitlistGroup).filter(WaitlistGroup.groupName == 'assault').one() + + logi_wl = None + dps_wl = None + sniper_wl = None + for wl in waitlistGroup.waitlists: + if wl.waitlistType == 'dps': + dps_wl = wl + if wl.waitlistType == 'logi': + logi_wl = wl + if wl.waitlistType == 'sniper': + sniper_wl = wl + + collection = ShipCheckCollection( + checkCollectionName = 'AssaultAssignments', + waitlistGroupID = waitlistGroup.groupID, + defaultTargetID = dps_wl.id, + defaultTag = 'other' + ) + + db.session.add(collection) + add_default_sorting(collection, logi_wl, dps_wl, sniper_wl) + db.session.commit() + + + waitlistGroup = db.session.query(WaitlistGroup).filter(WaitlistGroup.groupName == 'vanguard').one() + + logi_wl = None + dps_wl = None + sniper_wl = None + for wl in waitlistGroup.waitlists: + if wl.waitlistType == 'dps': + dps_wl = wl + if wl.waitlistType == 'logi': + logi_wl = wl + if wl.waitlistType == 'sniper': + sniper_wl = wl + + collection = ShipCheckCollection( + checkCollectionName = 'VanguardAssignments', + waitlistGroupID = waitlistGroup.groupID, + defaultTargetID = dps_wl.id, + defaultTag = 'other' + ) + + db.session.add(collection) + add_default_sorting(collection, logi_wl, dps_wl, sniper_wl) + db.session.commit() + From dbc24e5536da6430b490004c06469a76b0d9943d Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 19:44:01 +0200 Subject: [PATCH 07/22] removed some teamspeak related info/pages if you disabled teamspeak also removed some messages if there is no teamspeak server set --- templates/xup-form.html | 2 ++ waitlist/blueprints/__init__.py | 5 +++-- waitlist/blueprints/settings/teamspeak.py | 10 ++++++++-- waitlist/blueprints/xup/submission.py | 19 ++++++++++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/templates/xup-form.html b/templates/xup-form.html index e8297274..54d55523 100644 --- a/templates/xup-form.html +++ b/templates/xup-form.html @@ -28,10 +28,12 @@ {% endif %} +{% if ts %} +{% endif %}
diff --git a/waitlist/blueprints/__init__.py b/waitlist/blueprints/__init__.py index 19f95b06..a178d4f3 100644 --- a/waitlist/blueprints/__init__.py +++ b/waitlist/blueprints/__init__.py @@ -13,7 +13,8 @@ from flask_login import login_required, current_user, login_user, logout_user from waitlist.utility import config -from waitlist.utility.config import stattool_enabled, stattool_uri, stattool_sri +from waitlist.utility.config import stattool_enabled, stattool_uri,\ + stattool_sri, disable_teamspeak from waitlist.base import app, db from waitlist.storage.database import WaitlistGroup, TeamspeakDatum, CalendarEvent, WaitlistEntry, Account, Trivia @@ -73,7 +74,7 @@ def index(): activegroups = db.session.query(WaitlistGroup).filter(WaitlistGroup.enabled == True).all() active_ts_setting_id = sget_active_ts_id() active_ts_setting = None - if active_ts_setting_id is not None: + if not disable_teamspeak and active_ts_setting_id is not None: active_ts_setting = db.session.query(TeamspeakDatum).get(active_ts_setting_id) events = db.session.query(CalendarEvent).filter(CalendarEvent.eventTime > datetime.utcnow()).order_by( diff --git a/waitlist/blueprints/settings/teamspeak.py b/waitlist/blueprints/settings/teamspeak.py index a7026ef0..22ec26e5 100644 --- a/waitlist/blueprints/settings/teamspeak.py +++ b/waitlist/blueprints/settings/teamspeak.py @@ -14,8 +14,10 @@ from waitlist.storage.database import TeamspeakDatum from waitlist.ts3.connection import change_connection from waitlist.utility.settings import sget_active_ts_id, sset_active_ts_id +from waitlist.utility.config import disable_teamspeak from flask_babel import gettext, lazy_gettext + bp = Blueprint('teamspeak', __name__) logger = logging.getLogger(__name__) @@ -76,6 +78,10 @@ def teamspeak_change(): ) db.session.add(ts) db.session.commit() + # set as active ts if there was none before + if sget_active_ts_id() is None: + sset_active_ts_id(ts.teamspeakID) + change_connection() elif action == "remove" and perm_edit_server.can(): teamspeak_id = int(request.form['teamspeakID']) db.session.query(TeamspeakDatum).filter(TeamspeakDatum.teamspeakID == teamspeak_id).delete() @@ -95,5 +101,5 @@ def teamspeak_change(): return redirect(url_for("teamspeak.teamspeak")) - -add_menu_entry('teamspeak.teamspeak', lazy_gettext('TS Settings'), perm_view_server.can) +if not disable_teamspeak: + add_menu_entry('teamspeak.teamspeak', lazy_gettext('TS Settings'), perm_view_server.can) diff --git a/waitlist/blueprints/xup/submission.py b/waitlist/blueprints/xup/submission.py index 99fc62de..a734a2b3 100644 --- a/waitlist/blueprints/xup/submission.py +++ b/waitlist/blueprints/xup/submission.py @@ -10,7 +10,7 @@ from waitlist.data.sse import EntryAddedSSE, send_server_sent_event,\ FitAddedSSE from waitlist.storage.database import WaitlistGroup, WaitlistEntry, Shipfit,\ - InvType, FitModule, MarketGroup, HistoryEntry + InvType, FitModule, MarketGroup, HistoryEntry, TeamspeakDatum from waitlist.storage.modules import resist_ships, logi_ships, sniper_ships,\ sniper_weapons, dps_weapons, weapongroups, dps_ships, t3c_ships from waitlist.utility.history_utils import create_history_object @@ -22,6 +22,8 @@ from flask_babel import gettext, ngettext from typing import Dict, List, Tuple from waitlist.utility.constants import location_flags, groups +from waitlist.utility.settings import sget_active_ts_id +from waitlist.utility.config import disable_teamspeak import operator logger = logging.getLogger(__name__) @@ -351,7 +353,12 @@ def index(): .order_by(WaitlistGroup.ordering).first() # noinspection PyPep8 activegroups = db.session.query(WaitlistGroup).filter(WaitlistGroup.enabled == True).all() - return render_template("xup.html", newbro=new_bro, group=defaultgroup, groups=activegroups) + ts_settings = None + ts_id = sget_active_ts_id() + if not disable_teamspeak and ts_id is not None: + ts_settings = db.session.query(TeamspeakDatum).get(ts_id) + return render_template("xup.html", newbro=new_bro, group=defaultgroup, + groups=activegroups, ts=ts_settings) @bp.route("/", methods=['GET']) @@ -364,8 +371,14 @@ def update(fit_id: int): .order_by(WaitlistGroup.ordering).first() # noinspection PyPep8 activegroups = db.session.query(WaitlistGroup).filter(WaitlistGroup.enabled == True).all() + ts_settings = None + ts_id = sget_active_ts_id() + if ts_id is not None: + ts_settings = db.session.query(TeamspeakDatum).get(ts_id) + return render_template("xup.html", newbro=new_bro, group=defaultgroup, - groups=activegroups, update=True, oldFitID=fit_id) + groups=activegroups, update=True, oldFitID=fit_id, + ts=ts_settings) @bp.route("/update", methods=['POST']) From 2b9c084525cc8c7c200fd24cff365a6d490288af Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 19:56:54 +0200 Subject: [PATCH 08/22] remove Test TS button if no ts is enabled --- templates/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/index.html b/templates/index.html index d9d09873..ec1904fa 100644 --- a/templates/index.html +++ b/templates/index.html @@ -168,9 +168,11 @@
+ {% if ts %} + {% endif %}
  • From 017a5086ac98627d72b28abe408be2be89a0a741 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Fri, 26 Apr 2019 20:50:23 +0200 Subject: [PATCH 09/22] added option to have everyone banned by default --- waitlist/utility/config.py | 2 ++ waitlist/utility/eve_id_utils.py | 39 ++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/waitlist/utility/config.py b/waitlist/utility/config.py index ad6acbf3..752fc95f 100644 --- a/waitlist/utility/config.py +++ b/waitlist/utility/config.py @@ -76,6 +76,7 @@ def set_if_not_exists(self, section, option, value): config.add_section("security") config.set_if_not_exists("security", "scramble_names", "False") config.set_if_not_exists("security", "require_auth_for_chars", "False") +config.set_if_not_exists("security", "banned_by_default", "False") if not config.has_section("disable"): config.add_section("disable") @@ -127,6 +128,7 @@ def set_if_not_exists(self, section, option, value): scramble_names = config.get("security", "scramble_names") == "True" require_auth_for_chars = config.get("security", "require_auth_for_chars") == "True" +banned_by_default = config.get("security", "banned_by_default") == "True" disable_teamspeak = config.get("disable", "teamspeak") == "True" diff --git a/waitlist/utility/eve_id_utils.py b/waitlist/utility/eve_id_utils.py index 85fabb2f..620da1ab 100644 --- a/waitlist/utility/eve_id_utils.py +++ b/waitlist/utility/eve_id_utils.py @@ -3,6 +3,7 @@ from esipy import EsiClient from waitlist.utility import outgate +from waitlist.utility.config import banned_by_default from waitlist.utility.sde import add_type_by_id_to_database from waitlist.storage.database import Constellation, SolarSystem, Station,\ InvType, Account, Character, Ban, Whitelist @@ -163,24 +164,32 @@ def is_char_banned(char: Character) -> Tuple[bool, str]: return True, "Character" corp_id, alli_id = outgate.character.get_affiliations(char.get_eve_id()) - # if he is on whitelist let him pass - - corp_banned = is_charid_banned(corp_id) - alli_banned = is_charid_banned(alli_id) - if is_charid_whitelisted(corp_id): + if banned_by_default: + if is_charid_whitelisted(corp_id): return False, "" - - if corp_banned: - return True, "Corporation" - - if is_charid_whitelisted(alli_id): + if is_charid_banned(corp_id): + return True, "Corporation" + if is_charid_whitelisted(alli_id): return False, "" - - if alli_banned: - return True, "Alliance" - - return False, "" + return True, "Everyone Banned by default" + else: + corp_banned = is_charid_banned(corp_id) + alli_banned = is_charid_banned(alli_id) + + if is_charid_whitelisted(corp_id): + return False, "" + + if corp_banned: + return True, "Corporation" + + if is_charid_whitelisted(alli_id): + return False, "" + + if alli_banned: + return True, "Alliance" + + return False, "" except ApiException as e: logger.info("Failed to check if %d was banned, because of Api error, code=%d msg=%s", char.get_eve_id(), e.code, e.msg) From 955768adf28ceb9f65e3d288c10b4657c04417a7 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:14:50 +0200 Subject: [PATCH 10/22] updated some python dependencies and related code also fixed werkzeug to 0.15.2 because it already made problems from 0.14 to 0.15 --- requirements.txt | 22 +++++++++++----------- waitlist/entry.py | 8 +++++++- waitlist/utility/config.py | 14 ++++++++++++++ waitlist/utility/sde.py | 2 +- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/requirements.txt b/requirements.txt index 28a3f89b..9a6f45f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,17 @@ Flask>=1.0.2 -PyYAML>=3.12 -SQLAlchemy>=1.2.7 -Werkzeug>=0.14.1 -alembic>=0.9.9 -bcrypt>=3.1.1 +PyYAML>=5.1 +SQLAlchemy>=1.3.3 +Werkzeug==0.15.2 +alembic>=1.0.9 +bcrypt>=3.1.6 blinker>=1.4 -gevent>=1.3.1 -requests>=2.18.4 +gevent>=1.4.0 +requests>=2.21.0 esipy==0.5.0 Flask-Assets>=0.12 -Flask-htmlmin>=1.2 +Flask-htmlmin>=1.5.0 Flask-Login>=0.4.1 -Flask-Migrate>=2.0.0 +Flask-Migrate>=2.4.0 Flask-Principal>=0.4.0 Flask-SeaSurf>=0.2.2 Flask-SQLAlchemy>=2.3.2 @@ -19,6 +19,6 @@ Flask-CDN>=1.5.3 flask-limiter>=1.0.1 ts3==1.0.6 Flask-Script>=2.0.6 -Flask-Babel>=0.11.2 +Flask-Babel>=0.12.2 csscompressor>=0.9.5 -flasgger>=0.9.0 \ No newline at end of file +flasgger>=0.9.2 diff --git a/waitlist/entry.py b/waitlist/entry.py index 3a9617a8..3788de47 100644 --- a/waitlist/entry.py +++ b/waitlist/entry.py @@ -112,7 +112,13 @@ def register_blueprints(): def run_server(): from waitlist.base import app from waitlist.utility import config - app.wsgi_app = ProxyFix(app.wsgi_app) + from werkzeug.middleware.proxy_fix import ProxyFix + from gevent.pywsgi import WSGIServer + if config.proxy_enabled: + app.wsgi_app = ProxyFix(app.wsgi_app, x_for=config.proxy_for, + x_host=config.proxy_host, + x_proto=config.proxy_proto, + x_prefix=config.proxy_prefix) wsgi_logger = logging.getLogger("gevent.pywsgi.WSGIServer") server = WSGIServer((config.server_bind, config.server_port), app, log=wsgi_logger, error_log=wsgi_logger) diff --git a/waitlist/utility/config.py b/waitlist/utility/config.py index 752fc95f..807a34f2 100644 --- a/waitlist/utility/config.py +++ b/waitlist/utility/config.py @@ -60,6 +60,14 @@ def set_if_not_exists(self, section, option, value): config.set_if_not_exists("cdn", "eve_img_server", "https://imageserver.eveonline.com/{0}.{1}") config.set_if_not_exists("cdn", "eve_img_server_webp", "False") +if not config.has_section("proxy"): + config.add_section("proxy") +config.set_if_not_exists("proxy", "enabled", "False") +config.set_if_not_exists("proxy", "x_forward_for", "1") +config.set_if_not_exists("proxy", "x_forward_proto", "1") +config.set_if_not_exists("proxy", "x_forward_host", "1") +config.set_if_not_exists("proxy", "x_forward_prefix", "1") + if not config.has_section("cookies"): config.add_section("cookies") config.set_if_not_exists("cookies", "secure_cookies", "False") @@ -148,6 +156,12 @@ def set_if_not_exists(self, section, option, value): overview_show_count_for_approvals = config.get("overview", "show_count_for_approvals") == "True" +proxy_enabled = config.get("proxy", "enabled") == "True" +proxy_for = int(config.get("proxy", "x_forward_for")) +proxy_proto = int(config.get("proxy", "x_forward_proto")) +proxy_host = int(config.get("proxy", "x_forward_host")) +proxy_prefix = int(config.get("proxy", "x_forward_prefix")) + """ The following content is for reading menus diff --git a/waitlist/utility/sde.py b/waitlist/utility/sde.py index c89e159a..79bdd8e8 100644 --- a/waitlist/utility/sde.py +++ b/waitlist/utility/sde.py @@ -464,7 +464,7 @@ def update_stations(filename): next_scalar_type = "key" station = None att_key = None - for ev in yaml.parse(f): + for ev in yaml.parse(f, Loader=yaml.SafeLoader): if isinstance(ev, MappingStartEvent): # 1 mapping per station station = Station() # create new station From 2eed28ad88c1b497111c27cefd7a5946e7795ea1 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:18:18 +0200 Subject: [PATCH 11/22] various small fixed to newly implemented code --- setup_shipclassifications.py | 2 +- static/js/waitlist-dom.js | 4 ++-- .../settings/ship_assignment/check_edit.html | 6 ++--- .../ship_assignment/collection_edit.html | 24 +++++++++++++++---- .../ship_assignment/collection_list.html | 2 +- waitlist/blueprints/fittings.py | 10 ++++---- .../blueprints/settings/ship_assignment.py | 13 +++++++++- waitlist/blueprints/xup/submission.py | 3 ++- waitlist/storage/database.py | 3 ++- waitlist/utility/fitting_utils.py | 10 ++++---- waitlist/utility/sde.py | 4 ++-- 11 files changed, 55 insertions(+), 26 deletions(-) diff --git a/setup_shipclassifications.py b/setup_shipclassifications.py index 8fba1c62..66ce92e6 100644 --- a/setup_shipclassifications.py +++ b/setup_shipclassifications.py @@ -91,7 +91,7 @@ def add_default_sorting(collection: ShipCheckCollection, logi_wl, dps_wl, sniper checkType = check_types.MODULE_CHECK_MARKETGROUP, order = 2, modifier = Decimal('1.00'), - checkTag = 'sniper' + checkTag = 'dps' ) collection.checks.append(check) diff --git a/static/js/waitlist-dom.js b/static/js/waitlist-dom.js index e50f7fd8..85fec540 100644 --- a/static/js/waitlist-dom.js +++ b/static/js/waitlist-dom.js @@ -100,7 +100,7 @@ waitlist.listdom = (function(){ case "other": return "OTHER"; default: - return "UNKNOWN"; + return jsonFit.wl_type; } } @@ -822,4 +822,4 @@ waitlist.listdom = (function(){ setStatusDom: setStatusDom, clearWaitlists: clearWaitlists }; -})(); \ No newline at end of file +})(); diff --git a/templates/settings/ship_assignment/check_edit.html b/templates/settings/ship_assignment/check_edit.html index db47b37c..cede411e 100644 --- a/templates/settings/ship_assignment/check_edit.html +++ b/templates/settings/ship_assignment/check_edit.html @@ -4,7 +4,7 @@ {% block head %} {{ super() }} -{% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", +{% assets filters="babili", output="gen/ass_chk_edit.%(version)s.js", "js/ship_assignment/check_edit.js" %} {% endassets %} @@ -16,7 +16,7 @@
    - +
    @@ -60,7 +60,7 @@
    - +
    diff --git a/templates/settings/ship_assignment/collection_edit.html b/templates/settings/ship_assignment/collection_edit.html index 5107d8ec..9183cc3b 100644 --- a/templates/settings/ship_assignment/collection_edit.html +++ b/templates/settings/ship_assignment/collection_edit.html @@ -4,7 +4,7 @@ {% block head %} {{ super() }} -{% assets filters="babili", output="gen/ass_coll_list.%(version)s.js", +{% assets filters="babili", output="gen/ass_coll_edit.%(version)s.js", "js/ship_assignment/collection.js", "js/ship_assignment/collection_edit.js" %} {% endassets %} @@ -16,7 +16,7 @@
    - +
    @@ -39,7 +39,7 @@
    - +
    @@ -50,7 +50,7 @@
    - +
    @@ -95,11 +95,25 @@
    - +
    +
    +
    + +
    + + +
    + +
    +
    diff --git a/templates/settings/ship_assignment/collection_list.html b/templates/settings/ship_assignment/collection_list.html index ec8a5c67..1db9bb2b 100644 --- a/templates/settings/ship_assignment/collection_list.html +++ b/templates/settings/ship_assignment/collection_list.html @@ -29,7 +29,7 @@
    - +
    diff --git a/waitlist/blueprints/fittings.py b/waitlist/blueprints/fittings.py index 923f68f4..ba23655f 100644 --- a/waitlist/blueprints/fittings.py +++ b/waitlist/blueprints/fittings.py @@ -42,7 +42,7 @@ perm_comp_unlimited = perm_manager.get_permission('comphistory_unlimited') -def get_waitlist_entry_for_list(wl_id: int, creating_time: datetime, existing_entries: List[WaitlistEntry]) -> Tuple[bool, WaitlistEntry]: +def get_waitlist_entry_for_list(wl_id: int, creating_time: datetime, existing_entries: List[WaitlistEntry], user) -> Tuple[bool, WaitlistEntry]: """Gets the corsponding waitlist entry or creates a new one The first entry of the tuple indicates if the entry was newly created """ @@ -51,9 +51,9 @@ def get_waitlist_entry_for_list(wl_id: int, creating_time: datetime, existing_en return False, entry entry = WaitlistEntry() entry.creation = creating_time # for sorting entries - entry.user = entry.user # associate a user with the entry + entry.user = user # associate a user with the entry entry.waitlist_id = wl_id - existing_entries.append(logi_entry) + existing_entries.append(entry) db.session.add(entry) return True, entry @@ -112,7 +112,7 @@ def move_to_waitlists(): event = FitRemovedSSE(entry.waitlist.group.groupID, entry.waitlist.id, entry.id, fit.id, entry.user) _sseEvents.append(event) entry.fittings.remove(fit) - is_new, new_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, new_entry_timedate, waitlist_entries) + is_new, new_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, new_entry_timedate, waitlist_entries, entry.user) new_entry.fittings.append(fit) # fits in a created entry will be sent out later a whole entry if is_new: @@ -187,7 +187,7 @@ def api_move_fit_to_waitlist(): if fit.waitlist is not None and wl_entry is not None and fit.waitlist.id == wl_entry.id: flask.abort(409, 'This fit was already moved') - is_entry_new, wl_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, creation_time, [wl_entry] if wl_entry is not None else []) + is_entry_new, wl_entry = get_waitlist_entry_for_list(fit.targetWaitlistID, creation_time, [wl_entry] if wl_entry is not None else [], entry.user) # remove fit from old entry event = FitRemovedSSE(entry.waitlist.group.groupID, entry.waitlist_id, entry.id, fit.id, entry.user) diff --git a/waitlist/blueprints/settings/ship_assignment.py b/waitlist/blueprints/settings/ship_assignment.py index 3d68dda2..6ff77c1a 100644 --- a/waitlist/blueprints/settings/ship_assignment.py +++ b/waitlist/blueprints/settings/ship_assignment.py @@ -193,7 +193,7 @@ def check_change(check_id:int) -> Response: check.checkType = check_type check.checkName = name check.modifier = check_modifier - check.tag = tag + check.checkTag = tag # add new items # this needs to be done after changing the type # because otherwise we add to the wrong relationship @@ -228,4 +228,15 @@ def check_change(check_id:int) -> Response: return redirect(url_for('.collection_edit', collection_id=check.collection.checkCollectionID)) +@bp.route('/check/delete', methods=['POST']) +@login_required +@perm_manager.require('ship_assignment_edit') +def check_delete(): + check_id = int(request.form['check_id']) + check = db.session.query(ShipCheck).get(check_id) + db.session.delete(check) + db.session.commit() + return redirect(request.referrer) + + add_menu_entry('ship_assignment.ship_assignments', lazy_gettext('Ship Classification'), perm_manager.get_permission('ship_assignment_edit').can) diff --git a/waitlist/blueprints/xup/submission.py b/waitlist/blueprints/xup/submission.py index 591c1c05..98415cc8 100644 --- a/waitlist/blueprints/xup/submission.py +++ b/waitlist/blueprints/xup/submission.py @@ -10,7 +10,8 @@ from waitlist.data.sse import EntryAddedSSE, send_server_sent_event,\ FitAddedSSE from waitlist.storage.database import WaitlistGroup, WaitlistEntry, Shipfit,\ - TeamspeakDatum, InvType, FitModule, MarketGroup, HistoryEntry + TeamspeakDatum, InvType, FitModule, MarketGroup, HistoryEntry, Waitlist,\ + ShipCheckCollection from waitlist.storage.modules import resist_ships, logi_ships from waitlist.utility.history_utils import create_history_object from waitlist.utility.fitting_utils import get_fit_format, parse_dna_fitting,\ diff --git a/waitlist/storage/database.py b/waitlist/storage/database.py index 87e9d82f..e5f6286c 100644 --- a/waitlist/storage/database.py +++ b/waitlist/storage/database.py @@ -1478,4 +1478,5 @@ def ids(self, value): self.check_market_groups = value if self.checkType == check_types.SHIP_CHECK_INVGROUP: self.check_groups = value - + def __repr__(self): + return f'' diff --git a/waitlist/utility/fitting_utils.py b/waitlist/utility/fitting_utils.py index 478dd8df..347f9d25 100644 --- a/waitlist/utility/fitting_utils.py +++ b/waitlist/utility/fitting_utils.py @@ -2,7 +2,7 @@ from decimal import Decimal from sqlalchemy import literal from waitlist.utility.constants import location_flags, effects, check_types -from typing import List, Dict, Optional, Tuple, AbstractSet +from typing import List, Dict, Optional, Tuple, AbstractSet, Union from waitlist.storage.database import InvType, Shipfit, FitModule,\ MarketGroup, ShipCheckCollection, ShipCheck, Waitlist, InvGroup from waitlist.base import db @@ -360,7 +360,7 @@ def get_waitlist_type_for_modules(checks: List[ShipCheck], fit: Shipfit) -> Opti # for modules we need to hit every module once or never # never only if there is no rule for it! # so after getting a rule hit on a module, remove the module - result_count_map: Dict[int, Tuple(Decimal, Set[str])] = dict() + result_count_map: Dict[int, List[Union[Decimal, Set[str]]]] = dict() for check in checks: # lets see if this check applies to this ship if not does_check_apply(check, fit.ship_type): @@ -368,7 +368,7 @@ def get_waitlist_type_for_modules(checks: List[ShipCheck], fit: Shipfit) -> Opti logger.debug('Doing check %s with type %d and target %s and mods %r', check.checkName, check.checkType, check.checkTarget.waitlistType, mod_ids) if check.checkTargetID not in result_count_map: - result_count_map[check.checkTargetID] = (Decimal("0.00"), set()) + result_count_map[check.checkTargetID] = [Decimal("0.00"), set()] modifier = Decimal("1.00") if check.modifier is None else check.modifier if check.checkType == check_types.MODULE_CHECK_TYPEID: remaining_mods = [] @@ -429,6 +429,8 @@ def get_waitlist_type_for_fit(fit: Shipfit, waitlist_group_id: int) -> Tuple[str module_checks, ship_type_checks )) + module_checks = [] + ship_type_checks = [] if check.checkType in [check_types.MODULE_CHECK_MARKETGROUP, check_types.MODULE_CHECK_TYPEID]: module_checks.append(check) @@ -447,7 +449,7 @@ def get_waitlist_type_for_fit(fit: Shipfit, waitlist_group_id: int) -> Tuple[str if module_data is not None and module_data[1][0] >= Decimal("4.00"): ship_wl_id = module_data[0] if len(module_data[1][1]) > 0: - tag = module_data[1][1][0] + tag = module_data[1][1].pop() break ship_data = get_waitlist_type_for_ship_type(check_tuple[1], fit.ship_type) if ship_data is not None: diff --git a/waitlist/utility/sde.py b/waitlist/utility/sde.py index 79bdd8e8..a6900ccd 100644 --- a/waitlist/utility/sde.py +++ b/waitlist/utility/sde.py @@ -483,9 +483,9 @@ def update_stations(filename): elif isinstance(ev, MappingEndEvent): # write it db.session.merge(station) - + db.session.commit() - + f.close() From b1f41e6eb1c3adf19791bcc45d125f46be3a4a89 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:33:08 +0200 Subject: [PATCH 12/22] implemented properly merging base and user logger config --- waitlist/entry.py | 53 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/waitlist/entry.py b/waitlist/entry.py index 3788de47..b4bc0722 100644 --- a/waitlist/entry.py +++ b/waitlist/entry.py @@ -3,21 +3,43 @@ import os import json -# setup logging -logger_config = os.path.join('.', 'config', 'logger.base.json') -if os.path.isfile(logger_config): - with open(logger_config, 'r') as fp: - cfg = json.load(fp) - logging.config.dictConfig(cfg) - -logger_config = os.path.join('.', 'config', 'logger.user.json') -if os.path.isfile(logger_config): - with open(logger_config, 'r') as fp: - cfg = json.load(fp) - logging.config.dictConfig(cfg) - -from werkzeug.contrib.fixers import ProxyFix -from gevent.pywsgi import WSGIServer + +def merge_dicts(destination, source): + for key, value in source.items(): + if isinstance(value, dict): + # if there is no dict there we need to create one + subdict = destination.setdefault(key, {}) + if not isinstance(subdict, dict): + print('Error merging configs on', key) + else: + merge_dicts(subdict, value) + else: + destination[key] = value + + return destination + + +def setup_logging(): + # setup logging + base_cfg = None + user_cfg = None + logger_config = os.path.join('.', 'config', 'logger.base.json') + if os.path.isfile(logger_config): + with open(logger_config, 'r') as fp: + base_cfg = json.load(fp) + + logger_config = os.path.join('.', 'config', 'logger.user.json') + if os.path.isfile(logger_config): + with open(logger_config, 'r') as fp: + user_cfg = json.load(fp) + # if we have both we need to merge them + if base_cfg is not None and user_cfg is not None: + merge_dicts(base_cfg, user_cfg) + # if there is only user config we can ignore it + elif user_cfg is not None: + base_cfg = user_cfg + + logging.config.dictConfig(base_cfg) def register_blueprints(): from waitlist.blueprints.fittings import bp_waitlist @@ -125,6 +147,7 @@ def run_server(): server.serve_forever() def main(): + setup_logging() import argparse parser = argparse.ArgumentParser(description='Waitlist management') parser.add_argument('-c', '--create-config', action='store_true', From 15cdbe3a6234355a170720467a97803f34711533 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:33:41 +0200 Subject: [PATCH 13/22] implemented configuration option to disabled scruffy xups --- waitlist/blueprints/xup/submission.py | 24 ++++++++++++++++++------ waitlist/utility/config.py | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/waitlist/blueprints/xup/submission.py b/waitlist/blueprints/xup/submission.py index 98415cc8..fcf77a1f 100644 --- a/waitlist/blueprints/xup/submission.py +++ b/waitlist/blueprints/xup/submission.py @@ -22,7 +22,7 @@ from typing import Dict, List, Tuple from waitlist.utility.constants import location_flags, groups from waitlist.utility.settings import sget_active_ts_id -from waitlist.utility.config import disable_teamspeak +from waitlist.utility.config import disable_teamspeak, disable_scruffy_mode import operator logger = logging.getLogger(__name__) @@ -61,24 +61,25 @@ def submit(): current_user.poke_me = poke_me db.session.commit() # check if it is scruffy - if fittings.lower().startswith("scruffy"): + if not disable_scruffy_mode and fittings.lower().startswith("scruffy"): # scruffy mode scruffy fittings = fittings.lower() _, _, ship_type = fittings.rpartition(" ") ship_types = [] # check for , to see if it is a multi value shiptype + allowed_types = [tpl[0].strip() for tpl in db.session.query(Waitlist.waitlistType).filter((~Waitlist.group.has(WaitlistGroup.queueID == Waitlist.id)) & (Waitlist.groupID == group_id))] if "," in ship_type: for stype in ship_type.split(","): stype = stype.strip() - if stype == WaitlistNames.logi or stype == WaitlistNames.dps or stype == WaitlistNames.sniper: + if stype in allowed_types: ship_types.append(stype) else: - if ship_type == WaitlistNames.logi or ship_type == WaitlistNames.dps or ship_type == WaitlistNames.sniper: + if ship_type in allowed_types: ship_types.append(ship_type) # check if shiptype is valid if len(ship_types) <= 0: - flash(gettext("Valid entries are scruffy [dps|logi|sniper,..]")) + flash(gettext("Valid entries are scruffy %(types)s", types=','.join(allowed_types)), 'danger') return redirect(url_for('index')) queue = group.xuplist @@ -94,10 +95,21 @@ def submit(): h_entry = create_history_object(current_user.get_eve_id(), "xup") for stype in ship_types: - fit = Shipfit() + wl = db.session.query(Waitlist).filter( + (Waitlist.groupID == group_id) & (Waitlist.waitlistType == stype) + ).first() + target_wl_id = None + if wl is not None: + target_wl_id = wl.id + if target_wl_id is None: + target_wl_id = db.session.query(ShipCheckCollection).filter( + (ShipCheckCollection.waitlistGroupID == group_id) + ).one().defaultTargetID + fit: Shipfit = Shipfit() fit.ship_type = 0 # #System >.> fit.wl_type = stype fit.modules = ':' + fit.targetWaitlistID = target_wl_id wl_entry.fittings.append(fit) if not _newEntryCreated: _newFits.append(fit) diff --git a/waitlist/utility/config.py b/waitlist/utility/config.py index 807a34f2..acb387f9 100644 --- a/waitlist/utility/config.py +++ b/waitlist/utility/config.py @@ -89,6 +89,7 @@ def set_if_not_exists(self, section, option, value): if not config.has_section("disable"): config.add_section("disable") config.set_if_not_exists("disable", "teamspeak", "False") +config.set_if_not_exists("disable", "scruffy_mode", "True") if not config.has_section("pageinfo"): config.add_section("pageinfo") @@ -139,6 +140,7 @@ def set_if_not_exists(self, section, option, value): banned_by_default = config.get("security", "banned_by_default") == "True" disable_teamspeak = config.get("disable", "teamspeak") == "True" +disable_scruffy_mode = config.get("disable", "scruffy_mode") == "True" influence_link = config.get("pageinfo", "influence_link") From 2de84a9a672b6cf8985d23a20b9857344c5eb75b Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:34:00 +0200 Subject: [PATCH 14/22] changed all waitlists on frontpage to have part of the width instead of 1/4th --- templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/index.html b/templates/index.html index ec1904fa..70eee82d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -265,7 +265,7 @@
    1 %}data-t
    {% for wlist in lists %} -
    +
    0 From 857262587a844cc4d910037607f24931c304d10d Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:34:17 +0200 Subject: [PATCH 15/22] updated migrations --- migrations/versions/dee8dcee93e4_.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/migrations/versions/dee8dcee93e4_.py b/migrations/versions/dee8dcee93e4_.py index 9cbd029b..11d4f09f 100644 --- a/migrations/versions/dee8dcee93e4_.py +++ b/migrations/versions/dee8dcee93e4_.py @@ -125,11 +125,19 @@ def upgrade(): # now we can remove the nullable=True op.alter_column('waitlist_groups', 'queueID', existing_type=sa.Integer(), nullable=False) op.create_foreign_key(op.f('fk_waitlist_groups_queueID_waitlists'), 'waitlist_groups', 'waitlists', ['queueID'], ['id']) + op.alter_column('fittings', 'wl_type', + existing_type=sa.String(length=10), + type_=sa.String(length=20), + existing_nullable=True) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('fittings', 'wl_type', + existing_type=sa.String(length=20), + type_=sa.String(length=10), + existing_nullable=True) op.drop_constraint(op.f('fk_waitlist_groups_queueID_waitlists'), 'waitlist_groups', type_='foreignkey') op.drop_column('waitlist_groups', 'queueID') op.drop_constraint(op.f('fk_invtypes_group_id_invgroup'), 'invtypes', type_='foreignkey') From 872c9be611ff053758b351c53ddf5e1c6a5ec8cc Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:34:32 +0200 Subject: [PATCH 16/22] updated translations --- translations/de/LC_MESSAGES/messages.po | 308 ++++++++++++++++++------ translations/en/LC_MESSAGES/messages.po | 306 +++++++++++++++++------ 2 files changed, 476 insertions(+), 138 deletions(-) diff --git a/translations/de/LC_MESSAGES/messages.po b/translations/de/LC_MESSAGES/messages.po index 95245f34..65b9ef2b 100644 --- a/translations/de/LC_MESSAGES/messages.po +++ b/translations/de/LC_MESSAGES/messages.po @@ -4,16 +4,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2019-04-15 12:35+0200\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-04-15 10:48+0000\n" +"POT-Creation-Date: 2019-04-27 21:26+0200\n" +"PO-Revision-Date: 2019-04-27 21:28+0200\n" "Last-Translator: Constantin Wenger \n" "Language-Team: German\n" "Language: de\n" -"X-Generator: Zanata 4.6.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: config/themes.example.json msgid "Standard" @@ -29,23 +29,23 @@ msgstr "Dunkel-Violett" #: templates/about.html:15 msgid "" -"Eve-Inc-Waitlist Created by Bruce " -"Warhead and Beryl Slanjava" +"Eve-Inc-Waitlist Created by Bruce Warhead and Beryl Slanjava" msgstr "" -"Eve-Inc-Waitlist erstellt von Bruce " +"Eve-Inc-Waitlist erstellt von Bruce " "Warhead und Beryl Slanjava" #: templates/about.html:17 msgid "" "Fitting " -"Display (Eve-UI) and Fitting Stats by Quie'scens" +"Display (Eve-UI) and Fitting Stats by Quie'scens" msgstr "" -"Ausrüstungsanzeige (Eve-UI) und Ausrüstungsstatistiken by Quie'scens" +"Ausrüstungsanzeige (Eve-UI) und Ausrüstungsstatistiken by Quie'scens" #: templates/base.html:88 msgid "ISK Donations are appreciated" @@ -101,8 +101,8 @@ msgstr "Wie funktionieren die Warnungsausdrücke?" #: templates/help.html:40 msgid "" -"For expression evaluation expr-eval is used.\n" +"For expression evaluation expr-eval is used.\n" " The variables, open, xup, logi, dps, sniper, other are " "provided, open being a boolean(true/false) while the others are numbers.\n" " You can have one expression per Waitlist Group, there is no need for more " @@ -136,7 +136,8 @@ msgid "" " Binary operators, take two arguments. Unary ones only take one. Now that we " "have established this we are going to move on to an example." msgstr "" -"Für unsere Verwendung müssen wir nur unäre und binäre Operatoren betrachten.\n" +"Für unsere Verwendung müssen wir nur unäre und binäre Operatoren " +"betrachten.\n" "Binäre Operatoren, nehmen zwei Argumente. Unäre nehmen nur einenes. Nachdem " "wir dies eingeführt haben, gehen wir nun zu einem Beispiel über." @@ -189,8 +190,8 @@ msgid "" "So here again we have two subexpressions inside this subexpression. " "(xup == 0) and (logi < 2)." msgstr "" -"Hier haben wir wieder zwei Unterausdrücke in dem Unterausdruck. (xup ==" -" 0) and (logi < 2)." +"Hier haben wir wieder zwei Unterausdrücke in dem Unterausdruck. (xup " +"== 0) and (logi < 2)." #: templates/help.html:68 msgid "" @@ -200,7 +201,8 @@ msgid "" "what it is." msgstr "" "Wir wissen das dies zwei Unterausdrucke sind durch den Rang von Operatoren.\n" -"Das muss dich aber nicht interessieren, falls sie nicht wissen was dies ist.\n" +"Das muss dich aber nicht interessieren, falls sie nicht wissen was dies " +"ist.\n" "Benutzen sie einfach () um jeden Ausdruck." #: templates/help.html:73 @@ -237,12 +239,12 @@ msgid "" "equal\n" " > greater then, < less then\n" " And to connect these expressions, the operators:\n" -" and and or. Keep in mind the \"or\" is a \"true " -"or\", not the way it often is used in language, it is not an \"either or\". " -"On this \"or\" both can be true.\n" +" and and or. Keep in mind the \"or\" is a \"true or" +"\", not the way it often is used in language, it is not an \"either or\". On " +"this \"or\" both can be true.\n" " There are other also useful operators, that can be used you can find them " -"under expr-eval.\n" +"under expr-eval.\n" " But the ones introduced here, should be enough to write decent notification " "logic and should cover most use cases." msgstr "" @@ -291,44 +293,44 @@ msgstr "Gebe HIER diene Stimme für das beliebteste Kommandomitglied ab." msgid "Browser" msgstr "Browser" -#: templates/index.html:172 +#: templates/index.html:173 msgid "Test TS" msgstr "Teste TS" -#: templates/index.html:175 +#: templates/index.html:177 msgid "Leave Waitlists" msgstr "Warteliste verlassen" -#: templates/index.html:192 templates/settings/fleet.html:111 +#: templates/index.html:194 templates/settings/fleet.html:111 msgid "Fleet Manager" msgstr "Flotten Verwalter" -#: templates/index.html:208 templates/settings/fleet.html:134 +#: templates/index.html:210 templates/settings/fleet.html:134 msgid "Constellation" msgstr "Konstellation" -#: templates/index.html:213 templates/settings/fleet.html:146 +#: templates/index.html:215 templates/settings/fleet.html:146 msgid "Dockup" msgstr "Basis" -#: templates/index.html:218 +#: templates/index.html:220 msgid "HQ System" msgstr "HQ System" -#: templates/index.html:230 +#: templates/index.html:232 #, python-format msgid "" "This waitlist is currently closed however\n" " another is open!" msgstr "" -"Diese Warteliste ist momentan geschlossen, es ist jedoch eine andere Wartelist offen." +"Diese Warteliste ist momentan geschlossen, es ist jedoch eine andere Wartelist offen." -#: templates/index.html:242 waitlist/blueprints/calendar/__init__.py:7 +#: templates/index.html:244 waitlist/blueprints/calendar/__init__.py:7 msgid "Events" msgstr "Veranstaltungen" -#: templates/index.html:258 +#: templates/index.html:260 #, python-format msgid "" "Help us! We would like your feedbackHilf uns! Wir hätten gerne Rückmedlung von dir!" -#: templates/index.html:278 templates/xup-form.html:64 +#: templates/index.html:280 templates/xup-form.html:66 msgid "All Waitlists are closed!" msgstr "Alle Wartelisten sind geschlossen!" @@ -362,53 +364,53 @@ msgstr "Ich bin neu bei %(title)s oder Sansha-Überfällen" msgid "Fleet to x-up for" msgstr "Flotte für die man sich einschreibt" -#: templates/xup-form.html:33 +#: templates/xup-form.html:34 msgid "Poke me on TS (exact charactername required, case sensitive)" msgstr "" "Auf TS anstupsen (exakter Name wie im Spiel benötigt, Groß-/Kleinschreibung " "beachten)" -#: templates/xup-form.html:36 +#: templates/xup-form.html:38 msgid "Fittings" msgstr "Ausrüstungen" -#: templates/xup-form.html:40 +#: templates/xup-form.html:42 msgid "Caldari Battleship Level" msgstr "Caldari Kampfschiff Level" -#: templates/xup-form.html:42 +#: templates/xup-form.html:44 msgid "No Caldari BS" msgstr "Kein Caldari Kampfschiff" -#: templates/xup-form.html:43 templates/xup-form.html:58 +#: templates/xup-form.html:45 templates/xup-form.html:60 msgid "1" msgstr "1" -#: templates/xup-form.html:44 templates/xup-form.html:57 +#: templates/xup-form.html:46 templates/xup-form.html:59 msgid "2" msgstr "2" -#: templates/xup-form.html:45 templates/xup-form.html:56 +#: templates/xup-form.html:47 templates/xup-form.html:58 msgid "3" msgstr "3" -#: templates/xup-form.html:46 templates/xup-form.html:55 +#: templates/xup-form.html:48 templates/xup-form.html:57 msgid "4" msgstr "4" -#: templates/xup-form.html:47 templates/xup-form.html:54 +#: templates/xup-form.html:49 templates/xup-form.html:56 msgid "5" msgstr "5" -#: templates/xup-form.html:51 +#: templates/xup-form.html:53 msgid "Logistic Cruiser Level" msgstr "Logistikkreuzer Stufe" -#: templates/xup-form.html:53 +#: templates/xup-form.html:55 msgid "No Logi" msgstr "Kein Support" -#: templates/xup-form.html:61 +#: templates/xup-form.html:63 msgid "Enter On Waitlist" msgstr "Einschreiben" @@ -493,6 +495,9 @@ msgstr "Bestätigen" #: templates/settings/base.html:3 templates/settings/ccvotes.html:3 #: templates/settings/fleet.html:3 templates/settings/mail/index.html:3 #: templates/settings/permissions/config.html:3 templates/settings/sde.html:3 +#: templates/settings/ship_assignment/check_edit.html:3 +#: templates/settings/ship_assignment/collection_edit.html:3 +#: templates/settings/ship_assignment/collection_list.html:3 #: templates/settings/ts.html:3 templates/settings/whitelist.html:3 #: waitlist/utility/mainmenu/config_loader.py:181 msgid "Settings" @@ -529,7 +534,9 @@ msgstr "Bevorstehende Veranstaltungen" #: templates/calendar/settings.html:54 templates/feedback/settings.html:18 #: templates/settings/accounts.html:122 templates/settings/bans.html:49 -#: templates/settings/fleet.html:209 templates/settings/whitelist.html:49 +#: templates/settings/fleet.html:209 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/settings/whitelist.html:49 #: templates/waitlist/tools/history_search.html:48 msgid "Actions" msgstr "Aktionen" @@ -736,11 +743,13 @@ msgstr "Ausdrucksziel" #: templates/notifications/alarm.html:42 #: templates/settings/permissions/config.html:27 +#: templates/settings/ship_assignment/collection_list.html:57 msgid "Add" msgstr "Hinzufügen" -#: templates/notifications/alarm.html:49 templates/waitlist/history.html:39 -#: templates/waitlist/history_cut.html:43 +#: templates/notifications/alarm.html:49 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/waitlist/history.html:39 templates/waitlist/history_cut.html:43 #: templates/waitlist/tools/history_search.html:99 msgid "Target" msgstr "Ziel" @@ -897,7 +906,9 @@ msgstr "Begründung" msgid "Ban" msgstr "Sperre" -#: templates/settings/bans.html:31 templates/settings/whitelist.html:31 +#: templates/settings/bans.html:31 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/settings/whitelist.html:31 msgid "Name" msgstr "Name" @@ -957,8 +968,9 @@ msgstr "Die Wartelisten dieser Gruppe leeren!" msgid "Display Name" msgstr "Anzeigename" -#: templates/settings/fleet.html:50 templates/waitlist/ccvote.html:26 -#: templates/waitlist/ccvote.html:35 +#: templates/settings/fleet.html:50 +#: templates/settings/ship_assignment/collection_edit.html:58 +#: templates/waitlist/ccvote.html:26 templates/waitlist/ccvote.html:35 msgid "Please Select" msgstr "Bitte auswählen" @@ -1042,6 +1054,7 @@ msgstr "Niemand" #: templates/settings/fleet.html:216 #: templates/settings/permissions/config.html:39 +#: templates/settings/ship_assignment/collection_list.html:71 msgid "Remove" msgstr "Entfernen" @@ -1315,6 +1328,139 @@ msgstr "Rollen Anzeigename" msgid "Permission" msgstr "Recht" +#: templates/settings/ship_assignment/check_edit.html:3 +msgid "Ship Check Edit" +msgstr "Schiffsüberprüfung Ändern" + +#: templates/settings/ship_assignment/check_edit.html:18 +#: templates/settings/ship_assignment/collection_edit.html:52 +msgid "Check Name" +msgstr "Prüfungs-Name" + +#: templates/settings/ship_assignment/check_edit.html:22 +#: templates/settings/ship_assignment/collection_edit.html:56 +msgid "Check Type" +msgstr "Prüfungs-Typ" + +#: templates/settings/ship_assignment/check_edit.html:30 +#: templates/settings/ship_assignment/collection_edit.html:65 +msgid "Check Target" +msgstr "Prüfungs-Ziel" + +#: templates/settings/ship_assignment/check_edit.html:38 +#: templates/settings/ship_assignment/collection_edit.html:73 +msgid "Check Order" +msgstr "Prüfungs-Rang" + +#: templates/settings/ship_assignment/check_edit.html:42 +#: templates/settings/ship_assignment/collection_edit.html:77 +msgid "Check Modifier" +msgstr "Prüfungs-Wert" + +#: templates/settings/ship_assignment/check_edit.html:46 +#: templates/settings/ship_assignment/collection_edit.html:81 +msgid "IDs comma seperated" +msgstr "IDs mit Komma getrennt" + +#: templates/settings/ship_assignment/check_edit.html:50 +#: templates/settings/ship_assignment/collection_edit.html:85 +msgid "Restrict by Type" +msgstr "Auf Inventar-Arten einschränken" + +#: templates/settings/ship_assignment/check_edit.html:54 +#: templates/settings/ship_assignment/collection_edit.html:89 +msgid "Restrict by Inventory Group" +msgstr "Auf Inventar-Gruppen einschränken" + +#: templates/settings/ship_assignment/check_edit.html:58 +#: templates/settings/ship_assignment/collection_edit.html:93 +msgid "Restrict by Market Group" +msgstr "Auf Markt-Gruppen einschränken" + +#: templates/settings/ship_assignment/check_edit.html:62 +#: templates/settings/ship_assignment/collection_edit.html:97 +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Tag" +msgstr "Etikett" + +#: templates/settings/ship_assignment/check_edit.html:65 +msgid "Change Check" +msgstr "Prüfung Ändern" + +#: templates/settings/ship_assignment/collection_edit.html:3 +#: templates/settings/ship_assignment/collection_list.html:3 +msgid "Ship Classification Selection" +msgstr "Schiffszuweisungsauswahl" + +#: templates/settings/ship_assignment/collection_edit.html:18 +#: templates/settings/ship_assignment/collection_list.html:17 +#: templates/settings/ship_assignment/collection_list.html:31 +msgid "Collection Name" +msgstr "Gruppierungsname" + +#: templates/settings/ship_assignment/collection_edit.html:30 +#: templates/settings/ship_assignment/collection_list.html:43 +msgid "Target if no rule matches" +msgstr "Ziel wenn keine Prüfung zutrifft" + +#: templates/settings/ship_assignment/collection_edit.html:41 +#: templates/settings/ship_assignment/collection_list.html:54 +msgid "Default Tag" +msgstr "Standard Etikett" + +#: templates/settings/ship_assignment/collection_edit.html:44 +msgid "Change Collection Information" +msgstr "Gruppierungsinformation ändern" + +#: templates/settings/ship_assignment/collection_edit.html:100 +msgid "Add Check" +msgstr "Prüfung Hinzufügen" + +#: templates/settings/ship_assignment/collection_edit.html:107 +msgid "Check to Delete" +msgstr "Zu löschende Prüfung" + +#: templates/settings/ship_assignment/collection_edit.html:114 +msgid "Delete Check" +msgstr "Lösche Prüfung" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Type" +msgstr "Art" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Order" +msgstr "Sortierreihenfolge" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "modifier" +msgstr "Wert" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "TypeIDs" +msgstr "Art IDs" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by Type" +msgstr "E per Art" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by InvGroup" +msgstr "E per Inv-Gruppe" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by Market Group" +msgstr "E per Markt-Gruppe" + +#: templates/settings/ship_assignment/collection_edit.html:126 +#: templates/settings/ship_assignment/collection_list.html:24 +msgid "Edit" +msgstr "Ändern" + +#: templates/settings/ship_assignment/collection_list.html:35 +msgid "Group" +msgstr "Gruppe" + #: templates/trivia/index.html:3 #, python-format msgid "This trivia runs from %(fromtime)s to %(totime)s" @@ -1468,7 +1614,7 @@ msgstr "Bis" msgid "Get Info" msgstr "Lade Info" -#: waitlist/blueprints/__init__.py:107 +#: waitlist/blueprints/__init__.py:108 msgid "Tokens where removed, please use the EVE SSO" msgstr "Zugangsschlüssel wurden entfernt, bitte benutzen den EVE SSO Login" @@ -1543,7 +1689,7 @@ msgstr "Die Aktion konnte nicht durchgeführt werden, ApiException %(ex)s" #, python-format msgid "Character with name %(char_name)s could not be found!" msgstr "" -"Ein Charakter mit dem Namen $(char_name)s konnte nicht gefunden werden!" +"Ein Charakter mit dem Namen %(char_name)s konnte nicht gefunden werden!" #: waitlist/blueprints/settings/accounts.py:380 msgid "Failed to get info for this character because of sso error" @@ -1764,6 +1910,10 @@ msgstr "" "Es gab einen Fehler während versucht wurde die Rolle mit id=%(role_id)d zu " "löschen" +#: waitlist/blueprints/settings/ship_assignment.py:242 +msgid "Ship Classification" +msgstr "Schiffszuteilungen" + #: waitlist/blueprints/settings/staticdataimport.py:38 msgid "Type IDs were updated!" msgstr "Typen IDs wurde geupdatet!" @@ -1784,7 +1934,7 @@ msgstr "Stationen wurde geupdatet!" msgid "Layouts were updated!" msgstr "Aufbaudaten wurden geupdatet!" -#: waitlist/blueprints/settings/teamspeak.py:99 +#: waitlist/blueprints/settings/teamspeak.py:105 msgid "TS Settings" msgstr "TS Einstellungen" @@ -1796,21 +1946,22 @@ msgstr "" "Danke für deine Teilnahme, die Gewinner werden bekannt gegeben nachdem das " "Quiz beendet wurde." -#: waitlist/blueprints/xup/submission.py:54 +#: waitlist/blueprints/xup/submission.py:55 msgid "X-UP is disabled!!!" msgstr "Einschreibung ist Deaktiviert" -#: waitlist/blueprints/xup/submission.py:80 -msgid "Valid entries are scruffy [dps|logi|sniper,..]" -msgstr "Erlaubte Einträge sind: scruffy [dps|logi|sniper,..]" +#: waitlist/blueprints/xup/submission.py:82 +#, python-format +msgid "Valid entries are scruffy %(types)s" +msgstr "Erlaubte Einträge sind: scruffy %(types)s" -#: waitlist/blueprints/xup/submission.py:116 +#: waitlist/blueprints/xup/submission.py:129 #, python-format msgid "You were added as %(ship_type)s" msgstr "Du wurdest als %(ship_type)s hinzugefügt" -#: waitlist/blueprints/xup/submission.py:210 -#: waitlist/blueprints/xup/submission.py:336 +#: waitlist/blueprints/xup/submission.py:223 +#: waitlist/blueprints/xup/submission.py:295 #, python-format msgid "" "You submitted one fit to be check by a fleet comp before getting on the " @@ -1825,6 +1976,26 @@ msgstr[1] "" "Du hast %(num)d Ausrüstungen zur Überprüfung durch einen Flotten-Verwalter " "gesendet, bevor du auf die Warteliste gesetzt wirst." +#: waitlist/utility/constants/check_types.py:10 +msgid "Hull by TypeId" +msgstr "Hülle per Arten-ID" + +#: waitlist/utility/constants/check_types.py:11 +msgid "Hull by Inventory Group" +msgstr "Hülle per Inventar-Gruppe" + +#: waitlist/utility/constants/check_types.py:12 +msgid "Hull by Market Group" +msgstr "Hülle per Markt-Gruppe" + +#: waitlist/utility/constants/check_types.py:13 +msgid "Module by TypeId" +msgstr "Modul per Art-ID" + +#: waitlist/utility/constants/check_types.py:14 +msgid "Module by Market Group" +msgstr "Modul per Markt-Gruppe" + #: waitlist/utility/flask/__init__.py:76 #, python-format msgid "" @@ -1881,4 +2052,3 @@ msgstr "Verwaltungsverlauf" #: waitlist/utility/mainmenu/config_loader.py:185 msgid "Not loggedin" msgstr "Abgemeldet" - diff --git a/translations/en/LC_MESSAGES/messages.po b/translations/en/LC_MESSAGES/messages.po index 3891e5e0..212177f9 100644 --- a/translations/en/LC_MESSAGES/messages.po +++ b/translations/en/LC_MESSAGES/messages.po @@ -4,16 +4,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2019-04-15 12:35+0200\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-04-15 10:46+0000\n" +"POT-Creation-Date: 2019-04-27 21:26+0200\n" +"PO-Revision-Date: 2019-04-27 21:28+0200\n" "Last-Translator: Constantin Wenger \n" "Language-Team: English\n" "Language: en\n" -"X-Generator: Zanata 4.6.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #: config/themes.example.json msgid "Standard" @@ -29,23 +29,23 @@ msgstr "Dark Purple" #: templates/about.html:15 msgid "" -"Eve-Inc-Waitlist Created by Bruce " -"Warhead and Beryl Slanjava" +"Eve-Inc-Waitlist Created by Bruce Warhead and Beryl Slanjava" msgstr "" -"Eve-Inc-Waitlist Created by Bruce " -"Warhead and Beryl Slanjava" +"Eve-Inc-Waitlist Created by Bruce Warhead and Beryl Slanjava" #: templates/about.html:17 msgid "" "Fitting " -"Display (Eve-UI) and Fitting Stats by Quie'scens" +"Display (Eve-UI) and Fitting Stats by Quie'scens" msgstr "" "Fitting " -"Display (Eve-UI) and Fitting Stats by Quie'scens" +"Display (Eve-UI) and Fitting Stats by Quie'scens" #: templates/base.html:88 msgid "ISK Donations are appreciated" @@ -99,16 +99,16 @@ msgstr "How do Alarm Expressions work?" #: templates/help.html:40 msgid "" -"For expression evaluation expr-eval is used.\n" +"For expression evaluation expr-eval is used.\n" " The variables, open, xup, logi, dps, sniper, other are " "provided, open being a boolean(true/false) while the others are numbers.\n" " You can have one expression per Waitlist Group, there is no need for more " "then one, because using (expression) or (expression) would be the same as " "using two expression for one group." msgstr "" -"For expression evaluation expr-eval is used.\n" +"For expression evaluation expr-eval is used.\n" " The variables, open, xup, logi, dps, sniper, other are " "provided, open being a boolean(true/false) while the others are numbers.\n" " You can have one expression per Waitlist Group, there is no need for more " @@ -234,12 +234,12 @@ msgid "" "equal\n" " > greater then, < less then\n" " And to connect these expressions, the operators:\n" -" and and or. Keep in mind the \"or\" is a \"true " -"or\", not the way it often is used in language, it is not an \"either or\". " -"On this \"or\" both can be true.\n" +" and and or. Keep in mind the \"or\" is a \"true or" +"\", not the way it often is used in language, it is not an \"either or\". On " +"this \"or\" both can be true.\n" " There are other also useful operators, that can be used you can find them " -"under expr-eval.\n" +"under expr-eval.\n" " But the ones introduced here, should be enough to write decent notification " "logic and should cover most use cases." msgstr "" @@ -248,12 +248,12 @@ msgstr "" "equal\n" " > greater then, < less then\n" " And to connect these expressions, the operators:\n" -" and and or. Keep in mind the \"or\" is a \"true " -"or\", not the way it often is used in language, it is not an \"either or\". " -"On this \"or\" both can be true.\n" +" and and or. Keep in mind the \"or\" is a \"true or" +"\", not the way it often is used in language, it is not an \"either or\". On " +"this \"or\" both can be true.\n" " There are other also useful operators, that can be used you can find them " -"under expr-eval.\n" +"under expr-eval.\n" " But the ones introduced here, should be enough to write decent notification " "logic and should cover most use cases." @@ -288,31 +288,31 @@ msgstr "Vote your favorite Command Core Member HERE" msgid "Browser" msgstr "Browser" -#: templates/index.html:172 +#: templates/index.html:173 msgid "Test TS" msgstr "Test TS" -#: templates/index.html:175 +#: templates/index.html:177 msgid "Leave Waitlists" msgstr "Leave Waitlists" -#: templates/index.html:192 templates/settings/fleet.html:111 +#: templates/index.html:194 templates/settings/fleet.html:111 msgid "Fleet Manager" msgstr "Fleet Manager" -#: templates/index.html:208 templates/settings/fleet.html:134 +#: templates/index.html:210 templates/settings/fleet.html:134 msgid "Constellation" msgstr "Constellation" -#: templates/index.html:213 templates/settings/fleet.html:146 +#: templates/index.html:215 templates/settings/fleet.html:146 msgid "Dockup" msgstr "Dockup" -#: templates/index.html:218 +#: templates/index.html:220 msgid "HQ System" msgstr "HQ System" -#: templates/index.html:230 +#: templates/index.html:232 #, python-format msgid "" "This waitlist is currently closed however\n" @@ -321,11 +321,11 @@ msgstr "" "This waitlist is currently closed however\n" " another is open!" -#: templates/index.html:242 waitlist/blueprints/calendar/__init__.py:7 +#: templates/index.html:244 waitlist/blueprints/calendar/__init__.py:7 msgid "Events" msgstr "Events" -#: templates/index.html:258 +#: templates/index.html:260 #, python-format msgid "" "Help us! We would like your feedbackHelp us! We would like your feedback!" -#: templates/index.html:278 templates/xup-form.html:64 +#: templates/index.html:280 templates/xup-form.html:66 msgid "All Waitlists are closed!" msgstr "All Waitlists are closed!" @@ -359,51 +359,51 @@ msgstr "I am new to %(title)s or Incursions" msgid "Fleet to x-up for" msgstr "Fleet to x-up for" -#: templates/xup-form.html:33 +#: templates/xup-form.html:34 msgid "Poke me on TS (exact charactername required, case sensitive)" msgstr "Poke me on TS (exact charactername required, case sensitive)" -#: templates/xup-form.html:36 +#: templates/xup-form.html:38 msgid "Fittings" msgstr "Fittings" -#: templates/xup-form.html:40 +#: templates/xup-form.html:42 msgid "Caldari Battleship Level" msgstr "Caldari Battleship Level" -#: templates/xup-form.html:42 +#: templates/xup-form.html:44 msgid "No Caldari BS" msgstr "No Caldari BS" -#: templates/xup-form.html:43 templates/xup-form.html:58 +#: templates/xup-form.html:45 templates/xup-form.html:60 msgid "1" msgstr "1" -#: templates/xup-form.html:44 templates/xup-form.html:57 +#: templates/xup-form.html:46 templates/xup-form.html:59 msgid "2" msgstr "2" -#: templates/xup-form.html:45 templates/xup-form.html:56 +#: templates/xup-form.html:47 templates/xup-form.html:58 msgid "3" msgstr "3" -#: templates/xup-form.html:46 templates/xup-form.html:55 +#: templates/xup-form.html:48 templates/xup-form.html:57 msgid "4" msgstr "4" -#: templates/xup-form.html:47 templates/xup-form.html:54 +#: templates/xup-form.html:49 templates/xup-form.html:56 msgid "5" msgstr "5" -#: templates/xup-form.html:51 +#: templates/xup-form.html:53 msgid "Logistic Cruiser Level" msgstr "Logistic Cruiser Level" -#: templates/xup-form.html:53 +#: templates/xup-form.html:55 msgid "No Logi" msgstr "No Logi" -#: templates/xup-form.html:61 +#: templates/xup-form.html:63 msgid "Enter On Waitlist" msgstr "Enter On Waitlist" @@ -488,6 +488,9 @@ msgstr "Authenticate" #: templates/settings/base.html:3 templates/settings/ccvotes.html:3 #: templates/settings/fleet.html:3 templates/settings/mail/index.html:3 #: templates/settings/permissions/config.html:3 templates/settings/sde.html:3 +#: templates/settings/ship_assignment/check_edit.html:3 +#: templates/settings/ship_assignment/collection_edit.html:3 +#: templates/settings/ship_assignment/collection_list.html:3 #: templates/settings/ts.html:3 templates/settings/whitelist.html:3 #: waitlist/utility/mainmenu/config_loader.py:181 msgid "Settings" @@ -524,7 +527,9 @@ msgstr "Outstanding Events" #: templates/calendar/settings.html:54 templates/feedback/settings.html:18 #: templates/settings/accounts.html:122 templates/settings/bans.html:49 -#: templates/settings/fleet.html:209 templates/settings/whitelist.html:49 +#: templates/settings/fleet.html:209 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/settings/whitelist.html:49 #: templates/waitlist/tools/history_search.html:48 msgid "Actions" msgstr "Actions" @@ -731,11 +736,13 @@ msgstr "Expression Target" #: templates/notifications/alarm.html:42 #: templates/settings/permissions/config.html:27 +#: templates/settings/ship_assignment/collection_list.html:57 msgid "Add" msgstr "Add" -#: templates/notifications/alarm.html:49 templates/waitlist/history.html:39 -#: templates/waitlist/history_cut.html:43 +#: templates/notifications/alarm.html:49 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/waitlist/history.html:39 templates/waitlist/history_cut.html:43 #: templates/waitlist/tools/history_search.html:99 msgid "Target" msgstr "Target" @@ -892,7 +899,9 @@ msgstr "Reason" msgid "Ban" msgstr "Ban" -#: templates/settings/bans.html:31 templates/settings/whitelist.html:31 +#: templates/settings/bans.html:31 +#: templates/settings/ship_assignment/collection_edit.html:120 +#: templates/settings/whitelist.html:31 msgid "Name" msgstr "Name" @@ -952,8 +961,9 @@ msgstr "Clear This Groups lists!" msgid "Display Name" msgstr "Display Name" -#: templates/settings/fleet.html:50 templates/waitlist/ccvote.html:26 -#: templates/waitlist/ccvote.html:35 +#: templates/settings/fleet.html:50 +#: templates/settings/ship_assignment/collection_edit.html:58 +#: templates/waitlist/ccvote.html:26 templates/waitlist/ccvote.html:35 msgid "Please Select" msgstr "Please Select" @@ -1037,6 +1047,7 @@ msgstr "None" #: templates/settings/fleet.html:216 #: templates/settings/permissions/config.html:39 +#: templates/settings/ship_assignment/collection_list.html:71 msgid "Remove" msgstr "Remove" @@ -1308,6 +1319,139 @@ msgstr "Role Display Name" msgid "Permission" msgstr "Permission" +#: templates/settings/ship_assignment/check_edit.html:3 +msgid "Ship Check Edit" +msgstr "Ship Check Edit" + +#: templates/settings/ship_assignment/check_edit.html:18 +#: templates/settings/ship_assignment/collection_edit.html:52 +msgid "Check Name" +msgstr "Check Name" + +#: templates/settings/ship_assignment/check_edit.html:22 +#: templates/settings/ship_assignment/collection_edit.html:56 +msgid "Check Type" +msgstr "Check Type" + +#: templates/settings/ship_assignment/check_edit.html:30 +#: templates/settings/ship_assignment/collection_edit.html:65 +msgid "Check Target" +msgstr "Check Target" + +#: templates/settings/ship_assignment/check_edit.html:38 +#: templates/settings/ship_assignment/collection_edit.html:73 +msgid "Check Order" +msgstr "Check Order" + +#: templates/settings/ship_assignment/check_edit.html:42 +#: templates/settings/ship_assignment/collection_edit.html:77 +msgid "Check Modifier" +msgstr "Check Modifier" + +#: templates/settings/ship_assignment/check_edit.html:46 +#: templates/settings/ship_assignment/collection_edit.html:81 +msgid "IDs comma seperated" +msgstr "IDs comma seperated" + +#: templates/settings/ship_assignment/check_edit.html:50 +#: templates/settings/ship_assignment/collection_edit.html:85 +msgid "Restrict by Type" +msgstr "Restrict by Type" + +#: templates/settings/ship_assignment/check_edit.html:54 +#: templates/settings/ship_assignment/collection_edit.html:89 +msgid "Restrict by Inventory Group" +msgstr "Restrict by Inventory Group" + +#: templates/settings/ship_assignment/check_edit.html:58 +#: templates/settings/ship_assignment/collection_edit.html:93 +msgid "Restrict by Market Group" +msgstr "Restrict by Market Group" + +#: templates/settings/ship_assignment/check_edit.html:62 +#: templates/settings/ship_assignment/collection_edit.html:97 +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Tag" +msgstr "Tag" + +#: templates/settings/ship_assignment/check_edit.html:65 +msgid "Change Check" +msgstr "Change Check" + +#: templates/settings/ship_assignment/collection_edit.html:3 +#: templates/settings/ship_assignment/collection_list.html:3 +msgid "Ship Classification Selection" +msgstr "Ship Classification Selection" + +#: templates/settings/ship_assignment/collection_edit.html:18 +#: templates/settings/ship_assignment/collection_list.html:17 +#: templates/settings/ship_assignment/collection_list.html:31 +msgid "Collection Name" +msgstr "Collection Name" + +#: templates/settings/ship_assignment/collection_edit.html:30 +#: templates/settings/ship_assignment/collection_list.html:43 +msgid "Target if no rule matches" +msgstr "Target if no rule matches" + +#: templates/settings/ship_assignment/collection_edit.html:41 +#: templates/settings/ship_assignment/collection_list.html:54 +msgid "Default Tag" +msgstr "Default Tag" + +#: templates/settings/ship_assignment/collection_edit.html:44 +msgid "Change Collection Information" +msgstr "Change Collection Information" + +#: templates/settings/ship_assignment/collection_edit.html:100 +msgid "Add Check" +msgstr "Add Check" + +#: templates/settings/ship_assignment/collection_edit.html:107 +msgid "Check to Delete" +msgstr "Check to Delete" + +#: templates/settings/ship_assignment/collection_edit.html:114 +msgid "Delete Check" +msgstr "Delete Check" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Type" +msgstr "Type" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "Order" +msgstr "Order" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "modifier" +msgstr "Value" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "TypeIDs" +msgstr "TypeIDs" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by Type" +msgstr "R by Type" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by InvGroup" +msgstr "R by InvGroup" + +#: templates/settings/ship_assignment/collection_edit.html:120 +msgid "R by Market Group" +msgstr "R by Market Group" + +#: templates/settings/ship_assignment/collection_edit.html:126 +#: templates/settings/ship_assignment/collection_list.html:24 +msgid "Edit" +msgstr "Edit" + +#: templates/settings/ship_assignment/collection_list.html:35 +msgid "Group" +msgstr "Group" + #: templates/trivia/index.html:3 #, python-format msgid "This trivia runs from %(fromtime)s to %(totime)s" @@ -1459,7 +1603,7 @@ msgstr "To" msgid "Get Info" msgstr "Get Info" -#: waitlist/blueprints/__init__.py:107 +#: waitlist/blueprints/__init__.py:108 msgid "Tokens where removed, please use the EVE SSO" msgstr "Tokens where removed, please use the EVE SSO" @@ -1738,6 +1882,10 @@ msgstr "Role with id=%(role_id)d was deleted" msgid "There was an unknown error deleting Role with id=%(role_id)d" msgstr "There was an unknown error deleting Role with id=%(role_id)d" +#: waitlist/blueprints/settings/ship_assignment.py:242 +msgid "Ship Classification" +msgstr "Ship Classification" + #: waitlist/blueprints/settings/staticdataimport.py:38 msgid "Type IDs were updated!" msgstr "Type IDs were updated!" @@ -1758,7 +1906,7 @@ msgstr "Stations were updated!" msgid "Layouts were updated!" msgstr "Layouts were updated!" -#: waitlist/blueprints/settings/teamspeak.py:99 +#: waitlist/blueprints/settings/teamspeak.py:105 msgid "TS Settings" msgstr "TS Settings" @@ -1770,21 +1918,22 @@ msgstr "" "Thank you for participating, winners will be announced after the trivia is " "finished" -#: waitlist/blueprints/xup/submission.py:54 +#: waitlist/blueprints/xup/submission.py:55 msgid "X-UP is disabled!!!" msgstr "X-UP is disabled!!!" -#: waitlist/blueprints/xup/submission.py:80 -msgid "Valid entries are scruffy [dps|logi|sniper,..]" -msgstr "Valid entries are scruffy [dps|logi|sniper,..]" +#: waitlist/blueprints/xup/submission.py:82 +#, python-format +msgid "Valid entries are scruffy %(types)s" +msgstr "Valid entries are scruffy %(types)s" -#: waitlist/blueprints/xup/submission.py:116 +#: waitlist/blueprints/xup/submission.py:129 #, python-format msgid "You were added as %(ship_type)s" msgstr "You were added as %(ship_type)s" -#: waitlist/blueprints/xup/submission.py:210 -#: waitlist/blueprints/xup/submission.py:336 +#: waitlist/blueprints/xup/submission.py:223 +#: waitlist/blueprints/xup/submission.py:295 #, python-format msgid "" "You submitted one fit to be check by a fleet comp before getting on the " @@ -1799,6 +1948,26 @@ msgstr[1] "" "You submitted %(num)d fits to be check by a fleet comp before getting on the " "waitlist." +#: waitlist/utility/constants/check_types.py:10 +msgid "Hull by TypeId" +msgstr "Hull by TypeId" + +#: waitlist/utility/constants/check_types.py:11 +msgid "Hull by Inventory Group" +msgstr "Hull by Inventory Group" + +#: waitlist/utility/constants/check_types.py:12 +msgid "Hull by Market Group" +msgstr "Hull by Market Group" + +#: waitlist/utility/constants/check_types.py:13 +msgid "Module by TypeId" +msgstr "Module by TypeId" + +#: waitlist/utility/constants/check_types.py:14 +msgid "Module by Market Group" +msgstr "Module by Market Group" + #: waitlist/utility/flask/__init__.py:76 #, python-format msgid "" @@ -1854,4 +2023,3 @@ msgstr "Comp History" #: waitlist/utility/mainmenu/config_loader.py:185 msgid "Not loggedin" msgstr "Not loggedin" - From 60dbc058a6d0cbcf4ec0c6a85c19023126e7ded5 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Sat, 27 Apr 2019 21:35:04 +0200 Subject: [PATCH 17/22] updated version info --- CHANGELOG.md | 13 +++++++++++++ setup.py | 2 +- waitlist/data/version.py | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14edcd0e..7f2742a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,17 @@ #Changelog +* 1.7.0: + * Features: + * Added UI and Database based sorting and tagging of fits + * Added config option to have everyone banned by default, so only whitelisted characters have access + * Added config option to disable scruffy mode disable->scruffy_mode + * Improvements: + * Some messages and pages related to Teamspeak are now hidden if TS is disabled or no configuration set + * Implemented proper merging of base and user logger config because using pythons dictConfig really isn't very good + * If TS is disabled Teamspeak related pages do not show up anymore, if there is no active TS teamspeak related messages should not show anymore + * Changes: + * Updated minimum version of various python requirements + * Made werkzeug a fix version requirement since it broke between 0.14 and 0.15 also updated to 0.15.2 + * Waitlists on frontpage now use part of the with instead of 1/4th (which made the 5th go into another row) * 1.6.5: * Improvements: * Added import of market groups diff --git a/setup.py b/setup.py index 1bd6e625..0bed0934 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="EVE Incursion waitlist", - version="1.6.5", + version="1.7.0", author="SpeedProg", author_email="speedprogde@googlemail.com", description="Waitlist geared towards EveOnline Incursion Groups", diff --git a/waitlist/data/version.py b/waitlist/data/version.py index 52543f02..d5341a46 100644 --- a/waitlist/data/version.py +++ b/waitlist/data/version.py @@ -1 +1 @@ -version = "1.6.5-$Format:%h$" +version = "1.7.0-$Format:%h$" From 1c96bcd9cf3be6ff5d243332e71fa081209a2f70 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Mon, 29 Apr 2019 14:02:58 +0200 Subject: [PATCH 18/22] fixed sending data with 204 reponse --- waitlist/blueprints/api/ui/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waitlist/blueprints/api/ui/__init__.py b/waitlist/blueprints/api/ui/__init__.py index bd361745..1895c953 100644 --- a/waitlist/blueprints/api/ui/__init__.py +++ b/waitlist/blueprints/api/ui/__init__.py @@ -58,7 +58,7 @@ def post_esi_openwindow_newmail(): if response.is_error(): flask.abort(response.error(), response.code()) - return make_response('OK', response.code()) + return make_response('', response.code()) def handle_open_ui_sso_cb(tokens): From f55abb5d3fba2bf5c714a47c790c43b991aca0d0 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Mon, 29 Apr 2019 14:03:30 +0200 Subject: [PATCH 19/22] fixed having wrong title on help page --- templates/help.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/help.html b/templates/help.html index b02d8d77..e069f715 100644 --- a/templates/help.html +++ b/templates/help.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block title %}Settings{% endblock %} +{% block title %}Help{% endblock %} {% block head %} {{ super() }} From edcf6d090ba03f3ff1f96f6e3d5622bd8ce02ea1 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Mon, 29 Apr 2019 14:04:49 +0200 Subject: [PATCH 20/22] added ability to put the public api behind login --- waitlist/blueprints/api/waitlist.py | 16 +++++++++++++--- waitlist/utility/config.py | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/waitlist/blueprints/api/waitlist.py b/waitlist/blueprints/api/waitlist.py index c612b30b..ba706ee5 100644 --- a/waitlist/blueprints/api/waitlist.py +++ b/waitlist/blueprints/api/waitlist.py @@ -7,8 +7,9 @@ from flask import jsonify from waitlist.utility.json import make_json_groups, make_json_group, make_json_waitlists_base_data,\ make_json_waitlist_base_data +from waitlist.utility.config import disable_public_api import flask -from flask_login import current_user +from flask_login import current_user, login_required from flask.globals import request from flask_limiter.util import get_ipaddr from urllib.parse import urlencode @@ -17,6 +18,13 @@ logger = logging.getLogger(__name__) +def api_login_required(f): + """If we require login apply the check""" + if disable_public_api: + return login_required(f) + return f + + def get_ratekey_func_with_arguments(arglist): def ratekeyfunc(): addr = get_ipaddr() @@ -35,7 +43,8 @@ class WaitlistGroupsAPI(MethodView): decorators = [ limiter.limit("1/minute", key_func=get_ratekey_func_with_arguments(['group_id']), exempt_when=lambda: current_user.is_authenticated), - limiter.limit("5/minute", exempt_when=lambda: current_user.is_authenticated) + limiter.limit("5/minute", exempt_when=lambda: current_user.is_authenticated), + api_login_required ] @classmethod @@ -54,7 +63,8 @@ class WaitlistBaseDataAPI(MethodView): decorators = [ limiter.limit("1/minute", key_func=get_ratekey_func_with_arguments(['waitlist_id']), exempt_when=lambda: current_user.is_authenticated), - limiter.limit("5/minute", exempt_when=lambda: current_user.is_authenticated) + limiter.limit("5/minute", exempt_when=lambda: current_user.is_authenticated), + api_login_required ] @classmethod diff --git a/waitlist/utility/config.py b/waitlist/utility/config.py index acb387f9..def80e90 100644 --- a/waitlist/utility/config.py +++ b/waitlist/utility/config.py @@ -90,6 +90,7 @@ def set_if_not_exists(self, section, option, value): config.add_section("disable") config.set_if_not_exists("disable", "teamspeak", "False") config.set_if_not_exists("disable", "scruffy_mode", "True") +config.set_if_not_exists("disable", "public_api", "False") if not config.has_section("pageinfo"): config.add_section("pageinfo") @@ -141,6 +142,7 @@ def set_if_not_exists(self, section, option, value): disable_teamspeak = config.get("disable", "teamspeak") == "True" disable_scruffy_mode = config.get("disable", "scruffy_mode") == "True" +disable_public_api = config.get("disable", "public_api") == "True" influence_link = config.get("pageinfo", "influence_link") From ca1853d352bb2dd529380c7f9c359a2106e31ba2 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Mon, 29 Apr 2019 14:13:03 +0200 Subject: [PATCH 21/22] added community name from config file to the end of pagetitles --- templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/base.html b/templates/base.html index 17c9c679..728e44c8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -50,7 +50,7 @@ -{% block title %}{% endblock %} +{% block title %}{% endblock %}{%if title %} - {{title}}{% endif %} {% endblock %} {% set header_insert = get_header_insert() %} {% if header_insert is not none %} From 77b7f2df981f17e078915c4faf2cf96241b2ab75 Mon Sep 17 00:00:00 2001 From: SpeedProg Date: Mon, 29 Apr 2019 14:59:20 +0200 Subject: [PATCH 22/22] updated Changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f2742a0..ff8b58e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Added UI and Database based sorting and tagging of fits * Added config option to have everyone banned by default, so only whitelisted characters have access * Added config option to disable scruffy mode disable->scruffy_mode + * Added config option to disable public api access without login disable->public_api * Improvements: * Some messages and pages related to Teamspeak are now hidden if TS is disabled or no configuration set * Implemented proper merging of base and user logger config because using pythons dictConfig really isn't very good @@ -12,6 +13,10 @@ * Updated minimum version of various python requirements * Made werkzeug a fix version requirement since it broke between 0.14 and 0.15 also updated to 0.15.2 * Waitlists on frontpage now use part of the with instead of 1/4th (which made the 5th go into another row) + * Website titles now have the community_name config option at the end + * Fixes: + * Sending data with some from esi forwarded 204 response + * Wrong title on Help page * 1.6.5: * Improvements: * Added import of market groups