root.py 19.1 KB
import zipfile
from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, g
import os
import shutil
from datetime import datetime
import uuid
from flask import request
from db.database import db
from flask_migrate import Migrate
from main import app
import requests
import subprocess
from flask import current_app
import yaml
from functools import wraps
from languages.views import get_locale


with app.app_context():

    #migrate = Migrate(app, db)
    def generate_id():
        generated_id = uuid.uuid4().hex[:32]
        return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)])
    class Component(db.Model):
        __bind_key__ = 'db2'
        __tablename__ = 'component'
        __table_args__ = {'extend_existing': True}
        id = db.Column(db.String(36), primary_key=True, default=generate_id)
        name = db.Column(db.String(100), nullable=False)
        description = db.Column(db.String(200))
        version = db.Column(db.String(20))
        git_link = db.Column(db.String(200))
        dependencies = db.Column(db.String)
        date_installed = db.Column(db.DateTime, default=datetime.utcnow)
        installed = db.Column(db.Boolean, default=False)

        def __init__(self, name, description, version, git_link,  dependencies, installed):
            self.name = name
            self.description = description
            self.version = version
            self.git_link = git_link
            self.dependencies = dependencies
            self.installed = installed
        def __repr__(self):
            return f"Component('{self.name}', '{self.version}')"
        @classmethod
        def get_repository_by_id(self,rep_id):
            component = db.session.query(Component).filter(Component.id == rep_id).first()
            return component
    components_bp = Blueprint('components', __name__, template_folder='templates')
    config = yaml.safe_load(open("db/first-login.yml"))


    def first_login_required(view_func):
        @wraps(view_func)
        def decorated_view(*args, **kwargs):
            if 'username' not in session:
                return redirect(url_for('first_login'))
            return view_func(*args, **kwargs)

        return decorated_view


    def find_language():
        components = Component.query.all()
        languages_paths = []
        # Додаємо головну директорію languages
        languages_paths.append('languages')
        # Знаходимо шляхи до директорій languages всередині папки components
        for component in components:
            component_languages_directory = 'components/' + component.name + '/languages'
            languages_paths.append(component_languages_directory)
        result = ';'.join(languages_paths)
        return result

    @app.route('/', methods=['GET', 'POST'])
    @first_login_required
    def home():
        return redirect('/dashboard')


    @app.route('/login', methods=['GET', 'POST'])
    def first_login():
        if request.method == "POST":
            username = request.form.get("username")
            password = request.form.get("password")
            for user in config["users"]:
                if user["username"] == username and user["password"] == password:
                    session['username'] = username  # Збереження ім'я користувача в сесії
                    return redirect(url_for('components.dashboard'))
            return "Невірне ім'я користувача або пароль."
        return render_template('first-login.html')


    @app.route('/logout')
    def logout():
        session.pop('username', None)  # Видалення ім'я користувача з сесії
        return redirect(url_for('login'))


    @components_bp.route('/change_language/<lang>')
    def change_language(lang):
        session['lang'] = lang
        app.config['CURRENT_LANGUAGE'] = lang
        return redirect(url_for('components.dashboard'))

    @components_bp.route('/dashboard')
    @first_login_required
    def dashboard():

            # Компоненти доступні для встановлення
        try:
            # GET-запит до API
            response = requests.get('http://127.0.0.1:8001/api/components')
            json_data = response.json()
            # Перетворення JSON-об'єкту на масив
            component_server = [item for item in json_data]
        except:
            component_server = None

        # Встановлені компоненти
        components = Component.query.all()
        components_names = [component.name for component in components]
        # Отримання значення пошукового запиту з параметрів URL
        search_query = request.args.get('search_query')
        #print(search_query)
        filtered_components = []
        if search_query:
            filtered_components = [component for component in component_server if
                                   (search_query.lower() in component['name'].lower() if component['name'] else False) or
                                   (search_query.lower() in component['description'].lower() if component[
                                       'description'] else False)]
        else:
            filtered_components = component_server
        current_language = app.config['CURRENT_LANGUAGE'] #get_locale()

        return render_template('dashboard.html', components=components,
                               components_names=components_names, component_server=filtered_components,
                               search_query=search_query, language=current_language)

    @components_bp.route('/show_components/<string:component_id>')
    @first_login_required
    def show_components(component_id):
        response = requests.get('http://127.0.0.1:8001/api/components')
        json_data = response.json()
        selected_component = next((component for component in json_data if component['id'] == component_id), None)
        return render_template('component-info.html', selected_component=selected_component)

    @components_bp.route('/install_components_git/<string:component_id>')
    @first_login_required
    def install_components_git(component_id):
        # Шлях до головної папки проекту
        project_folder = 'components'
        #component = Component.get_repository_by_id(component_id)
        response = requests.get('http://127.0.0.1:8001/api/components')
        json_data = response.json()
        selected_component = next((component for component in json_data if component['id'] == component_id), None)
        # Назва репозиторія
        repository_name = selected_component['name']
        # Шлях до папки репозиторія в межах проекту
        repository_folder = os.path.join(project_folder, repository_name)
        # URL репозиторія

        git_repo_url = selected_component['git_link']
        try:
            # Перевірка наявності папки репозиторія
            if not os.path.exists(repository_folder):
                # Створення папки репозиторія
                os.makedirs(repository_folder)
            # Шлях до файлу __init__.py
            init_file = os.path.join(repository_folder, '__init__.py')
            # Перевірка наявності файлу __init__.py
            if not os.path.exists(init_file):
                # Створення пустого файлу __init__.py
                open(init_file, 'a').close()
            #підключення до приватного репозиторію
            #os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW'
            #git_repo_url_with_token = git_repo_url.replace('https://',
            #                                               f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@')

            # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія
            command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, '--target=' + repository_folder]
            # Виконуємо команду встановлення
            subprocess.check_call(command)

            # Шлях до файлу, до якого потрібно додати код
            file_path = 'routes.py'
            # Код, який потрібно додати
            code = selected_component['dependencies']
            # Відкриття файлу у режимі дозапису
            with open(file_path, 'a') as file:
                # Запис нового коду у файл
                file.write('\n')
                file.write(code)
                file.write('\n')
            component =  Component.query.filter_by(name=selected_component['name']).first()
            if not component:
                new_component = Component(
                        name=selected_component['name'],
                        description=selected_component['description'],
                        version=selected_component['version'],
                        git_link=selected_component['git_link'],
                        dependencies=selected_component['dependencies'],
                        installed=True
                    )
                # Add the new component to the database
                db.session.add(new_component)
                db.session.commit()

            # Повертаємо повідомлення про успішне встановлення
            return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
        except subprocess.CalledProcessError as e:
            return 'Error installing : ' + str(e)

    @components_bp.route('/install_components/<string:component_id>')
    @first_login_required
    def install_component_from_archive(component_id):
        # Шлях до головної папки проекту
        project_folder = 'components'
        # Отримати відповідну компоненту зі списку компонент
        response = requests.get('http://127.0.0.1:8001/api/components')
        json_data = response.json()
        selected_component = next((component for component in json_data if component['id'] == component_id), None)
        if selected_component is None:
            return 'Component not found'
        # Отримати посилання на архів компоненти та версію
        archive_url = selected_component['latest_component_data']
        version = selected_component['latest_version']
        try:
            # Створити шлях до папки компоненти згідно назви та версії
            component_folder = os.path.join(project_folder)
            os.makedirs(component_folder, exist_ok=True)
            # Завантажити архів компоненти
            response = requests.get(archive_url, stream=True)
            response.raise_for_status()
            # Шлях до завантаженого архіву
            archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip")
            # Встановити залежності з файлу requirements.txt

            # Зберегти архів на диск
            with open(archive_path, "wb") as file:
                for chunk in response.iter_content(chunk_size=8192):
                    file.write(chunk)
            # Розпакувати архів
            with zipfile.ZipFile(archive_path, "r") as zip_ref:
                zip_ref.extractall(component_folder)

            # Видалити архів
            os.remove(archive_path)

            # Шлях до файлу, до якого потрібно додати код
            file_path = 'routes.py'
            # Код, який потрібно додати
            code = f'''from components.{selected_component['name']}.{selected_component['name']}.views import {selected_component['name']}\napp.register_blueprint({selected_component['name']}, url_prefix='/{selected_component['name']}')'''
            #selected_component['dependencies']

            # Відкриття файлу у режимі дозапису
            with open(file_path, 'a') as file:
                # Запис нового коду у файл
                file.write('\n')
                file.write(code)
                file.write('\n')

            # Оновити базу даних з встановленою компонентою
            component = Component.query.filter_by(name=selected_component['name']).first()
            if not component:
                component = Component(
                    name=selected_component['name'],
                    description=selected_component['description'],
                    version=version,
                    git_link=selected_component['git_link'],
                    dependencies=code,
                    installed=True
                )
                db.session.add(component)
            else:
                component.version = version
                component.git_link = selected_component['git_link']
                component.dependencies = code
                component.installed = True

            db.session.commit()

            return f'''Component installed successfully: {selected_component["name"]} v{version},
                    \n \n please wait installing requirments...     
                    <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />'''

        except Exception as e:
            return f'Error installing component: {str(e)}'

    @components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET'])
    @first_login_required
    def install_requirments(selected_component_name):
        requirements_file = os.path.join('components', selected_component_name, "requirements.txt")
        if os.path.isfile(requirements_file):
            pip_command = f"{current_app.config['VENV_BIN_PATH']}/python -m pip install -r {requirements_file}"
            subprocess.run(pip_command, shell=True, check=True)
        return f'''Requirements installed successfully
         \n \n please wait installing requirments components...     
         <meta http-equiv="refresh" content="1;url=/install-requirments-components" />'''


    @components_bp.route('/install-requirments-components')
    @first_login_required
    def install_requirements_components():
        # Откриття файлу requirements_components.txt
        requirements_file = 'requirements_components.txt'
        component_ids = None
        if os.path.isfile(requirements_file):
            with open('requirements_components.txt', 'r') as file:
                component_ids = file.read().splitlines()
        if component_ids:
            for component_id in component_ids:
                # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти
                response = requests.get(
                    f'/install_components/{component_id}')
            return f'Requirements  components  installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
        else:
            return f'<meta http-equiv="refresh" content="1;url=/dashboard" />'
                # Опрацювання відповіді (за потреби)




    @components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET'])
    @first_login_required
    def remove_dependencies(component_id):
        # Знаходимо компоненту за її ID
        component = Component.query.get(component_id)
        if not component:
            return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'

        # Шлях до файлу, з якого потрібно видалити залежності
        file_path = 'routes.py'

        # Зчитуємо вміст файлу
        with open(file_path, 'r') as file:
            lines = file.readlines()

        # Видаляємо рядки, що містять залежності компоненти
        updated_lines = [line for line in lines if line.strip() not in component.dependencies]

        # Записуємо оновлений вміст у файл
        with open(file_path, 'w') as file:
            file.writelines(updated_lines)

        # Оновлюємо статус компоненти
        component.installed = False
        db.session.commit()

        return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />'

    @components_bp.route('/add_dependencies/<string:component_id>', methods=['GET'])
    @first_login_required
    def add_dependencies(component_id):

        # Знаходимо компоненту за її ID
        component = Component.query.get(component_id)
        if not component:
            return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'

        # Шлях до файлу, з якого потрібно видалити залежності
        file_path = 'routes.py'
        code = component.dependencies
        # Відкриття файлу у режимі дозапису
        with open(file_path, 'a') as file:
            # Запис нового коду у файл
            file.write(code)

        # Оновлюємо статус компоненти
        component.installed = True
        db.session.commit()
        return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'

    @components_bp.route('/remove-component/<string:component_id>')
    @first_login_required
    def remove_component(component_id):
        # Шлях до головної папки проекту
        project_folder = 'components'
        component = Component.query.get(component_id)
        # Назва репозиторія
        repository_name = component.name
        # Шлях до папки репозиторія в межах проекту
        repository_folder = os.path.join(project_folder, repository_name)
        try:
            # Перевірка наявності папки репозиторія
            if os.path.exists(repository_folder):
                # Видалення папки репозиторія
                shutil.rmtree(repository_folder)
            # Видаляємо компоненту з бази
            if component:
                db.session.delete(component)
                db.session.commit()

            # Повертаємо повідомлення про успішне видалення
            return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
        except Exception as e:
            # Повертаємо повідомлення про помилку видалення
            return 'Error removing component: ' + str(e)
    app.register_blueprint(components_bp)