toconnell / kdm-manager

An interactive campaign manager for the game "Monster", by Kingdom Death. Development blog and release notes at https://blog.kdm-manager.com This project has no affiliation with Kingdom Death and is a totally independent, fan-maintained project.
http://kdm-manager.com
Other
26 stars 11 forks source link

API: settlement get_monster_options() method can throw a 500 if there are no monsters of a given type #487

Closed toconnell closed 6 years ago

toconnell commented 6 years ago

From production email alerts:

Method: GET URL: https://192.168.0.110:8013/settlement/get/5aa922814af5ca1cf5546843 JSON: None

The full traceback is as follows:

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/Flask-0.12.2-py2.7.egg/flask/app.py", line 1612, in full_dispatch_request
 rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/Flask-0.12.2-py2.7.egg/flask/app.py", line 1598, in dispatch_request
 return self.view_functions[rule.endpoint](**req.view_args)
File "/home/toconnell/kdm-manager/v2/api/utils.py", line 505, in wrapped_function
 resp = make_response(f(*args, **kwargs))
File "/usr/lib/python2.7/dist-packages/celery/local.py", line 188, in __call__
 return self._get_current_object()(*a, **kw)
File "/usr/lib/python2.7/dist-packages/celery/app/task.py", line 420, in __call__
 return self.run(*args, **kwargs)
File "./api.py", line 274, in collection_action
 return asset_object.request_response(action)
File "/home/toconnell/kdm-manager/v2/api/models/settlements.py", line 3787, in request_response
 return Response(response=self.serialize(), status=200, mimetype="application/json")
File "/home/toconnell/kdm-manager/v2/api/models/settlements.py", line 436, in serialize
 output["game_assets"]["nemesis_options"] = self.get_monster_options("nemesis_monsters")
File "/home/toconnell/kdm-manager/v2/api/models/settlements.py", line 3116, in get_monster_options
 for n in self.settlement[monster_type]:
KeyError: 'nemesis_monsters'
toconnell commented 6 years ago

Yeah, looks like some joker removed all quarries and broke the website. Good for him. Fixing this now...

toconnell commented 6 years ago

Added some graceful failures for smart-asses and trouble-makers:

@@ -3075,7 +3113,7 @@ class Settlement(Models.UserAsset):
         # now convert our list into a set (just in case) and then go on to
         # remove anything we've already got present in the settlement
         option_set = set(options)
-        for n in self.settlement[monster_type]:
+        for n in self.settlement.get(monster_type, []):
             if n in option_set:
                 option_set.remove(n)

@@ -3128,13 +3166,13 @@ class Settlement(Models.UserAsset):

         candidate_handles = []
         if context == "showdown_options":
-            candidate_handles.extend(self.settlement["quarries"])
+            candidate_handles.extend(self.settlement.get("quarries", []))
         elif context == "nemesis_encounters":
-            candidate_handles.extend(self.settlement["nemesis_monsters"])
+            candidate_handles.extend(self.settlement.get("nemesis_monsters", []))
             candidate_handles.append(self.campaign.final_boss)
         elif context == "defeated_monsters":
-            candidate_handles.extend(self.settlement["quarries"])
-            candidate_handles.extend(self.settlement["nemesis_monsters"])
+            candidate_handles.extend(self.settlement.get("quarries", []))
+            candidate_handles.extend(self.settlement.get("nemesis_monsters",[]))
             candidate_handles.extend(self.get_special_showdowns())
             candidate_handles.append(self.campaign.final_boss)
         elif context == "special_showdown_options":