-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add querying endpoints for filters #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,4 +2,4 @@ Flask==3.0.0 | |
| Flask-CORS==4.0.0 | ||
| Flask-SQLAlchemy==3.1.1 | ||
| python-dotenv==1.0.0 | ||
| SQLAlchemy==2.0.23 | ||
| SQLAlchemy==2.0.35 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| from flask import Blueprint, request, jsonify | ||
| from database import db | ||
| from sqlalchemy import inspect | ||
| from models import StudySpot | ||
| from datetime import datetime | ||
| import logging | ||
|
|
@@ -59,6 +60,73 @@ def health_check(): | |
|
|
||
| TIME_PATTERN = re.compile(r'^([01]\d|2[0-3]):([0-5]\d)$') | ||
|
|
||
| @api_bp.route('/schema', methods=['GET']) | ||
| def get_schema(): | ||
| """Return database schema information.""" | ||
| try: | ||
| # Get all tables | ||
| inspector = inspect(db.engine) | ||
| tables = inspector.get_table_names() | ||
|
|
||
| schema = {} | ||
| for table in tables: | ||
| columns = inspector.get_columns(table) | ||
| schema[table] = { | ||
| 'columns': [ | ||
| { | ||
| 'name': col['name'], | ||
| 'type': str(col['type']), | ||
| 'nullable': col['nullable'], | ||
| 'default': str(col['default']) if col['default'] is not None else None | ||
| } | ||
| for col in columns | ||
| ] | ||
| } | ||
|
|
||
| return jsonify(schema), 200 | ||
| except Exception as e: | ||
| logger.error(f"Error getting schema: {str(e)}") | ||
| return jsonify({'error': 'Failed to get schema'}), 500 | ||
|
|
||
| @api_bp.route('/study_spots/raw', methods=['GET']) | ||
| def get_raw_study_spots(): | ||
| """Return raw StudySpot data as-is from database.""" | ||
| try: | ||
| spots = StudySpot.query.all() | ||
| return jsonify([s.to_dict() for s in spots]), 200 | ||
|
Comment on lines
+91
to
+96
|
||
| except Exception as e: | ||
| logger.error(f"Error fetching raw study spots: {str(e)}") | ||
| return jsonify({'error': 'Failed to fetch study spots'}), 500 | ||
|
|
||
| @api_bp.route('/study_spots/distinct/<column>', methods=['GET']) | ||
| def get_distinct_values(column): | ||
| try: | ||
| allowed_columns = {'spot_type', 'noise_level', 'tags', 'access_hours'} | ||
| if column not in allowed_columns: | ||
| return jsonify({'error': 'Invalid column name'}), 400 | ||
|
|
||
| if column == 'access_hours': | ||
| # For open now, return boolean options as JSON booleans | ||
| return jsonify([True, False]), 200 | ||
| elif column in {'spot_type', 'tags'}: | ||
| # Handle JSON arrays | ||
| spots = StudySpot.query.all() | ||
| values = set() | ||
|
Comment on lines
+111
to
+114
|
||
| for spot in spots: | ||
| col_data = getattr(spot, column) | ||
| if col_data: | ||
| for item in col_data: | ||
| if item: | ||
| values.add(str(item)) | ||
| else: | ||
| # Handle regular string columns | ||
| values = db.session.query(getattr(StudySpot, column)).distinct().all() | ||
| values = [v[0] for v in values if v[0] is not None] | ||
|
|
||
| return jsonify(sorted(list(values))), 200 | ||
| except Exception as e: | ||
| logger.error(f"Error fetching distinct values for column {column}: {str(e)}") | ||
| return jsonify({'error': 'Failed to fetch distinct values'}), 500 | ||
|
|
||
| def _normalize_access_hours(value): | ||
| """ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
/api/schemaendpoint exposes internal database structure (table/column names, types, defaults) and is currently publicly accessible with permissive CORS. This is sensitive information that can aid attackers; consider removing this from the public API or gating it behind admin auth / an environment flag (e.g., only enabled in development).