Skip to content

Commit 08647fb

Browse files
committed
a
1 parent 0d5db02 commit 08647fb

File tree

10 files changed

+214
-369
lines changed

10 files changed

+214
-369
lines changed

.github/workflows/starter-no-infra_msdcos-poython-postgres-pap3.yml

Lines changed: 0 additions & 81 deletions
This file was deleted.

app.py

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import os
2-
from flask import Flask, redirect, render_template, request, send_from_directory, url_for, jsonify
2+
from datetime import datetime
3+
4+
from flask import Flask, redirect, render_template, request, send_from_directory, url_for
35
from flask_migrate import Migrate
46
from flask_sqlalchemy import SQLAlchemy
57
from flask_wtf.csrf import CSRFProtect
6-
from datetime import datetime, timezone
7-
# Main application
8+
9+
810
app = Flask(__name__, static_folder='static')
911
csrf = CSRFProtect(app)
1012

11-
# Configuración según entorno
13+
# WEBSITE_HOSTNAME exists only in production environment
1214
if 'WEBSITE_HOSTNAME' not in os.environ:
15+
# local development, where we'll use environment variables
1316
print("Loading config.development and environment variables from .env file.")
1417
app.config.from_object('azureproject.development')
15-
else:
18+
else:
19+
# production
1620
print("Loading config.production.")
1721
app.config.from_object('azureproject.production')
1822

@@ -21,70 +25,99 @@
2125
SQLALCHEMY_TRACK_MODIFICATIONS=False,
2226
)
2327

24-
# Inicializar base de datos
28+
# Initialize the database connection
2529
db = SQLAlchemy(app)
30+
31+
# Enable Flask-Migrate commands "flask db init/migrate/upgrade" to work
2632
migrate = Migrate(app, db)
2733

28-
# Importar modelos después de inicializar db
29-
from models import Restaurant, Review, ImageData
34+
# The import must be done after db initialization due to circular import issue
35+
from models import Restaurant, Review
3036

3137
@app.route('/', methods=['GET'])
3238
def index():
3339
print('Request for index page received')
3440
restaurants = Restaurant.query.all()
3541
return render_template('index.html', restaurants=restaurants)
3642

43+
@app.route('/<int:id>', methods=['GET'])
44+
def details(id):
45+
restaurant = Restaurant.query.where(Restaurant.id == id).first()
46+
reviews = Review.query.where(Review.restaurant == id)
47+
return render_template('details.html', restaurant=restaurant, reviews=reviews)
3748

49+
@app.route('/create', methods=['GET'])
50+
def create_restaurant():
51+
print('Request for add restaurant page received')
52+
return render_template('create_restaurant.html')
3853

54+
@app.route('/add', methods=['POST'])
55+
@csrf.exempt
56+
def add_restaurant():
57+
try:
58+
name = request.values.get('restaurant_name')
59+
street_address = request.values.get('street_address')
60+
description = request.values.get('description')
61+
except (KeyError):
62+
# Redisplay the question voting form.
63+
return render_template('add_restaurant.html', {
64+
'error_message': "You must include a restaurant name, address, and description",
65+
})
66+
else:
67+
restaurant = Restaurant()
68+
restaurant.name = name
69+
restaurant.street_address = street_address
70+
restaurant.description = description
71+
db.session.add(restaurant)
72+
db.session.commit()
3973

40-
@app.route('/images', methods=['GET'])
41-
def image_table():
42-
print('Request for image table page received')
43-
images = ImageData.query.order_by(ImageData.upload_time.desc()).all()
44-
return render_template('index.html', images=images)
74+
return redirect(url_for('details', id=restaurant.id))
4575

76+
@app.route('/review/<int:id>', methods=['POST'])
4677
@csrf.exempt
47-
@app.route('/upload_image', methods=['POST'])
48-
def upload_image():
49-
print('Request to upload image received')
50-
if not request.is_json:
51-
return jsonify({"error": "Request must be JSON"}), 400
52-
53-
data = request.get_json()
54-
filename = data.get('filename')
55-
pixel_red = data.get('pixel_red')
56-
pixel_green = data.get('pixel_green')
57-
pixel_blue = data.get('pixel_blue')
58-
username = data.get('username')
59-
60-
61-
if not all([filename, pixel_red, pixel_green, pixel_blue, username]):
62-
return jsonify({"error": "All fields ('filename', 'pixel_red', 'pixel_green', 'pixel_blue', 'username') are required"}), 400
63-
78+
def add_review(id):
6479
try:
65-
new_image = ImageData(
66-
filename=filename,
67-
pixel_red=pixel_red,
68-
pixel_green=pixel_green,
69-
pixel_blue=pixel_blue,
70-
username=username,
71-
upload_time=datetime.now(timezone.utc)
72-
73-
)
74-
#db.session.create_all()
75-
#db.session.commit()
76-
db.session.add(new_image)
80+
user_name = request.values.get('user_name')
81+
rating = request.values.get('rating')
82+
review_text = request.values.get('review_text')
83+
except (KeyError):
84+
#Redisplay the question voting form.
85+
return render_template('add_review.html', {
86+
'error_message': "Error adding review",
87+
})
88+
else:
89+
review = Review()
90+
review.restaurant = id
91+
review.review_date = datetime.now()
92+
review.user_name = user_name
93+
review.rating = int(rating)
94+
review.review_text = review_text
95+
db.session.add(review)
7796
db.session.commit()
78-
return jsonify({"message": "Image uploaded successfully"}), 201
79-
except Exception as e:
80-
db.session.rollback()
81-
return jsonify({"error": str(e)}), 500
97+
98+
return redirect(url_for('details', id=id))
99+
100+
@app.context_processor
101+
def utility_processor():
102+
def star_rating(id):
103+
reviews = Review.query.where(Review.restaurant == id)
104+
105+
ratings = []
106+
review_count = 0
107+
for review in reviews:
108+
ratings += [review.rating]
109+
review_count += 1
110+
111+
avg_rating = sum(ratings) / len(ratings) if ratings else 0
112+
stars_percent = round((avg_rating / 5.0) * 100) if review_count > 0 else 0
113+
return {'avg_rating': avg_rating, 'review_count': review_count, 'stars_percent': stars_percent}
114+
115+
return dict(star_rating=star_rating)
82116

