A corporation manager and dashboard for EVE Online
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

184 lignes
7.3 KiB

  1. # -*- coding: utf-8 -*-
  2. from datetime import datetime
  3. import sqlite3
  4. from flask import g
  5. from werkzeug.local import LocalProxy
  6. __all__ = ["CampaignDB"]
  7. class CampaignDB:
  8. """Database manager for internal storage for the Campaigns module."""
  9. path = None
  10. def __init__(self):
  11. if self.path is None:
  12. raise RuntimeError("CampaignDB.path not set")
  13. self._conn = sqlite3.connect(self.path)
  14. @classmethod
  15. def _get(cls):
  16. """Return the current database, or allocate a new one if necessary."""
  17. if not hasattr(g, "_campaign_db"):
  18. g._campaign_db = cls()
  19. return g._campaign_db
  20. @classmethod
  21. def pre_hook(cls):
  22. """Hook to be called before a request context.
  23. Sets up the g.campaign_db proxy.
  24. """
  25. g.campaign_db = LocalProxy(cls._get)
  26. @classmethod
  27. def post_hook(cls, exc):
  28. """Hook to be called when tearing down an application context.
  29. Closes the database if necessary.
  30. """
  31. if hasattr(g, "_campaign_db"):
  32. g._campaign_db.close()
  33. def close(self):
  34. """Close the database connection."""
  35. return self._conn.close()
  36. def check_operation(self, campaign, operation):
  37. """Return the last updated timestamp and key for the given operation.
  38. Return (None, None) if the given operation was never updated.
  39. """
  40. query = """SELECT lu_date, lu_key FROM last_updated
  41. WHERE lu_campaign = ? AND lu_operation = ?"""
  42. res = self._conn.execute(query, (campaign, operation)).fetchall()
  43. if not res:
  44. return None, None
  45. return datetime.strptime(res[0][0], "%Y-%m-%d %H:%M:%S"), res[0][1]
  46. def touch_operation(self, campaign, operation, key=None):
  47. """Mark the given operation as just updated, or add it."""
  48. with self._conn as conn:
  49. cur = conn.execute("BEGIN TRANSACTION")
  50. cur.execute("""UPDATE last_updated
  51. SET lu_date = CURRENT_TIMESTAMP, lu_key = ?
  52. WHERE lu_campaign = ? AND lu_operation = ?""", (
  53. key, campaign, operation))
  54. if cur.rowcount == 0:
  55. cur.execute("""INSERT INTO last_updated
  56. (lu_campaign, lu_operation, lu_key) VALUES (?, ?, ?)""", (
  57. campaign, operation, key))
  58. def set_overview(self, campaign, operation, primary, secondary=None):
  59. """Set overview information for this operation."""
  60. with self._conn as conn:
  61. conn.execute("""INSERT OR REPLACE INTO overview
  62. (ov_campaign, ov_operation, ov_primary, ov_secondary)
  63. VALUES (?, ?, ?, ?)""", (
  64. campaign, operation, primary, secondary))
  65. def get_overview(self, campaign, operation):
  66. """Return a 2-tuple of overview information for this operation."""
  67. query = """SELECT ov_primary, ov_secondary FROM overview
  68. WHERE ov_campaign = ? AND ov_operation = ?"""
  69. res = self._conn.execute(query, (campaign, operation)).fetchall()
  70. return tuple(res[0]) if res else (0, None)
  71. def has_kill(self, kill_id):
  72. """Return whether the database has a killmail with the given ID."""
  73. query = "SELECT 1 FROM kill WHERE kill_id = ?"
  74. res = self._conn.execute(query, (kill_id,)).fetchall()
  75. return bool(res)
  76. def add_kill(self, kill):
  77. """Insert a killmail into the database."""
  78. try:
  79. datetime.strptime(kill["killTime"], "%Y-%m-%d %H:%M:%S")
  80. except ValueError:
  81. raise RuntimeError("Invalid kill_date=%s for kill_id=%d" % (
  82. kill["killTime"], kill["killID"]))
  83. query = """INSERT OR REPLACE INTO kill (
  84. kill_id, kill_date, kill_system, kill_victim_shipid,
  85. kill_victim_charid, kill_victim_charname, kill_victim_corpid,
  86. kill_victim_corpname, kill_victim_allianceid,
  87. kill_victim_alliancename, kill_victim_factionid,
  88. kill_victim_factionname, kill_value)
  89. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"""
  90. victim = kill["victim"]
  91. args = (
  92. int(kill["killID"]), kill["killTime"], int(kill["solarSystemID"]),
  93. int(victim["shipTypeID"]), int(victim["characterID"]),
  94. victim["characterName"], int(victim["corporationID"]),
  95. victim["corporationName"], int(victim["allianceID"]),
  96. victim["allianceName"], int(victim["factionID"]),
  97. victim["factionName"], float(kill["zkb"]["totalValue"]))
  98. with self._conn as conn:
  99. conn.execute(query, args)
  100. def get_kill_associations(self, campaign, kill_id):
  101. """Return a list of operations associated with a campaign and kill."""
  102. query = """SELECT ok_operation FROM oper_kill
  103. WHERE ok_campaign = ? AND ok_killid = ?"""
  104. res = self._conn.execute(query, (campaign, kill_id)).fetchall()
  105. return [row[0] for row in res]
  106. def associate_kill(self, campaign, kill_id, operations):
  107. """Associate a killmail with a set of campaign/operations."""
  108. query = """INSERT OR IGNORE INTO oper_kill
  109. (ok_campaign, ok_operation, ok_killid) VALUES (?, ?, ?)"""
  110. arglist = [(campaign, op, kill_id) for op in operations]
  111. with self._conn as conn:
  112. conn.executemany(query, arglist)
  113. def count_kills(self, campaign, operation):
  114. """Return the number of matching kills and the total kill value."""
  115. query = """SELECT COUNT(*), TOTAL(kill_value)
  116. FROM oper_kill
  117. JOIN kill ON ok_killid = kill_id
  118. WHERE ok_campaign = ? AND ok_operation = ?"""
  119. res = self._conn.execute(query, (campaign, operation)).fetchall()
  120. return tuple(res[0])
  121. def get_associated_kills(self, campaign, operation, limit=5, offset=0):
  122. """Return a list of kills associated with a campaign/operation.
  123. Kills are returned as dictionaries most recent first, up to a limit.
  124. Use -1 for no limit.
  125. """
  126. if not isinstance(limit, int):
  127. raise ValueError(limit)
  128. if not isinstance(offset, int):
  129. raise ValueError(offset)
  130. query = """SELECT kill_id, kill_date, kill_system, kill_victim_shipid,
  131. kill_victim_charid, kill_victim_charname, kill_victim_corpid,
  132. kill_victim_corpname, kill_victim_allianceid,
  133. kill_victim_alliancename, kill_victim_factionid,
  134. kill_victim_factionname, kill_value
  135. FROM oper_kill
  136. JOIN kill ON ok_killid = kill_id
  137. WHERE ok_campaign = ? AND ok_operation = ?
  138. ORDER BY ok_killid DESC LIMIT {} OFFSET {}"""
  139. qform = query.format(limit, offset)
  140. res = self._conn.execute(qform, (campaign, operation)).fetchall()
  141. return [{
  142. "id": row[0],
  143. "date": datetime.strptime(row[1], "%Y-%m-%d %H:%M:%S"),
  144. "system": row[2],
  145. "victim": {
  146. "ship_id": row[3],
  147. "char_id": row[4],
  148. "char_name": row[5],
  149. "corp_id": row[6],
  150. "corp_name": row[7],
  151. "alliance_id": row[8],
  152. "alliance_name": row[9],
  153. "faction_id": row[10],
  154. "faction_name": row[11]
  155. },
  156. "value": row[12]
  157. } for row in res]