From dcbb57b47469730494420179bac8b8d6cf9306e6 Mon Sep 17 00:00:00 2001 From: Sudo-JHare Date: Tue, 15 Apr 2025 20:03:13 +1000 Subject: [PATCH] Incremental Update POC complete --- .env | 4 + .gitignore | 123 +++++++++ Dockerfile | 1 - app/routes.py | 124 ++++++--- app/templates/New folder/app_detail.html.txt | 58 ++++ app/templates/New folder/base.html.txt | 183 +++++++++++++ app/templates/New folder/edit_app.html.txt | 214 +++++++++++++++ app/templates/New folder/gallery.html.txt | 247 ++++++++++++++++++ app/templates/New folder/login.html.txt | 32 +++ app/templates/New folder/my_listings.html.txt | 33 +++ app/templates/New folder/register.html.txt | 193 ++++++++++++++ .../New folder/register_user.html.txt | 40 +++ app/templates/base.html | 158 +++++++++-- app/templates/gallery.html | 74 ++---- app/templates/register.html | 2 +- instance/smart_app_gallery.db | Bin 86016 -> 86016 bytes ...a8-506e-41ef-9b9a-4e260345b8d7_A1_test.png | Bin 0 -> 36217 bytes 17 files changed, 1367 insertions(+), 119 deletions(-) create mode 100644 .env create mode 100644 .gitignore create mode 100644 app/templates/New folder/app_detail.html.txt create mode 100644 app/templates/New folder/base.html.txt create mode 100644 app/templates/New folder/edit_app.html.txt create mode 100644 app/templates/New folder/gallery.html.txt create mode 100644 app/templates/New folder/login.html.txt create mode 100644 app/templates/New folder/my_listings.html.txt create mode 100644 app/templates/New folder/register.html.txt create mode 100644 app/templates/New folder/register_user.html.txt create mode 100644 uploads/da0e7aa8-506e-41ef-9b9a-4e260345b8d7_A1_test.png diff --git a/.env b/.env new file mode 100644 index 0000000..99e1fbb --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +GOOGLE_CLIENT_ID=your-google-client-id +GOOGLE_CLIENT_SECRET=your-google-client-secret +GITHUB_CLIENT_ID=Ov23liuhXJZtRpcdqFzf +GITHUB_CLIENT_SECRET=a3c5db76c59eae2dfcc84c2c59019e019210c47a \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..781b277 --- /dev/null +++ b/.gitignore @@ -0,0 +1,123 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually ignored by MicroPython Checkignore tool +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff (if used later, good to have) +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff +instance/ # Important: Ignore instance folder (contains DB, config secrets) +.webassets-cache + +# Scrapy stuff (if used later) +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# PEP 582; used by PDM, Flit, and Rye +__pypackages__/ + +# Celery stuff (if used later) +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env # Important: Ignore environment file (contains secrets) +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# PyDev project settings +.pydevproject + +# VSCode Pylance cache +.pylance_cache/ + +# Editor directories and files +.idea/ +.vscode/ +*.sublime-project +*.sublime-workspace +*.DS_Store +Thumbs.db diff --git a/Dockerfile b/Dockerfile index 0bf687d..79f6611 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,6 @@ RUN pip install --no-cache-dir -r requirements.txt COPY app/ app/ COPY static/ static/ COPY instance/ instance/ -copy uploads app/uploads/ COPY config.py . COPY .env . EXPOSE 5000 diff --git a/app/routes.py b/app/routes.py index 2980bfd..5a1d5da 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,5 +1,5 @@ #app/routes.py -from flask import Blueprint, render_template, redirect, url_for, flash, request +from flask import Blueprint, render_template, redirect, url_for, flash, request, send_from_directory, abort # Added send_from_directory and abort from flask_login import login_required, current_user from app import db from app.models import SmartApp, ApplicationType, Category, OSSupport, FHIRSupport, Speciality, PricingLicense, DesignedFor, EHRSupport @@ -16,12 +16,25 @@ logger = logging.getLogger(__name__) gallery_bp = Blueprint('gallery', __name__) +# Absolute path to the upload folder inside the container UPLOAD_FOLDER = '/app/uploads/' ALLOWED_EXTENSIONS = {'jpg', 'png'} def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS +# New route to serve uploaded files +@gallery_bp.route('/uploads/') +def uploaded_file(filename): + # Use the absolute path to the directory inside the container + absolute_upload_folder = os.path.abspath(UPLOAD_FOLDER) + logger.debug(f"Attempting to serve file: {filename} from {absolute_upload_folder}") + try: + return send_from_directory(absolute_upload_folder, filename) + except FileNotFoundError: + logger.error(f"File not found: {os.path.join(absolute_upload_folder, filename)}") + abort(404) + @gallery_bp.route('/') def index(): return redirect(url_for('gallery.gallery')) @@ -92,22 +105,22 @@ def app_detail(app_id): if app.categories: category_ids = [int(cid) for cid in app.categories.split(',') if cid] app_categories = Category.query.filter(Category.id.in_(category_ids)).all() - + app_specialties = [] if app.specialties: speciality_ids = [int(sid) for sid in app.specialties.split(',') if sid] app_specialties = Speciality.query.filter(Speciality.id.in_(speciality_ids)).all() - + app_os_supports = [] if app.os_support: os_ids = [int(oid) for oid in app.os_support.split(',') if oid] app_os_supports = OSSupport.query.filter(OSSupport.id.in_(os_ids)).all() - + app_ehr_supports = [] if app.ehr_support: ehr_ids = [int(eid) for eid in app.ehr_support.split(',') if eid] app_ehr_supports = EHRSupport.query.filter(EHRSupport.id.in_(ehr_ids)).all() - + return render_template( 'app_detail.html', app=app, @@ -134,6 +147,7 @@ def register(): # Ensure upload folder exists try: + # Use the absolute path inside the container os.makedirs(UPLOAD_FOLDER, exist_ok=True) logger.debug(f"Ensured {UPLOAD_FOLDER} exists") except Exception as e: @@ -189,6 +203,7 @@ def register(): file = form.logo_upload.data if allowed_file(file.filename): filename = secure_filename(f"{uuid.uuid4()}_{file.filename}") + # Use absolute path for saving save_path = os.path.join(UPLOAD_FOLDER, filename) logger.debug(f"Attempting to save logo to {save_path}") try: @@ -199,7 +214,8 @@ def register(): logger.error(f"Failed to save logo to {save_path}") flash('Failed to save logo.', 'danger') return render_template('register.html', form=form) - logo_url = f"/app/uploads/{filename}" + # Store URL path for web access + logo_url = f"/uploads/{filename}" # CHANGED logger.debug(f"Set logo_url to {logo_url}") except Exception as e: logger.error(f"Error saving logo to {save_path}: {e}") @@ -209,11 +225,13 @@ def register(): # Handle app images app_images = [] if form.app_image_urls.data: - app_images.extend([url.strip() for url in form.app_image_urls.data.splitlines() if url.strip()]) - if form.app_image_uploads.data: + # Keep existing URLs if they are valid URLs + app_images.extend([url.strip() for url in form.app_image_urls.data.splitlines() if url.strip().startswith(('http://', 'https://'))]) + if form.app_image_uploads.data: # Check if a file was uploaded file = form.app_image_uploads.data - if allowed_file(file.filename): + if file and allowed_file(file.filename): # Check if file object exists and is allowed filename = secure_filename(f"{uuid.uuid4()}_{file.filename}") + # Use absolute path for saving save_path = os.path.join(UPLOAD_FOLDER, filename) logger.debug(f"Attempting to save app image to {save_path}") try: @@ -224,7 +242,8 @@ def register(): logger.error(f"Failed to save app image to {save_path}") flash('Failed to save app image.', 'danger') return render_template('register.html', form=form) - app_images.append(f"/app/uploads/{filename}") + # Store URL path for web access + app_images.append(f"/uploads/{filename}") # CHANGED except Exception as e: logger.error(f"Error saving app image to {save_path}: {e}") flash('Error saving app image.', 'danger') @@ -235,7 +254,7 @@ def register(): description=form.description.data, developer=form.developer.data, contact_email=form.contact_email.data, - logo_url=logo_url or None, + logo_url=logo_url or None, # Use the potentially updated logo_url launch_url=form.launch_url.data, client_id=form.client_id.data, scopes=scopes, @@ -247,7 +266,7 @@ def register(): specialties=','.join(map(str, form.specialties.data)) if form.specialties.data else None, licensing_pricing_id=form.licensing_pricing.data, os_support=','.join(map(str, form.os_support.data)) if form.os_support.data else None, - app_images=','.join(app_images) if app_images else None, + app_images=','.join(app_images) if app_images else None, # Use the potentially updated app_images list ehr_support=','.join(map(str, form.ehr_support.data)) if form.ehr_support.data else None, user_id=current_user.id ) @@ -271,8 +290,9 @@ def edit_app(app_id): if app.user_id != current_user.id: flash('You can only edit your own apps.', 'danger') return redirect(url_for('gallery.app_detail', app_id=app_id)) - + form = SmartAppForm(obj=app) + # Pre-populate multi-select fields correctly on GET request if not form.is_submitted(): if app.categories: form.categories.data = [int(cid) for cid in app.categories.split(',') if cid] @@ -282,8 +302,14 @@ def edit_app(app_id): form.os_support.data = [int(oid) for oid in app.os_support.split(',') if oid] if app.ehr_support: form.ehr_support.data = [int(eid) for eid in app.ehr_support.split(',') if eid] + # Pre-populate the image URL textarea if app.app_images: - form.app_image_urls.data = '\n'.join(app.app_images.split(',') if app.app_images else []) + # Filter out internal paths if mixed with URLs, show only URLs or internal paths formatted for web + current_images = [img for img in app.app_images.split(',') if img.startswith(('http://', 'https://', '/uploads/'))] + form.app_image_urls.data = '\n'.join(current_images) + else: + form.app_image_urls.data = '' # Ensure it's empty if no images + if form.validate_on_submit(): scopes = form.scopes.data @@ -298,6 +324,7 @@ def edit_app(app_id): # Ensure upload folder exists try: + # Use the absolute path inside the container os.makedirs(UPLOAD_FOLDER, exist_ok=True) logger.debug(f"Ensured {UPLOAD_FOLDER} exists") except Exception as e: @@ -305,6 +332,7 @@ def edit_app(app_id): flash('Error creating upload directory.', 'danger') return render_template('edit_app.html', form=form, app=app) + # Handle new filter options (same as register) if form.application_type_new.data: app_type = ApplicationType(name=form.application_type_new.data) db.session.add(app_type) @@ -314,11 +342,14 @@ def edit_app(app_id): category = Category(name=form.categories_new.data) db.session.add(category) db.session.commit() + # Ensure data is list before append if it was None initially + if form.categories.data is None: form.categories.data = [] form.categories.data.append(category.id) if form.os_support_new.data: os_support = OSSupport(name=form.os_support_new.data) db.session.add(os_support) db.session.commit() + if form.os_support.data is None: form.os_support.data = [] form.os_support.data.append(os_support.id) if form.fhir_compatibility_new.data: fhir = FHIRSupport(name=form.fhir_compatibility_new.data) @@ -329,6 +360,7 @@ def edit_app(app_id): speciality = Speciality(name=form.specialties_new.data) db.session.add(speciality) db.session.commit() + if form.specialties.data is None: form.specialties.data = [] form.specialties.data.append(speciality.id) if form.licensing_pricing_new.data: pricing = PricingLicense(name=form.licensing_pricing_new.data) @@ -344,60 +376,70 @@ def edit_app(app_id): ehr = EHRSupport(name=form.ehr_support_new.data) db.session.add(ehr) db.session.commit() + if form.ehr_support.data is None: form.ehr_support.data = [] form.ehr_support.data.append(ehr.id) - logo_url = form.logo_url.data - if form.logo_upload.data: + + # Handle logo update + logo_url = form.logo_url.data # Get URL from form first + if form.logo_upload.data: # If new logo uploaded, it takes precedence file = form.logo_upload.data if allowed_file(file.filename): filename = secure_filename(f"{uuid.uuid4()}_{file.filename}") + # Use absolute path for saving save_path = os.path.join(UPLOAD_FOLDER, filename) - logger.debug(f"Attempting to save logo to {save_path}") + logger.debug(f"Attempting to save updated logo to {save_path}") try: file.save(save_path) if os.path.exists(save_path): - logger.debug(f"Successfully saved logo to {save_path}") + logger.debug(f"Successfully saved updated logo to {save_path}") else: - logger.error(f"Failed to save logo to {save_path}") - flash('Failed to save logo.', 'danger') - return render_template('edit_app.html', form=form, app=app) - logo_url = f"/app/uploads/{filename}" + logger.error(f"Failed to save updated logo to {save_path}") + flash('Failed to save logo.', 'danger') + return render_template('edit_app.html', form=form, app=app) + # Store URL path for web access + logo_url = f"/uploads/{filename}" # CHANGED logger.debug(f"Set logo_url to {logo_url}") except Exception as e: - logger.error(f"Error saving logo to {save_path}: {e}") + logger.error(f"Error saving updated logo to {save_path}: {e}") flash('Error saving logo.', 'danger') return render_template('edit_app.html', form=form, app=app) - elif not logo_url: - logo_url = app.logo_url + elif not logo_url: # If no new upload AND URL field is empty, keep existing + logo_url = app.logo_url # Keep the old one only if the field is empty - app_images = [] - if form.app_image_urls.data: - app_images.extend([url.strip() for url in form.app_image_urls.data.splitlines() if url.strip()]) - if form.app_image_uploads.data: + # Handle app images update + # Start with URLs provided in the text area + app_images = [url.strip() for url in form.app_image_urls.data.splitlines() if url.strip()] + + if form.app_image_uploads.data: # Check if a file was uploaded file = form.app_image_uploads.data - if allowed_file(file.filename): + if file and allowed_file(file.filename): # Check if file object exists and is allowed filename = secure_filename(f"{uuid.uuid4()}_{file.filename}") + # Use absolute path for saving save_path = os.path.join(UPLOAD_FOLDER, filename) - logger.debug(f"Attempting to save app image to {save_path}") + logger.debug(f"Attempting to save updated app image to {save_path}") try: file.save(save_path) if os.path.exists(save_path): - logger.debug(f"Successfully saved app image to {save_path}") + logger.debug(f"Successfully saved updated app image to {save_path}") else: - logger.error(f"Failed to save app image to {save_path}") - flash('Failed to save app image.', 'danger') - return render_template('edit_app.html', form=form, app=app) - app_images.append(f"/app/uploads/{filename}") + logger.error(f"Failed to save updated app image to {save_path}") + flash('Failed to save app image.', 'danger') + return render_template('edit_app.html', form=form, app=app) + # Add the new image's URL path + app_images.append(f"/uploads/{filename}") # CHANGED except Exception as e: - logger.error(f"Error saving app image to {save_path}: {e}") + logger.error(f"Error saving updated app image to {save_path}: {e}") flash('Error saving app image.', 'danger') return render_template('edit_app.html', form=form, app=app) + + # Update app object app.name = form.name.data app.description = form.description.data app.developer = form.developer.data app.contact_email = form.contact_email.data - app.logo_url = logo_url or None + app.logo_url = logo_url # Use the final determined logo_url app.launch_url = form.launch_url.data app.client_id = form.client_id.data app.scopes = scopes @@ -409,7 +451,7 @@ def edit_app(app_id): app.specialties = ','.join(map(str, form.specialties.data)) if form.specialties.data else None app.licensing_pricing_id = form.licensing_pricing.data app.os_support = ','.join(map(str, form.os_support.data)) if form.os_support.data else None - app.app_images = ','.join(app_images) if app_images else None + app.app_images = ','.join(app_images) if app_images else None # Use the final list of image URLs/paths app.ehr_support = ','.join(map(str, form.ehr_support.data)) if form.ehr_support.data else None try: db.session.commit() @@ -421,8 +463,11 @@ def edit_app(app_id): return render_template('edit_app.html', form=form, app=app) flash('App updated successfully!', 'success') return redirect(url_for('gallery.app_detail', app_id=app_id)) + + # Render the edit form on GET or if validation fails return render_template('edit_app.html', form=form, app=app) + @gallery_bp.route('/gallery/delete/', methods=['POST']) @login_required def delete_app(app_id): @@ -441,6 +486,7 @@ def my_listings(): apps = SmartApp.query.filter_by(user_id=current_user.id).all() return render_template('my_listings.html', apps=apps) +# Keep the test route as is, it uses placeholder URLs directly @gallery_bp.route('/test/add') @login_required def add_test_app(): diff --git a/app/templates/New folder/app_detail.html.txt b/app/templates/New folder/app_detail.html.txt new file mode 100644 index 0000000..5fa52e1 --- /dev/null +++ b/app/templates/New folder/app_detail.html.txt @@ -0,0 +1,58 @@ + + + +{% extends "base.html" %} + +{% block title %}{{ app.name }}{% endblock %} + +{% block content %} +
+

