Commit 0fd79827789847350a22a18ec18d78471d7bc0cf
1 parent
282a39ee6f
Exists in
master
add k2, k2obj class, other
Showing 38 changed files with 618 additions and 464 deletions Inline Diff
- __pycache__/main.cpython-310.pyc
- __pycache__/routes.cpython-310.pyc
- components/k2test/.idea/.gitignore
- components/k2test/.idea/gittest.iml
- components/k2test/.idea/inspectionProfiles/profiles_settings.xml
- components/k2test/.idea/misc.xml
- components/k2test/.idea/modules.xml
- components/k2test/.idea/vcs.xml
- components/k2test/__pycache__/__init__.cpython-310.pyc
- components/k2test/k2test/__pycache__/__init__.cpython-310.pyc
- components/k2test/k2test/__pycache__/views.cpython-310.pyc
- components/k2test/k2test/languages/en/LC_MESSAGES/messages.mo
- components/k2test/k2test/languages/en/LC_MESSAGES/messages.po
- components/k2test/k2test/languages/uk/LC_MESSAGES/messages.mo
- components/k2test/k2test/languages/uk/LC_MESSAGES/messages.po
- components/k2test/k2test/templates/login.html
- components/k2test/k2test/templates/new2.html
- components/k2test/k2test/views.py
- components/k2test/requirements.txt
- db/__pycache__/database.cpython-310.pyc
- db/database.db
- db/database.py
- k2/__pycache__/k2cfg.cpython-310.pyc
- k2/__pycache__/k2inst.cpython-310.pyc
- k2/__pycache__/k2obj.cpython-310.pyc
- k2/__pycache__/root.cpython-310.pyc
- k2/k2cfg.py
- k2/k2inst.py
- k2/k2obj.py
- k2/root.py
- languages/__pycache__/find_language.cpython-310.pyc
- languages/__pycache__/views.cpython-310.pyc
- languages/babel_translation_directories.yml
- languages/find_language.py
- languages/views.py
- main.py
- routes.py
- templates/dashboard.html
__pycache__/main.cpython-310.pyc
No preview for this file type
__pycache__/routes.cpython-310.pyc
No preview for this file type
components/k2test/.idea/.gitignore
| File was created | 1 | # Default ignored files | |
| 2 | /shelf/ | ||
| 3 | /workspace.xml | ||
| 4 |
components/k2test/.idea/gittest.iml
| File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <module type="PYTHON_MODULE" version="4"> | ||
| 3 | <component name="NewModuleRootManager"> | ||
| 4 | <content url="file://$MODULE_DIR$"> | ||
| 5 | <excludeFolder url="file://$MODULE_DIR$/venv" /> | ||
| 6 | </content> | ||
| 7 | <orderEntry type="inheritedJdk" /> | ||
| 8 | <orderEntry type="sourceFolder" forTests="false" /> | ||
| 9 | </component> | ||
| 10 | </module> |
components/k2test/.idea/inspectionProfiles/profiles_settings.xml
| File was created | 1 | <component name="InspectionProjectProfileManager"> | |
| 2 | <settings> | ||
| 3 | <option name="USE_PROJECT_PROFILE" value="false" /> | ||
| 4 | <version value="1.0" /> | ||
| 5 | </settings> | ||
| 6 | </component> |
components/k2test/.idea/misc.xml
| File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | ||
| 3 | <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (gittest)" project-jdk-type="Python SDK" /> | ||
| 4 | <component name="PyCharmProfessionalAdvertiser"> | ||
| 5 | <option name="shown" value="true" /> | ||
| 6 | </component> | ||
| 7 | </project> |
components/k2test/.idea/modules.xml
| File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | ||
| 3 | <component name="ProjectModuleManager"> | ||
| 4 | <modules> | ||
| 5 | <module fileurl="file://$PROJECT_DIR$/.idea/gittest.iml" filepath="$PROJECT_DIR$/.idea/gittest.iml" /> | ||
| 6 | </modules> | ||
| 7 | </component> | ||
| 8 | </project> |
components/k2test/.idea/vcs.xml
| File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | ||
| 3 | <component name="VcsDirectoryMappings"> | ||
| 4 | <mapping directory="$PROJECT_DIR$" vcs="Git" /> | ||
| 5 | </component> | ||
| 6 | </project> |
components/k2test/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/k2test/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/k2test/__pycache__/views.cpython-310.pyc
No preview for this file type
components/k2test/k2test/languages/en/LC_MESSAGES/messages.mo
No preview for this file type
components/k2test/k2test/languages/en/LC_MESSAGES/messages.po
| File was created | 1 | msgid "Installed components" | |
| 2 | msgstr "Installed components" | ||
| 3 | |||
| 4 | msgid "Name" | ||
| 5 | msgstr "Name" | ||
| 6 | |||
| 7 | msgid "Description" | ||
| 8 | msgstr "Description" | ||
| 9 | |||
| 10 | msgid "Version" | ||
| 11 | msgstr "Version" | ||
| 12 | |||
| 13 | msgid "Dependencies" | ||
| 14 | msgstr "Dependencies" | ||
| 15 | |||
| 16 | msgid "Git Link" | ||
| 17 | msgstr "Git Link" | ||
| 18 | |||
| 19 | msgid "Install At" | ||
| 20 | msgstr "Install At" | ||
| 21 | |||
| 22 | msgid "Status" | ||
| 23 | msgstr "Status" | ||
| 24 | |||
| 25 | msgid "Action" | ||
| 26 | msgstr "Action" | ||
| 27 | |||
| 28 | msgid "Components Shop" | ||
| 29 | msgstr "Components Shop" | ||
| 30 | |||
| 31 | msgid "New 2 page" | ||
| 32 | msgstr "New 2 page" | ||
| 33 |
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.mo
No preview for this file type
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.po
| File was created | 1 | msgid "New 2 page" | |
| 2 | msgstr "Нова сторінка 2" | ||
| 3 |
components/k2test/k2test/templates/login.html
| File was created | 1 | login | |
| 2 |
components/k2test/k2test/templates/new2.html
| File was created | 1 | ||
| 2 | |||
| 3 | <h2>{{ _('New 2 page') }}</h2> |
components/k2test/k2test/views.py
| File was created | 1 | from flask import render_template, redirect, request | |
| 2 | from flask_login import login_user, current_user, logout_user, login_required | ||
| 3 | from flask import current_app as k2 | ||
| 4 | from flask import Blueprint, json | ||
| 5 | from flask_sqlalchemy import SQLAlchemy | ||
| 6 | |||
| 7 | |||
| 8 | |||
| 9 | k2test = Blueprint('k2test', __name__, template_folder='templates', static_folder='static',) | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | @k2test.route('/new') | ||
| 14 | def new_component(): | ||
| 15 | db = k2.extensions['sqlalchemy'].db | ||
| 16 | connection = db.engine.connect() | ||
| 17 | query = db.text("SELECT email, login FROM k2users") | ||
| 18 | result = connection.execute(query).fetchall() | ||
| 19 | rows = [dict(email=row.email, login=row.login) for row in result] | ||
| 20 | # Перетворення результату на JSON | ||
| 21 | json_result = json.dumps(rows) | ||
| 22 | return json_result | ||
| 23 | |||
| 24 | @k2test.route('/new2') | ||
| 25 | def new_component2(): | ||
| 26 | return render_template('new2.html') | ||
| 27 | |||
| 28 | @k2test.route('/new3') | ||
| 29 | def new_component3(): | ||
| 30 | return 'сторінка 3' | ||
| 31 | |||
| 32 | @k2test.route('/new4') | ||
| 33 | def new_component4(): | ||
| 34 | return 'сторінка 4' | ||
| 35 |
components/k2test/requirements.txt
| File was created | 1 | Flask-Login==0.6.2 | |
| 2 |
db/__pycache__/database.cpython-310.pyc
No preview for this file type
db/database.db
No preview for this file type
db/database.py
| 1 | from flask_sqlalchemy import SQLAlchemy | File was deleted | |
| 2 | from sqlalchemy import text | ||
| 3 | import yaml | ||
| 4 | import os | ||
| 5 | # load database settings from yml file | ||
| 6 | def init_db_uri(): | ||
| 7 | with open('db/db.yml', 'r') as f: | ||
| 8 | db_config = yaml.load(f, Loader=yaml.FullLoader) | ||
| 9 | return db_config | ||
| 10 | # creating a connection string | ||
| 11 | db = SQLAlchemy() | ||
| 12 | |||
| 13 | def init_db(app): | ||
| 14 | db_config = init_db_uri() | ||
| 15 | db_uri = f"mysql+{db_config['driver']}://{db_config['user']}:{db_config['password']}@{db_config['host']}/{db_config['dbname']}" | ||
| 16 | app.config['SQLALCHEMY_DATABASE_URI'] = db_uri | ||
| 17 | basedir = os.path.abspath(os.path.dirname(__file__)) | ||
| 18 | db_path = os.path.join(basedir, '', '', 'database.db') | ||
| 19 | app.config['SQLALCHEMY_BINDS'] = {'db2': f'sqlite:///{db_path}'} | ||
| 20 | db.init_app(app) | ||
| 21 | 1 | from flask_sqlalchemy import SQLAlchemy | |
| 22 | 2 | from sqlalchemy import text | |
| 23 | 3 | import yaml | |
| 24 | 4 | import os |
k2/__pycache__/k2cfg.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2inst.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2obj.cpython-310.pyc
No preview for this file type
k2/__pycache__/root.cpython-310.pyc
No preview for this file type
k2/k2cfg.py
| File was created | 1 | from flask_sqlalchemy import SQLAlchemy | |
| 2 | from sqlalchemy import text | ||
| 3 | from .k2obj import k2obj | ||
| 4 | import yaml | ||
| 5 | import os | ||
| 6 | import requests | ||
| 7 | import pytz | ||
| 8 | import os | ||
| 9 | import sys | ||
| 10 | from flask import session | ||
| 11 | |||
| 12 | class k2(k2obj): | ||
| 13 | |||
| 14 | version = '2.5.1.27' | ||
| 15 | db = SQLAlchemy() | ||
| 16 | domain = 'http://127.0.0.1:5000/' | ||
| 17 | update_domain ='http://127.0.0.1:8001/' | ||
| 18 | venv_bin_path = os.path.join(os.path.dirname(sys.prefix), 'venv/Scripts') | ||
| 19 | json_sort_keys = False | ||
| 20 | timezone = pytz.timezone('Europe/Kiev') | ||
| 21 | secret_key = 'JH&INH987gFDHdsagh&8dwbjdw8ckw' | ||
| 22 | default_language = 'en' | ||
| 23 | current_language = '' | ||
| 24 | babel_translation_directories = '' | ||
| 25 | |||
| 26 | def __init__(self): | ||
| 27 | super().__init__() | ||
| 28 | |||
| 29 | @classmethod | ||
| 30 | def load_babel_translation_directories(cls): | ||
| 31 | with open('languages/babel_translation_directories.yml', 'r') as f: | ||
| 32 | data = yaml.safe_load(f) | ||
| 33 | cls.babel_translation_directories = data['babel_translation_directories'] | ||
| 34 | |||
| 35 | @classmethod | ||
| 36 | def get_locale(cls): | ||
| 37 | if 'lang' in session: | ||
| 38 | # Отримати обрану мову з сеансу користувача | ||
| 39 | return session['lang'] | ||
| 40 | else: | ||
| 41 | # Повернути мову за замовчуванням з налаштувань додатку | ||
| 42 | return cls.default_language #app.config['DEFAULT_LANGUAGE'] | ||
| 43 | |||
| 44 | @classmethod | ||
| 45 | def search_babel_translation_directories(cls): | ||
| 46 | response = requests.get(f'{cls.domain}api/languages') | ||
| 47 | if response.status_code == 200: | ||
| 48 | cls.babel_translation_directories = response.text | ||
| 49 | data = {'babel_translation_directories': response.text} | ||
| 50 | else: | ||
| 51 | cls.babel_translation_directories = 'languages' | ||
| 52 | data = {'babel_translation_directories': 'languages'} | ||
| 53 | |||
| 54 | with open('languages/babel_translation_directories.yml', 'w') as f: | ||
| 55 | yaml.dump(data, f) | ||
| 56 | |||
| 57 | # load database settings from yml file | ||
| 58 | def init_db_uri(self): | ||
| 59 | with open('db/db.yml', 'r') as f: | ||
| 60 | db_config = yaml.load(f, Loader=yaml.FullLoader) | ||
| 61 | return db_config | ||
| 62 | |||
| 63 | # creating a connection string | ||
| 64 | |||
| 65 | |||
| 66 | def init_db(self, app): | ||
| 67 | db_config = self.init_db_uri() | ||
| 68 | db_uri = f"mysql+{db_config['driver']}://{db_config['user']}:{db_config['password']}@{db_config['host']}/{db_config['dbname']}" | ||
| 69 | app.config['SQLALCHEMY_DATABASE_URI'] = db_uri | ||
| 70 | db_path = '../db/database.db' | ||
| 71 | app.config['SQLALCHEMY_BINDS'] = {'db2': f'sqlite:///{db_path}'} | ||
| 72 | self.db.init_app(app) | ||
| 73 | |||
| 74 | |||
| 75 | |||
| 76 | |||
| 77 | |||
| 78 |
k2/k2inst.py
| File was created | 1 | import zipfile | |
| 2 | from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, g | ||
| 3 | import os | ||
| 4 | import shutil | ||
| 5 | from datetime import datetime | ||
| 6 | import uuid | ||
| 7 | from flask import request | ||
| 8 | from k2.k2cfg import k2 | ||
| 9 | from flask_migrate import Migrate | ||
| 10 | import requests | ||
| 11 | import subprocess | ||
| 12 | from flask import current_app | ||
| 13 | import yaml | ||
| 14 | from functools import wraps | ||
| 15 | |||
| 16 | db = k2.db | ||
| 17 | #migrate = Migrate(app, db) | ||
| 18 | def generate_id(): | ||
| 19 | generated_id = uuid.uuid4().hex[:32] | ||
| 20 | return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)]) | ||
| 21 | class Component(db.Model): | ||
| 22 | __bind_key__ = 'db2' | ||
| 23 | __tablename__ = 'component' | ||
| 24 | __table_args__ = {'extend_existing': True} | ||
| 25 | id = db.Column(db.String(36), primary_key=True, default=generate_id) | ||
| 26 | name = db.Column(db.String(100), nullable=False) | ||
| 27 | description = db.Column(db.String(200)) | ||
| 28 | version = db.Column(db.String(20)) | ||
| 29 | git_link = db.Column(db.String(200)) | ||
| 30 | dependencies = db.Column(db.String) | ||
| 31 | date_installed = db.Column(db.DateTime, default=datetime.utcnow) | ||
| 32 | installed = db.Column(db.Boolean, default=False) | ||
| 33 | |||
| 34 | def __init__(self, name, description, version, git_link, dependencies, installed): | ||
| 35 | self.name = name | ||
| 36 | self.description = description | ||
| 37 | self.version = version | ||
| 38 | self.git_link = git_link | ||
| 39 | self.dependencies = dependencies | ||
| 40 | self.installed = installed | ||
| 41 | def __repr__(self): | ||
| 42 | return f"Component('{self.name}', '{self.version}')" | ||
| 43 | @classmethod | ||
| 44 | def get_repository_by_id(self,rep_id): | ||
| 45 | component = db.session.query(Component).filter(Component.id == rep_id).first() | ||
| 46 | return component | ||
| 47 | components_bp = Blueprint('components', __name__, template_folder='templates') | ||
| 48 | config = yaml.safe_load(open("db/first-login.yml")) | ||
| 49 | |||
| 50 | def first_login_required(view_func): | ||
| 51 | @wraps(view_func) | ||
| 52 | def decorated_view(*args, **kwargs): | ||
| 53 | if 'username' not in session: | ||
| 54 | return redirect(url_for('first_login')) | ||
| 55 | return view_func(*args, **kwargs) | ||
| 56 | |||
| 57 | return decorated_view | ||
| 58 | |||
| 59 | |||
| 60 | @components_bp.route('/api/languages', methods=['GET']) | ||
| 61 | def find_language(): | ||
| 62 | components = Component.query.all() | ||
| 63 | languages_paths = [] | ||
| 64 | # Додаємо головну директорію languages | ||
| 65 | languages_paths.append('languages') | ||
| 66 | # Знаходимо шляхи до директорій languages всередині папки components | ||
| 67 | for component in components: | ||
| 68 | component_languages_directory = 'components/' + component.name + '/' + component.name + '/languages' | ||
| 69 | languages_paths.append(component_languages_directory) | ||
| 70 | result = ';'.join(languages_paths) | ||
| 71 | print(result) | ||
| 72 | return result | ||
| 73 | |||
| 74 | @components_bp.route('/', methods=['GET', 'POST']) | ||
| 75 | @first_login_required | ||
| 76 | def home(): | ||
| 77 | return redirect('/dashboard') | ||
| 78 | |||
| 79 | @components_bp.route('/login', methods=['GET', 'POST']) | ||
| 80 | def first_login(): | ||
| 81 | if request.method == "POST": | ||
| 82 | username = request.form.get("username") | ||
| 83 | password = request.form.get("password") | ||
| 84 | for user in config["users"]: | ||
| 85 | if user["username"] == username and user["password"] == password: | ||
| 86 | session['username'] = username # Збереження ім'я користувача в сесії | ||
| 87 | return redirect(url_for('components.dashboard')) | ||
| 88 | return "Невірне ім'я користувача або пароль." | ||
| 89 | return render_template('first-login.html') | ||
| 90 | |||
| 91 | @components_bp.route('/logout') | ||
| 92 | def logout(): | ||
| 93 | session.pop('username', None) # Видалення ім'я користувача з сесії | ||
| 94 | return redirect(url_for('first_login')) | ||
| 95 | |||
| 96 | @components_bp.route('/change_language/<lang>') | ||
| 97 | def change_language(lang): | ||
| 98 | session['lang'] = lang | ||
| 99 | k2.current_language = lang | ||
| 100 | return redirect(url_for('components.dashboard')) | ||
| 101 | |||
| 102 | @components_bp.route('/dashboard') | ||
| 103 | @first_login_required | ||
| 104 | def dashboard(): | ||
| 105 | |||
| 106 | # Компоненти доступні для встановлення | ||
| 107 | try: | ||
| 108 | # GET-запит до API | ||
| 109 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 110 | json_data = response.json() | ||
| 111 | # Перетворення JSON-об'єкту на масив | ||
| 112 | component_server = [item for item in json_data] | ||
| 113 | except: | ||
| 114 | component_server = None | ||
| 115 | |||
| 116 | # Встановлені компоненти | ||
| 117 | components = Component.query.all() | ||
| 118 | components_names = [component.name for component in components] | ||
| 119 | # Отримання значення пошукового запиту з параметрів URL | ||
| 120 | search_query = request.args.get('search_query') | ||
| 121 | #print(search_query) | ||
| 122 | filtered_components = [] | ||
| 123 | if search_query: | ||
| 124 | filtered_components = [component for component in component_server if | ||
| 125 | (search_query.lower() in component['name'].lower() if component['name'] else False) or | ||
| 126 | (search_query.lower() in component['description'].lower() if component[ | ||
| 127 | 'description'] else False)] | ||
| 128 | else: | ||
| 129 | filtered_components = component_server | ||
| 130 | current_language = k2.current_language | ||
| 131 | |||
| 132 | return render_template('dashboard.html', components=components, | ||
| 133 | components_names=components_names, component_server=filtered_components, | ||
| 134 | search_query=search_query, language=current_language ) | ||
| 135 | |||
| 136 | @components_bp.route('/show_components/<string:component_id>') | ||
| 137 | @first_login_required | ||
| 138 | def show_components(component_id): | ||
| 139 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 140 | json_data = response.json() | ||
| 141 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 142 | return render_template('component-info.html', selected_component=selected_component) | ||
| 143 | |||
| 144 | @components_bp.route('/install_components_git/<string:component_id>') | ||
| 145 | @first_login_required | ||
| 146 | def install_components_git(component_id): | ||
| 147 | # Шлях до головної папки проекту | ||
| 148 | project_folder = 'components' | ||
| 149 | #component = Component.get_repository_by_id(component_id) | ||
| 150 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 151 | json_data = response.json() | ||
| 152 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 153 | # Назва репозиторія | ||
| 154 | repository_name = selected_component['name'] | ||
| 155 | # Шлях до папки репозиторія в межах проекту | ||
| 156 | repository_folder = os.path.join(project_folder, repository_name) | ||
| 157 | # URL репозиторія | ||
| 158 | |||
| 159 | git_repo_url = selected_component['git_link'] | ||
| 160 | try: | ||
| 161 | # Перевірка наявності папки репозиторія | ||
| 162 | if not os.path.exists(repository_folder): | ||
| 163 | # Створення папки репозиторія | ||
| 164 | os.makedirs(repository_folder) | ||
| 165 | # Шлях до файлу __init__.py | ||
| 166 | init_file = os.path.join(repository_folder, '__init__.py') | ||
| 167 | # Перевірка наявності файлу __init__.py | ||
| 168 | if not os.path.exists(init_file): | ||
| 169 | # Створення пустого файлу __init__.py | ||
| 170 | open(init_file, 'a').close() | ||
| 171 | #підключення до приватного репозиторію | ||
| 172 | #os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW' | ||
| 173 | #git_repo_url_with_token = git_repo_url.replace('https://', | ||
| 174 | # f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@') | ||
| 175 | |||
| 176 | # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія | ||
| 177 | command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, '--target=' + repository_folder] | ||
| 178 | # Виконуємо команду встановлення | ||
| 179 | subprocess.check_call(command) | ||
| 180 | |||
| 181 | # Шлях до файлу, до якого потрібно додати код | ||
| 182 | file_path = 'routes.py' | ||
| 183 | # Код, який потрібно додати | ||
| 184 | code = selected_component['dependencies'] | ||
| 185 | # Відкриття файлу у режимі дозапису | ||
| 186 | with open(file_path, 'a') as file: | ||
| 187 | # Запис нового коду у файл | ||
| 188 | file.write('\n') | ||
| 189 | file.write(code) | ||
| 190 | file.write('\n') | ||
| 191 | component = Component.query.filter_by(name=selected_component['name']).first() | ||
| 192 | if not component: | ||
| 193 | new_component = Component( | ||
| 194 | name=selected_component['name'], | ||
| 195 | description=selected_component['description'], | ||
| 196 | version=selected_component['version'], | ||
| 197 | git_link=selected_component['git_link'], | ||
| 198 | dependencies=selected_component['dependencies'], | ||
| 199 | installed=True | ||
| 200 | ) | ||
| 201 | # Add the new component to the database | ||
| 202 | db.session.add(new_component) | ||
| 203 | db.session.commit() | ||
| 204 | |||
| 205 | # Повертаємо повідомлення про успішне встановлення | ||
| 206 | return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 207 | except subprocess.CalledProcessError as e: | ||
| 208 | return 'Error installing : ' + str(e) | ||
| 209 | |||
| 210 | @components_bp.route('/install_components/<string:component_id>') | ||
| 211 | @first_login_required | ||
| 212 | def install_component_from_archive(component_id): | ||
| 213 | # Шлях до головної папки проекту | ||
| 214 | project_folder = 'components' | ||
| 215 | # Отримати відповідну компоненту зі списку компонент | ||
| 216 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 217 | json_data = response.json() | ||
| 218 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 219 | if selected_component is None: | ||
| 220 | return 'Component not found' | ||
| 221 | # Отримати посилання на архів компоненти та версію | ||
| 222 | archive_url = selected_component['latest_component_data'] | ||
| 223 | version = selected_component['latest_version'] | ||
| 224 | try: | ||
| 225 | # Створити шлях до папки компоненти згідно назви та версії | ||
| 226 | component_folder = os.path.join(project_folder) | ||
| 227 | os.makedirs(component_folder, exist_ok=True) | ||
| 228 | # Завантажити архів компоненти | ||
| 229 | response = requests.get(archive_url, stream=True) | ||
| 230 | response.raise_for_status() | ||
| 231 | # Шлях до завантаженого архіву | ||
| 232 | archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip") | ||
| 233 | # Встановити залежності з файлу requirements.txt | ||
| 234 | |||
| 235 | # Зберегти архів на диск | ||
| 236 | with open(archive_path, "wb") as file: | ||
| 237 | for chunk in response.iter_content(chunk_size=8192): | ||
| 238 | file.write(chunk) | ||
| 239 | # Розпакувати архів | ||
| 240 | with zipfile.ZipFile(archive_path, "r") as zip_ref: | ||
| 241 | zip_ref.extractall(component_folder) | ||
| 242 | |||
| 243 | # Видалити архів | ||
| 244 | os.remove(archive_path) | ||
| 245 | |||
| 246 | # Шлях до файлу, до якого потрібно додати код | ||
| 247 | file_path = 'routes.py' | ||
| 248 | # Код, який потрібно додати | ||
| 249 | 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']}')''' | ||
| 250 | #selected_component['dependencies'] | ||
| 251 | |||
| 252 | # Відкриття файлу у режимі дозапису | ||
| 253 | with open(file_path, 'a') as file: | ||
| 254 | # Запис нового коду у файл | ||
| 255 | file.write('\n') | ||
| 256 | file.write(code) | ||
| 257 | file.write('\n') | ||
| 258 | |||
| 259 | # Оновити базу даних з встановленою компонентою | ||
| 260 | component = Component.query.filter_by(name=selected_component['name']).first() | ||
| 261 | if not component: | ||
| 262 | component = Component( | ||
| 263 | name=selected_component['name'], | ||
| 264 | description=selected_component['description'], | ||
| 265 | version=version, | ||
| 266 | git_link=selected_component['git_link'], | ||
| 267 | dependencies=code, | ||
| 268 | installed=True | ||
| 269 | ) | ||
| 270 | db.session.add(component) | ||
| 271 | else: | ||
| 272 | component.version = version | ||
| 273 | component.git_link = selected_component['git_link'] | ||
| 274 | component.dependencies = code | ||
| 275 | component.installed = True | ||
| 276 | |||
| 277 | db.session.commit() | ||
| 278 | |||
| 279 | |||
| 280 | k2.search_babel_translation_directories() | ||
| 281 | |||
| 282 | return f'''Component installed successfully: {selected_component["name"]} v{version} {k2.babel_translation_directories}, | ||
| 283 | \n \n please wait installing requirments... | ||
| 284 | <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />''' | ||
| 285 | |||
| 286 | except Exception as e: | ||
| 287 | return f'Error installing component: {str(e)}' | ||
| 288 | |||
| 289 | @components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET']) | ||
| 290 | @first_login_required | ||
| 291 | def install_requirments(selected_component_name): | ||
| 292 | requirements_file = os.path.join('components', selected_component_name, "requirements.txt") | ||
| 293 | if os.path.isfile(requirements_file): | ||
| 294 | pip_command = f"{k2.venv_bin_path}/python -m pip install -r {requirements_file}" | ||
| 295 | subprocess.run(pip_command, shell=True, check=True) | ||
| 296 | return f'''Requirements installed successfully | ||
| 297 | \n \n please wait installing requirments components... | ||
| 298 | <meta http-equiv="refresh" content="1;url=/install-requirments-components" />''' | ||
| 299 | |||
| 300 | |||
| 301 | @components_bp.route('/install-requirments-components') | ||
| 302 | @first_login_required | ||
| 303 | def install_requirements_components(): | ||
| 304 | # Откриття файлу requirements_components.txt | ||
| 305 | requirements_file = 'requirements_components.txt' | ||
| 306 | component_ids = None | ||
| 307 | if os.path.isfile(requirements_file): | ||
| 308 | with open('requirements_components.txt', 'r') as file: | ||
| 309 | component_ids = file.read().splitlines() | ||
| 310 | if component_ids: | ||
| 311 | for component_id in component_ids: | ||
| 312 | # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти | ||
| 313 | response = requests.get( | ||
| 314 | f'/install_components/{component_id}') | ||
| 315 | return f'Requirements components installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 316 | else: | ||
| 317 | return f'<meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 318 | # Опрацювання відповіді (за потреби) | ||
| 319 | |||
| 320 | |||
| 321 | @components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET']) | ||
| 322 | @first_login_required | ||
| 323 | def remove_dependencies(component_id): | ||
| 324 | # Знаходимо компоненту за її ID | ||
| 325 | component = Component.query.get(component_id) | ||
| 326 | if not component: | ||
| 327 | return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 328 | |||
| 329 | # Шлях до файлу, з якого потрібно видалити залежності | ||
| 330 | file_path = 'routes.py' | ||
| 331 | |||
| 332 | # Зчитуємо вміст файлу | ||
| 333 | with open(file_path, 'r') as file: | ||
| 334 | lines = file.readlines() | ||
| 335 | |||
| 336 | # Видаляємо рядки, що містять залежності компоненти | ||
| 337 | updated_lines = [line for line in lines if line.strip() not in component.dependencies] | ||
| 338 | |||
| 339 | # Записуємо оновлений вміст у файл | ||
| 340 | with open(file_path, 'w') as file: | ||
| 341 | file.writelines(updated_lines) | ||
| 342 | |||
| 343 | # Оновлюємо статус компоненти | ||
| 344 | component.installed = False | ||
| 345 | db.session.commit() | ||
| 346 | |||
| 347 | return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 348 | |||
| 349 | @components_bp.route('/add_dependencies/<string:component_id>', methods=['GET']) | ||
| 350 | @first_login_required | ||
| 351 | def add_dependencies(component_id): | ||
| 352 | |||
| 353 | # Знаходимо компоненту за її ID | ||
| 354 | component = Component.query.get(component_id) | ||
| 355 | if not component: | ||
| 356 | return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 357 | |||
| 358 | # Шлях до файлу, з якого потрібно видалити залежності | ||
| 359 | file_path = 'routes.py' | ||
| 360 | code = component.dependencies | ||
| 361 | # Відкриття файлу у режимі дозапису | ||
| 362 | with open(file_path, 'a') as file: | ||
| 363 | # Запис нового коду у файл | ||
| 364 | file.write(code) | ||
| 365 | |||
| 366 | # Оновлюємо статус компоненти | ||
| 367 | component.installed = True | ||
| 368 | db.session.commit() | ||
| 369 | return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 370 | |||
| 371 | @components_bp.route('/remove-component/<string:component_id>') | ||
| 372 | @first_login_required | ||
| 373 | def remove_component(component_id): | ||
| 374 | # Шлях до головної папки проекту | ||
| 375 | project_folder = 'components' | ||
| 376 | component = Component.query.get(component_id) | ||
| 377 | # Назва репозиторія | ||
| 378 | repository_name = component.name | ||
| 379 | # Шлях до папки репозиторія в межах проекту | ||
| 380 | repository_folder = os.path.join(project_folder, repository_name) | ||
| 381 | try: | ||
| 382 | # Перевірка наявності папки репозиторія | ||
| 383 | if os.path.exists(repository_folder): | ||
| 384 | # Видалення папки репозиторія | ||
| 385 | shutil.rmtree(repository_folder) | ||
| 386 | # Видаляємо компоненту з бази | ||
| 387 | if component: | ||
| 388 | db.session.delete(component) | ||
| 389 | db.session.commit() | ||
| 390 | |||
| 391 | # Повертаємо повідомлення про успішне видалення | ||
| 392 | return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 393 | except Exception as e: | ||
| 394 | # Повертаємо повідомлення про помилку видалення | ||
| 395 | return 'Error removing component: ' + str(e) | ||
| 396 |
k2/k2obj.py
| File was created | 1 | class k2obj: | |
| 2 | name = '' | ||
| 3 | version = '' | ||
| 4 | domain = '' | ||
| 5 | timezone = '' | ||
| 6 | menu = '' | ||
| 7 | |||
| 8 | |||
| 9 |
k2/root.py
| 1 | import zipfile | File was deleted | |
| 2 | from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, g | ||
| 3 | import os | ||
| 4 | import shutil | ||
| 5 | from datetime import datetime | ||
| 6 | import uuid | ||
| 7 | from flask import request | ||
| 8 | from db.database import db | ||
| 9 | from flask_migrate import Migrate | ||
| 10 | from main import app | ||
| 11 | import requests | ||
| 12 | import subprocess | ||
| 13 | from flask import current_app | ||
| 14 | import yaml | ||
| 15 | from functools import wraps | ||
| 16 | from languages.views import get_locale | ||
| 17 | |||
| 18 | |||
| 19 | with app.app_context(): | ||
| 20 | |||
| 21 | #migrate = Migrate(app, db) | ||
| 22 | def generate_id(): | ||
| 23 | generated_id = uuid.uuid4().hex[:32] | ||
| 24 | return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)]) | ||
| 25 | class Component(db.Model): | ||
| 26 | __bind_key__ = 'db2' | ||
| 27 | __tablename__ = 'component' | ||
| 28 | __table_args__ = {'extend_existing': True} | ||
| 29 | id = db.Column(db.String(36), primary_key=True, default=generate_id) | ||
| 30 | name = db.Column(db.String(100), nullable=False) | ||
| 31 | description = db.Column(db.String(200)) | ||
| 32 | version = db.Column(db.String(20)) | ||
| 33 | git_link = db.Column(db.String(200)) | ||
| 34 | dependencies = db.Column(db.String) | ||
| 35 | date_installed = db.Column(db.DateTime, default=datetime.utcnow) | ||
| 36 | installed = db.Column(db.Boolean, default=False) | ||
| 37 | |||
| 38 | def __init__(self, name, description, version, git_link, dependencies, installed): | ||
| 39 | self.name = name | ||
| 40 | self.description = description | ||
| 41 | self.version = version | ||
| 42 | self.git_link = git_link | ||
| 43 | self.dependencies = dependencies | ||
| 44 | self.installed = installed | ||
| 45 | def __repr__(self): | ||
| 46 | return f"Component('{self.name}', '{self.version}')" | ||
| 47 | @classmethod | ||
| 48 | def get_repository_by_id(self,rep_id): | ||
| 49 | component = db.session.query(Component).filter(Component.id == rep_id).first() | ||
| 50 | return component | ||
| 51 | components_bp = Blueprint('components', __name__, template_folder='templates') | ||
| 52 | config = yaml.safe_load(open("db/first-login.yml")) | ||
| 53 | |||
| 54 | |||
| 55 | def first_login_required(view_func): | ||
| 56 | @wraps(view_func) | ||
| 57 | def decorated_view(*args, **kwargs): | ||
| 58 | if 'username' not in session: | ||
| 59 | return redirect(url_for('first_login')) | ||
| 60 | return view_func(*args, **kwargs) | ||
| 61 | |||
| 62 | return decorated_view | ||
| 63 | |||
| 64 | |||
| 65 | def find_language(): | ||
| 66 | components = Component.query.all() | ||
| 67 | languages_paths = [] | ||
| 68 | # Додаємо головну директорію languages | ||
| 69 | languages_paths.append('languages') | ||
| 70 | # Знаходимо шляхи до директорій languages всередині папки components | ||
| 71 | for component in components: | ||
| 72 | component_languages_directory = 'components/' + component.name + '/languages' | ||
| 73 | languages_paths.append(component_languages_directory) | ||
| 74 | result = ';'.join(languages_paths) | ||
| 75 | return result | ||
| 76 | |||
| 77 | @app.route('/', methods=['GET', 'POST']) | ||
| 78 | @first_login_required | ||
| 79 | def home(): | ||
| 80 | return redirect('/dashboard') | ||
| 81 | |||
| 82 | |||
| 83 | @app.route('/login', methods=['GET', 'POST']) | ||
| 84 | def first_login(): | ||
| 85 | if request.method == "POST": | ||
| 86 | username = request.form.get("username") | ||
| 87 | password = request.form.get("password") | ||
| 88 | for user in config["users"]: | ||
| 89 | if user["username"] == username and user["password"] == password: | ||
| 90 | session['username'] = username # Збереження ім'я користувача в сесії | ||
| 91 | return redirect(url_for('components.dashboard')) | ||
| 92 | return "Невірне ім'я користувача або пароль." | ||
| 93 | return render_template('first-login.html') | ||
| 94 | |||
| 95 | |||
| 96 | @app.route('/logout') | ||
| 97 | def logout(): | ||
| 98 | session.pop('username', None) # Видалення ім'я користувача з сесії | ||
| 99 | return redirect(url_for('login')) | ||
| 100 | |||
| 101 | |||
| 102 | @components_bp.route('/change_language/<lang>') | ||
| 103 | def change_language(lang): | ||
| 104 | session['lang'] = lang | ||
| 105 | app.config['CURRENT_LANGUAGE'] = lang | ||
| 106 | return redirect(url_for('components.dashboard')) | ||
| 107 | |||
| 108 | @components_bp.route('/dashboard') | ||
| 109 | @first_login_required | ||
| 110 | def dashboard(): | ||
| 111 | |||
| 112 | # Компоненти доступні для встановлення | ||
| 113 | try: | ||
| 114 | # GET-запит до API | ||
| 115 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 116 | json_data = response.json() | ||
| 117 | # Перетворення JSON-об'єкту на масив | ||
| 118 | component_server = [item for item in json_data] | ||
| 119 | except: | ||
| 120 | component_server = None | ||
| 121 | |||
| 122 | # Встановлені компоненти | ||
| 123 | components = Component.query.all() | ||
| 124 | components_names = [component.name for component in components] | ||
| 125 | # Отримання значення пошукового запиту з параметрів URL | ||
| 126 | search_query = request.args.get('search_query') | ||
| 127 | #print(search_query) | ||
| 128 | filtered_components = [] | ||
| 129 | if search_query: | ||
| 130 | filtered_components = [component for component in component_server if | ||
| 131 | (search_query.lower() in component['name'].lower() if component['name'] else False) or | ||
| 132 | (search_query.lower() in component['description'].lower() if component[ | ||
| 133 | 'description'] else False)] | ||
| 134 | else: | ||
| 135 | filtered_components = component_server | ||
| 136 | current_language = app.config['CURRENT_LANGUAGE'] #get_locale() | ||
| 137 | |||
| 138 | return render_template('dashboard.html', components=components, | ||
| 139 | components_names=components_names, component_server=filtered_components, | ||
| 140 | search_query=search_query, language=current_language) | ||
| 141 | |||
| 142 | @components_bp.route('/show_components/<string:component_id>') | ||
| 143 | @first_login_required | ||
| 144 | def show_components(component_id): | ||
| 145 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 146 | json_data = response.json() | ||
| 147 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 148 | return render_template('component-info.html', selected_component=selected_component) | ||
| 149 | |||
| 150 | @components_bp.route('/install_components_git/<string:component_id>') | ||
| 151 | @first_login_required | ||
| 152 | def install_components_git(component_id): | ||
| 153 | # Шлях до головної папки проекту | ||
| 154 | project_folder = 'components' | ||
| 155 | #component = Component.get_repository_by_id(component_id) | ||
| 156 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 157 | json_data = response.json() | ||
| 158 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 159 | # Назва репозиторія | ||
| 160 | repository_name = selected_component['name'] | ||
| 161 | # Шлях до папки репозиторія в межах проекту | ||
| 162 | repository_folder = os.path.join(project_folder, repository_name) | ||
| 163 | # URL репозиторія | ||
| 164 | |||
| 165 | git_repo_url = selected_component['git_link'] | ||
| 166 | try: | ||
| 167 | # Перевірка наявності папки репозиторія | ||
| 168 | if not os.path.exists(repository_folder): | ||
| 169 | # Створення папки репозиторія | ||
| 170 | os.makedirs(repository_folder) | ||
| 171 | # Шлях до файлу __init__.py | ||
| 172 | init_file = os.path.join(repository_folder, '__init__.py') | ||
| 173 | # Перевірка наявності файлу __init__.py | ||
| 174 | if not os.path.exists(init_file): | ||
| 175 | # Створення пустого файлу __init__.py | ||
| 176 | open(init_file, 'a').close() | ||
| 177 | #підключення до приватного репозиторію | ||
| 178 | #os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW' | ||
| 179 | #git_repo_url_with_token = git_repo_url.replace('https://', | ||
| 180 | # f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@') | ||
| 181 | |||
| 182 | # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія | ||
| 183 | command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, '--target=' + repository_folder] | ||
| 184 | # Виконуємо команду встановлення | ||
| 185 | subprocess.check_call(command) | ||
| 186 | |||
| 187 | # Шлях до файлу, до якого потрібно додати код | ||
| 188 | file_path = 'routes.py' | ||
| 189 | # Код, який потрібно додати | ||
| 190 | code = selected_component['dependencies'] | ||
| 191 | # Відкриття файлу у режимі дозапису | ||
| 192 | with open(file_path, 'a') as file: | ||
| 193 | # Запис нового коду у файл | ||
| 194 | file.write('\n') | ||
| 195 | file.write(code) | ||
| 196 | file.write('\n') | ||
| 197 | component = Component.query.filter_by(name=selected_component['name']).first() | ||
| 198 | if not component: | ||
| 199 | new_component = Component( | ||
| 200 | name=selected_component['name'], | ||
| 201 | description=selected_component['description'], | ||
| 202 | version=selected_component['version'], | ||
| 203 | git_link=selected_component['git_link'], | ||
| 204 | dependencies=selected_component['dependencies'], | ||
| 205 | installed=True | ||
| 206 | ) | ||
| 207 | # Add the new component to the database | ||
| 208 | db.session.add(new_component) | ||
| 209 | db.session.commit() | ||
| 210 | |||
| 211 | # Повертаємо повідомлення про успішне встановлення | ||
| 212 | return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 213 | except subprocess.CalledProcessError as e: | ||
| 214 | return 'Error installing : ' + str(e) | ||
| 215 | |||
| 216 | @components_bp.route('/install_components/<string:component_id>') | ||
| 217 | @first_login_required | ||
| 218 | def install_component_from_archive(component_id): | ||
| 219 | # Шлях до головної папки проекту | ||
| 220 | project_folder = 'components' | ||
| 221 | # Отримати відповідну компоненту зі списку компонент | ||
| 222 | response = requests.get('http://127.0.0.1:8001/api/components') | ||
| 223 | json_data = response.json() | ||
| 224 | selected_component = next((component for component in json_data if component['id'] == component_id), None) | ||
| 225 | if selected_component is None: | ||
| 226 | return 'Component not found' | ||
| 227 | # Отримати посилання на архів компоненти та версію | ||
| 228 | archive_url = selected_component['latest_component_data'] | ||
| 229 | version = selected_component['latest_version'] | ||
| 230 | try: | ||
| 231 | # Створити шлях до папки компоненти згідно назви та версії | ||
| 232 | component_folder = os.path.join(project_folder) | ||
| 233 | os.makedirs(component_folder, exist_ok=True) | ||
| 234 | # Завантажити архів компоненти | ||
| 235 | response = requests.get(archive_url, stream=True) | ||
| 236 | response.raise_for_status() | ||
| 237 | # Шлях до завантаженого архіву | ||
| 238 | archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip") | ||
| 239 | # Встановити залежності з файлу requirements.txt | ||
| 240 | |||
| 241 | # Зберегти архів на диск | ||
| 242 | with open(archive_path, "wb") as file: | ||
| 243 | for chunk in response.iter_content(chunk_size=8192): | ||
| 244 | file.write(chunk) | ||
| 245 | # Розпакувати архів | ||
| 246 | with zipfile.ZipFile(archive_path, "r") as zip_ref: | ||
| 247 | zip_ref.extractall(component_folder) | ||
| 248 | |||
| 249 | # Видалити архів | ||
| 250 | os.remove(archive_path) | ||
| 251 | |||
| 252 | # Шлях до файлу, до якого потрібно додати код | ||
| 253 | file_path = 'routes.py' | ||
| 254 | # Код, який потрібно додати | ||
| 255 | 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']}')''' | ||
| 256 | #selected_component['dependencies'] | ||
| 257 | |||
| 258 | # Відкриття файлу у режимі дозапису | ||
| 259 | with open(file_path, 'a') as file: | ||
| 260 | # Запис нового коду у файл | ||
| 261 | file.write('\n') | ||
| 262 | file.write(code) | ||
| 263 | file.write('\n') | ||
| 264 | |||
| 265 | # Оновити базу даних з встановленою компонентою | ||
| 266 | component = Component.query.filter_by(name=selected_component['name']).first() | ||
| 267 | if not component: | ||
| 268 | component = Component( | ||
| 269 | name=selected_component['name'], | ||
| 270 | description=selected_component['description'], | ||
| 271 | version=version, | ||
| 272 | git_link=selected_component['git_link'], | ||
| 273 | dependencies=code, | ||
| 274 | installed=True | ||
| 275 | ) | ||
| 276 | db.session.add(component) | ||
| 277 | else: | ||
| 278 | component.version = version | ||
| 279 | component.git_link = selected_component['git_link'] | ||
| 280 | component.dependencies = code | ||
| 281 | component.installed = True | ||
| 282 | |||
| 283 | db.session.commit() | ||
| 284 | |||
| 285 | return f'''Component installed successfully: {selected_component["name"]} v{version}, | ||
| 286 | \n \n please wait installing requirments... | ||
| 287 | <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />''' | ||
| 288 | |||
| 289 | except Exception as e: | ||
| 290 | return f'Error installing component: {str(e)}' | ||
| 291 | |||
| 292 | @components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET']) | ||
| 293 | @first_login_required | ||
| 294 | def install_requirments(selected_component_name): | ||
| 295 | requirements_file = os.path.join('components', selected_component_name, "requirements.txt") | ||
| 296 | if os.path.isfile(requirements_file): | ||
| 297 | pip_command = f"{current_app.config['VENV_BIN_PATH']}/python -m pip install -r {requirements_file}" | ||
| 298 | subprocess.run(pip_command, shell=True, check=True) | ||
| 299 | return f'''Requirements installed successfully | ||
| 300 | \n \n please wait installing requirments components... | ||
| 301 | <meta http-equiv="refresh" content="1;url=/install-requirments-components" />''' | ||
| 302 | |||
| 303 | |||
| 304 | @components_bp.route('/install-requirments-components') | ||
| 305 | @first_login_required | ||
| 306 | def install_requirements_components(): | ||
| 307 | # Откриття файлу requirements_components.txt | ||
| 308 | requirements_file = 'requirements_components.txt' | ||
| 309 | component_ids = None | ||
| 310 | if os.path.isfile(requirements_file): | ||
| 311 | with open('requirements_components.txt', 'r') as file: | ||
| 312 | component_ids = file.read().splitlines() | ||
| 313 | if component_ids: | ||
| 314 | for component_id in component_ids: | ||
| 315 | # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти | ||
| 316 | response = requests.get( | ||
| 317 | f'/install_components/{component_id}') | ||
| 318 | return f'Requirements components installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 319 | else: | ||
| 320 | return f'<meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 321 | # Опрацювання відповіді (за потреби) | ||
| 322 | |||
| 323 | |||
| 324 | |||
| 325 | |||
| 326 | @components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET']) | ||
| 327 | @first_login_required | ||
| 328 | def remove_dependencies(component_id): | ||
| 329 | # Знаходимо компоненту за її ID | ||
| 330 | component = Component.query.get(component_id) | ||
| 331 | if not component: | ||
| 332 | return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 333 | |||
| 334 | # Шлях до файлу, з якого потрібно видалити залежності | ||
| 335 | file_path = 'routes.py' | ||
| 336 | |||
| 337 | # Зчитуємо вміст файлу | ||
| 338 | with open(file_path, 'r') as file: | ||
| 339 | lines = file.readlines() | ||
| 340 | |||
| 341 | # Видаляємо рядки, що містять залежності компоненти | ||
| 342 | updated_lines = [line for line in lines if line.strip() not in component.dependencies] | ||
| 343 | |||
| 344 | # Записуємо оновлений вміст у файл | ||
| 345 | with open(file_path, 'w') as file: | ||
| 346 | file.writelines(updated_lines) | ||
| 347 | |||
| 348 | # Оновлюємо статус компоненти | ||
| 349 | component.installed = False | ||
| 350 | db.session.commit() | ||
| 351 | |||
| 352 | return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 353 | |||
| 354 | @components_bp.route('/add_dependencies/<string:component_id>', methods=['GET']) | ||
| 355 | @first_login_required | ||
| 356 | def add_dependencies(component_id): | ||
| 357 | |||
| 358 | # Знаходимо компоненту за її ID | ||
| 359 | component = Component.query.get(component_id) | ||
| 360 | if not component: | ||
| 361 | return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 362 | |||
| 363 | # Шлях до файлу, з якого потрібно видалити залежності | ||
| 364 | file_path = 'routes.py' | ||
| 365 | code = component.dependencies | ||
| 366 | # Відкриття файлу у режимі дозапису | ||
| 367 | with open(file_path, 'a') as file: | ||
| 368 | # Запис нового коду у файл | ||
| 369 | file.write(code) | ||
| 370 | |||
| 371 | # Оновлюємо статус компоненти | ||
| 372 | component.installed = True | ||
| 373 | db.session.commit() | ||
| 374 | return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 375 | |||
| 376 | @components_bp.route('/remove-component/<string:component_id>') | ||
| 377 | @first_login_required | ||
| 378 | def remove_component(component_id): | ||
| 379 | # Шлях до головної папки проекту | ||
| 380 | project_folder = 'components' | ||
| 381 | component = Component.query.get(component_id) | ||
| 382 | # Назва репозиторія | ||
| 383 | repository_name = component.name | ||
| 384 | # Шлях до папки репозиторія в межах проекту | ||
| 385 | repository_folder = os.path.join(project_folder, repository_name) | ||
| 386 | try: | ||
| 387 | # Перевірка наявності папки репозиторія | ||
| 388 | if os.path.exists(repository_folder): | ||
| 389 | # Видалення папки репозиторія | ||
| 390 | shutil.rmtree(repository_folder) | ||
| 391 | # Видаляємо компоненту з бази | ||
| 392 | if component: | ||
| 393 | db.session.delete(component) | ||
| 394 | db.session.commit() | ||
| 395 | |||
| 396 | # Повертаємо повідомлення про успішне видалення | ||
| 397 | return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />' | ||
| 398 | except Exception as e: | ||
| 399 | # Повертаємо повідомлення про помилку видалення | ||
| 400 | return 'Error removing component: ' + str(e) | ||
| 401 | app.register_blueprint(components_bp) |
languages/__pycache__/find_language.cpython-310.pyc
No preview for this file type
languages/__pycache__/views.cpython-310.pyc
No preview for this file type
languages/babel_translation_directories.yml
| File was created | 1 | babel_translation_directories: languages;components/k2test/k2test/languages | |
| 2 |
languages/find_language.py
| 1 | from k2.root import Component | File was deleted | |
| 2 | 1 | from k2.root import Component | |
| 3 | 2 |
languages/views.py
| 1 | import yaml | File was deleted | |
| 2 | from flask import session, g | ||
| 3 | from main import app, babel | ||
| 4 | |||
| 5 | def load_languages(): | ||
| 6 | with open('languages/languages.yml', 'r') as file: | ||
| 7 | languages = yaml.safe_load(file) | ||
| 8 | return print(languages) | ||
| 9 | |||
| 10 | def get_locale(): | ||
| 11 | if 'lang' in session: | ||
| 12 | # Отримати обрану мову з сеансу користувача | ||
| 13 | return session['lang'] | ||
| 14 | else: | ||
| 15 | # Повернути мову за замовчуванням з налаштувань додатку | ||
| 16 | return app.config['DEFAULT_LANGUAGE'] | ||
| 17 | babel.init_app(app, locale_selector=get_locale) | ||
| 18 | 1 | import yaml |
main.py
| 1 | import pytz | ||
| 2 | from flask import Flask | ||
| 3 | from flask_cors import CORS | 1 | from flask_cors import CORS |
| 4 | from db.database import init_db | ||
| 5 | import os | ||
| 6 | import sys | ||
| 7 | from k2.root import * | ||
| 8 | from flask_login import LoginManager | ||
| 9 | from flask_babel import Babel | 2 | from flask_babel import Babel |
| 3 | #from k2.k2inst import * | ||
| 4 | from flask import Flask | ||
| 5 | from k2.k2cfg import k2 | ||
| 10 | 6 | ||
| 11 | |||
| 12 | # configure flask app | 7 | # configure flask app |
| 13 | app = Flask(__name__) | 8 | app = Flask(__name__) |
| 14 | venv_path = os.path.join(os.path.dirname(sys.prefix), 'venv/Scripts') | 9 | app.config['SECRET_KEY'] = k2.secret_key |
| 15 | app.config['VENV_BIN_PATH'] = venv_path | 10 | app.config.from_object(k2) |
| 16 | app.config['JSON_SORT_KEYS'] = False | ||
| 17 | app.config['TIMEZONE'] = pytz.timezone('Europe/Kiev') | ||
| 18 | app.config['SECRET_KEY'] = 'JH&INH987gFDHdsagh&8dwbjdw8ckw' | ||
| 19 | app.config['DOMAIN'] = 'http://127.0.0.1:5001/' | ||
| 20 | app.config['DEFAULT_LANGUAGE'] = 'en' | ||
| 21 | app.config['CURRENT_LANGUAGE'] = '' | ||
| 22 | app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'languages;components/k2test/k2test/languages' | ||
| 23 | 11 | ||
| 24 | # setting flask app | 12 | # init db |
| 25 | init_db(app) | 13 | k2().init_db(app) |
| 26 | CORS(app) | 14 | CORS(app) |
| 15 | |||
| 16 | #translate | ||
| 17 | k2.load_babel_translation_directories() | ||
| 18 | app.config['BABEL_TRANSLATION_DIRECTORIES'] = k2.babel_translation_directories | ||
| 27 | babel = Babel(app) | 19 | babel = Babel(app) |
| 20 | babel.init_app(app, locale_selector=k2.get_locale) |
routes.py
| 1 | from flask import Flask | 1 | from flask import Flask |
| 2 | #app = Flask(__name__) | 2 | #app = Flask(__name__) |
| 3 | from main import app, babel | 3 | from main import app, babel |
| 4 | from k2.k2inst import components_bp | ||
| 5 | app.register_blueprint(components_bp) | ||
| 6 | |||
| 7 | from components.k2test.k2test.views import k2test | ||
| 8 | app.register_blueprint(k2test, url_prefix='/k2test') | ||
| 4 | 9 |
templates/dashboard.html
| 1 | {% extends "base.html" %} | 1 | {% extends "base.html" %} |
| 2 | 2 | ||
| 3 | {% block styles %} | 3 | {% block styles %} |
| 4 | <style> | 4 | <style> |
| 5 | .table { | 5 | .table { |
| 6 | border-collapse: collapse; | 6 | border-collapse: collapse; |
| 7 | width: 100%; | 7 | width: 100%; |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | .table th, .table td { | 10 | .table th, .table td { |
| 11 | text-align: left; | 11 | text-align: left; |
| 12 | padding: 8px; | 12 | padding: 8px; |
| 13 | border-bottom: 1px solid #ddd; | 13 | border-bottom: 1px solid #ddd; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | .table tr:hover { | 16 | .table tr:hover { |
| 17 | background-color: #f5f5f5; | 17 | background-color: #f5f5f5; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | .search-form { | 20 | .search-form { |
| 21 | margin-bottom: 20px; | 21 | margin-bottom: 20px; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | .search-form .input-group { | 24 | .search-form .input-group { |
| 25 | width: 300px; | 25 | width: 300px; |
| 26 | } | 26 | } |
| 27 | </style> | 27 | </style> |
| 28 | {% endblock %} | 28 | {% endblock %} |
| 29 | 29 | ||
| 30 | {% block content %} | 30 | {% block content %} |
| 31 | <h1>K2CloudERP-2.5.1.27</h1> | 31 | <h1>K2CloudERP-2.5.1.27</h1> |
| 32 | <p> <a href="/logout">вихід</a></p> | 32 | <p> <a href="/logout">вихід</a></p> |
| 33 | <p> <a href="{{ url_for('components.change_language', lang='en') }}">en</a> | <a href="{{ url_for('components.change_language', lang='uk') }}">uk</a></p> | 33 | <p> <a href="{{ url_for('components.change_language', lang='en') }}">en</a> | <a href="{{ url_for('components.change_language', lang='uk') }}">uk</a></p> |
| 34 | {{language}} | 34 | {{language}} |
| 35 | {{lang_d}} | ||
| 35 | 36 | ||
| 36 | <h2>{{ _('Installed components') }}</h2> | 37 | <h2>{{ _('Installed components') }}</h2> |
| 37 | 38 | ||
| 38 | <table class="table"> | 39 | <table class="table"> |
| 39 | <thead> | 40 | <thead> |
| 40 | <tr> | 41 | <tr> |
| 41 | <th>{{_('Name')}}</th> | 42 | <th>{{_('Name')}}</th> |
| 42 | <th>{{_('Description')}}</th> | 43 | <th>{{_('Description')}}</th> |
| 43 | <th>{{_('Version')}}</th> | 44 | <th>{{_('Version')}}</th> |
| 44 | <th>{{_('Dependencies')}}</th> | 45 | <th>{{_('Dependencies')}}</th> |
| 45 | <th>{{_('Git Link')}}</th> | 46 | <th>{{_('Git Link')}}</th> |
| 46 | <th>{{_('Install At')}}</th> | 47 | <th>{{_('Install At')}}</th> |
| 47 | <th>{{_('Status')}}</th> | 48 | <th>{{_('Status')}}</th> |
| 48 | <th>{{_('Action')}}</th> | 49 | <th>{{_('Action')}}</th> |
| 49 | </tr> | 50 | </tr> |
| 50 | </thead> | 51 | </thead> |
| 51 | 52 | ||
| 52 | <tbody> | 53 | <tbody> |
| 53 | <tr> | 54 | <tr> |
| 54 | <td>k2root</td> | 55 | <td>k2root</td> |
| 55 | <td>main component</td> | 56 | <td>main component</td> |
| 56 | <td colspan="6">2.5.1.27</td></tr> | 57 | <td colspan="6">2.5.1.27</td></tr> |
| 57 | 58 | ||
| 58 | {% for component in components %} | 59 | {% for component in components %} |
| 59 | <tr> | 60 | <tr> |
| 60 | <td>{{ component.name }}</td> | 61 | <td>{{ component.name }}</td> |
| 61 | <td>{{ component.description }}</td> | 62 | <td>{{ component.description }}</td> |
| 62 | <td>{{ component.version }}</td> | 63 | <td>{{ component.version }}</td> |
| 63 | <td>{{ component.dependencies }}</td> | 64 | <td>{{ component.dependencies }}</td> |
| 64 | <td>{{ component.git_link }}</td> | 65 | <td>{{ component.git_link }}</td> |
| 65 | <td>{{ component.date_installed }}</td> | 66 | <td>{{ component.date_installed }}</td> |
| 66 | <td> | 67 | <td> |
| 67 | {% if component.installed %} | 68 | {% if component.installed %} |
| 68 | Yes | 69 | Yes |
| 69 | {% else %} | 70 | {% else %} |
| 70 | No | 71 | No |
| 71 | {% endif %} | 72 | {% endif %} |
| 72 | </td> | 73 | </td> |
| 73 | <td> | 74 | <td> |
| 74 | {% if component.installed %} | 75 | {% if component.installed %} |
| 75 | <a href="/remove_dependencies/{{ component.id }}" class="btn btn-primary">Вимкнути</a> | 76 | <a href="/remove_dependencies/{{ component.id }}" class="btn btn-primary">Вимкнути</a> |
| 76 | {% else %} | 77 | {% else %} |
| 77 | <a href="/add_dependencies/{{ component.id }}" class="btn btn-primary">Увімкнути</a> | 78 | <a href="/add_dependencies/{{ component.id }}" class="btn btn-primary">Увімкнути</a> |
| 78 | <!-- Button trigger modal --> | 79 | <!-- Button trigger modal --> |
| 79 | <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#components-{{ component.id }}"> | 80 | <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#components-{{ component.id }}"> |
| 80 | Видалити | 81 | Видалити |
| 81 | </button> | 82 | </button> |
| 82 | 83 | ||
| 83 | <!-- Modal --> | 84 | <!-- Modal --> |
| 84 | <div class="modal fade" id="components-{{ component.id }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> | 85 | <div class="modal fade" id="components-{{ component.id }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> |
| 85 | <div class="modal-dialog"> | 86 | <div class="modal-dialog"> |
| 86 | <div class="modal-content"> | 87 | <div class="modal-content"> |
| 87 | <div class="modal-header"> | 88 | <div class="modal-header"> |
| 88 | <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1> | 89 | <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1> |
| 89 | <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | 90 | <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
| 90 | </div> | 91 | </div> |
| 91 | <div class="modal-body"> | 92 | <div class="modal-body"> |
| 92 | Видалити компоненту? | 93 | Видалити компоненту? |
| 93 | </div> | 94 | </div> |
| 94 | <div class="modal-footer"> | 95 | <div class="modal-footer"> |
| 95 | <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> | 96 | <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> |
| 96 | <a href="/remove-component/{{ component.id }}" class="btn btn-danger">Видалити</a> | 97 | <a href="/remove-component/{{ component.id }}" class="btn btn-danger">Видалити</a> |
| 97 | </div> | 98 | </div> |
| 98 | </div> | 99 | </div> |
| 99 | </div> | 100 | </div> |
| 100 | </div> | 101 | </div> |
| 101 | {% endif %} | 102 | {% endif %} |
| 102 | </td> | 103 | </td> |
| 103 | </tr> | 104 | </tr> |
| 104 | {% endfor %} | 105 | {% endfor %} |
| 105 | </tbody> | 106 | </tbody> |
| 106 | </table> | 107 | </table> |
| 107 | 108 | ||
| 108 | 109 | ||
| 109 | 110 | ||
| 110 | 111 | ||
| 111 | 112 | ||
| 112 | 113 | ||
| 113 | <div class="container px-4 py-5" id="hanging-icons"> | 114 | <div class="container px-4 py-5" id="hanging-icons"> |
| 114 | <h2 class="pb-2 border-bottom">{{_('Components Shop')}}</h2> | 115 | <h2 class="pb-2 border-bottom">{{_('Components Shop')}}</h2> |
| 115 | <form action="{{ url_for('components.dashboard') }}" method="GET" class="search-form"> | 116 | <form action="{{ url_for('components.dashboard') }}" method="GET" class="search-form"> |
| 116 | <div class="input-group"> | 117 | <div class="input-group"> |
| 117 | <input type="text" name="search_query" class="form-control" placeholder="Search components"> | 118 | <input type="text" name="search_query" class="form-control" placeholder="Search components"> |
| 118 | <button type="submit" class="btn btn-primary">Search</button> | 119 | <button type="submit" class="btn btn-primary">Search</button> |
| 119 | </div> | 120 | </div> |
| 120 | </form> | 121 | </form> |
| 121 | 122 | ||
| 122 | 123 | ||
| 123 | <div class="row g-4 py-5 row-cols-1 row-cols-lg-3"> | 124 | <div class="row g-4 py-5 row-cols-1 row-cols-lg-3"> |
| 124 | {% if component_server %} | 125 | {% if component_server %} |
| 125 | {% for component in component_server %} | 126 | {% for component in component_server %} |
| 126 | <div class="col d-flex align-items-start"> | 127 | <div class="col d-flex align-items-start"> |
| 127 | <div class="icon-square bg-light text-dark flex-shrink-0 me-3"> | 128 | <div class="icon-square bg-light text-dark flex-shrink-0 me-3"> |
| 128 | <img class="d-block mx-auto mb-4" src="/static/img/logo-k2.png" alt="" width="60"> | 129 | <img class="d-block mx-auto mb-4" src="/static/img/logo-k2.png" alt="" width="60"> |
| 129 | </div> | 130 | </div> |
| 130 | <div> | 131 | <div> |
| 131 | <h2>{{ component.name|title }}</h2> | 132 | <h2>{{ component.name|title }}</h2> |
| 132 | <p>{{ component.description }}</p> | 133 | <p>{{ component.description }}</p> |
| 133 | <p>ВЕРСІЯ {{ component.version }}</p> | 134 | <p>ВЕРСІЯ {{ component.latest_version }}</p> |
| 134 | {% if component.name in components_names %} | 135 | {% if component.name in components_names %} |
| 135 | <button type="button" class="btn btn-success">Installed</button> | 136 | <button type="button" class="btn btn-success">Installed</button> |
| 136 | {% else %} | 137 | {% else %} |
| 137 | <a href="/show_components/{{ component.id }}" class="btn btn-primary">Install</a> | 138 | <a href="/show_components/{{ component.id }}" class="btn btn-primary">Install</a> |
| 138 | {% endif %} | 139 | {% endif %} |
| 139 | </div> | 140 | </div> |
| 140 | </div> | 141 | </div> |
| 141 | {% endfor %} | 142 | {% endfor %} |
| 142 | {% else %} | 143 | {% else %} |
| 143 | <div class="col"> | 144 | <div class="col"> |
| 144 | <p>No components available.</p> | 145 | <p>No components available.</p> |
| 145 | </div> | 146 | </div> |
| 146 | {% endif %} | 147 | {% endif %} |
| 147 | </div> | 148 | </div> |
| 148 | </div> | 149 | </div> |
| 149 | 150 | ||
| 150 | {% endblock %} | 151 | {% endblock %} |
| 151 | 152 |