diff --git a/__pycache__/app.cpython-310.pyc b/__pycache__/app.cpython-310.pyc index b9ce1e3aa29d92c195b48be313ba3b1c4dc13780..2ddbc362cecbb9d0dbfb57f383e3f5061f3993bd 100644 GIT binary patch delta 85 zcmcc0ahHQPpO=@50SGubmZm(P$SceEYohiG@#<9WEcq0H6v19bMurrjU@+Dco~*|B li_vtlB9r=LKPFeM5KYEgtSPBUrRkd|Gwow!5nyEb4*&zs17h|zB1Id!)9<{9 diff --git a/app.py b/app.py index 10257b3..3f0a0f6 100644 --- a/app.py +++ b/app.py @@ -39,7 +39,7 @@ k2.platform =k2.get_platform() from routes import * if __name__ == '__main__': - app.run() + app.run(debug=True) diff --git a/components/__pycache__/__init__.cpython-310.pyc b/components/__pycache__/__init__.cpython-310.pyc index 2b8cc53c35907b9f7932f4b54e004f649448974e..8c00ab9c264ea6898b8863a22f3e65540999a8a4 100644 GIT binary patch delta 27 hcmZ3%xQLNEpO=@50SG>^EuF}1!{|EELw#bYF#uO#2HyYx delta 34 ocmZ3)xPp;8pO=@50SMSjXHDd`Vf3Epq0SbcoRgZEH!EcoOeEAKC5gXIT2DQy zx$Q~zqF3qBe_=2C7wpM@LrluDdr&CD8{WL{z4_kz-sPQkd8b`B)a{#v4R!nR;9;p+ z-!ISf%jo0mS#302|E*mpigw@qyw<39s)HSYxQjh(+Y(d49L^E+xa(Lhr4ss%-$RZF zJ0c9CAk7jd3*rcxz=S450AT|#16Vp>El69CnFMhPn4iRheC2@_fQ&Sa#N;W6747rrAXSEB#gFF>3*0r(9gd93QU@*>i_@% delta 399 zcmah^Jxjx27)+u=t*uoMq{LzbyA<>0{mz>VmExq(U2(Aac%z}vmNpdKs#D#RY)-{V zNA2K`aB}w-xQm+_ad9ihal_p`JU5zXqltE{tM!}pUA6w$y5GnxsfG6w%ZeRPByCKbFcOr9NbrCJp%h+- zm>&s}u9;Px{yPV47jl;pfT%67oxXrb&1XwDpWp&ipQriOxHMmSQ>y9bwy{5_D9YZf O)mj$Xn)S$C&-ek=pl>|@ diff --git a/k2/__pycache__/__init__.cpython-310.pyc b/k2/__pycache__/__init__.cpython-310.pyc index 0b969aa4bbdb362ad9759ab368ae88bc0ef4bbc2..b3cdc03d73a66c7abef88e4e6c78cfcbe62ca106 100644 GIT binary patch delta 27 hcmZ3$IE#@xpO=@50SG>`EuF}1!)QCvLw#bYHUL$R2EYIS delta 34 ocmbQmxPXy6pO=@50SGusXHDd`VRWA8q0SbcoRgZEH!)uu0D$5Mp#T5? diff --git a/k2/__pycache__/k2admmenu.cpython-310.pyc b/k2/__pycache__/k2admmenu.cpython-310.pyc index 273ea0e8a650de6bd5d29b5b643ad56e0888e53d..fc23aee72c12d755b80cdc5a140905c96f1c6835 100644 GIT binary patch delta 31 lcmX>jbxevopO=@50SG>`E#1h?#>{9pS%_JEvpq8}7XW$(2I2q! delta 38 scmX>mbw-LipO=@50SGMa&fUn(#?0t4S%_JkEj~FXH8F3qB{MG<0JypdUH||9 diff --git a/k2/__pycache__/k2cfg.cpython-310.pyc b/k2/__pycache__/k2cfg.cpython-310.pyc index 04eb5413b4ac25f715b04ad348616554b8a7892f..e757aa16d592e1951f0e9969bd861f30316399b2 100644 GIT binary patch delta 63 zcmX>qd03J+pO=@50SG>`Elqi|k(Z50N-CqIq@dVJUq9QZv>+w1Bvmgtzo@`SFST^C SCet-Wt4Yl2n{}CIZ~_2aBNJHw delta 67 zcmX>sc~p`&pO=@50SNxynVa%rBQG11m{>+hNr9EVzM-X&o}rnAo{@o`k&)$OU8ZY{ W4wG4!)!E{cb5axYHfuA_-~<4K{1UGK diff --git a/k2/__pycache__/k2comp.cpython-310.pyc b/k2/__pycache__/k2comp.cpython-310.pyc index 232ed1d5b51c8aa0597beae32ec283acd3fb6d23..12e3b65321e4b4dd19aeb96401a835a87fae9d1e 100644 GIT binary patch delta 31 lcmdnPzm1`E#1iN#>i+rIfzkxb3LOi8vuG62af;% delta 38 scmdnSzlWbYpO=@50SGusXKmzmV`Oxk9K@*37N4AxnwYn_lF^n80ITi^Z~y=R diff --git a/k2/__pycache__/k2obj.cpython-310.pyc b/k2/__pycache__/k2obj.cpython-310.pyc index eae49dbca202b207582b66a37d6c5ce86d37250f..b60ba80f53d9ae9882b045bfb8039799c25c92b5 100644 GIT binary patch delta 30 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 delta 7451 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 EzxaxYTmS$7 diff --git a/k2/k2rout.py b/k2/k2rout.py index d6cf10b..c457201 100644 --- a/k2/k2rout.py +++ b/k2/k2rout.py @@ -18,6 +18,8 @@ from sqlalchemy import text from flask_jwt_extended import get_jwt_identity, jwt_required from flask_login import login_user, current_user, logout_user, login_required import platform +import uuid + # initialize db @@ -28,6 +30,9 @@ config = yaml.safe_load(open("db/first-login.yml")) db = k2.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)]) def first_login_required(view_func): @wraps(view_func) @@ -81,10 +86,20 @@ def find_language(): @components_bp.route('/', methods=['GET', 'POST']) def home(): - components = Component.query.all() - components_names = [component.name for component in components] - if 'k2site' in components_names: - return redirect(url_for('k2site.main_page')) #змінити на ендпоінт головної k2site + + components_folder = 'components' + + with open(f"{components_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + + if components_data is None: + return redirect('/dashboard') + + k2site_component = next( + (comp for comp in components_data['components'] if comp['name'] == 'k2site' and comp.get('installed', False)), + None) + if k2site_component: + return redirect(url_for('k2site.main_page')) # else: return redirect('/dashboard') @@ -112,11 +127,20 @@ def change_language(lang): @components_bp.route('/dashboard') def dashboard(): - components = Component.query.all() + #components = Component.query.all() + with open(f"components/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + if components_data is None or 'components' not in components_data: + components = [] + else: + components = components_data['components'] components_names = [] - components_names = [component.name for component in components] - if 'k2site' in components_names: - return redirect(url_for('components.home')) + components_names = [component['name'] for component in components] + k2site_component = next( + (comp for comp in components_data['components'] if comp['name'] == 'k2site' and comp.get('installed', False)), + None) + if k2site_component: + return redirect(url_for('components.component_list_dasb')) else: # Компоненти доступні для встановлення # GET-запит до API @@ -129,8 +153,8 @@ def dashboard(): component_server = None # Встановлені компоненти - components = Component.query.all() - components_names = [component.name for component in components] + #components = Component.query.all() + #components_names = [component.name for component in components] # Отримання значення пошукового запиту з параметрів URL search_query = request.args.get('search_query') # print(search_query) @@ -291,25 +315,59 @@ def install_component_from_archive(component_id): file.write(code) file.write('\n') - # Update database with the installed component - 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) + # Зчитати вміст файлу YAML + with open(f"{project_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + if components_data == None: + components_data = {'components': []} + + + + # Перевірити унікальність імен компонентів + existing_component = next((c for c in components_data['components'] if c['name'] == selected_component['name']), + None) + if existing_component: + # Оновити існуючий компонент + existing_component['id'] = generate_id() + existing_component['version'] = version + existing_component['git_link'] = selected_component['git_link'] + existing_component['dependencies'] = code + existing_component['installed'] = True else: - component.version = version - component.git_link = selected_component['git_link'] - component.dependencies = code - component.installed = True + # Додати новий компонент до списку + components_data['components'].append({ + 'id': generate_id(), + 'name': selected_component['name'], + 'description': selected_component['description'], + 'version': version, + 'git_link': selected_component['git_link'], + 'dependencies': code, + 'installed': True + }) + + # Записати оновлений вміст у файл YAML + with open(f"{project_folder}/components.yml", 'a') as file: + yaml.dump(components_data, file) - db.session.commit() + # Update database with the installed component + # 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() # add language folders k2.search_babel_translation_directories() @@ -368,164 +426,184 @@ def install_requirements_components(): @components_bp.route('/remove_dependencies/', methods=['GET']) def remove_dependencies(component_id): # Знаходимо компоненту за її ID - component = Component.query.get(component_id) - if not component: - return 'Component not found ' + #component = Component.query.get(component_id) + #if not component: + # return 'Component not found ' + with open(f"components/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + if components_data is None: + return None + # Шукати компонент за id + for component in components_data['components']: + if component['id'] == component_id: + component + # remove menu items - component_name = component.name + 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") + #requests.get(f"{k2.domain}api/add-to-menu") # remove routes 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] + 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 + with open(f"components/components.yml", 'w') as file: + yaml.dump(components_data, file) + - component.installed = False - db.session.commit() - 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: + # Зчитати вміст файлу YAML + with open(f"components/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + + if components_data is None: + return 'Component not found ' + + # Знайти компоненту за ID + component = None + for comp in components_data['components']: + if comp['id'] == component_id: + component = comp + break + + if component is None: return 'Component not found ' file_path = 'routes.py' - code = component.dependencies + code = component['dependencies'] # Відкриття файлу у режимі дозапису with open(file_path, 'a') as file: # Запис нового коду у файл file.write(code) # Оновлюємо статус компоненти - component.installed = True - db.session.commit() - + component['installed'] = True + + # Оновлення вмісту файлу YAML + with open(f"components/components.yml", 'w') as file: + yaml.dump(components_data, file) + return 'Dependencies added successfully ' @components_bp.route('/remove-component/') 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() + # Шлях до папки з компонентами + components_folder = 'components' - # Повертаємо повідомлення про успішне видалення - return 'Component removed successfully ' - except Exception as e: - # Повертаємо повідомлення про помилку видалення - 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) + # Зчитати вміст файлу YAML + with open(f"{components_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + + if components_data is None: + return 'Component not found ' + + # Знайти компоненту за ID + component = None + for comp in components_data['components']: + if comp['id'] == component_id: + component = comp + break + + if component is None: + return 'Component not found ' + + # Видалити папку репозиторія компоненти + repository_folder = os.path.join(components_folder, component['name']) + if os.path.exists(repository_folder): + shutil.rmtree(repository_folder) + + # Видалити компоненту зі списку + components_data['components'] = [comp for comp in components_data['components'] if comp['id'] != component_id] + + # Записати оновлений вміст у файл YAML + with open(f"{components_folder}/components.yml", 'w') as file: + yaml.dump(components_data, file) + + return 'Component removed successfully ' # menu @components_bp.route('/api/add-to-menu', methods=['GET']) def add_to_menu(): + components_folder = 'components' data = [] response = requests.get(f"{k2.domain}/menu-admin-items") data.append(response.json()[0]) prev_menu = response.json()[0]['title'] for item in response.json()[0]['children']: - name_menu = 'k2itm'+ item['to'].replace('/','-') + name_menu = 'k2itm' + item['to'].replace('/', '-') caption_menu = item['title'] add_menu_with_permissions_db(name_menu, prev_menu, caption_menu) - 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") - if response.status_code == 200: - data.append(response.json()[0]) - #prev_menu = - prev_menu = response.json()[0]['title'] - for item in response.json()[0]['children']: - name_menu = 'k2itm'+ item['to'].replace('/','-') - caption_menu = item['title'] - add_menu_with_permissions_db(name_menu, prev_menu, caption_menu) - else: - continue - # add component_name key for menu items - #for item in data: - # item['component_name'] = components_names - #k2.menu = data - return data + # Отримати дані з файлу YAML кожного компонента + with open(f"{components_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + if components_data is not None: + # Отримати імена всіх компонентів + components_names = [comp['name'] for comp in components_data['components']] + for component_name in components_names: + # Виконати запит до відповідного роуту компонента + response = requests.get(f"{k2.domain}{component_name}/menu-admin-items") + + if response.status_code == 200: + data.append(response.json()[0]) + prev_menu = response.json()[0]['title'] + + for item in response.json()[0]['children']: + name_menu = 'k2itm' + item['to'].replace('/', '-') + caption_menu = item['title'] + add_menu_with_permissions_db(name_menu, prev_menu, caption_menu) + + return jsonify(data) @components_bp.route('/api/main-menu/') @login_required def get_admin_menu(): - components = Component.query.all() - components_names = [component.name for component in components] + + components_folder = 'components' + # + with open(f"{components_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + + if components_data is None: + return jsonify([]) + # Отримати список імен компонентів + components_names = [comp['name'] for comp in components_data['components']] if 'k2site' in components_names: role_id = current_user.get_role_id() - filter_menu = [] - response = requests.get(f"{k2.domain}api/add-to-menu") - menu_items_list = K2admin_menus.get_menu_items_by_roles(role_id) - for item in response.json(): - filtered_children = [] - for im in item['children']: - if 'k2itm' + im['to'].replace('/','-') in menu_items_list: - filtered_children.append(im) - if filtered_children: - item['children'] = filtered_children - filter_menu.append(item) - # filter_menu.append({"heading": 'APPS & PAGES'}) - return jsonify(filter_menu) + + # Виконати запит до роуту '/api/add-to-menu' + response = requests.get(f"{k2.domain}api/add-to-menu") + menu_items_list = K2admin_menus.get_menu_items_by_roles(role_id) + + filter_menu = [] + + for item in response.json(): + filtered_children = [] + + for im in item['children']: + if 'k2itm' + im['to'].replace('/', '-') in menu_items_list: + filtered_children.append(im) + + if filtered_children: + item['children'] = filtered_children + filter_menu.append(item) + + return jsonify(filter_menu) + + return jsonify([]) def add_menu_with_permissions_db(name_menu, prev_menu, caption_menu): @@ -569,7 +647,6 @@ def component_add_dasb(): try: response = requests.get(f'{k2.update_domain}api/components') json_data = response.json() - # Перетворення JSON-об'єкту на масив component_server = [item for item in json_data] except: component_server = None @@ -585,9 +662,19 @@ def component_add_dasb(): 'description'] else False)] else: filtered_components = component_server - components = Component.query.all() - components_names = [component.name for component in components] - components_version = [{component.name: component.version} for component in components] + project_folder = 'components' + with open(f"{project_folder}/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + + components_names = [] + components_version = [] + # Отримати імена та версії компонентів з даних YAML + if components_data is not None: + for component in components_data['components']: + name = component['name'] + version = component['version'] + components_names.append(name) + components_version.append({name: version}) return render_template('dashboard-add.html', component_server=filtered_components, search_query=search_query, components_names=components_names, components_version=components_version ) @@ -597,7 +684,12 @@ def component_add_dasb(): @components_bp.route('/component-list') @login_required def component_list_dasb(): - components = Component.query.all() + with open(f"components/components.yml", 'r') as file: + components_data = yaml.safe_load(file) + if components_data is None or 'components' not in components_data: + components = [] + else: + components = components_data['components'] return render_template('dashboard-list.html', components=components) diff --git a/languages/babel_translation_directories.yml b/languages/babel_translation_directories.yml index a9a983a..ec0c8d4 100644 --- a/languages/babel_translation_directories.yml +++ b/languages/babel_translation_directories.yml @@ -1 +1 @@ -babel_translation_directories: languages;components/k2test/k2test/languages;components/k2site/k2site/languages +babel_translation_directories: languages diff --git a/languages/en/LC_MESSAGES/messages.mo b/languages/en/LC_MESSAGES/messages.mo index 5e6a00578f70df6cbbc10b864ab1406a9a281bed..b711a0ea810ba3a0f76260835a9ba8e2417a67ec 100644 GIT binary patch delta 23 ecmdnWv6W*(1QVCJu7Rn7p@Eg5$>t=c%Zva|Ee2x% delta 23 ecmdnWv6W*(1QVB;u91a;p|O>b>Eo1QVCJu7Rn7p@Eg5$>t;`K_&oLQU)FX delta 23 ecmey&@tI>o1QVB;u91a;p|O>b>E