{{ app.name }}

+
+
+ {% if app.logo_url %} + {{ app.name }} logo + {% else %} + No Logo + {% endif %} +

Description: {{ app.description }}

+

Developer: {{ app.developer }}

+

Contact Email: {{ app.contact_email }}

+

Launch URL: {{ app.launch_url }}

+

Client ID: {{ app.client_id }}

+

Scopes: {{ app.scopes }}

+ {% if app.website %} +

Website: {{ app.website }}

+ {% endif %} + {% if app_categories %} +

Categories: {{ app_categories | map(attribute='name') | join(', ') }}

+ {% endif %} + {% if app_specialties %} +

Specialties: {{ app_specialties | map(attribute='name') | join(', ') }}

+ {% endif %} + {% if app_os_supports %} +

OS Support: {{ app_os_supports | map(attribute='name') | join(', ') }}

+ {% endif %} + {% if app_ehr_supports %} +

EHR Support: {{ app_ehr_supports | map(attribute='name') | join(', ') }}

+ {% endif %} + {% if app.app_images %} +
Additional Images:
+
+ {% for img_url in app.app_images.split(',') %} +
+ App Image +
+ {% endfor %} +
+ {% endif %} + {% if current_user.is_authenticated and current_user.id == app.user_id %} + Edit App +
+ +
+ {% endif %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/base.html.txt b/app/templates/New folder/base.html.txt new file mode 100644 index 0000000..b082a18 --- /dev/null +++ b/app/templates/New folder/base.html.txt @@ -0,0 +1,183 @@ + + + + + + + SMARTFLARE - Smart App Gallery - {% block title %}{% endblock %} + + + + + + +
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + {% block content %}{% endblock %} +
+ + + + \ No newline at end of file diff --git a/app/templates/New folder/edit_app.html.txt b/app/templates/New folder/edit_app.html.txt new file mode 100644 index 0000000..042858f --- /dev/null +++ b/app/templates/New folder/edit_app.html.txt @@ -0,0 +1,214 @@ + + +{% extends "base.html" %} + +{% block content %} +

Edit App: {{ app.name }}

+
+ {{ form.hidden_tag() }} +
+ {{ form.name.label(class="form-label") }} + {{ form.name(class="form-control") }} + {% for error in form.name.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.description.label(class="form-label") }} + {{ form.description(class="form-control", rows=4) }} + {% for error in form.description.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.developer.label(class="form-label") }} + {{ form.developer(class="form-control") }} + {% for error in form.developer.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.contact_email.label(class="form-label") }} + {{ form.contact_email(class="form-control") }} + {% for error in form.contact_email.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.logo_url.label(class="form-label") }} + {{ form.logo_url(class="form-control") }} + Enter a URL or upload a new logo below. Leave blank to keep current logo. + {% for error in form.logo_url.errors %} + {{ error }} + {% endfor %} + {% if app.logo_url %} +

