diff --git a/k2/k2rout.py b/k2/k2rout.py index 4a37121..18d8b50 100644 --- a/k2/k2rout.py +++ b/k2/k2rout.py @@ -1,5 +1,5 @@ import zipfile -from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, g +from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, jsonify import os import shutil from flask import request @@ -15,12 +15,11 @@ import os import sys # initialize db -#migrate = Migrate(app, db) +# migrate = Migrate(app, db) components_bp = Blueprint('components', __name__, template_folder='templates') config = yaml.safe_load(open("db/first-login.yml")) - db = k2.db @@ -30,23 +29,25 @@ def first_login_required(view_func): if 'username' not in session: return redirect(url_for('components.first_login')) return view_func(*args, **kwargs) - return decorated_view - -def append_to_yaml_file(file_path, data): - with open(file_path, 'r') as f: - existing_data = yaml.safe_load(f) or [] - if not existing_data: - start_id = 1 - else: - start_id = max(item.get('id', 0) for item in existing_data) + 1 + return decorated_view - for i, item in enumerate(data, start=start_id): - item['id'] = i - existing_data.append(item) - with open(file_path, 'w') as f: - yaml.dump(existing_data, f, default_flow_style=False) +# def append_to_yaml_file(file_path, data): +# with open(file_path, 'r') as f: +# existing_data = yaml.safe_load(f) or [] +# +# if not existing_data: +# start_id = 1 +# else: +# start_id = max(item.get('id', 0) for item in existing_data) + 1 +# +# for i, item in enumerate(data, start=start_id): +# item['id'] = i +# existing_data.append(item) +# +# with open(file_path, 'w') as f: +# yaml.dump(existing_data, f, default_flow_style=False) def remove_from_yaml_file(file_path, component_name): @@ -58,6 +59,7 @@ def remove_from_yaml_file(file_path, component_name): with open(file_path, 'w') as f: yaml.dump(updated_data, f, default_flow_style=False) + @components_bp.route('/api/languages', methods=['GET']) def find_language(): components = Component.query.all() @@ -72,29 +74,13 @@ def find_language(): print(result) return result -@components_bp.route('/api/add-to-menu', methods=['GET']) -def add_to_menu(): - data = [] - components = Component.query.all() - components_names = [component.name for component in components] - for components_names in components_names: - response = requests.get(f"{k2.domain}{components_names}/menu-admin-items") - print(response) - if response.status_code == 200: - data.append(response.json()[0]) - else: - data - # add component_name key for menu items - for item in data: - item['component_name'] = components_names - k2.menu = data - return k2.menu @components_bp.route('/home', methods=['GET', 'POST']) @first_login_required def home(): return redirect('/dashboard') + @components_bp.route('/first-login', methods=['GET', 'POST']) def first_login(): if request.method == "POST": @@ -114,10 +100,11 @@ def change_language(lang): k2.current_language = lang return redirect(url_for('components.dashboard')) + @components_bp.route('/dashboard') @first_login_required def dashboard(): - # Компоненти доступні для встановлення + # Компоненти доступні для встановлення try: # GET-запит до API response = requests.get(f'{k2.update_domain}api/components') @@ -132,7 +119,7 @@ def dashboard(): components_names = [component.name for component in components] # Отримання значення пошукового запиту з параметрів URL search_query = request.args.get('search_query') - #print(search_query) + # print(search_query) filtered_components = [] if search_query: filtered_components = [component for component in component_server if @@ -145,7 +132,8 @@ def dashboard(): return render_template('dashboard.html', components=components, components_names=components_names, component_server=filtered_components, - search_query=search_query, language=k2.menu ) + search_query=search_query, language=k2.menu) + @components_bp.route('/show_components/') def show_components(component_id): @@ -154,11 +142,12 @@ def show_components(component_id): 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/') def install_components_git(component_id): # Шлях до головної папки проекту project_folder = 'components' - #component = Component.get_repository_by_id(component_id) + # component = Component.get_repository_by_id(component_id) response = requests.get(f'{k2.update_domain}api/components') json_data = response.json() selected_component = next((component for component in json_data if component['id'] == component_id), None) @@ -180,13 +169,14 @@ def install_components_git(component_id): 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://', + # підключення до приватного репозиторію + # 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] + command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, + '--target=' + repository_folder] # Виконуємо команду встановлення subprocess.check_call(command) @@ -200,16 +190,16 @@ def install_components_git(component_id): file.write('\n') file.write(code) file.write('\n') - component = Component.query.filter_by(name=selected_component['name']).first() + 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 - ) + 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() @@ -219,6 +209,7 @@ def install_components_git(component_id): except subprocess.CalledProcessError as e: return 'Error installing : ' + str(e) + @components_bp.route('/install_components/') def install_component_from_archive(component_id): # Шлях до головної папки проекту @@ -241,8 +232,6 @@ def install_component_from_archive(component_id): 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): @@ -250,15 +239,22 @@ def install_component_from_archive(component_id): # Розпакувати архів with zipfile.ZipFile(archive_path, "r") as zip_ref: zip_ref.extractall(component_folder) - # Видалити архів os.remove(archive_path) - - # Шлях до файлу, до якого потрібно додати код + #перейменувати якщо git + component_name = selected_component['name'] + old_folder_path = os.path.join(component_folder, component_name + ".git") + new_folder_path = os.path.join(component_folder, component_name) + # Перевірка наявності папки зі старою назвою + if os.path.exists(old_folder_path) and os.path.isdir(old_folder_path): + # Перейменування папки зі старою назвою на нову назву + os.rename(old_folder_path, new_folder_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'] + # selected_component['dependencies'] # Відкриття файлу у режимі дозапису with open(file_path, 'a') as file: @@ -267,7 +263,7 @@ def install_component_from_archive(component_id): file.write(code) file.write('\n') - #Update database with the installed component + # Update database with the installed component component = Component.query.filter_by(name=selected_component['name']).first() if not component: component = Component( @@ -287,7 +283,7 @@ def install_component_from_archive(component_id): db.session.commit() - #add language folders + # add language folders k2.search_babel_translation_directories() return f'''Component installed successfully: {selected_component["name"]} v{version} {k2.babel_translation_directories}, \n \n please wait installing requirments... @@ -296,23 +292,13 @@ def install_component_from_archive(component_id): except Exception as e: return f'Error installing component: {str(e)}' + @components_bp.route('/install-requirments/', methods=['GET']) def install_requirments(selected_component_name): - #menu items api - response = requests.get(f"{k2.domain}{selected_component_name}/menu-items") - if response.status_code == 200: - data = response.json() - - else: - data = [] - # add component_name key for menu items - for item in data: - item['component_name'] = selected_component_name - file_path = 'components/menu.yml' - append_to_yaml_file(file_path, data) + # menu items get_admin_menu() - #install requirements + # install requirements requirements_file = os.path.join('components', selected_component_name, "requirements.txt") if os.path.isfile(requirements_file): pip_command = f"{k2.venv_bin_path}/python -m pip install -r {requirements_file}" @@ -321,6 +307,7 @@ def install_requirments(selected_component_name): \n \n please wait installing requirments components... ''' + @components_bp.route('/install-requirments-components') def install_requirements_components(): # Откриття файлу requirements_components.txt @@ -337,7 +324,8 @@ def install_requirements_components(): return f'Requirements components installed successfully ' else: return f'' - # Опрацювання відповіді (за потреби) + # Опрацювання відповіді (за потреби) + @components_bp.route('/remove_dependencies/', methods=['GET']) def remove_dependencies(component_id): @@ -345,11 +333,11 @@ def remove_dependencies(component_id): component = Component.query.get(component_id) if not component: return 'Component not found ' - #remove menu items - component_name = component.name - file_path = "components/menu.yml" - remove_from_yaml_file(file_path, component_name) - + # remove menu items + component_name = component.name + # file_path = "components/menu.yml" + # remove_from_yaml_file(file_path, component_name) + requests.get(f"{k2.domain}api/add-to-menu") # remove routes file_path = 'routes.py' with open(file_path, 'r') as file: @@ -364,15 +352,14 @@ def remove_dependencies(component_id): return 'Component successfully turn off ' + @components_bp.route('/add_dependencies/', methods=['GET']) def add_dependencies(component_id): - # Знаходимо компоненту за її ID component = Component.query.get(component_id) if not component: return 'Component not found ' - # Шлях до файлу, з якого потрібно видалити залежності file_path = 'routes.py' code = component.dependencies # Відкриття файлу у режимі дозапису @@ -385,6 +372,7 @@ def add_dependencies(component_id): db.session.commit() return 'Dependencies added successfully ' + @components_bp.route('/remove-component/') def remove_component(component_id): # Шлях до головної папки проекту @@ -410,7 +398,80 @@ def remove_component(component_id): # Повертаємо повідомлення про помилку видалення return 'Error removing component: ' + str(e) + + + +@components_bp.route('/component/add') +def component_add(): + # components for install + try: + # GET-requests to API + response = requests.get(f'{k2.update_domain}api/components') + json_data = response.json() + for item in json_data: + item['button'] = f"{k2.domain}/install_components/{item['id']}" + + except: + json_data = None + return jsonify(json_data) + + +@components_bp.route('/component/list') +def component_list(): + # Встановлені компоненти + component_list = [] + components = Component.query.all() + for component in components: + component_dict = {} + component_dict['name'] = component.name + component_dict['id'] = component.id + component_dict['description'] = component.description + component_dict['version'] = component.version + component_dict['button_off'] =f"{k2.domain}/remove_dependencies/{component.id}" + component_dict['button_on'] = f"{k2.domain}/add_dependencies/{component.id}" + component_dict['button_del'] = f"{k2.domain}/remove-component/{component.id}" + component_list.append(component_dict) + return jsonify(component_list) + +# menu +@components_bp.route('/api/add-to-menu', methods=['GET']) +def add_to_menu(): + data = [] + response = requests.get(f"{k2.domain}/menu-admin-items") + data.append(response.json()[0]) + components = Component.query.all() + components_names = [component.name for component in components] + for components_names in components_names: + response = requests.get(f"{k2.domain}{components_names}/menu-admin-items") + print(response) + if response.status_code == 200: + data.append(response.json()[0]) + else: + data + # add component_name key for menu items + for item in data: + item['component_name'] = components_names + k2.menu = data + return k2.menu + + @components_bp.route('/api/main-menu/') def get_admin_menu(): requests.get(f"{k2.domain}api/add-to-menu") return k2.menu + + +@components_bp.route('/menu-admin-items') +def menu_items(): + menu = [ + { + "title": 'Add components', + "icon": {"icon": 'mdi-account-circle-outline'}, + "children": [ + {'title': 'Install components', 'to': 'component-add'}, + {'title': 'Installed components', 'to': 'component-list'}, + + ], + }] + return menu +