Skip to content

Commit

Permalink
Re-organize flask app
Browse files Browse the repository at this point in the history
  • Loading branch information
lemeryfertitta committed Dec 24, 2023
1 parent 9e43599 commit 8dfa7ef
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 6 deletions.
3 changes: 1 addition & 2 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
# TODO: Modify this Procfile to fit your needs
web: gunicorn app:app
web: gunicorn climbdex:create_app()
11 changes: 11 additions & 0 deletions climbdex/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import flask

import climbdex.api
import climbdex.views


def create_app():
app = flask.Flask(__name__, instance_relative_config=True)
app.register_blueprint(climbdex.api.blueprint)
app.register_blueprint(climbdex.views.blueprint)
return app
36 changes: 36 additions & 0 deletions climbdex/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import flask

import climbdex.db

blueprint = flask.Blueprint("api", __name__)


@blueprint.route("/api/v1/<board_name>/layouts")
def layouts(board_name):
return flask.jsonify(climbdex.db.get_data(board_name, "layouts"))


@blueprint.route("/api/v1/<board_name>/layouts/<layout_id>/sizes")
def sizes(board_name, layout_id):
return flask.jsonify(
climbdex.db.get_data(board_name, "sizes", {"layout_id": layout_id})
)


@blueprint.route("/api/v1/<board_name>/layouts/<layout_id>/sizes/<size_id>/sets")
def sets(board_name, layout_id, size_id):
return flask.jsonify(
climbdex.db.get_data(
board_name, "sets", {"layout_id": layout_id, "size_id": size_id}
)
)


@blueprint.route("/api/v1/search/count")
def resultsCount():
return flask.jsonify(climbdex.db.get_search_count(flask.request.args))


@blueprint.route("/api/v1/search")
def search():
return flask.jsonify(climbdex.db.get_search_results(flask.request.args))
191 changes: 191 additions & 0 deletions climbdex/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import flask
import sqlite3

QUERIES = {
"angles": """
SELECT angle
FROM products_angles
JOIN layouts
ON layouts.product_id = products_angles.product_id
WHERE layouts.id = $layout_id
ORDER BY angle ASC""",
"colors": """
SELECT
placement_roles.id,
'#' || placement_roles.screen_color
FROM placement_roles
JOIN layouts
ON layouts.product_id = placement_roles.product_id
WHERE layouts.id = $layout_id""",
"grades": """
SELECT
difficulty,
boulder_name
FROM difficulty_grades
WHERE is_listed = 1
ORDER BY difficulty ASC""",
"holds": """
SELECT
placements.id,
holes.x,
holes.y
FROM placements
INNER JOIN holes
ON placements.hole_id=holes.id
WHERE placements.layout_id = $layout_id
AND placements.set_id = $set_id""",
"layouts": """
SELECT id, name
FROM layouts
WHERE is_listed=1
AND password IS NULL""",
"layout_name": """
SELECT name
FROM layouts
WHERE id = $layout_id""",
"image_filename": """
SELECT
image_filename
FROM product_sizes_layouts_sets
WHERE layout_id = $layout_id
AND product_size_id = $size_id
AND set_id = $set_id""",
"search": """
SELECT
climbs.uuid,
climbs.setter_username,
climbs.name,
climbs.description,
climbs.frames,
climb_stats.angle,
climb_stats.ascensionist_count,
(SELECT boulder_name FROM difficulty_grades WHERE difficulty = ROUND(climb_stats.display_difficulty)) AS difficulty,
climb_stats.quality_average
FROM climbs
LEFT JOIN climb_stats
ON climb_stats.climb_uuid = climbs.uuid
INNER JOIN product_sizes
ON product_sizes.id = $size_id
WHERE climbs.frames_count = 1
AND climbs.is_draft = 0
AND climbs.is_listed = 1
AND climbs.layout_id = $layout_id
AND climbs.edge_left >= product_sizes.edge_left
AND climbs.edge_right <= product_sizes.edge_right
AND climbs.edge_bottom >= product_sizes.edge_bottom
AND climbs.edge_top <= product_sizes.edge_top
AND climb_stats.ascensionist_count >= $min_ascents
AND climb_stats.display_difficulty BETWEEN $min_grade AND $max_grade
AND climb_stats.quality_average >= $min_rating
""",
"sets": """
SELECT
sets.id,
sets.name
FROM sets
INNER JOIN product_sizes_layouts_sets psls on sets.id = psls.set_id
WHERE psls.product_size_id = $size_id
AND psls.layout_id = $layout_id""",
"size_name": """
SELECT
product_sizes.name
FROM product_sizes
INNER JOIN layouts
ON product_sizes.product_id = layouts.product_id
WHERE layouts.id = $layout_id
AND product_sizes.id = $size_id""",
"sizes": """
SELECT
product_sizes.id,
product_sizes.name,
product_sizes.description
FROM product_sizes
INNER JOIN layouts
ON product_sizes.product_id = layouts.product_id
WHERE layouts.id = $layout_id""",
"size_dimensions": """
SELECT
edge_left,
edge_right,
edge_bottom,
edge_top
FROM product_sizes
WHERE id = $size_id""",
}


