import os from enum import Enum from flask import Flask, jsonify, request from flask_sqlalchemy import SQLAlchemy from sqlalchemy import Boolean, case, Column, ForeignKey, String, Integer from sqlalchemy.orm import relationship, validates from seed import APPLICATION_GROUPS, APPLICATIONS, APPLICATIONS_ROLES, VENDORS, VENDOR_ROLES flask_app = Flask('demo') flask_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///demo.db' flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(flask_app) class Brand(Enum): THEORCHARD = 'theorchard' AWAL = 'awal' KNR = 'knr' SME = 'sme' class ApplicationGroup(db.Model): __tablename__ = 'application_groups' id = Column(String(255), primary_key=True, unique=True) name = Column(String(255), nullable=False) description = Column(String(255), nullable=False) applications = relationship('Application', back_populates='group') def to_dict(self): return { 'id': self.id, # 'name': self.name, # 'description': self.description, # 'applications': [app.to_dict(True) for app in self.applications] } class Application(db.Model): __tablename__ = 'applications' id = Column(String(255), primary_key=True, unique=True) display_name = Column(String(255), nullable=False) description = Column(String(255), nullable=False) icon = Column(String(255), nullable=False) group_id = Column(String(255), ForeignKey('application_groups.id'), nullable=False) group = relationship('ApplicationGroup', back_populates='applications') roles = relationship('ApplicationRole', back_populates='application') url = Column(String(255), nullable=True) subdomain = Column(String(255), nullable=True) page = Column(String(255), nullable=True) @validates('url', 'subdomain') def validate_fields(self, key, value): if key == 'url' and value is not None: if self.subdomain is not None: raise ValueError("Subdomain must be None when URL is provided") elif key == 'subdomain' and value is None: if self.url is None: raise ValueError('Subdomain must be provided when URL is null') return value def to_dict(self, include_roles=False): d = { 'id': self.id, # 'display_name': self.display_name, # 'description': self.description, # 'icon': self.icon, 'group': { 'id': self.group.id, # 'name': self.group.name }, 'url': self.url, 'subdomain': self.subdomain, 'page': self.page } if include_roles: d['roles'] = [role.to_dict() for role in self.roles] return d def get_url(self, brand): if self.url: return self.url url = f'https://{self.subdomain}.{brand}.com' if self.page: url += self.page return url class ApplicationRole(db.Model): __tablename__ = 'application_roles' id = Column(String(255), primary_key=True) name = Column(String(255), nullable=False) default = Column(Boolean, nullable=False) application_id = Column(String(255), ForeignKey('applications.id'), nullable=False) application = relationship('Application', back_populates='roles') def to_dict(self): return { 'id': self.id, # 'name': self.name, 'default': self.default, 'application_id': self.application_id, } class Vendor(db.Model): __tablename__ = 'vendors' vendor_id = Column(Integer, primary_key=True) name = Column(String(255), nullable=False) brand = Column(String(255), nullable=False) migrated_to_abacus = Column(Boolean, nullable=False) roles = relationship('VendorRoles', back_populates='vendor') class VendorRoles(db.Model): __tablename__ = 'vendor_roles' vendor_id = Column(Integer, ForeignKey('vendors.vendor_id'), primary_key=True) vendor = relationship('Vendor', back_populates='roles') role_id = Column(String(255), ForeignKey('application_roles.id'), primary_key=True) def create_tables(): with flask_app.app_context(): db.drop_all() db.create_all() db.session.commit() def seed_data(): with flask_app.app_context(): for group in APPLICATION_GROUPS: application_group = ApplicationGroup( id=group['id'], name=group['name'], description=group['description'] ) db.session.add(application_group) for app in APPLICATIONS: application = Application( id=app['id'], display_name=app['display_name'], description=app['description'], group_id=app['group_id'], icon=app['icon'], url=app['url'] if 'url' in app else None, subdomain=app['subdomain'] if 'subdomain' in app else None, page=app['page'] if 'page' in app else None ) db.session.add(application) for role in APPLICATIONS_ROLES: application_role = ApplicationRole( id=role['id'], name=role['name'], default=role['default'], application_id=role['application_id'] ) db.session.add(application_role) for v in VENDORS: vendor = Vendor( vendor_id=v['vendor_id'], name=v['name'], brand=v['brand'], migrated_to_abacus=v['migrated_to_abacus'] ) db.session.add(vendor) for vr in VENDOR_ROLES: vendor_role = VendorRoles( vendor_id=vr['vendor_id'], role_id=vr['role_id'] ) db.session.add(vendor_role) db.session.commit() create_tables() seed_data() @flask_app.route('/applications/groups', methods=['GET']) def get_application_groups(): """ Admin endpoint to get all application groups :return: """ groups = ApplicationGroup.query.all() return jsonify([group.to_dict() for group in groups]) @flask_app.route('/applications', methods=['GET']) def get_applications(): """ Admin endpoint to get all applications abd full details :return: """ apps = Application.query.all() return jsonify([app.to_dict(False) for app in apps]) @flask_app.route('/roles', methods=['GET']) def get_roles(): """ Admin endpoint to get all roles :return: """ roles = ApplicationRole.query.all() return jsonify([role.to_dict() for role in roles]) @flask_app.route('/applications/dataloader', methods=['POST']) def get_applications_by_ids(): """ Endpoint to get applications by ids :return: """ application_ids = request.get_json() applications = Application.query.filter(Application.id.in_(application_ids)).all() applications_data = [app.to_dict(False) for app in applications] return jsonify(applications_data) @flask_app.route('/applications/roles/dataloader', methods=['POST']) def get_applications_roles_by_application_ids(): """ Admin Endpoint to get all roles for a list of applications :return: """ application_ids = request.get_json() order = case({id: index for index, id in enumerate(application_ids)}, value=Application.id) query = (Application.query .filter(Application.id.in_(application_ids)) .order_by(order)) applications = query.all() roles_data = [[role.id for role in app.roles] for app in applications] return jsonify(roles_data) @flask_app.route('/roles/dataloader', methods=['POST']) def get_roles_by_ids(): role_ids = request.get_json() print(role_ids) order = case({id: index for index, id in enumerate(role_ids)}, value=ApplicationRole.id) query = (ApplicationRole.query .filter(ApplicationRole.id.in_(role_ids)) .order_by(order)) roles = query.all() roles_data = [role.to_dict() for role in roles] return jsonify(roles_data) @flask_app.route('/vendor//applications', methods=['GET']) def get_account_applications(vendor_id): account = Vendor.query.get(vendor_id) if not account: return jsonify([]) account_role_ids = [account_role.role_id for account_role in account.roles] # Fetch applications with a distinct filter and preload roles applications = Application.query \ .join(ApplicationRole) \ .filter(ApplicationRole.id.in_(account_role_ids)) \ .distinct() \ .all() # Prepare the output by iterating over applications and collecting relevant roles result = [] for app in applications: # Extract role_ids for this application that are in the account's roles filtered_role_ids = [role.id for role in app.roles if role.id in account_role_ids] result.append({ 'id': app.id, 'roles': filtered_role_ids, 'url': app.get_url(account.brand) }) return jsonify({ 'applications': result }) if __name__ == '__main__': port = int(os.getenv('PORT', 5000)) flask_app.run(host='0.0.0.0', debug=True, port=port)