Skip to content

Commit

Permalink
Update from private repo
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Sep 23, 2024
1 parent 4e08451 commit 4ef8bc6
Show file tree
Hide file tree
Showing 31 changed files with 1,066 additions and 10,698 deletions.
28 changes: 14 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
.env
.vscode/
env/
__pycache__/
logic/__pycache__/
models/__pycache__/
sqlite_db.db
venv/
formInfo.log
.DS_Store
queryInfo.log
reports/
app/reports/
app/feedback
.env
.vscode/
env/
__pycache__/
sqlite_db.db
venv/
formInfo.log
.DS_Store
queryInfo.log
reports/
app/reports/
!app/logic/reports
app/feedback
api_response.json
185 changes: 38 additions & 147 deletions app/app.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from flask import Flask, render_template, jsonify, send_file, request
from dotenv import load_dotenv
from app.reports import sanitize_and_process_reports
from app.feedback import sanitize_and_process_feedback
from app.softwareTable import create_software_table

import os
from app.logic.reports.reports import sanitize_and_process_reports, save_user_report
from app.logic.reports.feedback import sanitize_and_process_feedback, save_user_feedback
from app.logic.example_use import find_example_use
from app.logic.software_table.softwareTable import create_software_table
from app.logic.lastUpdated import get_last_updated
import re
import json

import pandas as pd
from datetime import datetime
# import logging

app = Flask(__name__)
Expand All @@ -18,62 +17,47 @@
def software_search():
try:
df = pd.read_csv("./data/CSV/softwareTable.csv", keep_default_na=False)
print("Table found!")
except FileNotFoundError as e:
df = create_software_table()
print(e)

table = df.to_html(classes='table-striped" id = "softwareTable',index=False,border=1).replace('\\n', '<br>')
return render_template("software_search.html",table=table)

# column map with column names as keys and index as values. special characters are stripped from column names so "✨General Tags" becomes "GeneralTags"
column_map = {re.sub(r'[^a-zA-Z0-9]', '', col): df.columns.get_loc(col) for col in df.columns}

last_updated = get_last_updated()

return render_template("software_search.html",
table=table,
column_map=column_map,
last_updated=last_updated)

# 'Example Use' Modal Route
@app.route("/example_use/<path:software_name>")
def get_example_use(software_name):

if software_name == '7-Zip':
software_name = '7z'

file_directory = "./data/exampleUse/"
example_use = find_example_use(software_name)
if example_use:
return (jsonify({"use": example_use}))

normalize_software_name = re.escape(software_name).lower()

pattern = re.compile(normalize_software_name, re.IGNORECASE)

try:
for filename in os.listdir(file_directory):
if pattern.search(filename):
with open(os.path.join(file_directory,filename),'r') as file:
file_content = file.read()
return(jsonify({"use": file_content}))
return jsonify({"use": '**Unable to find use case record**'})
except Exception as e:
print(e)
return(jsonify({"use": '**Unable to find use case record**'})), 500
return (jsonify({"use": '**Unable to find use case record**'}))

# 'Report Issue' Button Route
@app.route("/report-issue", methods=['POST'])
def report_issue():
issue_report = request.get_json()

if issue_report['reportDetails']:
report = sanitize_and_process_reports(issue_report)
current_datetime = report['datetime']
user_report = request.get_json()

report_folder = os.path.join('reports', current_datetime)
os.makedirs(report_folder, exist_ok=True)
report_filename = os.path.join(report_folder, 'report.json')
with open(report_filename, 'w') as f:
json.dump(report, f, indent=4)
if 'reportDetails' in user_report:
issue_report = sanitize_and_process_reports(user_report)
report_saved = save_user_report(issue_report)

else:
current_datetime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
report_folder = os.path.join('reports', current_datetime)
os.makedirs(report_folder, exist_ok=True)
report_filename = os.path.join(report_folder, 'report.json')
with open(report_filename, 'w') as f:
json.dump(issue_report, f, indent=4)
if report_saved:
return jsonify({'success': "Issue reported successfully"})

return({'error': "Unable to save issue report"}), 500