def get_board_database(board_name):
try:
return flask.g.database
except AttributeError:
flask.g.database = sqlite3.connect(f"data/{board_name}/db.sqlite3")
return flask.g.database


def get_data(board_name, query_name, binds={}):
database = get_board_database(board_name)
cursor = database.cursor()
cursor.execute(QUERIES[query_name], binds)
return cursor.fetchall()


def get_search_count(args):
base_sql, binds = get_search_base_sql_and_binds(args)
database = get_board_database(args.get("board"))
cursor = database.cursor()
cursor.execute(f"SELECT COUNT(*) FROM ({base_sql})", binds)
return cursor.fetchall()[0][0]


def get_search_results(args):
base_sql, binds = get_search_base_sql_and_binds(args)
order_by_sql_name = {
"ascents": "climb_stats.ascensionist_count",
"difficulty": "climb_stats.display_difficulty",
"name": "climbs.name",
"quality": "climb_stats.quality_average",
}[flask.request.args.get("sortBy")]
sort_order = "ASC" if flask.request.args.get("sortOrder") == "asc" else "DESC"
ordered_sql = f"{base_sql} ORDER BY {order_by_sql_name} {sort_order}"

limited_sql = f"{ordered_sql} LIMIT $limit OFFSET $offset"
binds["limit"] = int(flask.request.args.get("pageSize", 10))
binds["offset"] = int(flask.request.args.get("page", 0)) * int(binds["limit"])

database = get_board_database(flask.request.args.get("board"))
cursor = database.cursor()
results = cursor.execute(limited_sql, binds).fetchall()
print(results)
return results


def get_search_base_sql_and_binds(args):
sql = QUERIES["search"]
binds = {
"layout_id": args.get("layout"),
"size_id": args.get("size"),
"min_ascents": args.get("minAscents"),
"min_grade": args.get("minGrade"),
"max_grade": args.get("maxGrade"),
"min_rating": args.get("minRating"),
}

angle = args.get("angle")
if angle and angle != "any":
sql += " AND climb_stats.angle = $angle"
binds["angle"] = angle

holds = args.get("holds")
if holds:
sql += " AND climbs.frames LIKE $like_string"
like_string_center = "%".join(
sorted(
f"p{hold_string}"
for hold_string in holds.split("p")
if len(hold_string) > 0
)
)
like_string = f"%{like_string_center}%"
binds["like_string"] = like_string

return sql, binds
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 7 additions & 3 deletions static/js/results.js → climbdex/static/js/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,18 @@ function drawResultsPage(pageNumber, pageSize) {
rating,
] = result;

