Fix many bugs related to GUI not receiving a correct timestamp, as well as extending feature out to all other fit entities.

This commit is contained in:
blitzmann
2017-05-07 02:02:54 -04:00
parent f9b7376cc7
commit 1604ea1f2c
8 changed files with 112 additions and 45 deletions

View File

@@ -18,11 +18,12 @@
# ===============================================================================
from sqlalchemy import Table, Column, Integer, ForeignKey, DateTime
from sqlalchemy.orm import mapper
from sqlalchemy.orm import mapper, relation
import sqlalchemy.sql.functions as func
from eos.db import saveddata_meta
from eos.saveddata.cargo import Cargo
from eos.saveddata.fit import Fit
cargo_table = Table("cargo", saveddata_meta,
Column("ID", Integer, primary_key=True),
@@ -33,4 +34,8 @@ cargo_table = Table("cargo", saveddata_meta,
Column("modified", DateTime, nullable=True, onupdate=func.now()),
)
mapper(Cargo, cargo_table)
mapper(Cargo, cargo_table,
properties={
"owner": relation(Fit)
}
)

View File

@@ -18,11 +18,12 @@
# ===============================================================================
from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean, DateTime
from sqlalchemy.orm import mapper
from sqlalchemy.orm import mapper, relation
import sqlalchemy.sql.functions as func
from eos.db import saveddata_meta
from eos.saveddata.drone import Drone
from eos.saveddata.fit import Fit
drones_table = Table("drones", saveddata_meta,
Column("groupID", Integer, primary_key=True),
@@ -35,4 +36,8 @@ drones_table = Table("drones", saveddata_meta,
Column("modified", DateTime, nullable=True, onupdate=func.now())
)
mapper(Drone, drones_table)
mapper(Drone, drones_table,
properties={
"owner": relation(Fit)
}
)

View File

@@ -58,8 +58,9 @@ fits_table = Table("fits", saveddata_meta,
Column("modeID", Integer, nullable=True),
Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT),
Column("notes", String, nullable=True),
Column("ignoreRestrictions", Boolean, default=0),
Column("created", DateTime, nullable=True, default=func.now()),
Column("modified", DateTime, nullable=True, onupdate=func.now())
Column("modified", DateTime, nullable=True, default=func.now(), onupdate=func.now())
)
projectedFits_table = Table("projectedFits", saveddata_meta,
@@ -142,49 +143,70 @@ es_Fit._Fit__commandFits = association_proxy(
"booster_fit", # .. and return the booster fit
creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit)
)
# These relationships are broken out so that we can easily access it in the events stuff
# We sometimes don't want particular relationships to cause a fit modified update (eg: projecting
# a fit onto another would 'modify' both fits unless the following relationship is ignored)
projectedFitSourceRel = relationship(
ProjectedFit,
primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID,
backref='source_fit',
collection_class=attribute_mapped_collection('victimID'),
cascade='all, delete, delete-orphan')
boostedOntoRel = relationship(
CommandFit,
primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID,
backref='booster_fit',
collection_class=attribute_mapped_collection('boostedID'),
cascade='all, delete, delete-orphan')
mapper(es_Fit, fits_table,
properties={
"_Fit__modules" : relation(
"_Fit__modules": relation(
Module,
collection_class=HandledModuleList,
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa
order_by=modules_table.c.position,
cascade='all, delete, delete-orphan'),
"_Fit__projectedModules" : relation(
"_Fit__projectedModules": relation(
Module,
collection_class=HandledProjectedModList,
cascade='all, delete, delete-orphan',
single_parent=True,
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa
"owner" : relation(
"owner": relation(
User,
backref="fits"),
"itemID" : fits_table.c.shipID,
"shipID" : fits_table.c.shipID,
"_Fit__boosters" : relation(
"itemID": fits_table.c.shipID,
"shipID": fits_table.c.shipID,
"_Fit__boosters": relation(
Booster,
collection_class=HandledImplantBoosterList,
cascade='all, delete, delete-orphan',
backref='owner',
single_parent=True),
"_Fit__drones" : relation(
"_Fit__drones": relation(
Drone,
collection_class=HandledDroneCargoList,
cascade='all, delete, delete-orphan',
single_parent=True,
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa
"_Fit__fighters" : relation(
"_Fit__fighters": relation(
Fighter,
collection_class=HandledDroneCargoList,
cascade='all, delete, delete-orphan',
single_parent=True,
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa
"_Fit__cargo" : relation(
"_Fit__cargo": relation(
Cargo,
collection_class=HandledDroneCargoList,
cascade='all, delete, delete-orphan',
single_parent=True,
primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)),
"_Fit__projectedDrones" : relation(
"_Fit__projectedDrones": relation(
Drone,
collection_class=HandledProjectedDroneList,
cascade='all, delete, delete-orphan',
@@ -196,46 +218,36 @@ mapper(es_Fit, fits_table,
cascade='all, delete, delete-orphan',
single_parent=True,
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa
"_Fit__implants" : relation(
"_Fit__implants": relation(
Implant,
collection_class=HandledImplantBoosterList,
cascade='all, delete, delete-orphan',
backref='fit',
backref='owner',
single_parent=True,
primaryjoin=fitImplants_table.c.fitID == fits_table.c.ID,
secondaryjoin=fitImplants_table.c.implantID == Implant.ID,
secondary=fitImplants_table),
"_Fit__character" : relation(
"_Fit__character": relation(
Character,
backref="fits"),
"_Fit__damagePattern" : relation(DamagePattern),
"_Fit__targetResists" : relation(TargetResists),
"projectedOnto" : relationship(
ProjectedFit,
primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID,
backref='source_fit',
collection_class=attribute_mapped_collection('victimID'),
cascade='all, delete, delete-orphan'),
"victimOf" : relationship(
"_Fit__damagePattern": relation(DamagePattern),
"_Fit__targetResists": relation(TargetResists),
"projectedOnto": projectedFitSourceRel,
"victimOf": relationship(
ProjectedFit,
primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID,
backref='victim_fit',
collection_class=attribute_mapped_collection('sourceID'),
cascade='all, delete, delete-orphan'),
"boostedOnto" : relationship(
CommandFit,
primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID,
backref='booster_fit',
collection_class=attribute_mapped_collection('boostedID'),
cascade='all, delete, delete-orphan'),
"boostedOf" : relationship(
"boostedOnto": boostedOntoRel,
"boostedOf": relationship(
CommandFit,
primaryjoin=fits_table.c.ID == commandFits_table.c.boostedID,
backref='boosted_fit',
collection_class=attribute_mapped_collection('boosterID'),
cascade='all, delete, delete-orphan'),
}
)
)
mapper(ProjectedFit, projectedFits_table,
properties={
@@ -244,5 +256,3 @@ mapper(ProjectedFit, projectedFits_table,
)
mapper(CommandFit, commandFits_table)

View File

@@ -2,9 +2,22 @@
import datetime
from sqlalchemy.event import listen
from sqlalchemy.orm.collections import InstrumentedList
from eos.db.saveddata.fit import projectedFitSourceRel, boostedOntoRel
from eos.saveddata.fit import Fit
from eos.saveddata.module import Module
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.cargo import Cargo
from eos.saveddata.implant import Implant
from eos.saveddata.booster import Booster
ignored_rels = [
projectedFitSourceRel,
boostedOntoRel
]
def update_fit_modified(target, value, oldvalue, initiator):
@@ -12,18 +25,29 @@ def update_fit_modified(target, value, oldvalue, initiator):
return
if value != oldvalue:
print "{} had a change via {}".format(target.owner, target)
target.owner.modified = datetime.datetime.now()
# some things (like Implants) have a backref to the fit, which actually produces a list.
# In this situation, simply take the 0 index to get to the fit.
# There may be cases in the future in which there are multiple fits, so this should be
# looked at more indepth later
if isinstance(target.owner, InstrumentedList):
parent = target.owner[0]
else:
parent = target.owner
# ensure this is a fit we're dealing with
if isinstance(parent, Fit):
parent.modified = datetime.datetime.now()
def apply_col_listeners(target, context):
# We only want to se these events when the module is first loaded (otherwise events will fire during the initial
# We only want to set these events when the module is first loaded (otherwise events will fire during the initial
# population of data). This runs through all columns and sets up "set" events on each column. We do it with each
# column because the alternative would be to do a before/after_update for the Mapper itself, however we're only
# allowed to change the local attributes during those events as that's inter-flush.
# See http://docs.sqlalchemy.org/en/rel_1_0/orm/session_events.html#mapper-level-events
# @todo replace with `inspect(Module).column_attrs` when mac binaries are updated
manager = getattr(target.__class__, "_sa_class_manager", None)
if manager:
for col in manager.mapper.column_attrs:
@@ -48,8 +72,15 @@ def apply_rel_listeners(target, context):
manager = getattr(target.__class__, "_sa_class_manager", None)
if manager:
for rel in manager.mapper.relationships:
if rel in ignored_rels:
continue
listen(rel, 'append', rel_listener)
listen(rel, 'remove', rel_listener)
listen(Fit, 'load', apply_rel_listeners)
listen(Module, 'load', apply_col_listeners)
listen(Module, 'load', apply_col_listeners)
listen(Drone, 'load', apply_col_listeners)
listen(Fighter, 'load', apply_col_listeners)
listen(Cargo, 'load', apply_col_listeners)
listen(Implant, 'load', apply_col_listeners)
listen(Booster, 'load', apply_col_listeners)

View File

@@ -21,6 +21,7 @@ import time
from copy import deepcopy
from itertools import chain
from math import sqrt, log, asinh
import datetime
from sqlalchemy.orm import validates, reconstructor
@@ -76,6 +77,8 @@ class Fit(object):
self.projected = False
self.name = name
self.timestamp = time.time()
self.created = None
self.modified = None
self.modeID = None
self.build()
@@ -179,6 +182,14 @@ class Fit(object):
self.__mode = mode
self.modeID = mode.item.ID if mode is not None else None
@property
def modifiedCoalesce(self):
"""
This is a property that should get whichever date is available for the fit. @todo: migrate old timestamp data
and ensure created / modified are set in database to get rid of this
"""
return self.modified or self.created or datetime.datetime.fromtimestamp(self.timestamp)
@property
def character(self):
return self.__character if self.__character is not None else Character.getAll0()

View File

@@ -926,7 +926,7 @@ class MainFrame(wx.Frame):
results.append((
fit.ID,
fit.name,
fit.modified or fit.created or datetime.datetime.fromtimestamp(fit.timestamp),
fit.modifiedCoalesce,
fit.ship.item
))
wx.PostEvent(self.shipBrowser, ImportSelected(fits=results, back=True))

View File

@@ -1994,7 +1994,7 @@ class FitItem(SFItem.SFBrowserItem):
if activeFit == self.fitID:
sFit = Fit.getInstance()
fit = sFit.getFit(activeFit)
self.timestamp = fit.modified
self.timestamp = fit.modifiedCoalesce
SFItem.SFBrowserItem.Refresh(self)

View File

@@ -267,10 +267,15 @@ class Fit(object):
pyfalog.debug("Searching for fit: {0}", name)
results = eos.db.searchFits(name)
fits = []
for fit in results:
fits.append((
fit.ID, fit.name, fit.ship.item.ID, fit.ship.item.name, fit.booster,
fit.timestamp))
fit.ID,
fit.name,
fit.ship.item.ID,
fit.ship.item.name,
fit.booster,
fit.modifiedCoalesce))
return fits
def addImplant(self, fitID, itemID, recalc=True):