Strategická: Další kousek webu
This commit is contained in:
parent
cf6377b21b
commit
7eee3cfcff
8 changed files with 202 additions and 54 deletions
|
@ -7,8 +7,6 @@ import argparse
|
|||
from sqlalchemy import exc, update
|
||||
import sys
|
||||
|
||||
g = db.Game(game_mode="", configuration={}, teams_count=1)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("game_id")
|
||||
parser.add_argument("--step", action="store_true")
|
||||
|
|
|
@ -6,20 +6,32 @@ import hra.lib as lib
|
|||
import sys
|
||||
from sqlalchemy import exc, update
|
||||
|
||||
ses = db.get_session()
|
||||
|
||||
mode = "occupy"
|
||||
teams_count = 6
|
||||
configuration = {}
|
||||
configuration = {
|
||||
"teams_width": 2,
|
||||
"teams_height": 3,
|
||||
"width_per_team": 10,
|
||||
"height_per_team": 10,
|
||||
}
|
||||
g = db.Game(game_mode=mode, configuration=configuration, teams_count=teams_count)
|
||||
|
||||
db.get_session().add(g)
|
||||
db.get_session().commit()
|
||||
ses.add(g)
|
||||
ses.commit()
|
||||
|
||||
g.lock()
|
||||
|
||||
s = db.State(game_id=g.game_id, round=0, state=g.get_logic().zero_state())
|
||||
ses.add(s)
|
||||
|
||||
for i in range(teams_count):
|
||||
t = db.Team(team_id=i, game_id=g.game_id, name="")
|
||||
ses.add(t)
|
||||
|
||||
db.get_session().add(s)
|
||||
g.current_round = 0
|
||||
g.working_on_next_state = False
|
||||
db.get_session().commit()
|
||||
ses.commit()
|
||||
|
||||
print(f"Přidána hra {g.game_id}. ")
|
||||
|
|
|
@ -78,7 +78,25 @@ class Game(Base):
|
|||
return hra.game.logic_by_mode[self.game_mode](self.teams_count, self.configuration)
|
||||
|
||||
def lock(self) -> 'Game':
|
||||
return get_session().query(Game).filter_by(game_id=self.game_id).with_for_update().first()
|
||||
ses = get_session()
|
||||
ses.expire_all()
|
||||
return ses.query(Game).filter_by(game_id=self.game_id).with_for_update().first()
|
||||
|
||||
|
||||
class Team(Base):
|
||||
__tablename__ = 'base'
|
||||
__table_args__ = (
|
||||
UniqueConstraint('game_id', 'team_id'),
|
||||
UniqueConstraint('user_id', 'name'),
|
||||
)
|
||||
|
||||
game_id = Column(Integer, ForeignKey('games.game_id'), nullable=False, primary_key=True)
|
||||
team_id = Column(Integer, nullable=False, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
name = Column(String(80), nullable=False)
|
||||
|
||||
game = relationship('Game', primaryjoin='Team.game_id == Game.game_id')
|
||||
user = relationship('User', primaryjoin='Team.user_id == User.id')
|
||||
|
||||
|
||||
class State(Base):
|
||||
|
|
|
@ -70,22 +70,18 @@ def init_request():
|
|||
if not user or not user.org:
|
||||
raise werkzeug.exceptions.Forbidden()
|
||||
g.user = user
|
||||
g.org = g.user and g.user.org
|
||||
|
||||
g.menu = [
|
||||
MenuItem('/', "Domů"),
|
||||
MenuItem('/bonuses', "Bonusy"),
|
||||
]
|
||||
if g.user and g.user.org:
|
||||
if g.org:
|
||||
g.menu += [
|
||||
MenuItem('/org/ranking', "Výsledky"),
|
||||
MenuItem('/org/act', "Aktuální kolo"),
|
||||
MenuItem('/org/admin', "Admin"),
|
||||
MenuItem('/org/su', "Vtělování se"),
|
||||
MenuItem('/org/users', "Uživatelé"),
|
||||
MenuItem(app.url_for(pages.web_org_games.__name__), "Hry"),
|
||||
MenuItem(app.url_for(pages.web_org_users.__name__), "Uživatelé")
|
||||
]
|
||||
else:
|
||||
g.menu += [
|
||||
MenuItem('/submitted', "Odevzdané kódy"),
|
||||
]
|
||||
|
||||
|
||||
|
@ -95,5 +91,5 @@ app.before_request(init_request)
|
|||
|
||||
|
||||
|
||||
import hra.web.pages
|
||||
import hra.web.pages as pages
|
||||
import hra.web.api
|
||||
|
|
|
@ -23,17 +23,18 @@ def args_get(name, type, optional=False, default=None):
|
|||
def get_context():
|
||||
if g.user is None:
|
||||
raise NeedLoginError
|
||||
game_id = args_get("game", int, True, 1)
|
||||
team_id = args_get('team', int, True, 0)
|
||||
game = db.get_session().query(db.Game).filter_by(game_id=game_id).first()
|
||||
if game is None:
|
||||
game_name = args_get("game", str, True, "main")
|
||||
team = db.get_session().query(db.Team).filter_by(user_id=g.user.id, name=game_name).one_or_none()
|
||||
if team is None:
|
||||
raise werkzeug.exceptions.NotFound("No such game")
|
||||
return game, team_id
|
||||
return team
|
||||
|
||||
|
||||
@app.route("/api/state", methods=['GET'])
|
||||
def api_state():
|
||||
game, team_id = get_context()
|
||||
team = get_context()
|
||||
game = team.game
|
||||
team_id = team.team_id
|
||||
state = game.current_state()
|
||||
if state is None:
|
||||
return json.dumps({
|
||||
|
@ -53,8 +54,9 @@ def api_action():
|
|||
return json.dumps({
|
||||
"status": "too-late",
|
||||
})
|
||||
|
||||
game, team_id = get_context()
|
||||
team = get_context()
|
||||
game = team.game
|
||||
team_id = team.team_id
|
||||
j = request.get_json()
|
||||
state = game.current_state()
|
||||
round_id = args_get('round', int)
|
||||
|
|
|
@ -95,6 +95,17 @@ class Bucket:
|
|||
self.builder.current_tag = self.before_tag
|
||||
self.before_tag = None
|
||||
|
||||
def serialize_append_to_list(self, out, indent):
|
||||
for i in self.content:
|
||||
if isinstance(i, Bucket):
|
||||
i.serialize_append_to_list(out, indent)
|
||||
elif isinstance(i, Markup):
|
||||
for j in i.__html__().split("\n"):
|
||||
out.append(indent_str(indent, j))
|
||||
else:
|
||||
for j in escape(str(i)).split("\n"):
|
||||
out.append(indent_str(indent, j))
|
||||
|
||||
|
||||
class Tag(Bucket):
|
||||
name: str
|
||||
|
@ -114,19 +125,7 @@ class Tag(Bucket):
|
|||
def serialize_append_to_list(self, out, indent):
|
||||
if self.is_paired:
|
||||
out.append(indent_str(indent, f"<{escape_tag_name(self.name)} {self.format_attributes()}>"))
|
||||
if indent is not None:
|
||||
indent += 1
|
||||
for i in self.content:
|
||||
if isinstance(i, Bucket):
|
||||
i.serialize_append_to_list(out, indent)
|
||||
elif isinstance(i, Markup):
|
||||
for j in i.__html__().split("\n"):
|
||||
out.append(indent_str(indent, j))
|
||||
else:
|
||||
for j in escape(str(i)).split("\n"):
|
||||
out.append(indent_str(indent, j))
|
||||
if indent is not None:
|
||||
indent -= 1
|
||||
super().serialize_append_to_list(out, indent + 1 if indent is not None else None)
|
||||
out.append(indent_str(indent, f"</{escape_tag_name(self.name)}>"))
|
||||
else:
|
||||
out.append(indent_str(indent, f"<{escape_tag_name(self.name)} {self.format_attributes()} />"))
|
||||
|
@ -134,21 +133,21 @@ class Tag(Bucket):
|
|||
|
||||
class Line(Bucket):
|
||||
def serialize_append_to_list(self, out, indent):
|
||||
out.append(indent_str(indent,"")[:-1])
|
||||
for i in self.content:
|
||||
if isinstance(i, Bucket):
|
||||
i.serialize_append_to_list(out, None)
|
||||
elif isinstance(i, Markup):
|
||||
out.append(i.__html__())
|
||||
out.append(escape(str(i)))
|
||||
out.append("\n")
|
||||
if indent is None:
|
||||
super().serialize_append_to_list(out, None)
|
||||
else:
|
||||
out.append(indent_str(indent,"")[:-1])
|
||||
super().serialize_append_to_list(out, None)
|
||||
out.append("\n")
|
||||
|
||||
|
||||
|
||||
class Builder:
|
||||
current_tag: Bucket
|
||||
root_tag: Bucket
|
||||
def __init__(self, tag: Bucket):
|
||||
def __init__(self, tag: Bucket = None):
|
||||
if tag is None:
|
||||
tag = Bucket(self)
|
||||
self.root_tag = tag
|
||||
self.current_tag = tag
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from hra.web import app
|
||||
|
||||
quick_form = app.jinja_env.get_template("bootstrap/wtf.html").module.quick_form
|
||||
form_field = app.jinja_env.get_template("bootstrap/wtf.html").module.form_field
|
||||
|
|
|
@ -71,7 +71,18 @@ class OptionalIntField(wtforms.IntegerField):
|
|||
except ValueError:
|
||||
raise wtforms.ValidationError('Nejedná se o číslo.')
|
||||
|
||||
|
||||
def user_link(user):
|
||||
b = html.Builder()
|
||||
with b.line():
|
||||
if user is None:
|
||||
b("-")
|
||||
else:
|
||||
if g.org:
|
||||
b.a(href=app.url_for(web_org_user.__name__, user_id=user.id))(user.username)
|
||||
else:
|
||||
b(user.username)
|
||||
return b.root_tag
|
||||
|
||||
|
||||
|
||||
class RegistrationForm(FlaskForm):
|
||||
|
@ -169,10 +180,120 @@ def web_index():
|
|||
b(f"Váš token je: {g.user.token}")
|
||||
return b.print_file()
|
||||
|
||||
@app.route("/game/<int:game_id>", methods=['GET'])
|
||||
def web_game(game_id):
|
||||
ses = db.get_session()
|
||||
game = ses.query(db.Game).filter_by(game_id=game_id).one_or_none()
|
||||
teams = ses.query(db.Team).filter_by(game_id=game_id).order_by(db.Team.team_id).all()
|
||||
if game is None:
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
b = BasePage()
|
||||
with b.p().table(_class="data full"):
|
||||
with b.thead():
|
||||
b.line().th()("Id")
|
||||
b.line().th()("User")
|
||||
if g.org:
|
||||
b.line().th()("Akce")
|
||||
for team in teams:
|
||||
with b.tr():
|
||||
b.line().td()(team.team_id)
|
||||
b.line().td()(user_link(team.user),": ", team.name)
|
||||
if g.org:
|
||||
with b.td():
|
||||
with b.div(_class="btn-group", role="group"):
|
||||
b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_org_game_userchange.__name__, game_id=game.game_id, team_id=team.team_id))("Změnit uživatele")
|
||||
#b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_game.__name__, game_id=g.game_id))("Detail")
|
||||
|
||||
return b.print_file()
|
||||
|
||||
@app.route("/org/games")
|
||||
def web_org_games():
|
||||
games = db.get_session().query(db.Game).order_by(db.Game.game_id).all()
|
||||
b = BasePage()
|
||||
with b.p().table(_class="data full"):
|
||||
with b.thead():
|
||||
b.line().th()("Id")
|
||||
b.line().th()("Kolo")
|
||||
b.line().th()("Akce")
|
||||
for g in games:
|
||||
with b.tr():
|
||||
b.line().td()(g.game_id)
|
||||
with b.line().td():
|
||||
if g.working_on_next_state:
|
||||
b.b()(g.current_round, "++")
|
||||
else:
|
||||
b(g.current_round)
|
||||
with b.td():
|
||||
b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_game.__name__, game_id=g.game_id))("Detail")
|
||||
return b.print_file()
|
||||
|
||||
class GameUserchangeForm(FlaskForm):
|
||||
name = StringField("Jméno hry z pohledu týmu")
|
||||
set_no_user = SubmitField("Bez uživatele")
|
||||
submit_no_change = wtforms.SubmitField("Bez změny", render_kw={"style": "display: none"})
|
||||
|
||||
|
||||
@app.route("/org/game/<int:game_id>/team/<int:team_id>/change_user", methods=['GET', 'POST'])
|
||||
def web_org_game_userchange(game_id, team_id):
|
||||
ses = db.get_session()
|
||||
game = ses.query(db.Game).filter_by(game_id=game_id).one_or_none()
|
||||
team_to_edit = ses.query(db.Team).filter_by(game_id=game_id, team_id=team_id).one_or_none()
|
||||
teams = ses.query(db.Team).filter_by(game_id=game_id).order_by(db.Team.team_id).all()
|
||||
users = db.get_session().query(db.User).order_by(db.User.id).all()
|
||||
if game is None or team_to_edit is None:
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
teams_by_user = {u.id:[] for u in users}
|
||||
for t in teams:
|
||||
if t.user_id is not None:
|
||||
teams_by_user[t.user_id].append(t)
|
||||
|
||||
form = GameUserchangeForm(obj=team_to_edit)
|
||||
if form.validate_on_submit():
|
||||
team_to_edit.name = form.name.data
|
||||
if "submit_no_change" not in request.form:
|
||||
team_to_edit.user_id = None
|
||||
for u in users:
|
||||
if f"set_user_{u.id}" in request.form:
|
||||
team_to_edit.user_id = u.id
|
||||
try:
|
||||
ses.commit()
|
||||
except exc.IntegrityError:
|
||||
flash("Duplicitní přiřazení", 'danger')
|
||||
ses.rollback()
|
||||
else:
|
||||
flash("Uživatel změněn", 'success')
|
||||
return redirect(app.url_for(web_game.__name__, game_id=game_id))
|
||||
|
||||
b = BasePage()
|
||||
with b.form(action="", method="POST", _class="form form-horizontal", role="form"):
|
||||
b(form.csrf_token)
|
||||
b(form.submit_no_change)
|
||||
with b.div(_class="form-row"):
|
||||
b(jinja_mac.form_field(form.name, size=8))
|
||||
with b.p().table(_class="data full"):
|
||||
with b.thead():
|
||||
b.line().th()("Username")
|
||||
b.line().th()("Přiřazení")
|
||||
b.line().th()("Akce")
|
||||
for u in users:
|
||||
with b.tr():
|
||||
b.line().td(user_link(u))
|
||||
with b.td():
|
||||
if len(teams_by_user[u.id]):
|
||||
with b.ul():
|
||||
for t in teams_by_user[u.id]:
|
||||
b.li(f"{t.team_id} -> {t.name}")
|
||||
b.line().td().input(_class="btn btn-danger" if u.id == team_to_edit.user_id else "btn btn-primary", _id="set_participation_state", name=f"set_user_{u.id}", type="submit", value="Nastavit stav účasti")
|
||||
b(jinja_mac.form_field(form.set_no_user))
|
||||
return b.print_file()
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route("/org/users")
|
||||
def web_users():
|
||||
users = db.get_session().query(db.User).all()
|
||||
def web_org_users():
|
||||
users = db.get_session().query(db.User).order_by(db.User.id).all()
|
||||
b = BasePage()
|
||||
with b.p().table(_class="data full"):
|
||||
with b.thead():
|
||||
|
@ -181,10 +302,11 @@ def web_users():
|
|||
b.line().th()("Akce")
|
||||
for u in users:
|
||||
with b.tr():
|
||||
b.line().th()(u.username)
|
||||
b.line().th()
|
||||
with b.th():
|
||||
b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_org_user.__name__, user_id=u.id))("Detail")
|
||||
b.line().td()(u.username)
|
||||
b.line().td()
|
||||
with b.td():
|
||||
with b.div(_class="btn-group", role="group"):
|
||||
b.a(_class="btn btn-xs btn-primary", href=app.url_for(web_org_user.__name__, user_id=u.id))("Detail")
|
||||
return b.print_file()
|
||||
|
||||
@app.route("/org/user/<int:user_id>", methods=['GET', 'POST'])
|
||||
|
|
Loading…
Reference in a new issue