Current Logo:

+ Current Logo + {% endif %} +
+
+ {{ form.logo_upload.label(class="form-label") }} + {{ form.logo_upload(class="form-control") }} + {% for error in form.logo_upload.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.launch_url.label(class="form-label") }} + {{ form.launch_url(class="form-control") }} + {% for error in form.launch_url.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.client_id.label(class="form-label") }} + {{ form.client_id(class="form-control") }} + {% for error in form.client_id.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.scopes.label(class="form-label") }} + {{ form.scopes(class="form-control", rows=3) }} + {% for error in form.scopes.errors %} + {{ error }} + {% endfor %} + {% if app.scopes and app.scopes.strip() %} +

Current Scopes: + {% for scope in app.scopes.split(',') %} + {% if scope.strip() %} + {{ scope.strip() }} + {% endif %} + {% endfor %} +

+ {% else %} +

No scopes defined.

+ {% endif %} +
+
+ {{ form.website.label(class="form-label") }} + {{ form.website(class="form-control") }} + {% for error in form.website.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.designed_for.label(class="form-label") }} + {{ form.designed_for(class="form-control") }} + {% for error in form.designed_for.errors %} + {{ error }} + {% endfor %} + {{ form.designed_for_new.label(class="form-label mt-2") }} + {{ form.designed_for_new(class="form-control") }} + {% for error in form.designed_for_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.application_type.label(class="form-label") }} + {{ form.application_type(class="form-control") }} + {% for error in form.application_type.errors %} + {{ error }} + {% endfor %} + {{ form.application_type_new.label(class="form-label mt-2") }} + {{ form.application_type_new(class="form-control") }} + {% for error in form.application_type_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.fhir_compatibility.label(class="form-label") }} + {{ form.fhir_compatibility(class="form-control") }} + {% for error in form.fhir_compatibility.errors %} + {{ error }} + {% endfor %} + {{ form.fhir_compatibility_new.label(class="form-label mt-2") }} + {{ form.fhir_compatibility_new(class="form-control") }} + {% for error in form.fhir_compatibility_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.categories.label(class="form-label") }} + {{ form.categories(class="form-control") }} + {% for error in form.categories.errors %} + {{ error }} + {% endfor %} + {{ form.categories_new.label(class="form-label mt-2") }} + {{ form.categories_new(class="form-control") }} + {% for error in form.categories_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.specialties.label(class="form-label") }} + {{ form.specialties(class="form-control") }} + {% for error in form.specialties.errors %} + {{ error }} + {% endfor %} + {{ form.specialties_new.label(class="form-label mt-2") }} + {{ form.specialties_new(class="form-control") }} + {% for error in form.specialties_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.licensing_pricing.label(class="form-label") }} + {{ form.licensing_pricing(class="form-control") }} + {% for error in form.licensing_pricing.errors %} + {{ error }} + {% endfor %} + {{ form.licensing_pricing_new.label(class="form-label mt-2") }} + {{ form.licensing_pricing_new(class="form-control") }} + {% for error in form.licensing_pricing_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.os_support.label(class="form-label") }} + {{ form.os_support(class="form-control") }} + {% for error in form.os_support.errors %} + {{ error }} + {% endfor %} + {{ form.os_support_new.label(class="form-label mt-2") }} + {{ form.os_support_new(class="form-control") }} + {% for error in form.os_support_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.app_image_urls.label(class="form-label") }} + {{ form.app_image_urls(class="form-control", rows=3) }} + {% for error in form.app_image_urls.errors %} + {{ error }} + {% endfor %} + {% if app.app_images %} +

