diff --git a/calefaction/modules/campaigns/database.py b/calefaction/modules/campaigns/database.py index 3faf09d..cac455c 100644 --- a/calefaction/modules/campaigns/database.py +++ b/calefaction/modules/campaigns/database.py @@ -98,6 +98,7 @@ class CampaignDB: except ValueError: raise RuntimeError("Invalid kill_date=%s for kill_id=%d" % ( kill["killTime"], kill["killID"])) + # ... Ensure IDs are all ints query = """INSERT OR REPLACE INTO kill ( kill_id, kill_date, kill_system, kill_victim_shipid, @@ -135,3 +136,34 @@ class CampaignDB: WHERE ok_campaign = ? AND ok_operation = ?""" res = self._conn.execute(query, (campaign, operation)).fetchall() return tuple(res[0]) + + def get_associated_kills(self, campaign, operation, limit=5, offset=0): + """Return a list of kills associated with a campaign/operation. + + Kills are returned as dictionaries most recent first, up to a limit. + Use -1 for no limit. + """ + if not isinstance(limit, int): + raise ValueError(limit) + if not isinstance(offset, int): + raise ValueError(offset) + + query = """SELECT kill_id, kill_date, kill_system, kill_victim_shipid, + kill_victim_charid, kill_victim_corpid, kill_victim_allianceid, + kill_victim_factionid, kill_value + FROM oper_kill + JOIN kill ON ok_killid = kill_id + WHERE ok_campaign = ? AND ok_operation = ? + ORDER BY ok_killid DESC LIMIT {} OFFSET {}""" + qform = query.format(limit, offset) + res = self._conn.execute(qform, (campaign, operation)).fetchall() + + return [{ + "id": row[0], + "date": datetime.strptime(row[1], "%Y-%m-%d %H:%M:%S"), + "system": row[2], + "victim": { + "ship_id": row[3], "char_id": row[4], "corp_id": row[5], + "alliance_id": row[6], "faction_id": row[7]}, + "value": row[8] + } for row in res] diff --git a/calefaction/modules/campaigns/getters.py b/calefaction/modules/campaigns/getters.py index 24acab3..9f22d80 100644 --- a/calefaction/modules/campaigns/getters.py +++ b/calefaction/modules/campaigns/getters.py @@ -53,12 +53,19 @@ def get_overview(cname, opname): else: logger.debug("Using cache (age=%d) for campaign=%s " "operation=%s", age, cname, opname) - return g.campaign_db.get_overview(cname, opname) + return g.campaign_db.get_overview(cname, opname) -def get_summary(name, opname, limit=5): +def get_summary(cname, opname, limit=5): """Return a sample fraction of results for the given campaign/operation.""" - ... - return [] + optype = config["campaigns"][cname]["operations"][opname]["type"] + if optype == "killboard": + kills = g.campaign_db.get_associated_kills(cname, opname, limit=limit) + return kills, "killboard_recent" + elif optype == "collection": + ... + return [], None + else: + raise RuntimeError("Unknown operation type: %s" % optype) def get_unit(operation, num, primary=True): """Return the correct form of the unit tracked by the given operation.""" diff --git a/requirements.txt b/requirements.txt index ab793fd..da70a16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ Flask==0.11.1 Flask-Mako==0.4 +humanize==0.5.1 PyYAML==3.12 requests==2.12.4 uWSGI==2.0.14 diff --git a/static/main.css b/static/main.css index 0bba3a3..0a51d32 100644 --- a/static/main.css +++ b/static/main.css @@ -353,11 +353,11 @@ h2 .disabled { text-decoration: line-through; } -h2 .disabled::after { - display: inline-block; - padding-left: 0.75em; - font-size: 75%; - content: "✘"; +h2 .disabled-info { + margin-left: 0.5em; + color: #989898; + font-size: 85%; + font-variant: none; } #operations { diff --git a/templates/campaigns/campaign.mako b/templates/campaigns/campaign.mako index 129c9b2..3a5c9c9 100644 --- a/templates/campaigns/campaign.mako +++ b/templates/campaigns/campaign.mako @@ -1,10 +1,15 @@ +<%! import humanize %> <%inherit file="../_default.mako"/> +<%namespace file="renderers.mako" import="render_summary"/> <%block name="title"> ${self.maketitle(campaign["title"], "Campaigns")}

Campaign: ${campaign["title"] | h} + % if not enabled: + + % endif

<% mod = g.config.modules.campaigns %>
@@ -15,8 +20,10 @@ <% operation = campaign["operations"][opname] primary, secondary = mod.get_overview(name, opname) - summary = mod.get_summary(name, opname, limit=5) + summary, renderer = mod.get_summary(name, opname, limit=5) klass = "big" if primary < 1000 else "medium" if primary < 1000000 else "small" + punit = mod.get_unit(operation, primary) + sunit = mod.get_unit(operation, secondary, primary=False) %>

@@ -25,21 +32,19 @@
${"{:,}".format(primary)} -
${mod.get_unit(operation, primary)}
+
${punit}
% if secondary is not None:
- ${"{:,.2f}".format(secondary)} - ${mod.get_unit(operation, secondary, primary=False)} + + ${humanize.intword(secondary) | h} + ${sunit} +
% endif
% if summary: -
    - % for item in summary: -
  • ${item}
  • - % endfor -
+ ${render_summary(renderer, summary)} % endif

% endfor diff --git a/templates/campaigns/renderers.mako b/templates/campaigns/renderers.mako new file mode 100644 index 0000000..47d96c7 --- /dev/null +++ b/templates/campaigns/renderers.mako @@ -0,0 +1,25 @@ +<%! import humanize %> +<%def name="_killboard_recent(summary)"> + + + +<%def name="render_summary(renderer, summary)"><% + if renderer == "killboard_recent": + return _killboard_recent(summary) + else: + raise RuntimeError("Unknown renderer: %s" % renderer) +%> diff --git a/templates/members/members.mako b/templates/members/members.mako index f55b775..c939081 100644 --- a/templates/members/members.mako +++ b/templates/members/members.mako @@ -8,7 +8,7 @@ % for member in members:
  • - ${member.name}'s Portrait + ${member.name}'s Portrait % if member.roles: ${member.name}${member.roles}