const difficultyAngleText = `${difficulty} at ${angle}\u00B0`;
const difficultyAngleText =
difficulty && angle ? `${difficulty} at ${angle}\u00B0` : "";
listButton.addEventListener("click", function () {
drawClimb(uuid, name, frames, setter, difficultyAngleText);
});
const nameText = document.createElement("p");
nameText.textContent = `${name} (${difficultyAngleText})`;
nameText.textContent = `${name} ${difficultyAngleText}`;
const statsText = document.createElement("p");
statsText.textContent = `${ascents} ascents, ${rating.toFixed(2)}\u2605`;
statsText.textContent =
ascents && rating
? `${ascents} ascents, ${rating.toFixed(2)}\u2605`
: "";
statsText.classList.add("fw-light");
listButton.appendChild(nameText);
listButton.appendChild(statsText);
Expand Down
File renamed without changes
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</div>
<div class="input-group mb-3">
<span class="input-group-text">Min Ascents</span>
<input type="number" class="form-control" id="input-min-ascents" value="5" min="0" name="minAscents" />
<input type="number" class="form-control" id="input-min-ascents" value="1" min="1" name="minAscents" />
</div>
<div class="input-group mb-3">
<span class="input-group-text">Min Rating</span>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
80 changes: 80 additions & 0 deletions climbdex/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import boardlib.api.aurora
import flask

import climbdex.db

blueprint = flask.Blueprint("view", __name__)


@blueprint.route("/")
def index():
return flask.render_template(
"boardSelection.html.j2",
)


@blueprint.route("/filter")
def filter():
board_name = flask.request.args.get("board")
layout_id = flask.request.args.get("layout")
size_id = flask.request.args.get("size")
set_ids = flask.request.args.getlist("set")
return flask.render_template(
"filterSelection.html.j2",
params=flask.request.args,
board_name=board_name,
layout_name=climbdex.db.get_data(
board_name, "layout_name", {"layout_id": layout_id}
)[0][0],
size_name=climbdex.db.get_data(
board_name, "size_name", {"layout_id": layout_id, "size_id": size_id}
)[0][0],
angles=climbdex.db.get_data(board_name, "angles", {"layout_id": layout_id}),
grades=climbdex.db.get_data(board_name, "grades"),
colors=climbdex.db.get_data(board_name, "colors", {"layout_id": layout_id}),
**get_draw_board_kwargs(board_name, layout_id, size_id, set_ids),
)


@blueprint.route("/results")
def results():
board_name = flask.request.args.get("board")
layout_id = flask.request.args.get("layout")
size_id = flask.request.args.get("size")
set_ids = flask.request.args.getlist("set")
return flask.render_template(
"results.html.j2",
app_url=boardlib.api.aurora.WEB_HOSTS[board_name],
colors=climbdex.db.get_data(board_name, "colors", {"layout_id": layout_id}),
**get_draw_board_kwargs(
board_name,
layout_id,
size_id,
set_ids,
),
)


def get_draw_board_kwargs(board_name, layout_id, size_id, set_ids):
images_to_holds = {}
for set_id in set_ids:
image_filename = climbdex.db.get_data(
board_name,
"image_filename",
{"layout_id": layout_id, "size_id": size_id, "set_id": set_id},
)[0][0]
image_url = f"{boardlib.api.aurora.API_HOSTS[board_name]}/img/{image_filename}"
images_to_holds[image_url] = climbdex.db.get_data(
board_name, "holds", {"layout_id": layout_id, "set_id": set_id}
)

size_dimensions = climbdex.db.get_data(
board_name, "size_dimensions", {"size_id": size_id}
)[0]
return {
"images_to_holds": images_to_holds,
"edge_left": size_dimensions[0],
"edge_right": size_dimensions[1],
"edge_bottom": size_dimensions[2],
"edge_top": size_dimensions[3],
}

0 comments on commit 8dfa7ef

Please sign in to comment.