Skip to content

Commit 5b9b474

Browse files
hectorBenoît LAVIALE
authored andcommitted
(Feat) Add Basic API on RTB Objects
1 parent 521deb8 commit 5b9b474

File tree

10 files changed

+570
-1
lines changed

10 files changed

+570
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,5 @@ __pycache__
7878

7979
# Readme
8080
!*README.md
81+
82+
venv/*

handlers/ApiV2/BoxApi.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import json
2+
from ..BaseHandlers import BaseHandler
3+
from libs.SecurityDecorators import apikey, restrict_ip_address
4+
from models.Box import Box
5+
from models.Corporation import Corporation
6+
from models.GameLevel import GameLevel
7+
import logging
8+
from models import dbsession
9+
10+
logger = logging.getLogger()
11+
12+
13+
class BoxApiHandler(BaseHandler):
14+
15+
@apikey
16+
@restrict_ip_address
17+
def get(self, id=None):
18+
if id is None or id == "":
19+
data = {"data": [box.to_dict() for box in Box.all()]}
20+
else:
21+
box = Box.by_id(id)
22+
if box is not None:
23+
data = {"data": box.to_dict()}
24+
else:
25+
data = {"message": "Box not found"}
26+
self.write(json.dumps(data))
27+
28+
@apikey
29+
@restrict_ip_address
30+
def post(self, *args, **kwargs):
31+
data = json.loads(self.request.body)
32+
logger.info(f"Posted data : {data}")
33+
if "corporation" not in data:
34+
data = {
35+
"data": {"corporation": None},
36+
"message": "Corporation is required",
37+
}
38+
self.write(json.dumps(data))
39+
return
40+
if "name" not in data:
41+
data = {"data": {"box": None}, "message": "Name is required"}
42+
self.write(json.dumps(data))
43+
return
44+
45+
if Box.by_name(data["name"]) is not None:
46+
data = {
47+
"data": {"box": None},
48+
"message": "This box already exists",
49+
}
50+
self.write(json.dumps(data))
51+
return
52+
53+
if Corporation.by_name(data["corporation"]) is None:
54+
data = {
55+
"data": {"corporation": data["corporation"]},
56+
"message": "This corporation does not exist",
57+
}
58+
self.write(json.dumps(data))
59+
return
60+
61+
new_box = Box()
62+
new_box.name = data["name"]
63+
new_box.description = data["description"] if "description" in data else ""
64+
new_box.corporation_id = (
65+
Corporation.by_name(data["corporation"]).id
66+
if "corporation" in data
67+
else None
68+
)
69+
70+
flag_submission_type = (
71+
data["flag_submission_type"]
72+
if "flag_submission_type" in data
73+
else "CLASSIC"
74+
)
75+
if flag_submission_type not in ["CLASSIC", "TOKEN"]:
76+
new_box.flag_submission_type = "CLASSIC"
77+
else:
78+
new_box.flag_submission_type = flag_submission_type
79+
80+
new_box.game_level_id = GameLevel.by_number(0).id
81+
82+
dbsession.add(new_box)
83+
dbsession.commit()
84+
data = {
85+
"data": {"box": new_box.to_dict()},
86+
"message": "This box has been created",
87+
}
88+
self.write(json.dumps(data))
89+
90+
@apikey
91+
@restrict_ip_address
92+
def delete(self, id: str):
93+
raise NotImplementedError()
94+
95+
@apikey
96+
@restrict_ip_address
97+
def put(self, *args, **kwargs):
98+
raise NotImplementedError()
99+
100+
def check_xsrf_cookie(self):
101+
pass

handlers/ApiV2/CorporationApi.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import json
2+
from ..BaseHandlers import BaseHandler
3+
from libs.SecurityDecorators import apikey, restrict_ip_address
4+
from models.Corporation import Corporation
5+
import logging
6+
from models import Team, dbsession
7+
8+
logger = logging.getLogger()
9+
10+
11+
class CorporationApiHandler(BaseHandler):
12+
13+
@apikey
14+
@restrict_ip_address
15+
def get(self, id: str = None):
16+
if id is None or id == "":
17+
data = {
18+
"data": [corporation.to_dict() for corporation in Corporation.all()]
19+
}
20+
else:
21+
corporation = Corporation.by_id(id)
22+
if corporation is not None:
23+
data = {"data": corporation.to_dict()}
24+
else:
25+
data = {"message": "Corporation not found"}
26+
self.write(json.dumps(data))
27+
28+
@apikey
29+
@restrict_ip_address
30+
def post(self, *args, **kwargs):
31+
data = json.loads(self.request.body)
32+
logger.info(f"Post data : {data}")
33+
34+
if Corporation.by_name(data["name"]) is not None:
35+
data = {
36+
"data": {"corporation": data["name"]},
37+
"message": "This corporation already exists",
38+
}
39+
self.write(json.dumps(data))
40+
return
41+
42+
new_corporation = Corporation()
43+
new_corporation.name = data["name"]
44+
new_corporation.locked = data["locked"] if "locked" in data else False
45+
new_corporation.description = (
46+
data["description"] if "description" in data else ""
47+
)
48+
49+
dbsession.add(new_corporation)
50+
dbsession.commit()
51+
data = {
52+
"data": {
53+
"corporation": new_corporation.to_dict(),
54+
},
55+
"message": "This corporation has been created",
56+
}
57+
self.write(json.dumps(data))
58+
59+
@apikey
60+
@restrict_ip_address
61+
def delete(self, id: str):
62+
corporation = Corporation.by_id(id)
63+
if corporation is not None:
64+
dbsession.delete(corporation)
65+
dbsession.commit()
66+
self.write(
67+
json.dumps(
68+
{
69+
"data": {"corporation": corporation.to_dict()},
70+
"message": "Corporation deleted",
71+
}
72+
)
73+
)
74+
else:
75+
self.write(
76+
json.dumps(
77+
{
78+
"data": {"corporation": None},
79+
"message": "Corporation not found",
80+
}
81+
)
82+
)
83+
84+
@apikey
85+
@restrict_ip_address
86+
def put(self, *args, **kwargs):
87+
raise NotImplementedError()
88+
89+
def check_xsrf_cookie(self):
90+
pass

handlers/ApiV2/FlagApi.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import json
2+
from ..BaseHandlers import BaseHandler
3+
from libs.SecurityDecorators import apikey, restrict_ip_address
4+
from models.Box import Box
5+
from models.Flag import Flag
6+
import logging
7+
from models import dbsession
8+
9+
10+
logger = logging.getLogger()
11+
12+
13+
class FlagApiHandler(BaseHandler):
14+
15+
@apikey
16+
@restrict_ip_address
17+
def get(self, id=None):
18+
if id is None or id == "":
19+
data = {"data": [flag.to_dict() for flag in Flag.all()]}
20+
else:
21+
flag = Flag.by_id(id)
22+
if flag is not None:
23+
data = {"data": flag.to_dict()}
24+
else:
25+
data = {"message": "Flag not found"}
26+
self.write(json.dumps(data))
27+
28+
@apikey
29+
@restrict_ip_address
30+
def post(self, *args, **kwargs):
31+
data = json.loads(self.request.body)
32+
logger.info(f"Post data : {data}")
33+
34+
if "box" not in data:
35+
data = {
36+
"data": {"box": None},
37+
"message": "Box is required",
38+
}
39+
self.write(json.dumps(data))
40+
return
41+
42+
if Box.by_name(data["box"]) is None:
43+
data = {
44+
"data": {"box": data["box"]},
45+
"message": "This box does not exist",
46+
}
47+
self.write(json.dumps(data))
48+
return
49+
box = Box.by_name(data["box"])
50+
51+
if Flag.by_token_and_box_id(data["token"], box.id) is not None:
52+
data = {
53+
"data": {
54+
"flag": data["token"],
55+
"box": data["box"],
56+
},
57+
"message": "This flag already exists",
58+
}
59+
self.write(json.dumps(data))
60+
return
61+
62+
new_flag = Flag()
63+
new_flag.name = data["name"]
64+
new_flag.token = data["token"]
65+
new_flag.value = int(data["value"]) if "value" in data else 1
66+
new_flag.box_id = box.id
67+
new_flag.type = "static"
68+
new_flag.description = data["description"] if "description" in data else ""
69+
70+
dbsession.add(new_flag)
71+
dbsession.commit()
72+
data = {"data": new_flag.to_dict(), "message": "This flag has been created"}
73+
self.write(json.dumps(data))
74+
75+
@apikey
76+
@restrict_ip_address
77+
def delete(self, id: str):
78+
raise NotImplementedError()
79+
80+
@apikey
81+
@restrict_ip_address
82+
def put(self, *args, **kwargs):
83+
raise NotImplementedError()
84+
85+
def check_xsrf_cookie(self):
86+
pass

handlers/ApiV2/TeamApi.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import json
2+
from ..BaseHandlers import BaseHandler
3+
from libs.SecurityDecorators import apikey, restrict_ip_address
4+
from models.Corporation import Corporation
5+
import logging
6+
from models import Team, dbsession
7+
8+
logger = logging.getLogger()
9+
10+
11+
class TeamApiHandler(BaseHandler):
12+
13+
@apikey
14+
@restrict_ip_address
15+
def get(self, id: str = None):
16+
with_flags = self.get_argument("with_flags", "false").lower() == "true"
17+
if id is None or id == "":
18+
data = {"data": [team.to_dict(with_flags) for team in Team.all()]}
19+
else:
20+
team = Team.by_uuid(id)
21+
if team is not None:
22+
data = {"data": team.to_dict(with_flags)}
23+
else:
24+
data = {"message": "Team not found"}
25+
self.write(json.dumps(data))
26+
27+
@apikey
28+
@restrict_ip_address
29+
def post(self, *args, **kwargs):
30+
raise NotImplementedError()
31+
32+
@apikey
33+
@restrict_ip_address
34+
def delete(self, id: str):
35+
raise NotImplementedError()
36+
37+
@apikey
38+
@restrict_ip_address
39+
def put(self, *args, **kwargs):
40+
raise NotImplementedError()
41+
42+
def check_xsrf_cookie(self):
43+
pass

handlers/ApiV2/__init__.py

Whitespace-only changes.

handlers/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
from handlers.StaticFileHandler import StaticFileHandler
5757
from handlers.UpgradeHandlers import *
5858
from handlers.UserHandlers import *
59+
from handlers.ApiV2 import FlagApi, TeamApi, CorporationApi, BoxApi
5960
from libs.ConsoleColors import *
6061
from libs.DatabaseConnection import DatabaseConnection
6162
from libs.Scoreboard import Scoreboard, score_bots
@@ -195,6 +196,10 @@ def get_cookie_secret():
195196
(r"/admin/resetdelete", AdminResetDeleteHandler),
196197
# API handlers - APIHandlers.py
197198
(r"/api/actions", APIActionHandler),
199+
(r"/api/v2/corporation/?(.*)", CorporationApi.CorporationApiHandler),
200+
(r"/api/v2/box/?(.*)", BoxApi.BoxApiHandler),
201+
(r"/api/v2/flag/?(.*)", FlagApi.FlagApiHandler),
202+
(r"/api/v2/team/?(.*)", TeamApi.TeamApiHandler),
198203
# Error handlers - ErrorHandlers.py
199204
(r"/403", UnauthorizedHandler),
200205
(r"/gamestatus", StopHandler),

models/Corporation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ def to_dict(self):
119119
"uuid": self.uuid,
120120
"name": self.name,
121121
"description": self.description,
122+
"id": self.id,
123+
"locked": self.locked,
122124
# "boxes": [box.uuid for box in self.boxes],
123125
}
124126

models/Team.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def file_by_file_name(self, file_name):
292292
ls = self.files.filter_by(file_name=file_name)
293293
return ls[0] if 0 < len(ls) else None
294294

295-
def to_dict(self):
295+
def to_dict(self, with_flags: bool = False):
296296
"""Use for JSON related tasks; return public data only"""
297297
return {
298298
"uuid": self.uuid,
@@ -301,6 +301,13 @@ def to_dict(self):
301301
"money": self.money,
302302
"avatar": self.avatar,
303303
"notes": self.notes,
304+
"score": {
305+
"money": self.get_score("money"),
306+
"flags": self.get_score("flag"),
307+
"hints": self.get_score("hint"),
308+
"bots": self.get_score("bot"),
309+
},
310+
"flags": [flag.to_dict() for flag in self.flags] if with_flags else [],
304311
}
305312

306313
def to_xml(self, parent):

0 commit comments

Comments
 (0)