83117
@app.route('/favicon.ico')
84118
def favicon():
85119
return send_from_directory(os.path.join(app.root_path, 'static'),
86120
'favicon.ico', mimetype='image/vnd.microsoft.icon')
87121

88-
89122
if __name__ == '__main__':
90-
app.run()
123+
app.run()

azureproject/production.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
22

3-
DATABASE_URI = 'postgresql+psycopg2://{dbuser}:{dbpass}@{dbhost}/{dbname}'.format(
4-
dbuser=os.getenv('AZURE_POSTGRESQL_USER'),
5-
dbpass=os.getenv('AZURE_POSTGRESQL_PASSWORD'),
6-
dbhost=os.getenv('AZURE_POSTGRESQL_HOST'),
7-
dbname=os.getenv('AZURE_POSTGRESQL_NAME')
8-
)
3+
# DATABASE_URI = 'postgresql+psycopg2://{dbuser}:{dbpass}@{dbhost}/{dbname}'.format(
4+
# dbuser=os.getenv('AZURE_POSTGRESQL_USER'),
5+
# dbpass=os.getenv('AZURE_POSTGRESQL_PASSWORD'),
6+
# dbhost=os.getenv('AZURE_POSTGRESQL_HOST'),
7+
# dbname=os.getenv('AZURE_POSTGRESQL_NAME')
8+
# )

migrations/env.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import with_statement
2+
13
import logging
24
from logging.config import fileConfig
35

@@ -14,43 +16,22 @@
1416
fileConfig(config.config_file_name)
1517
logger = logging.getLogger('alembic.env')
1618

17-
18-
def get_engine():
19-
try:
20-
# this works with Flask-SQLAlchemy<3 and Alchemical
21-
return current_app.extensions['migrate'].db.get_engine()
22-
except (TypeError, AttributeError):
23-
# this works with Flask-SQLAlchemy>=3
24-
return current_app.extensions['migrate'].db.engine
25-
26-
27-
def get_engine_url():
28-
try:
29-
return get_engine().url.render_as_string(hide_password=False).replace(
30-
'%', '%%')
31-
except AttributeError:
32-
return str(get_engine().url).replace('%', '%%')
33-
34-
3519
# add your model's MetaData object here
3620
# for 'autogenerate' support
3721
# from myapp import mymodel
3822
# target_metadata = mymodel.Base.metadata
39-
config.set_main_option('sqlalchemy.url', get_engine_url())
40-
target_db = current_app.extensions['migrate'].db
23+
config.set_main_option(
24+
'sqlalchemy.url',
25+
str(current_app.extensions['migrate'].db.get_engine().url).replace(
26+
'%', '%%'))
27+
target_metadata = current_app.extensions['migrate'].db.metadata
4128

4229
# other values from the config, defined by the needs of env.py,
4330
# can be acquired:
4431
# my_important_option = config.get_main_option("my_important_option")
4532
# ... etc.
4633

4734

48-
def get_metadata():
49-
if hasattr(target_db, 'metadatas'):
50-
return target_db.metadatas[None]
51-
return target_db.metadata
52-
53-
5435
def run_migrations_offline():
5536
"""Run migrations in 'offline' mode.
5637
@@ -65,7 +46,7 @@ def run_migrations_offline():
6546
"""
6647
url = config.get_main_option("sqlalchemy.url")
6748
context.configure(
68-
url=url, target_metadata=get_metadata(), literal_binds=True
49+
url=url, target_metadata=target_metadata, literal_binds=True
6950
)
7051

7152
with context.begin_transaction():
@@ -90,17 +71,14 @@ def process_revision_directives(context, revision, directives):
9071
directives[:] = []
9172
logger.info('No changes in schema detected.')
9273

93-
conf_args = current_app.extensions['migrate'].configure_args
94-
if conf_args.get("process_revision_directives") is None:
95-
conf_args["process_revision_directives"] = process_revision_directives
96-
97-
connectable = get_engine()
74+
connectable = current_app.extensions['migrate'].db.get_engine()
9875

9976
with connectable.connect() as connection:
10077
context.configure(
10178
connection=connection,
102-
target_metadata=get_metadata(),
103-
**conf_args
79+
target_metadata=target_metadata,
80+
process_revision_directives=process_revision_directives,
81+
**current_app.extensions['migrate'].configure_args
10482
)
10583

10684
with context.begin_transaction():

migrations/versions/.placeholder

Whitespace-only changes.

0 commit comments

Comments
 (0)