return jsonify({'message': 'Issue reported successfully'})
return jsonify({'error': 'Missing key reportDetails'}), 400


## Flask Route Definition for User Feedback Button
Expand All @@ -83,109 +67,16 @@ def process_feedback():
# Grab Ajax Request
user_feedback = request.get_json()

# Sanitize Feedback if necessary
if user_feedback['feedbackForm']:
feedback = sanitize_and_process_feedback(user_feedback)
current_datetime = feedback['datetime']

# Create folder and make feedback file
feedback_folder = os.path.join('feedback', current_datetime)
os.makedirs(feedback_folder, exist_ok=True)
feedback_filename = os.path.join(feedback_folder, 'feedback.json')
with open(feedback_filename, 'w') as f:
json.dump(feedback, f, indent=4)

else:
current_datetime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
feedback_folder = os.path.join('feedback', current_datetime)
os.makedirs(feedback_folder, exist_ok=True)
feedback_filename = os.path.join(feedback_folder, 'feedback.json')
with open(feedback_filename, 'w') as f:
json.dump(user_feedback, f, indent=4)

return jsonify({'success': 'Feedback processed successfully'})


######################
### TESTING-IGNORE ###
######################
# Set up basic logging
#logging.basicConfig(level=logging.DEBUG)

#@app.route("/data", methods=['POST'])
#def data():
try:
# Log start of the request processing
logging.debug("Starting to process request")
# Read parameters from DataTables
draw = request.form.get('draw', type=int, default=1) # A counter to ensure that the Ajax requests are processed sequentially.
start = request.form.get('start', type=int, default=0) # The starting index of the data to be fetched (for pagination)
length = request.form.get('length', type=int, default=10) # The number of records to fetch (page size)
order_column = request.form.get('order[0][column]', type=int, default=0) # The column index to sort by
order_dir = request.form.get('order[0][dir]', default='asc') # The direction of sorting ('asc' or 'desc')
search_value = request.form.get('search[value]', default='') # The search term entered by the user

logging.debug(f"Draw: {draw}, Start: {start}, Length: {length}, Order Column: {order_column}, Order Dir: {order_dir}, Search Value: {search_value}")

# Read the CSV file
csv_path = './data/CSV/softwareTable.csv' # Adjust path to your CSV file
logging.debug(f"Reading CSV file from: {csv_path}")
df = pd.read_csv(csv_path) # Adjust path to your CSV file

# Define the column mapping
columns = [
'Software','RP Name','✨Software Type','✨Software Class','✨Research Field','✨Research Area','✨Research Discipline','Software Description',
'✨Core Features','✨General Tags',"Software's Web Page",'Software Documentation','Example Software Use','RP Software Documentation','Version Info',
'✨AI Description','✨Example Use'
]
logging.debug(f"CSV columns: {columns}")

# Filtering
if search_value:
logging.debug(f"Applying search filter: {search_value}")
df = df[df.apply(lambda row: row.astype(str).str.contains(search_value, case=False).any(), axis=1)]

# Sorting
logging.debug(f"Sorting by column: {columns[order_column]}, direction: {order_dir}")
if order_dir == 'asc':
df = df.sort_values(by=columns[order_column])
else:
df = df.sort_values(by=columns[order_column], ascending=False)

# Paging
records_total = len(df)
logging.debug(f"Total records: {records_total}")
df_page = df.iloc[start:start+length]
records_filtered = len(df)
logging.debug(f"Filtered records: {records_filtered}")

# Prepare the response
# Reorder DataFrame columns to match the expected order
df_page_reordered = df_page[columns]

# Convert reordered DataFrame to list of dictionaries
data_reordered = df_page_reordered.to_dict(orient='records')

response = {
"draw": draw,
"recordsTotal": records_total,
"recordsFiltered": records_filtered,
"data": data_reordered
}

# Limit the data shown in logs for debugging
logging.debug(f"Records Total: {records_total}, Records Filtered: {records_filtered}")
logging.debug(f"Data Sample: {df_page.head().to_dict(orient='records')}")

return jsonify(response)

