From 9a5e24323a4ac4cae17858856566e452027368f1 Mon Sep 17 00:00:00 2001 From: Sudo-JHare Date: Sun, 11 May 2025 19:38:55 +1000 Subject: [PATCH] Add files via upload --- Dockerfile | 3 +- app/forms.py | 35 +++++++--- app/models.py | 17 ----- app/routes.py | 103 +++++++++++------------------ app/templates/admin_edit_user.html | 55 +++++++++++++++ app/templates/admin_users.html | 35 ++++++++++ app/templates/app_detail.html | 51 -------------- app/templates/base.html | 3 + app/templates/edit_app.html | 46 ------------- app/templates/gallery.html | 40 +---------- app/templates/login.html | 52 +++++++-------- app/templates/register.html | 36 +--------- requirements.txt | 3 +- seed.py | 20 +----- 14 files changed, 187 insertions(+), 312 deletions(-) create mode 100644 app/templates/admin_edit_user.html create mode 100644 app/templates/admin_users.html diff --git a/Dockerfile b/Dockerfile index 00a81e0..a69c404 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ COPY app/ app/ COPY static/ static/ COPY instance/ instance/ COPY config.py . -COPY seed.py . COPY .env . EXPOSE 5009 -CMD ["flask", "run", "--host=0.0.0.0" "--port=5009"] +CMD ["flask", "run", "--host=0.0.0.0"] \ No newline at end of file diff --git a/app/forms.py b/app/forms.py index feb9c89..42b4e10 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,9 +1,9 @@ from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed -from wtforms import StringField, TextAreaField, SubmitField, PasswordField, SelectField, SelectMultipleField +from wtforms import StringField, TextAreaField, SubmitField, PasswordField, SelectField, SelectMultipleField, BooleanField from wtforms.validators import DataRequired, Email, Length, EqualTo, Optional, ValidationError import re -from app.models import ApplicationType, Category, OSSupport, FHIRSupport, Speciality, PricingLicense, DesignedFor, EHRSupport +from app.models import Category, OSSupport, FHIRSupport, PricingLicense, DesignedFor, User from app import db def validate_url_or_path(form, field): @@ -17,6 +17,18 @@ def validate_url_or_path(form, field): if not re.match(url_pattern, field.data): raise ValidationError('Invalid URL or file path.') +def validate_username(form, field): + if field.data != form._obj.username: # Check if username changed + existing_user = User.query.filter_by(username=field.data).first() + if existing_user: + raise ValidationError('Username already taken.') + +def validate_email(form, field): + if field.data != form._obj.email: # Check if email changed + existing_user = User.query.filter_by(email=field.data).first() + if existing_user: + raise ValidationError('Email already registered.') + class FHIRAppForm(FlaskForm): name = StringField('App Name', validators=[DataRequired(), Length(min=3, max=100)]) description = TextAreaField('Description', validators=[DataRequired(), Length(min=10, max=500)]) @@ -25,31 +37,23 @@ class FHIRAppForm(FlaskForm): logo_url = StringField('Logo URL', validators=[Optional(), validate_url_or_path], render_kw={"placeholder": "https://example.com/logo.png or leave blank to upload"}) logo_upload = FileField('Upload Logo', validators=[FileAllowed(['jpg', 'png'], 'Images only!')]) launch_url = StringField('Launch URL', validators=[DataRequired(), Length(max=200)]) - client_id = StringField('Client ID', validators=[DataRequired(), Length(min=3, max=100)]) - scopes = TextAreaField('Scopes (comma-separated)', validators=[DataRequired(), Length(max=500)], render_kw={"placeholder": "patient/Patient.read,launch/patient"}) website = StringField('Company Website', validators=[Optional(), Length(max=200)], render_kw={"placeholder": "https://example.com"}) designed_for = SelectField('Designed For', coerce=int, validators=[DataRequired()]) - application_type = SelectField('Application Type', coerce=int, validators=[DataRequired()]) fhir_compatibility = SelectField('FHIR Compatibility', coerce=int, validators=[DataRequired()]) categories = SelectMultipleField('Categories', coerce=int, validators=[DataRequired()]) - specialties = SelectMultipleField('Specialties', coerce=int, validators=[DataRequired()]) licensing_pricing = SelectField('Licensing & Pricing', coerce=int, validators=[DataRequired()]) os_support = SelectMultipleField('OS Support', coerce=int, validators=[DataRequired()]) app_image_urls = TextAreaField('App Image URLs (one per line)', validators=[Optional(), Length(max=1000)], render_kw={"placeholder": "e.g., https://example.com/image1.png"}) app_image_uploads = FileField('Upload App Images', validators=[FileAllowed(['jpg', 'png'], 'Images only!')]) - ehr_support = SelectMultipleField('EHR Support', coerce=int, validators=[DataRequired()]) submit = SubmitField('Register App') def __init__(self, *args, **kwargs): super(FHIRAppForm, self).__init__(*args, **kwargs) - self.application_type.choices = [(t.id, t.name) for t in ApplicationType.query.all()] self.categories.choices = [(c.id, c.name) for c in Category.query.all()] self.os_support.choices = [(o.id, o.name) for o in OSSupport.query.all()] self.fhir_compatibility.choices = [(f.id, f.name) for f in FHIRSupport.query.all()] - self.specialties.choices = [(s.id, s.name) for s in Speciality.query.all()] self.licensing_pricing.choices = [(p.id, p.name) for p in PricingLicense.query.all()] self.designed_for.choices = [(d.id, d.name) for d in DesignedFor.query.all()] - self.ehr_support.choices = [(e.id, e.name) for e in EHRSupport.query.all()] class LoginForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Email()]) @@ -76,4 +80,13 @@ class ChangePasswordForm(FlaskForm): current_password = PasswordField('Current Password', validators=[DataRequired()]) new_password = PasswordField('New Password', validators=[DataRequired(), Length(min=6)]) confirm_password = PasswordField('Confirm New Password', validators=[DataRequired(), EqualTo('new_password')]) - submit = SubmitField('Change Password') \ No newline at end of file + submit = SubmitField('Change Password') + +class UserEditForm(FlaskForm): + username = StringField('Username', validators=[DataRequired(), Length(min=3, max=80), validate_username]) + email = StringField('Email', validators=[DataRequired(), Email(), validate_email]) + is_admin = BooleanField('Admin Status') + force_password_change = BooleanField('Force Password Change') + reset_password = PasswordField('Reset Password', validators=[Optional(), Length(min=6)]) + confirm_reset_password = PasswordField('Confirm Reset Password', validators=[Optional(), EqualTo('reset_password')]) + submit = SubmitField('Save Changes') \ No newline at end of file diff --git a/app/models.py b/app/models.py index 91b07c4..0b3ed5e 100644 --- a/app/models.py +++ b/app/models.py @@ -34,10 +34,6 @@ class User(db.Model): def get_id(self): return str(self.id) -class ApplicationType(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(100), unique=True, nullable=False) - class Category(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) @@ -50,10 +46,6 @@ class FHIRSupport(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) -class Speciality(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(100), unique=True, nullable=False) - class PricingLicense(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) @@ -62,10 +54,6 @@ class DesignedFor(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) -class EHRSupport(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(100), unique=True, nullable=False) - class FHIRApp(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) @@ -74,18 +62,13 @@ class FHIRApp(db.Model): contact_email = db.Column(db.String(120), nullable=False) logo_url = db.Column(db.String(200)) launch_url = db.Column(db.String(200), nullable=False) - client_id = db.Column(db.String(100), nullable=False) - scopes = db.Column(db.Text) website = db.Column(db.String(200)) designed_for_id = db.Column(db.Integer, db.ForeignKey('designed_for.id')) - application_type_id = db.Column(db.Integer, db.ForeignKey('application_type.id')) fhir_compatibility_id = db.Column(db.Integer, db.ForeignKey('fhir_support.id')) categories = db.Column(db.Text) # Comma-separated Category IDs - specialties = db.Column(db.Text) # Comma-separated Speciality IDs licensing_pricing_id = db.Column(db.Integer, db.ForeignKey('pricing_license.id')) os_support = db.Column(db.Text) # Comma-separated OSSupport IDs app_images = db.Column(db.Text) - ehr_support = db.Column(db.Text) # Comma-separated EHRSupport IDs user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) registration_date = db.Column(db.DateTime, default=datetime.utcnow) last_updated = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index 293c41b..27957ed 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,8 +1,8 @@ from flask import Blueprint, render_template, redirect, url_for, flash, request, send_from_directory, abort from flask_login import login_required, current_user from app import db -from app.models import FHIRApp, ApplicationType, Category, OSSupport, FHIRSupport, Speciality, PricingLicense, DesignedFor, EHRSupport -from app.forms import FHIRAppForm, GalleryFilterForm, CategoryForm +from app.models import FHIRApp, Category, OSSupport, FHIRSupport, PricingLicense, DesignedFor, User +from app.forms import FHIRAppForm, GalleryFilterForm, CategoryForm, UserEditForm from sqlalchemy import or_ import os import logging @@ -57,18 +57,12 @@ def gallery(): ) filter_params['search'] = search_term - application_type_ids = request.args.getlist('application_type', type=int) category_ids = request.args.getlist('category', type=int) os_support_ids = request.args.getlist('os_support', type=int) fhir_support_ids = request.args.getlist('fhir_support', type=int) - speciality_ids = request.args.getlist('speciality', type=int) pricing_license_ids = request.args.getlist('pricing_license', type=int) designed_for_ids = request.args.getlist('designed_for', type=int) - ehr_support_ids = request.args.getlist('ehr_support', type=int) - if application_type_ids: - query = query.filter(FHIRApp.application_type_id.in_(application_type_ids)) - filter_params['application_type'] = application_type_ids if category_ids: query = query.filter(or_(*[FHIRApp.categories.contains(str(cid)) for cid in category_ids])) filter_params['category'] = category_ids @@ -78,18 +72,12 @@ def gallery(): if fhir_support_ids: query = query.filter(FHIRApp.fhir_compatibility_id.in_(fhir_support_ids)) filter_params['fhir_support'] = fhir_support_ids - if speciality_ids: - query = query.filter(or_(*[FHIRApp.specialties.contains(str(sid)) for sid in speciality_ids])) - filter_params['speciality'] = speciality_ids if pricing_license_ids: query = query.filter(FHIRApp.licensing_pricing_id.in_(pricing_license_ids)) filter_params['pricing_license'] = pricing_license_ids if designed_for_ids: query = query.filter(FHIRApp.designed_for_id.in_(designed_for_ids)) filter_params['designed_for'] = designed_for_ids - if ehr_support_ids: - query = query.filter(or_(*[FHIRApp.ehr_support.contains(str(eid)) for eid in ehr_support_ids])) - filter_params['ehr_support'] = ehr_support_ids apps = query.all() for app in apps: @@ -99,14 +87,11 @@ def gallery(): apps=apps, form=form, filter_params=filter_params, - application_types=ApplicationType.query.all(), categories=Category.query.all(), os_supports=OSSupport.query.all(), fhir_supports=FHIRSupport.query.all(), - specialties=Speciality.query.all(), pricing_licenses=PricingLicense.query.all(), - designed_fors=DesignedFor.query.all(), - ehr_supports=EHRSupport.query.all() + designed_fors=DesignedFor.query.all() ) @gallery_bp.route('/gallery/') @@ -118,28 +103,16 @@ def app_detail(app_id): 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, app_categories=app_categories, - app_specialties=app_specialties, - app_os_supports=app_os_supports, - app_ehr_supports=app_ehr_supports + app_os_supports=app_os_supports ) @gallery_bp.route('/gallery/register', methods=['GET', 'POST']) @@ -147,16 +120,6 @@ def app_detail(app_id): def register(): form = FHIRAppForm() if form.validate_on_submit(): - scopes = form.scopes.data - valid_scopes = all( - scope.strip().startswith(('patient/', 'user/', 'launch', 'openid', 'fhirUser', 'offline_access', 'online_access')) - for scope in scopes.split(',') - if scope.strip() - ) - if not valid_scopes or not scopes.strip(): - flash('Invalid FHIR scopes. Use formats like patient/Patient.read, launch/patient.', 'danger') - return render_template('register.html', form=form) - try: os.makedirs(UPLOAD_FOLDER, exist_ok=True) logger.debug(f"Ensured {UPLOAD_FOLDER} exists") @@ -217,18 +180,13 @@ def register(): contact_email=form.contact_email.data, logo_url=logo_url or None, launch_url=form.launch_url.data, - client_id=form.client_id.data, - scopes=scopes, website=form.website.data or None, designed_for_id=form.designed_for.data, - application_type_id=form.application_type.data, fhir_compatibility_id=form.fhir_compatibility.data, categories=','.join(map(str, form.categories.data)) if form.categories.data else None, - 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, - ehr_support=','.join(map(str, form.ehr_support.data)) if form.ehr_support.data else None, user_id=current_user.id ) db.session.add(app) @@ -256,12 +214,8 @@ def edit_app(app_id): if not form.is_submitted(): if app.categories: form.categories.data = [int(cid) for cid in app.categories.split(',') if cid] - if app.specialties: - form.specialties.data = [int(sid) for sid in app.specialties.split(',') if sid] if app.os_support: 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] if app.app_images: 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) @@ -269,16 +223,6 @@ def edit_app(app_id): form.app_image_urls.data = '' if form.validate_on_submit(): - scopes = form.scopes.data - valid_scopes = all( - scope.strip().startswith(('patient/', 'user/', 'launch', 'openid', 'fhirUser', 'offline_access', 'online_access')) - for scope in scopes.split(',') - if scope.strip() - ) - if not valid_scopes or not scopes.strip(): - flash('Invalid FHIR scopes. Use formats like patient/Patient.read, launch/patient.', 'danger') - return render_template('edit_app.html', form=form, app=app) - try: os.makedirs(UPLOAD_FOLDER, exist_ok=True) logger.debug(f"Ensured {UPLOAD_FOLDER} exists") @@ -338,18 +282,13 @@ def edit_app(app_id): app.contact_email = form.contact_email.data app.logo_url = logo_url app.launch_url = form.launch_url.data - app.client_id = form.client_id.data - app.scopes = scopes app.website = form.website.data or None app.designed_for_id = form.designed_for.data - app.application_type_id = form.application_type.data app.fhir_compatibility_id = form.fhir_compatibility.data app.categories = ','.join(map(str, form.categories.data)) if form.categories.data else None - 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.ehr_support = ','.join(map(str, form.ehr_support.data)) if form.ehr_support.data else None try: db.session.commit() logger.debug(f"Updated app ID: {app.id}, logo_url: {app.logo_url}, app_images: {app.app_images}") @@ -417,3 +356,37 @@ def admin_apps(): return redirect(url_for('gallery.landing')) apps = FHIRApp.query.all() return render_template('admin_apps.html', apps=apps) + +@gallery_bp.route('/admin/users', methods=['GET']) +@login_required +def admin_users(): + if not current_user.is_admin: + flash('Admin access required.', 'danger') + return redirect(url_for('gallery.landing')) + users = User.query.all() + return render_template('admin_users.html', users=users) + +@gallery_bp.route('/admin/users/edit/', methods=['GET', 'POST']) +@login_required +def edit_user(user_id): + if not current_user.is_admin: + flash('Admin access required.', 'danger') + return redirect(url_for('gallery.landing')) + user = User.query.get_or_404(user_id) + form = UserEditForm(obj=user) + if form.validate_on_submit(): + user.username = form.username.data + user.email = form.email.data + user.is_admin = form.is_admin.data + user.force_password_change = form.force_password_change.data + if form.reset_password.data: + user.set_password(form.reset_password.data) + try: + db.session.commit() + flash(f'User "{user.username}" updated successfully.', 'success') + except Exception as e: + logger.error(f"Error updating user: {e}") + db.session.rollback() + flash('Error updating user.', 'danger') + return redirect(url_for('gallery.admin_users')) + return render_template('admin_edit_user.html', form=form, user=user) \ No newline at end of file diff --git a/app/templates/admin_edit_user.html b/app/templates/admin_edit_user.html new file mode 100644 index 0000000..0470381 --- /dev/null +++ b/app/templates/admin_edit_user.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} +{% block title %}Edit User{% endblock %} +{% block content %} +
+