Current Images:

+ {% for image in app.app_images.split(',') %} + App Image + {% endfor %} + {% endif %} +
+
+ {{ form.app_image_uploads.label(class="form-label") }} + {{ form.app_image_uploads(class="form-control") }} + {% for error in form.app_image_uploads.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.ehr_support.label(class="form-label") }} + {{ form.ehr_support(class="form-control") }} + {% for error in form.ehr_support.errors %} + {{ error }} + {% endfor %} + {{ form.ehr_support_new.label(class="form-label mt-2") }} + {{ form.ehr_support_new(class="form-control") }} + {% for error in form.ehr_support_new.errors %} + {{ error }} + {% endfor %} +
+ {{ form.submit(class="btn btn-primary") }} + Cancel +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/gallery.html.txt b/app/templates/New folder/gallery.html.txt new file mode 100644 index 0000000..fc7aa68 --- /dev/null +++ b/app/templates/New folder/gallery.html.txt @@ -0,0 +1,247 @@ + + +{% extends "base.html" %} + +{% block title %}Gallery{% endblock %} + +{% block content %} +
+ + + + +
+

Explore SMART on FHIR apps. Filter above to find the perfect app.

+ {% if apps %} +
+ {% for app in apps %} +
+
+ {% if app.logo_url %} + {{ app.name }} logo + {% else %} + No Logo + {% endif %} +
+
{{ app.name }}
+

