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:
@@ -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)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user