Edit User: {{ user.username }}

+
+ {{ 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.is_admin.label(class="form-check-label") }} + {{ form.is_admin(class="form-check-input") }} + {% for error in form.is_admin.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.force_password_change.label(class="form-check-label") }} + {{ form.force_password_change(class="form-check-input") }} + {% for error in form.force_password_change.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.reset_password.label(class="form-label") }} + {{ form.reset_password(class="form-control") }} + Leave blank to keep the current password. + {% for error in form.reset_password.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.confirm_reset_password.label(class="form-label") }} + {{ form.confirm_reset_password(class="form-control") }} + {% for error in form.confirm_reset_password.errors %} + {{ error }} + {% endfor %} +
+ {{ form.submit(class="btn btn-primary") }} + Cancel +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/admin_users.html b/app/templates/admin_users.html new file mode 100644 index 0000000..975be90 --- /dev/null +++ b/app/templates/admin_users.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} +{% block title %}Manage Users{% endblock %} +{% block content %} +
+

Manage Users

+ {% if users %} + + + + + + + + + + + + {% for user in users %} + + + + + + + + {% endfor %} + +
UsernameEmailAdminForce Password ChangeActions
{{ user.username }}{{ user.email }}{{ 'Yes' if user.is_admin else 'No' }}{{ 'Yes' if user.force_password_change else 'No' }} + Edit +
+ {% else %} +

