44
55from flask import Blueprint , g , jsonify , request
66
7- from gcm import auth , state , stock , store
7+ from gcm import auth , stock , store
88
99
1010bp = Blueprint ("stock" , __name__ )
1111
1212
13- def _item_from (payload ):
14- """The item a rule is about, from a request body, or an error
15- message."""
16- item = {
17- "label" : payload .get ("label" ),
18- "mod" : payload .get ("mod" ) or None ,
19- "internal" : payload .get ("internal" ),
20- "damage" : payload .get ("damage" ),
21- "kind" : payload .get ("kind" ) or "item" ,
22- "variant" : payload .get ("variant" ) or None ,
23- }
24- if not item ["label" ] or not item ["internal" ]:
25- return None , "missing label/internal"
26- if item ["kind" ] not in ("item" , "fluid" , "essentia" ):
27- return None , "kind must be item, fluid or essentia"
28- if item ["damage" ] is not None and (isinstance (item ["damage" ], bool ) or not isinstance (item ["damage" ], int )):
29- return None , "damage must be a whole number"
30- if item ["variant" ] is not None and not isinstance (item ["variant" ], str ):
31- return None , "variant must be a string"
32- return item , None
33-
34-
35- def _key (item ):
36- return store .items .item_key (item ["mod" ], item ["internal" ], item ["damage" ], item ["kind" ], item ["variant" ])
37-
38-
39- def _positive (value ):
40- return not isinstance (value , bool ) and isinstance (value , (int , float )) and value > 0
41-
42-
43- def _network_item (key ):
44- with state .network_lock :
45- return next ((it for it in state .network ["items" ] if store .items .key_of (it ) == key ), None )
46-
47-
4813@bp .route ("/api/stock/rules" , methods = ["GET" ])
4914@auth .viewer_required
5015def stock_rules_get ():
5116 """Every keep-in-stock target, and the signed-in user's own alerts,
5217 each with the item's amount in the latest scan (null before any)."""
53- with state .network_lock :
54- items = state .network ["items" ]
55- scanned = state .network ["updated_at" ] is not None or bool (items )
56- sizes = stock .current_sizes (items )
57- names = stock .variant_names (items )
58- with state .crafts_lock :
59- jobs = list (state .crafts ["jobs" ])
60- pending = stock .pending_auto_requests ()
61-
62- def with_item (rule ):
63- current = sizes .get (rule ["key" ], 0 ) if scanned else None
64- return {
65- "key" : rule ["key" ],
66- "label" : rule ["label" ],
67- "mod" : rule ["mod" ],
68- "internal" : rule ["internal" ],
69- "damage" : rule ["damage" ],
70- "kind" : rule ["kind" ],
71- "variant" : rule ["variant" ],
72- "icon" : stock .rule_icon (rule , names ),
73- "current" : current ,
74- }
75-
76- targets = []
77- for t in store .stock .targets ():
78- row = with_item (t )
79- low = row ["current" ] is not None and row ["current" ] < t ["keep_at_least" ]
80- # Only while low: a CPU making the item for some other reason
81- # isn't this target's doing.
82- cpu = stock .busy_cpu_making (t , jobs ) if low else None
83- if t ["key" ] in pending :
84- status = "requested"
85- elif cpu :
86- status = "crafting"
87- elif not t ["enabled" ]:
88- status = "off"
89- elif low and t ["last_status" ] in ("failed" , "waiting" ):
90- status = t ["last_status" ]
91- else :
92- status = "low" if low else "ok"
93- targets .append ({
94- ** row ,
95- "keep_at_least" : t ["keep_at_least" ],
96- "refill_to" : t ["refill_to" ],
97- "enabled" : t ["enabled" ],
98- "status" : status ,
99- "reason" : t ["last_reason" ] if status in ("failed" , "waiting" ) else None ,
100- "cpu" : cpu ,
101- "last_requested_at" : t ["last_requested_at" ],
102- "last_status" : t ["last_status" ],
103- "last_reason" : t ["last_reason" ],
104- })
105-
106- alerts = []
107- user = auth .session_user ()
108- if user :
109- for a in store .stock .alerts_for_user (user ["id" ]):
110- row = with_item (a )
111- alerts .append ({** row , "below" : a ["below" ], "low" : row ["current" ] is not None and row ["current" ] < a ["below" ]})
112- return jsonify ({"targets" : targets , "alerts" : alerts })
18+ return jsonify (stock .rules (auth .session_user ()))
11319
11420
11521@bp .route ("/api/stock/alert" , methods = ["POST" ])
11622@auth .login_required
11723def stock_alert_set ():
11824 payload = request .get_json (silent = True ) or {}
119- item , error = _item_from (payload )
25+ item , error = stock .item_from (payload )
26+ error = error or stock .set_alert (g .user ["id" ], item , payload .get ("below" ))
12027 if error :
12128 return jsonify ({"error" : error }), 400
122- below = payload .get ("below" )
123- if not _positive (below ):
124- return jsonify ({"error" : "below must be a positive number" }), 400
125- store .stock .set_alert (g .user ["id" ], item , below )
12629 return jsonify ({"ok" : True })
12730
12831
12932@bp .route ("/api/stock/alert/delete" , methods = ["POST" ])
13033@auth .login_required
13134def stock_alert_delete ():
132- item , error = _item_from (request .get_json (silent = True ) or {})
35+ item , error = stock . item_from (request .get_json (silent = True ) or {})
13336 if error :
13437 return jsonify ({"error" : error }), 400
135- store .stock .delete_alert (g .user ["id" ], _key (item ))
38+ store .stock .delete_alert (g .user ["id" ], stock . rule_key (item ))
13639 return jsonify ({"ok" : True })
13740
13841
@@ -141,32 +44,21 @@ def stock_alert_delete():
14144@auth .operator_required
14245def stock_target_set ():
14346 payload = request .get_json (silent = True ) or {}
144- item , error = _item_from (payload )
47+ item , error = stock .item_from (payload )
48+ error = error or stock .set_target (
49+ g .user ["id" ], item , payload .get ("keep_at_least" ), payload .get ("refill_to" ), payload .get ("enabled" , True )
50+ )
14551 if error :
14652 return jsonify ({"error" : error }), 400
147- keep , refill = payload .get ("keep_at_least" ), payload .get ("refill_to" )
148- if not _positive (keep ) or not _positive (refill ):
149- return jsonify ({"error" : "keep_at_least and refill_to must be positive numbers" }), 400
150- if refill <= keep :
151- return jsonify ({"error" : "refill_to must be more than keep_at_least" }), 400
152- enabled = payload .get ("enabled" , True )
153- if not isinstance (enabled , bool ):
154- return jsonify ({"error" : "enabled must be true or false" }), 400
155- # The game can only make what it has a pattern for, and the last
156- # scan is the only place that says.
157- network_item = _network_item (_key (item ))
158- if not (network_item and network_item .get ("isCraftable" )):
159- return jsonify ({"error" : "only items the network can craft can be kept in stock" }), 400
160- store .stock .set_target (g .user ["id" ], item , keep , refill , enabled )
16153 return jsonify ({"ok" : True })
16254
16355
16456@bp .route ("/api/stock/target/delete" , methods = ["POST" ])
16557@auth .login_required
16658@auth .operator_required
16759def stock_target_delete ():
168- item , error = _item_from (request .get_json (silent = True ) or {})
60+ item , error = stock . item_from (request .get_json (silent = True ) or {})
16961 if error :
17062 return jsonify ({"error" : error }), 400
171- store .stock .delete_target (_key (item ))
63+ store .stock .delete_target (stock . rule_key (item ))
17264 return jsonify ({"ok" : True })
0 commit comments