{{ app.description | truncate(100) }}

+

By {{ app.developer }}

+ View Details +
+
+
+ {% endfor %} +
+ {% else %} +

No apps match your filters. Try adjusting the filters above.

+ {% endif %} +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/login.html.txt b/app/templates/New folder/login.html.txt new file mode 100644 index 0000000..f069188 --- /dev/null +++ b/app/templates/New folder/login.html.txt @@ -0,0 +1,32 @@ + + + +{% extends "base.html" %} + +{% block content %} +

Login

+
+ {{ form.hidden_tag() }} +
+ {{ form.email.label(class="form-label") }} + {{ form.email(class="form-control") }} + {% for error in form.email.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.password.label(class="form-label") }} + {{ form.password(class="form-control") }} + {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ {{ form.submit(class="btn btn-primary") }} +
+
+

Or login with:

+ Google + GitHub +
+

Don't have an account? Register

+{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/my_listings.html.txt b/app/templates/New folder/my_listings.html.txt new file mode 100644 index 0000000..decfe2e --- /dev/null +++ b/app/templates/New folder/my_listings.html.txt @@ -0,0 +1,33 @@ + + +{% extends "base.html" %} + +{% block content %} +

My Listings

+ {% if apps %} +
+ {% for app in apps %} +
+
+ {% if app.logo_url %} + {{ app.name }} logo + {% endif %} +
+
{{ app.name }}
+

{{ app.description | truncate(100) }}

+

By {{ app.developer }}

+ View Details + Edit +
+ +
+
+
+
+ {% endfor %} +
+ {% else %} +

You haven't registered any apps yet.

+ Register an App + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/register.html.txt b/app/templates/New folder/register.html.txt new file mode 100644 index 0000000..367b44d --- /dev/null +++ b/app/templates/New folder/register.html.txt @@ -0,0 +1,193 @@ + + +{% extends "base.html" %} + +{% block content %} +

Register New App

+
+ {{ form.hidden_tag() }} +
+ {{ form.name.label(class="form-label") }} + {{ form.name(class="form-control") }} + {% for error in form.name.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.description.label(class="form-label") }} + {{ form.description(class="form-control", rows=4) }} + {% for error in form.description.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.developer.label(class="form-label") }} + {{ form.developer(class="form-control") }} + {% for error in form.developer.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.contact_email.label(class="form-label") }} + {{ form.contact_email(class="form-control") }} + {% for error in form.contact_email.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.logo_url.label(class="form-label") }} + {{ form.logo_url(class="form-control") }} + Enter a URL or upload a logo below. + {% for error in form.logo_url.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.logo_upload.label(class="form-label") }} + {{ form.logo_upload(class="form-control") }} + {% for error in form.logo_upload.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.launch_url.label(class="form-label") }} + {{ form.launch_url(class="form-control") }} + {% for error in form.launch_url.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.client_id.label(class="form-label") }} + {{ form.client_id(class="form-control") }} + {% for error in form.client_id.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.scopes.label(class="form-label") }} + {{ form.scopes(class="form-control", rows=3) }} + {% for error in form.scopes.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.website.label(class="form-label") }} + {{ form.website(class="form-control") }} + {% for error in form.website.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.designed_for.label(class="form-label") }} + {{ form.designed_for(class="form-control") }} + {% for error in form.designed_for.errors %} + {{ error }} + {% endfor %} + {{ form.designed_for_new.label(class="form-label mt-2") }} + {{ form.designed_for_new(class="form-control") }} + {% for error in form.designed_for_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.application_type.label(class="form-label") }} + {{ form.application_type(class="form-control") }} + {% for error in form.application_type.errors %} + {{ error }} + {% endfor %} + {{ form.application_type_new.label(class="form-label mt-2") }} + {{ form.application_type_new(class="form-control") }} + {% for error in form.application_type_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.fhir_compatibility.label(class="form-label") }} + {{ form.fhir_compatibility(class="form-control") }} + {% for error in form.fhir_compatibility.errors %} + {{ error }} + {% endfor %} + {{ form.fhir_compatibility_new.label(class="form-label mt-2") }} + {{ form.fhir_compatibility_new(class="form-control") }} + {% for error in form.fhir_compatibility_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.categories.label(class="form-label") }} + {{ 을 form.categories(class="form-control") }} + {% for error in form.categories.errors %} + {{ error }} + {% endfor %} + {{ form.categories_new.label(class="form-label mt-2") }} + {{ form.categories_new(class="form-control") }} + {% for error in form.categories_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.specialties.label(class="form-label") }} + {{ form.specialties(class="form-control") }} + {% for error in form.specialties.errors %} + {{ error }} + {% endfor %} + {{ form.specialties_new.label(class="form-label mt-2") }} + {{ form.specialties_new(class="form-control") }} + {% for error in form.specialties_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.licensing_pricing.label(class="form-label") }} + {{ form.licensing_pricing(class="form-control") }} + {% for error in form.licensing_pricing.errors %} + {{ error }} + {% endfor %} + {{ form.licensing_pricing_new.label(class="form-label mt-2") }} + {{ form.licensing_pricing_new(class="form-control") }} + {% for error in form.licensing_pricing_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.os_support.label(class="form-label") }} + {{ form.os_support(class="form-control") }} + {% for error in form.os_support.errors %} + {{ error }} + {% endfor %} + {{ form.os_support_new.label(class="form-label mt-2") }} + {{ form.os_support_new(class="form-control") }} + {% for error in form.os_support_new.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.app_image_urls.label(class="form-label") }} + {{ form.app_image_urls(class="form-control", rows=3) }} + {% for error in form.app_image_urls.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.app_image_uploads.label(class="form-label") }} + {{ form.app_image_uploads(class="form-control") }} + {% for error in form.app_image_uploads.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.ehr_support.label(class="form-label") }} + {{ form.ehr_support(class="form-control") }} + {% for error in form.ehr_support.errors %} + {{ error }} + {% endfor %} + {{ form.ehr_support_new.label(class="form-label mt-2") }} + {{ form.ehr_support_new(class="form-control") }} + {% for error in form.ehr_support_new.errors %} + {{ error }} + {% endfor %} +
+ {{ form.submit(class="btn btn-primary") }} + Cancel +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/New folder/register_user.html.txt b/app/templates/New folder/register_user.html.txt new file mode 100644 index 0000000..b807c98 --- /dev/null +++ b/app/templates/New folder/register_user.html.txt @@ -0,0 +1,40 @@ + + +{% extends "base.html" %} + +{% block content %} +