except Exception as e:
logging.error(f"Error occurred: {e}")
return jsonify({"error": str(e)})
##################
### END IGNORE ###
##################
if 'feedback' in user_feedback:
feedback_report = sanitize_and_process_feedback(user_feedback)
feedback_saved = save_user_feedback(feedback_report)

if feedback_saved:
return jsonify({'success': 'Feedback processed successfully'})

return({'error': "Unable to save user feedback"}), 500

return jsonify({'error': "Missing key feedback."}), 400

# Display Images
@app.route("/images/<filename>")
Expand Down
16 changes: 0 additions & 16 deletions app/feedback.py

This file was deleted.

39 changes: 39 additions & 0 deletions app/logic/example_use.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from pathlib import Path
import re


#########################################################################
# find_example_use #
# Search for and retrieve example usage of a specified software #
# from text files in a given directory. #
# parameters: #
# software_name {str}: Name of the software to search for #
# example_use_dir {str}: Directory path to search for example #
# usage files (default: 'data/exampleUse') #
# return: #
# {str or bool}: Content of the first matching file if found, #
# False if an error occurs or no match is found #
# notes: #
# - Searches for case-insensitive matches in file names #
# - Returns the entire content of the first matching file #
#########################################################################
def find_example_use(software_name, example_use_dir = 'data/exampleUse'):

normalized_software_name = re.escape(software_name).lower()

# software name pattern to search for in the files
pattern = re.compile(normalized_software_name, re.IGNORECASE)

example_use_path = Path.cwd() / example_use_dir

try:
for file_path in example_use_path.iterdir():
if pattern.search(file_path.stem): # get only the file name (with extensions like .txt)
with open(file_path, 'r') as file:
example_use = file.read()
return example_use

except Exception as e:
print(e)
return False

18 changes: 18 additions & 0 deletions app/logic/lastUpdated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from datetime import datetime
import pytz

def get_last_updated(file_path="./static/last_updated.txt", timezone='US/Eastern'):
"""
returns datetime of when the software_table data was last updated
"""
with open(file_path, 'r') as luf:
date_time = luf.readline().strip()

try:
date_obj = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S")
# Format output
output = date_obj.strftime("%B %d, %Y at %I:%M:%S %p Eastern Daylight Time")
return output
except Exception as e:
print("ERROR trying to convert datetime", e)
return(date_time)
61 changes: 61 additions & 0 deletions app/logic/reports/feedback.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from datetime import datetime
from pathlib import Path
import json


#########################################################################
# sanitize_and_process_feedback #
# Process the user feedback. Currently no code is added to for #
# sanitization. #
# parameter: #
# user_feedback {dict}: dict with feedback as a key and the #
# feedback retrieved from the user as values #
# return: #
# report{dict}: dict with datetime and feedback as keys. datetime #
# contains the date and time of when the report was received #
#########################################################################
def sanitize_and_process_feedback(user_feedback):
# Pull user-submitted form contents from modal
feedback_text = user_feedback['feedback']

# Generate timestamp
current_datetime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

# Create report
report = {
"datetime": current_datetime,
"feedback": feedback_text,
}

return report

#########################################################################
# save_user_feedback #
# creates a new directory for each feedback and dumps the feedback#
# text into a json file inside the dir. #
# parameter: #
# feedback_report{dict}: dict with 'feedback' and 'datetime' as #
# keys. obtained from sanitize_and_process_feedback function #
# return: #
# True{bool}: If feedback was successfully saved #
# False{bool}: If there was an error saving the feedback #
#########################################################################
def save_user_feedback(feedback_report):

try:
# cwd Returns the current working directory.
# In our case it returns the cwd of where the application was run from (the app dir) not this .py file
feedback_folder = Path.cwd() / "feedback" / feedback_report['datetime']
feedback_folder.mkdir(parents=True, exist_ok=True)
feedback_file = feedback_folder / "feedback.json"

with open(feedback_file, 'w') as f:
json.dump(feedback_report, f, indent=4)

return True

except Exception as e:
print(e)

return False

Loading

0 comments on commit 4ef8bc6

Please sign in to comment.