-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapp.py
More file actions
164 lines (132 loc) · 6.41 KB
/
Copy pathapp.py
File metadata and controls
164 lines (132 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""Flask application for managing vacation activities using Azure SQL Database."""
import logging
import os
from typing import List, Tuple
from activities import ActivitiesHelper
from flask import Flask, flash, redirect, render_template, request, url_for
# Initialize Flask application
app: Flask = Flask(__name__)
app.secret_key = os.environ.get('FLASK_SECRET_KEY', os.urandom(24))
# Configure logging
logging.basicConfig(
level=logging.INFO, # Set root logger to INFO to see all application logs
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Set external libraries to WARNING level to reduce noise
logging.getLogger('urllib3').setLevel(logging.WARNING)
logging.getLogger('azure').setLevel(logging.WARNING)
# Keep werkzeug (Flask) at INFO to see requests and enable VSCode browser popup
logging.getLogger('werkzeug').setLevel(logging.INFO)
# Get application logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Global variables for Azure SQL Database configuration
activities_helper: ActivitiesHelper
debug: bool = os.environ.get("FLASK_DEBUG", "false").lower() == "true"
activities: List[Tuple[str, str]] = []
def create_activity(activity: str | None = None) -> dict:
"""Create a activity with activity and timestamp."""
if not activity or not activity.strip():
raise ValueError("Activity cannot be None or empty")
return {
"username": username,
"activity": activity
}
def read_activities_from_db(username: str | None = None) -> List[Tuple[str, str]]:
"""Read all activities from the SQL Database."""
result = []
try:
if activities_helper and username:
activity_list = activities_helper.read_activities(username)
for activity in activity_list:
result.append((activity["id"], activity["activity"]))
except (ConnectionError, ValueError, KeyError) as e:
logger.error("Error reading activities: %s", e)
return result
@app.route('/', methods=['GET', 'POST'])
def index():
"""Handle the main page for viewing and adding activities."""
# Get edit data from query parameters (if any)
edit_id = request.args.get('edit_id')
edit_activity = request.args.get('edit_activity')
# Handle form submission. This part is not invoked when clicking the Edit button.
if request.method == 'POST':
activity_text = request.form.get('activity')
if activity_text:
try:
row_id = request.form.get('row_id')
if row_id:
# Update existing activity
if not row_id.strip():
raise ValueError("Row ID cannot be None or empty")
updated_activity = activities_helper.update_activity_by_id(row_id, activity_text)
if updated_activity:
flash('Activity updated.')
logger.info(f"Activity updated: {row_id}")
else:
# Create an activity document with the activity text provided
activity_doc: dict = create_activity(activity_text)
# Insert the activity into the database
inserted_activity = activities_helper.insert_activity(activity_doc)
if inserted_activity:
# Append the activity to the in-memory list
activities.append((inserted_activity["id"], inserted_activity["activity"]))
flash('Activity added.')
logger.info(f"Activity created: {inserted_activity['id']}")
except (ConnectionError, ValueError) as e:
logger.error("Error creating/updating activity: %s", e)
return redirect(url_for('index'))
# Always reload activities from SQL Database on GET (refresh)
activities.clear()
activities.extend(read_activities_from_db(username))
return render_template('index.html', activities=activities, username=username, edit_id=edit_id, edit_activity=edit_activity)
@app.route('/favicon.ico')
def favicon():
"""Serve the favicon from the static folder."""
return app.send_static_file('favicon.ico')
@app.route('/delete/<int:activity_id>', methods=['POST'])
def delete(activity_id: int):
"""Handle deletion of an activity by its index in the list."""
try:
if 0 <= activity_id < len(activities):
db_activity_id = activities[activity_id][0]
# Delete the activity from SQL Database
rows_deleted = activities_helper.delete_activity_by_id(db_activity_id)
if rows_deleted > 0:
flash('Activity deleted.')
logger.info(f"Activity deleted: {db_activity_id}")
else:
logger.warning(f"No activity found with ID: {db_activity_id}")
except (ConnectionError, ValueError) as e:
logger.error("Error deleting activity: %s", e)
return redirect(url_for('index'))
@app.route('/update/<int:activity_id>', methods=['GET'])
def update(activity_id: int):
"""Handle updating of an activity by its index in the list."""
try:
if 0 <= activity_id < len(activities):
db_activity_id = activities[activity_id][0]
activity_text = activities[activity_id][1]
# Redirect to index with edit parameters
return redirect(url_for('index', edit_id=db_activity_id, edit_activity=activity_text))
except (ConnectionError, ValueError) as e:
logger.error("Error preparing activity for update: %s", e)
return redirect(url_for('index'))
# Read debug environment variable
debug = os.environ.get("DEBUG", "false").lower() == "true"
# Initialize the application and Azure services when the module is loaded.
# This ensures that the setup runs regardless of how the app is started
# (e.g., via 'flask run' or directly).
activities_helper = ActivitiesHelper.from_env()
# Get username from form or environment variable
username = os.environ.get("LOGIN_NAME", "paolo")
# Validate username
if not username or not username.strip():
raise ValueError("Username cannot be None or empty")
if activities_helper:
# Read activities from SQL Database to populate the activities list
activities.extend(read_activities_from_db(username))
logger.info(f"Loaded {len(activities)} activities for user: {username}")
# Run the Flask application
if __name__ == '__main__':
app.run(debug=debug)