Register

+
+ {{ form.hidden_tag() }} +
+ {{ form.username.label(class="form-label") }} + {{ form.username(class="form-control") }} + {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.email.label(class="form-label") }} + {{ form.email(class="form-control") }} + {% for error in form.email.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.password.label(class="form-label") }} + {{ form.password(class="form-control") }} + {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.confirm_password.label(class="form-label") }} + {{ form.confirm_password(class="form-control") }} + {% for error in form.confirm_password.errors %} + {{ error }} + {% endfor %} +
+ {{ form.submit(class="btn btn-primary") }} +
+

Already have an account? Login

+{% endblock %} \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index d57faf5..f92dd3e 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,13 +1,11 @@ - - - - + SMARTFLARE - Smart App Gallery - {% block title %}{% endblock %} @@ -105,22 +184,21 @@
SMART App Gallery +
{{ form.categories.label(class="form-label") }} - {{ 을 form.categories(class="form-control") }} + {{ form.categories(class="form-control") }} {% for error in form.categories.errors %} {{ error }} {% endfor %} diff --git a/instance/smart_app_gallery.db b/instance/smart_app_gallery.db index fcddc267458958c9dde43d461f25c1a6dbaa142c..f4255008bcf63f4edc0c0b68097bcd2a7c13171c 100644 GIT binary patch delta 210 zcmZozz}m2Yb%Hdb;zSu|M#aX2tqF|F>{&K4@NL{IC}7CP$#|Rr1Q-uYT$n4?+!xF{M~PCD9<&JTcKi*VMo)RoBEYHBHwt z$ud#bB-O~wz}Unz$s)yk`b9s+!mx~zl7eC@ef_e`M7@HX#N^bB{G623BE97NTzz8$ v17jT%BLgE-T>}$cLsJCL6 zRLUBx(E)^Z!6#c|@a7j7{Ry%l!G!`&fa;WsN?=7eP+ST6SExc=Nj|W~C}n;C(W_O8 diff --git a/uploads/da0e7aa8-506e-41ef-9b9a-4e260345b8d7_A1_test.png b/uploads/da0e7aa8-506e-41ef-9b9a-4e260345b8d7_A1_test.png new file mode 100644 index 0000000000000000000000000000000000000000..5e31e83211bf66cbaa11da3f7d6ba7c75e27ceb0 GIT binary patch literal 36217 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