No users found.

+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/app_detail.html b/app/templates/app_detail.html index eb2d814..a9204af 100644 --- a/app/templates/app_detail.html +++ b/app/templates/app_detail.html @@ -55,16 +55,6 @@

{{ app.contact_email or 'Not specified.' }}

-
-
Client ID
-
-

{{ app.client_id or 'Not specified.' }}

-
-
-
Scopes
-
-

{{ app.scopes or 'Not specified.' }}

-
@@ -103,21 +93,6 @@ {% endif %}

-
-
Application Type
-
-

- {% if app.application_type %} - {{ app.application_type.name }} - {% else %} - Not specified. - {% endif %} -

-
- - -
-
FHIR Compatibility

@@ -129,34 +104,8 @@ {% endif %}

-
-
EHR Support
-
-

- {% if app_ehr_supports %} - {% for ehr in app_ehr_supports %} - {{ ehr.name }}{% if not loop.last %}, {% endif %} - {% endfor %} - {% else %} - Not specified. - {% endif %} -

-
-
-
Specialties
-
-

- {% if app_specialties %} - {% for speciality in app_specialties %} - {{ speciality.name }}{% if not loop.last %}, {% endif %} - {% endfor %} - {% else %} - Not specified. - {% endif %} -

-
OS Support

diff --git a/app/templates/base.html b/app/templates/base.html index d46f012..bffb365 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -306,6 +306,9 @@ + {% endif %} {% endif %} diff --git a/app/templates/edit_app.html b/app/templates/edit_app.html index 1d6793b..952029e 100644 --- a/app/templates/edit_app.html +++ b/app/templates/edit_app.html @@ -57,31 +57,6 @@ {{ 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") }} @@ -96,13 +71,6 @@ {{ 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.fhir_compatibility.label(class="form-label") }} {{ form.fhir_compatibility(class="form-control") }} @@ -117,13 +85,6 @@ {{ error }} {% endfor %}
-
- {{ form.specialties.label(class="form-label") }} - {{ form.specialties(class="form-control") }} - {% for error in form.specialties.errors %} - {{ error }} - {% endfor %} -
{{ form.licensing_pricing.label(class="form-label") }} {{ form.licensing_pricing(class="form-control") }} @@ -158,13 +119,6 @@ {{ 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.submit(class="btn btn-primary") }} Cancel diff --git a/app/templates/gallery.html b/app/templates/gallery.html index d7000e3..b5b0c77 100644 --- a/app/templates/gallery.html +++ b/app/templates/gallery.html @@ -35,18 +35,6 @@ - - @@ -142,7 +106,7 @@
Active Filters:
{% for key, values in filter_params.items() %} {% for value in values %} - {% set item = {'application_type': application_types, 'category': categories, 'os_support': os_supports, 'fhir_support': fhir_supports, 'speciality': specialties, 'pricing_license': pricing_licenses, 'designed_for': designed_fors, 'ehr_support': ehr_supports}[key] | selectattr('id', 'equalto', value) | first %} + {% set item = {'category': categories, 'os_support': os_supports, 'fhir_support': fhir_supports, 'pricing_license': pricing_licenses, 'designed_for': designed_fors}[key] | selectattr('id', 'equalto', value) | first %} {% if item %} {{ item.name }} {% endif %} diff --git a/app/templates/login.html b/app/templates/login.html index 8ab20b8..4b3af1a 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -1,32 +1,28 @@ - - - {% 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 +

Login

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

Don't have an account? Register

+
+ {{ 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/register.html b/app/templates/register.html index 7e4e079..83dce76 100644 --- a/app/templates/register.html +++ b/app/templates/register.html @@ -43,6 +43,7 @@ {{ form.logo_upload.label(class="form-label") }} {{ form.logo_upload(class="form-control") }} {% for error in form.logo_upload.errors %} + provocateur = provocateur + 1 {{ error }} {% endfor %}
@@ -53,20 +54,6 @@ {{ 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") }} @@ -81,13 +68,6 @@ {{ 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.fhir_compatibility.label(class="form-label") }} {{ form.fhir_compatibility(class="form-control") }} @@ -102,13 +82,6 @@ {{ error }} {% endfor %}
-
- {{ form.specialties.label(class="form-label") }} - {{ form.specialties(class="form-control") }} - {% for error in form.specialties.errors %} - {{ error }} - {% endfor %} -
{{ form.licensing_pricing.label(class="form-label") }} {{ form.licensing_pricing(class="form-control") }} @@ -137,13 +110,6 @@ {{ 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.submit(class="btn btn-primary") }} Cancel diff --git a/requirements.txt b/requirements.txt index aaf3e73..cefdc4a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,5 @@ email-validator==2.2.0 Flask-Login==0.6.3 Flask-OAuthlib==0.9.6 python-dotenv==1.0.1 -bcrypt==4.2.0 \ No newline at end of file +bcrypt==4.2.0 +flask-migrate==4.0.7 \ No newline at end of file diff --git a/seed.py b/seed.py index e47093e..19d1646 100644 --- a/seed.py +++ b/seed.py @@ -1,5 +1,5 @@ from app import db, create_app -from app.models import ApplicationType, Category, OSSupport, FHIRSupport, Speciality, PricingLicense, DesignedFor, EHRSupport, User +from app.models import Category, OSSupport, FHIRSupport, PricingLicense, DesignedFor, User app = create_app() @@ -29,13 +29,9 @@ with app.app_context(): # Seed admin user seed_admin_user() - # Seed application types - app_types = ['FHIR App', 'Bulk Data', 'Health Cards'] - seed_table(ApplicationType, app_types) - # Seed categories categories = [ - 'Care Coordination', 'Clinical Research', 'Data Visualization', 'Disease Management', + 'Care Coordination', 'Clinical Research', 'Data Visualization', ' Disease Management', 'Genomics', 'Medication Management', 'Patient Engagement', 'Population Health', 'Risk Calculation', 'FHIR Tools', 'Telehealth' ] @@ -49,14 +45,6 @@ with app.app_context(): fhir_supports = ['DSTU 2', 'STU 3', 'R4', 'R5'] seed_table(FHIRSupport, fhir_supports) - # Seed specialties - specialties = [ - 'Anesthesiology', 'Cardiology', 'Gastroenterology', 'Infectious Disease', 'Neurology', - 'Obstetrics', 'Oncology', 'Pediatrics', 'Pulmonology', 'Nephrology', 'Rheumatology', - 'Trauma', 'Primary Care' - ] - seed_table(Speciality, specialties) - # Seed pricing/licenses pricings = ['Open Source', 'Free', 'Per User', 'Site-Based', 'Subscription'] seed_table(PricingLicense, pricings) @@ -65,10 +53,6 @@ with app.app_context(): designed_fors = ['Clinicians', 'Patients', 'Patients & Clinicians', 'IT Professionals'] seed_table(DesignedFor, designed_fors) - # Seed EHR support - ehr_supports = ['Allscripts', 'Athenahealth', 'Epic', 'Cerner', 'Meditech'] - seed_table(EHRSupport, ehr_supports) - print("Database seeded successfully!") except Exception as e: print(f"Seeding failed: {str(e)}")