Commit 9045d204d93666896312d2c0aea2a8d664e1d0f0

Authored by Василь Свідрик
1 parent 3d1de393b8

get menu edit, add k2comp

Showing 44 changed files with 490 additions and 931 deletions Side-by-side Diff

  1 +/components/adm/
  2 +/components/grid/
  3 +/components/vue/
components/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/adm/README.md
1   -# main.py
2   -
3   -from components.adm.adm.views import adm
4   -from components.test.test.views import test
5   -
6   -app.register_blueprint(adm, url_prefix='/adm')
7   -
8   -cd components/adm
9   -pip install -r requirements.txt
10   -
11   -
12   -endpoint "http://127.0.0.1:5000/adm/register"
13   -dictionary to register in such way
14   -{
15   - "login": "xxx",
16   - "password": "xxx",
17   - "name": "xxx",
18   - "email": "xxx"
19   -}
20   -
21   -
22   -endpoint "http://127.0.0.1:5000/adm/login"
23   -dictionary to login in such way
24   -{
25   - "login":"xxx",
26   - "password":"xxx"
27   -}
28   -
29   -endpoint http://127.0.0.1:5000/adm/changePassword
30   -dictionary to changePassword in such way
31   -{
32   - "old_password":"xxx",
33   - "new_password": "xxx",
34   - "re_new_password": "xxx"
35   -}
36   -endpoint http://127.0.0.1:5000/adm/newUser
37   -{
38   - "login": "xxx",
39   - "password": "xxx",
40   - "name": "xxx",
41   - "email": "xxx",
42   - "phone": "xxx",
43   - "repassword": "xxx"
44   -
45   -}
components/adm/adm/.idea/.gitignore
1   -# Default ignored files
2   -/shelf/
3   -/workspace.xml
4   -# Editor-based HTTP Client requests
5   -/httpRequests/
6   -# Datasource local storage ignored files
7   -/dataSources/
8   -/dataSources.local.xml
components/adm/adm/.idea/adm.iml
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   - <orderEntry type="inheritedJdk" />
6   - <orderEntry type="sourceFolder" forTests="false" />
7   - </component>
8   - <component name="TemplatesService">
9   - <option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
10   - <option name="TEMPLATE_FOLDERS">
11   - <list>
12   - <option value="$MODULE_DIR$/templates" />
13   - </list>
14   - </option>
15   - </component>
16   -</module>
components/adm/adm/.idea/inspectionProfiles/Project_Default.xml
1   -<component name="InspectionProjectProfileManager">
2   - <profile version="1.0">
3   - <option name="myName" value="Project Default" />
4   - <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5   - <inspection_tool class="JSHint" enabled="true" level="ERROR" enabled_by_default="true" />
6   - <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
7   - <option name="ignoredPackages">
8   - <value>
9   - <list size="13">
10   - <item index="0" class="java.lang.String" itemvalue="blinker" />
11   - <item index="1" class="java.lang.String" itemvalue="greenlet" />
12   - <item index="2" class="java.lang.String" itemvalue="Werkzeug" />
13   - <item index="3" class="java.lang.String" itemvalue="Flask-WTF" />
14   - <item index="4" class="java.lang.String" itemvalue="SQLAlchemy" />
15   - <item index="5" class="java.lang.String" itemvalue="MarkupSafe" />
16   - <item index="6" class="java.lang.String" itemvalue="click" />
17   - <item index="7" class="java.lang.String" itemvalue="Flask-SQLAlchemy" />
18   - <item index="8" class="java.lang.String" itemvalue="Jinja2" />
19   - <item index="9" class="java.lang.String" itemvalue="Flask-Login" />
20   - <item index="10" class="java.lang.String" itemvalue="WTForms" />
21   - <item index="11" class="java.lang.String" itemvalue="itsdangerous" />
22   - <item index="12" class="java.lang.String" itemvalue="Flask" />
23   - </list>
24   - </value>
25   - </option>
26   - </inspection_tool>
27   - </profile>
28   -</component>
components/adm/adm/.idea/inspectionProfiles/profiles_settings.xml
1   -<component name="InspectionProjectProfileManager">
2   - <settings>
3   - <option name="USE_PROJECT_PROFILE" value="false" />
4   - <version value="1.0" />
5   - </settings>
6   -</component>
components/adm/adm/.idea/misc.xml
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
4   -</project>
components/adm/adm/.idea/modules.xml
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/adm.iml" filepath="$PROJECT_DIR$/.idea/adm.iml" />
6   - </modules>
7   - </component>
8   -</project>
components/adm/adm/.idea/vcs.xml
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/adm/adm/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/adm/adm/__pycache__/__init__.cpython-311.pyc
No preview for this file type
components/adm/adm/__pycache__/models.cpython-310.pyc
No preview for this file type
components/adm/adm/__pycache__/views.cpython-310.pyc
No preview for this file type
components/adm/adm/__pycache__/views.cpython-311.pyc
No preview for this file type
components/adm/adm/models.py
1   -import uuid
2   -from sqlalchemy import Column, Integer, String
3   -from sqlalchemy.ext.declarative import declarative_base
4   -from flask_jwt_extended import create_access_token
5   -from datetime import timedelta
6   -import hashlib
7   -from flask import current_app as k2
8   -
9   -
10   -Base = declarative_base()
11   -
12   -class k2users(Base):
13   - __tablename__ = 'k2users'
14   - user_id = Column(Integer, primary_key=True)
15   - login = Column(String(50))
16   - name = Column(String(50))
17   - email = Column(String(150))
18   - password = Column(String(50))
19   - phone = Column(String(20))
20   -
21   - def __init__(self, **kwargs):
22   - self.user_id = hashlib.md5(str(uuid.uuid4()).encode()).hexdigest()
23   - self.login = kwargs.get('login')
24   - self.password = hashlib.md5(kwargs.get('password').encode()).hexdigest()
25   - self.name = kwargs.get('name')
26   - self.email = kwargs.get('email')
27   - self.phone = kwargs.get('phone')
28   -
29   - def get_token(self, expire_time=24):
30   - expires_delta = timedelta(expire_time)
31   - token = create_access_token(identity=self.user_id, expires_delta=expires_delta)
32   - return token
33   -
34   - @classmethod
35   - def authenticate(cls, login, password):
36   - session = k2.extensions['sqlalchemy'].db.session
37   - user = ''
38   - try:
39   - user = session.query(cls).filter(cls.login == login).filter(cls.password == hashlib.md5(password.encode()).hexdigest()).one()
40   - except:
41   - user = None
42   -
43   - return user
components/adm/adm/views.py
1   -import hashlib
2   -import uuid
3   -from flask import Blueprint, request, jsonify
4   -from flask import current_app as k2
5   -from flask_jwt_extended import jwt_required, get_jwt_identity
6   -# from flask_sqlalchemy import session
7   -# from sqlalchemy.orm import sessionmaker
8   -# from k2.k2inst import Component
9   -
10   -from .models import k2users
11   -
12   -
13   -adm = Blueprint('adm', __name__, template_folder='templates', static_folder='static', static_url_path='/adm')
14   -
15   -
16   -@adm.route('/register', methods=["POST"])
17   -def register():
18   - params = request.json
19   - session = k2.extensions['sqlalchemy'].db.session
20   - try:
21   - user = k2users(**params)
22   - session.add(user)
23   - session.commit()
24   - token = user.get_token()
25   - return {'access_token': token}
26   - except:
27   - return jsonify({'error': 'Unauthorized'}), 401
28   -
29   -
30   -@adm.route('/login', methods=["POST"])
31   -def login():
32   - params = request.json
33   - login = params.get('login')
34   - password = params.get('password')
35   - user = k2users.authenticate(login, password)
36   - if user:
37   - token = user.get_token()
38   - return {'access_token': token}
39   - else:
40   - return jsonify({'error': 'Unauthorized'}), 401
41   -
42   -
43   -@adm.route('/logout', methods=["GET"])
44   -@jwt_required()
45   -def logout():
46   - response = {
47   - 'message': 'Logged out successfully'
48   - }
49   - return jsonify(response)
50   -
51   -
52   -@adm.route('/users', methods=["GET"])
53   -@jwt_required()
54   -def grid_users():
55   - return jsonify({"data": "users"})
56   -
57   -
58   -@adm.route('/roles', methods=["GET"])
59   -@jwt_required()
60   -def grid_roles():
61   - return jsonify({"data": "roles"})
62   -
63   -
64   -@adm.route('/usersclients', methods=["GET"])
65   -@jwt_required()
66   -def users_clients():
67   - return jsonify({"data": "roles"})
68   -
69   -@adm.route('/menuaaccess', methods=["GET"])
70   -@jwt_required()
71   -def menu_aaccess():
72   - return jsonify({"data": "roles"})
73   -
74   -
75   -@adm.route('/newUser', methods=["GET", "POST"])
76   -@jwt_required()
77   -def newUser():
78   - session = k2.extensions['sqlalchemy'].db.session
79   - exist = session.query(k2users).filter_by(login=request.json['login']).first()
80   - if not exist:
81   - res = k2users(
82   - user_id=hashlib.md5(str(uuid.uuid4()).encode()).hexdigest(),
83   - login=request.json['login'],
84   - name=request.json['name'],
85   - email=request.json['email'],
86   - password=hashlib.md5(request.json['password'].encode()).hexdigest(),
87   - phone=request.json['phone'])
88   - if res:
89   - session.add(res)
90   - session.commit()
91   - return jsonify({'status': 'ok'})
92   - else:
93   - return jsonify({'error': 'Such user exist'}), 404
94   -
95   -
96   -@adm.route('/changePassword', methods=["POST"])
97   -@jwt_required()
98   -def changePassword():
99   - session = k2.extensions['sqlalchemy'].db.session
100   - current_user = get_jwt_identity()
101   - user = session.query(k2users).filter_by(user_id=current_user).first()
102   - if user.password == hashlib.md5(request.json['old_password'].encode()).hexdigest():
103   - if request.json['new_password'] == request.json['re_new_password']:
104   - user.password = hashlib.md5(request.json['new_password'].encode()).hexdigest()
105   - session.commit()
106   - else:
107   - return jsonify({'error': 'Пароль не найден в базе'}), 404
108   - else:
109   - return jsonify({'error': 'Пароль не совпвдает'}), 404
110   - return jsonify({'status': 'ok'})
111   -
112   -
113   -@adm.route('/menu-items')
114   -def menu_items():
115   - menu = [
116   -
117   - {
118   - "title": 'Адміністрування сайту',
119   -
120   - "icon": {"icon": 'mdi mdi-database'},
121   - "children": [
122   - {'title': 'Зміна паролю', 'to': 'adm-changePassword'},
123   - {'title': 'Новий користувач', 'to': 'adm-newUser'},
124   - {'title': 'Користувачі', 'to': 'adm-users'},
125   - {'title': 'Користувачі клієнти', 'to': 'adm-usersclients'},
126   - {'title': 'Права', 'to': 'adm-roles'},
127   - {'title': 'Доступ до меню', 'to': 'adm-menuaaccess'},
128   - ],
129   - }]
130   -
131   - return menu
components/adm/requirements.txt
1   -blinker==1.6.2
2   -click==8.1.3
3   -dnspython==2.3.0
4   -email-validator==2.0.0.post2
5   -Flask==2.3.2
6   -Flask-Cors==3.0.10
7   -Flask-JWT-Extended==4.5.2
8   -Flask-Login==0.6.2
9   -Flask-Mail==0.9.1
10   -Flask-MySQLdb==1.0.1
11   -Flask-SQLAlchemy==3.0.3
12   -flask-staticdirs==1.0.1
13   -Flask-WTF==1.1.1
14   -greenlet==2.0.2
15   -idna==3.4
16   -itsdangerous==2.1.2
17   -Jinja2==3.1.2
18   -jsonify==0.5
19   -MarkupSafe==2.1.2
20   -mysql-connector-python==8.0.33
21   -mysqlclient==2.1.1
22   -protobuf==3.20.3
23   -PyJWT==2.7.0
24   -pytz==2023.3
25   -PyYAML==6.0
26   -six==1.16.0
27   -SQLAlchemy==2.0.15
28   -typing_extensions==4.6.2
29   -Werkzeug==2.3.4
30   -WTForms==3.0.1
components/adm/setup.py
1   -from setuptools import setup
2   -
3   -setup(
4   - name='adm',
5   - version='1.0.0',
6   - description='Description of my project',
7   - author='Your Name',
8   - author_email='yourname@example.com',
9   - keywords="adm, k2",
10   - python_requires=">=3.7, <=3.11.2",
11   - packages=['adm'],
12   - package_data={ # Optional
13   - },
14   - install_requires=[""],
15   -)
components/k2test/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/history.txt
  1 +1.0.0.0 base component
  2 +1.0.0.1 add some routes
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
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 1 msgid "New 2 page"
32   -msgstr "New 2 page"
  2 +msgstr "Нова сторінка 2"
  3 +msgid "title_menu_items"
  4 +msgstr "Test menu items"
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.mo
No preview for this file type
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.po
1 1 msgid "New 2 page"
2 2 msgstr "Нова сторінка 2"
  3 +msgid "title_menu_items"
  4 +msgstr "Тестова компонента"
components/k2test/k2test/templates/login.html
1   -login
components/k2test/k2test/views.py
1 1 from flask import render_template, redirect, request, jsonify
  2 +from flask_babel import gettext
2 3 from flask_login import login_user, current_user, logout_user, login_required
3 4 from flask import current_app as k2
4 5 from flask import Blueprint, json
5 6 from flask_sqlalchemy import SQLAlchemy
6 7  
7 8  
  9 +#bliueprint
  10 +k2test = Blueprint('k2test', __name__, template_folder='templates', static_folder='static')
8 11  
9   -k2test = Blueprint('k2test', __name__, template_folder='templates', static_folder='static',)
10   -
11   -
12   -
  12 +#component routes
13 13 @k2test.route('/new')
14 14 def new_component():
15 15 db = k2.extensions['sqlalchemy'].db
16 16  
... ... @@ -33,12 +33,12 @@
33 33 def new_component4():
34 34 return jsonify({'data': 'page new4'})
35 35  
36   -
37   -@k2test.route('/menu-items')
  36 +# menu items for admin
  37 +@k2test.route('/menu-admin-items')
38 38 def menu_items():
39 39 data = [
40 40 {
41   - 'title': 'Тестова компонента',
  41 + 'title': f"{gettext('title_menu_items')}",
42 42 'icon': {'icon': 'mdi-chart-timeline-variant'},
43 43 'children': [
44 44 {'title': 'Тест 3', 'to': 'k2test-new3'},
components/k2test/menu_items.yml
1   -- url:
2   - name: new2
3   - icon: mdi-chart-timeline-variant
4   - title: Тест 2
5   - category: Тестова компонента
6   -- url:
7   - name: new3
8   - icon: mdi-chart-timeline-variant
9   - title: Тест 3
10   - category: Тестова компонента
11   -- url:
12   - name: new4
13   - icon: mdi-chart-timeline-variant
14   - title: Тест 4
15   - category: Тестова компонента
components/k2test/setup.py
... ... @@ -4,8 +4,8 @@
4 4 name='k2test',
5 5 version='1.0.0',
6 6 description='Description of my project',
7   - author='Your Name',
8   - author_email='yourname@example.com',
  7 + author='k2 cloud',
  8 + author_email='rs@corp2.net',
9 9 keywords="k2test, k2",
10 10 python_requires=">=3.7, <=3.11.2",
11 11 packages=['k2test'],
components/menu.yml
1   -- heading: APPS & PAGES
2   -- children:
3   - - title: "\u0422\u0435\u0441\u0442 3"
4   - to: k2test-new3
5   - - title: "\u0422\u0435\u0441\u0442 3"
6   - to: k2test-new4
7   - component_name: k2test
8   - icon:
9   - icon: mdi-chart-timeline-variant
10   - id: 2
11   - title: "\u0422\u0435\u0441\u0442\u043E\u0432\u0430 \u043A\u043E\u043C\u043F\u043E\
12   - \u043D\u0435\u043D\u0442\u0430"
13   -- children:
14   - - title: "\u0417\u043C\u0456\u043D\u0430 \u043F\u0430\u0440\u043E\u043B\u044E"
15   - to: adm-changePassword
16   - - title: "\u041D\u043E\u0432\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\
17   - \u0432\u0430\u0447"
18   - to: adm-newUser
19   - - title: "\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456"
20   - to: adm-users
21   - - title: "\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456 \u043A\
22   - \u043B\u0456\u0454\u043D\u0442\u0438"
23   - to: adm-usersclients
24   - - title: "\u041F\u0440\u0430\u0432\u0430"
25   - to: adm-roles
26   - - title: "\u0414\u043E\u0441\u0442\u0443\u043F \u0434\u043E \u043C\u0435\u043D\u044E"
27   - to: adm-menuaaccess
28   - component_name: adm
29   - icon:
30   - icon: mdi mdi-database
31   - id: 3
32   - title: "\u0410\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0443\u0432\u0430\
33   - \u043D\u043D\u044F \u0441\u0430\u0439\u0442\u0443"
No preview for this file type
... ... @@ -9,11 +9,13 @@
9 9 import sys
10 10 from flask import session
11 11  
  12 +
  13 +
12 14 class k2(k2obj):
13 15 version = '2.5.1.27'
14 16 db = SQLAlchemy()
15 17 domain = 'http://127.0.0.1:5000/'
16   - update_domain ='http://127.0.0.1:8001/'
  18 + update_domain ='http://127.0.0.1:8002/'
17 19 venv_bin_path = os.path.join(os.path.dirname(sys.prefix), 'venv/Scripts')
18 20 json_sort_keys = False
19 21 timezone = pytz.timezone('Europe/Kiev')
20 22  
... ... @@ -21,7 +23,10 @@
21 23 default_language = 'en'
22 24 current_language = ''
23 25 babel_translation_directories = ''
  26 + components = ''
24 27  
  28 +
  29 +
25 30 def __init__(self):
26 31 super().__init__()
27 32  
... ... @@ -52,12 +57,6 @@
52 57  
53 58 with open('languages/babel_translation_directories.yml', 'w') as f:
54 59 yaml.dump(data, f)
55   - @classmethod
56   - def get_menu_elenents(cls):
57   - with open('components/menu.yml', 'r') as f:
58   - yaml_data = yaml.load(f, Loader=yaml.FullLoader)
59   - cls.menu = yaml_data
60   -
61 60  
62 61 # load database settings from yml file
63 62 def init_db_uri(self):
  1 +import uuid
  2 +from datetime import datetime
  3 +from .k2cfg import k2
  4 +
  5 +db = k2.db
  6 +def generate_id():
  7 + generated_id = uuid.uuid4().hex[:32]
  8 + return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)])
  9 +class Component(db.Model):
  10 + __bind_key__ = 'db2'
  11 + __tablename__ = 'component'
  12 + __table_args__ = {'extend_existing': True}
  13 + id = db.Column(db.String(36), primary_key=True, default=generate_id)
  14 + name = db.Column(db.String(100), nullable=False)
  15 + description = db.Column(db.String(200))
  16 + version = db.Column(db.String(20))
  17 + git_link = db.Column(db.String(200))
  18 + dependencies = db.Column(db.String)
  19 + date_installed = db.Column(db.DateTime, default=datetime.utcnow)
  20 + installed = db.Column(db.Boolean, default=False)
  21 +
  22 + def __init__(self, name, description, version, git_link, dependencies, installed):
  23 + self.name = name
  24 + self.description = description
  25 + self.version = version
  26 + self.git_link = git_link
  27 + self.dependencies = dependencies
  28 + self.installed = installed
  29 + def __repr__(self):
  30 + return f"Component('{self.name}', '{self.version}')"
  31 + @classmethod
  32 + def get_repository_by_id(self,rep_id):
  33 + component = db.session.query(Component).filter(Component.id == rep_id).first()
  34 + return component
  35 + @classmethod
  36 + def get_repository_by_id(self,rep_id):
  37 + component = db.session.query(Component).filter(Component.id == rep_id).first()
  38 + return component
k2/k2inst.py
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   -import os
16   -import sys
17   -
18   -
19   -# initialize db
20   -db = k2.db
21   -#migrate = Migrate(app, db)
22   -
23   -def generate_id():
24   - generated_id = uuid.uuid4().hex[:32]
25   - return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)])
26   -class Component(db.Model):
27   - __bind_key__ = 'db2'
28   - __tablename__ = 'component'
29   - __table_args__ = {'extend_existing': True}
30   - id = db.Column(db.String(36), primary_key=True, default=generate_id)
31   - name = db.Column(db.String(100), nullable=False)
32   - description = db.Column(db.String(200))
33   - version = db.Column(db.String(20))
34   - git_link = db.Column(db.String(200))
35   - dependencies = db.Column(db.String)
36   - date_installed = db.Column(db.DateTime, default=datetime.utcnow)
37   - installed = db.Column(db.Boolean, default=False)
38   -
39   - def __init__(self, name, description, version, git_link, dependencies, installed):
40   - self.name = name
41   - self.description = description
42   - self.version = version
43   - self.git_link = git_link
44   - self.dependencies = dependencies
45   - self.installed = installed
46   - def __repr__(self):
47   - return f"Component('{self.name}', '{self.version}')"
48   - @classmethod
49   - def get_repository_by_id(self,rep_id):
50   - component = db.session.query(Component).filter(Component.id == rep_id).first()
51   - return component
52   - @classmethod
53   - def get_repository_by_id(self,rep_id):
54   - component = db.session.query(Component).filter(Component.id == rep_id).first()
55   - return component
56   -components_bp = Blueprint('components', __name__, template_folder='templates')
57   -config = yaml.safe_load(open("db/first-login.yml"))
58   -
59   -def first_login_required(view_func):
60   - @wraps(view_func)
61   - def decorated_view(*args, **kwargs):
62   - if 'username' not in session:
63   - return redirect(url_for('components.first_login'))
64   - return view_func(*args, **kwargs)
65   - return decorated_view
66   -
67   -def append_to_yaml_file(file_path, data):
68   - with open(file_path, 'r') as f:
69   - existing_data = yaml.safe_load(f) or []
70   -
71   - if not existing_data:
72   - start_id = 1
73   - else:
74   - start_id = max(item.get('id', 0) for item in existing_data) + 1
75   -
76   - for i, item in enumerate(data, start=start_id):
77   - item['id'] = i
78   - existing_data.append(item)
79   -
80   - with open(file_path, 'w') as f:
81   - yaml.dump(existing_data, f, default_flow_style=False)
82   -
83   -
84   -def remove_from_yaml_file(file_path, component_name):
85   - with open(file_path, 'r') as f:
86   - existing_data = yaml.safe_load(f) or []
87   -
88   - updated_data = [item for item in existing_data if item.get('component_name') != component_name]
89   -
90   - with open(file_path, 'w') as f:
91   - yaml.dump(updated_data, f, default_flow_style=False)
92   -
93   -@components_bp.route('/api/languages', methods=['GET'])
94   -def find_language():
95   - components = Component.query.all()
96   - languages_paths = []
97   - # Додаємо головну директорію languages
98   - languages_paths.append('languages')
99   - # Знаходимо шляхи до директорій languages всередині папки components
100   - for component in components:
101   - component_languages_directory = 'components/' + component.name + '/' + component.name + '/languages'
102   - languages_paths.append(component_languages_directory)
103   - result = ';'.join(languages_paths)
104   - print(result)
105   - return result
106   -
107   -@components_bp.route('/', methods=['GET', 'POST'])
108   -@first_login_required
109   -def home():
110   - return redirect('/dashboard')
111   -
112   -@components_bp.route('/login', methods=['GET', 'POST'])
113   -def first_login():
114   - if request.method == "POST":
115   - username = request.form.get("username")
116   - password = request.form.get("password")
117   - for user in config["users"]:
118   - if user["username"] == username and user["password"] == password:
119   - session['username'] = username # Збереження ім'я користувача в сесії
120   - return redirect(url_for('components.dashboard'))
121   - return "Невірне ім'я користувача або пароль."
122   - return render_template('first-login.html')
123   -
124   -@components_bp.route('/logout')
125   -def logout():
126   - session.pop('username', None) # Видалення ім'я користувача з сесії
127   - return redirect(url_for('components.first_login'))
128   -
129   -@components_bp.route('/change_language/<lang>')
130   -def change_language(lang):
131   - session['lang'] = lang
132   - k2.current_language = lang
133   - return redirect(url_for('components.dashboard'))
134   -
135   -@components_bp.route('/dashboard')
136   -@first_login_required
137   -def dashboard():
138   -
139   - # Компоненти доступні для встановлення
140   - try:
141   - # GET-запит до API
142   - response = requests.get(f'{k2.update_domain}api/components')
143   - json_data = response.json()
144   - # Перетворення JSON-об'єкту на масив
145   - component_server = [item for item in json_data]
146   - except:
147   - component_server = None
148   -
149   - # Встановлені компоненти
150   - components = Component.query.all()
151   - components_names = [component.name for component in components]
152   - # Отримання значення пошукового запиту з параметрів URL
153   - search_query = request.args.get('search_query')
154   - #print(search_query)
155   - filtered_components = []
156   - if search_query:
157   - filtered_components = [component for component in component_server if
158   - (search_query.lower() in component['name'].lower() if component['name'] else False) or
159   - (search_query.lower() in component['description'].lower() if component[
160   - 'description'] else False)]
161   - else:
162   - filtered_components = component_server
163   - current_language = k2.current_language
164   -
165   - return render_template('dashboard.html', components=components,
166   - components_names=components_names, component_server=filtered_components,
167   - search_query=search_query, language=k2.menu )
168   -
169   -@components_bp.route('/show_components/<string:component_id>')
170   -def show_components(component_id):
171   - response = requests.get(f'{k2.update_domain}api/components')
172   - json_data = response.json()
173   - selected_component = next((component for component in json_data if component['id'] == component_id), None)
174   - return render_template('component-info.html', selected_component=selected_component)
175   -
176   -@components_bp.route('/install_components_git/<string:component_id>')
177   -def install_components_git(component_id):
178   - # Шлях до головної папки проекту
179   - project_folder = 'components'
180   - #component = Component.get_repository_by_id(component_id)
181   - response = requests.get(f'{k2.update_domain}api/components')
182   - json_data = response.json()
183   - selected_component = next((component for component in json_data if component['id'] == component_id), None)
184   - # Назва репозиторія
185   - repository_name = selected_component['name']
186   - # Шлях до папки репозиторія в межах проекту
187   - repository_folder = os.path.join(project_folder, repository_name)
188   - # URL репозиторія
189   -
190   - git_repo_url = selected_component['git_link']
191   - try:
192   - # Перевірка наявності папки репозиторія
193   - if not os.path.exists(repository_folder):
194   - # Створення папки репозиторія
195   - os.makedirs(repository_folder)
196   - # Шлях до файлу __init__.py
197   - init_file = os.path.join(repository_folder, '__init__.py')
198   - # Перевірка наявності файлу __init__.py
199   - if not os.path.exists(init_file):
200   - # Створення пустого файлу __init__.py
201   - open(init_file, 'a').close()
202   - #підключення до приватного репозиторію
203   - #os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW'
204   - #git_repo_url_with_token = git_repo_url.replace('https://',
205   - # f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@')
206   -
207   - # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія
208   - command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, '--target=' + repository_folder]
209   - # Виконуємо команду встановлення
210   - subprocess.check_call(command)
211   -
212   - # Шлях до файлу, до якого потрібно додати код
213   - file_path = 'routes.py'
214   - # Код, який потрібно додати
215   - code = selected_component['dependencies']
216   - # Відкриття файлу у режимі дозапису
217   - with open(file_path, 'a') as file:
218   - # Запис нового коду у файл
219   - file.write('\n')
220   - file.write(code)
221   - file.write('\n')
222   - component = Component.query.filter_by(name=selected_component['name']).first()
223   - if not component:
224   - new_component = Component(
225   - name=selected_component['name'],
226   - description=selected_component['description'],
227   - version=selected_component['version'],
228   - git_link=selected_component['git_link'],
229   - dependencies=selected_component['dependencies'],
230   - installed=True
231   - )
232   - # Add the new component to the database
233   - db.session.add(new_component)
234   - db.session.commit()
235   -
236   - # Повертаємо повідомлення про успішне встановлення
237   - return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
238   - except subprocess.CalledProcessError as e:
239   - return 'Error installing : ' + str(e)
240   -
241   -@components_bp.route('/install_components/<string:component_id>')
242   -def install_component_from_archive(component_id):
243   - # Шлях до головної папки проекту
244   - project_folder = 'components'
245   - # Отримати відповідну компоненту зі списку компонент
246   - response = requests.get(f'{k2.update_domain}api/components')
247   - json_data = response.json()
248   - selected_component = next((component for component in json_data if component['id'] == component_id), None)
249   - if selected_component is None:
250   - return 'Component not found'
251   - # Отримати посилання на архів компоненти та версію
252   - archive_url = selected_component['latest_component_data']
253   - version = selected_component['latest_version']
254   - try:
255   - # Створити шлях до папки компоненти згідно назви та версії
256   - component_folder = os.path.join(project_folder)
257   - os.makedirs(component_folder, exist_ok=True)
258   - # Завантажити архів компоненти
259   - response = requests.get(archive_url, stream=True)
260   - response.raise_for_status()
261   - # Шлях до завантаженого архіву
262   - archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip")
263   - # Встановити залежності з файлу requirements.txt
264   -
265   - # Зберегти архів на диск
266   - with open(archive_path, "wb") as file:
267   - for chunk in response.iter_content(chunk_size=8192):
268   - file.write(chunk)
269   - # Розпакувати архів
270   - with zipfile.ZipFile(archive_path, "r") as zip_ref:
271   - zip_ref.extractall(component_folder)
272   -
273   - # Видалити архів
274   - os.remove(archive_path)
275   -
276   - # Шлях до файлу, до якого потрібно додати код
277   - file_path = 'routes.py'
278   - # Код, який потрібно додати
279   - 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']}')'''
280   - #selected_component['dependencies']
281   -
282   - # Відкриття файлу у режимі дозапису
283   - with open(file_path, 'a') as file:
284   - # Запис нового коду у файл
285   - file.write('\n')
286   - file.write(code)
287   - file.write('\n')
288   -
289   - #Update database with the installed component
290   - component = Component.query.filter_by(name=selected_component['name']).first()
291   - if not component:
292   - component = Component(
293   - name=selected_component['name'],
294   - description=selected_component['description'],
295   - version=version,
296   - git_link=selected_component['git_link'],
297   - dependencies=code,
298   - installed=True
299   - )
300   - db.session.add(component)
301   - else:
302   - component.version = version
303   - component.git_link = selected_component['git_link']
304   - component.dependencies = code
305   - component.installed = True
306   -
307   - db.session.commit()
308   - # add menu items yml
309   - #file_path_input = f"components/{selected_component['name']}/menu_items.yml"
310   - #if os.path.exists(file_path_input):
311   - # with open(file_path_input, 'r', encoding='utf-8') as file:
312   - # data = yaml.safe_load(file)
313   - #else:
314   - # data = {
315   - # 'url': {'name': 'error'},
316   - # 'icon': 'error',
317   - # 'title': f"{selected_component['name']}--error",
318   - # 'category': 'error',
319   - # }
320   -
321   - #file_path = 'components/menu.yml'
322   - #append_to_yaml_file(file_path, data)
323   -
324   - #add language folders
325   - k2.search_babel_translation_directories()
326   - print(k2.domain)
327   - return f'''Component installed successfully: {selected_component["name"]} v{version} {k2.babel_translation_directories},
328   - \n \n please wait installing requirments...
329   - <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />'''
330   -
331   - except Exception as e:
332   - return f'Error installing component: {str(e)}'
333   -
334   -@components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET'])
335   -def install_requirments(selected_component_name):
336   - #menu items api
337   - response = requests.get(f"{k2.domain}{selected_component_name}/menu-items")
338   - if response.status_code == 200:
339   - data = response.json()
340   - print(data)
341   - else:
342   - data = [{
343   - 'url': {'name': 'error'},
344   - 'icon': 'error',
345   - 'title': f"{selected_component_name}--error",
346   - 'category': 'error',
347   - }]
348   - # add component_name key for menu items
349   - for item in data:
350   - item['component_name'] = selected_component_name
351   - file_path = 'components/menu.yml'
352   - append_to_yaml_file(file_path, data)
353   - k2.get_menu_elenents()
354   -
355   - #install requirements
356   - requirements_file = os.path.join('components', selected_component_name, "requirements.txt")
357   - if os.path.isfile(requirements_file):
358   - pip_command = f"{k2.venv_bin_path}/python -m pip install -r {requirements_file}"
359   - subprocess.run(pip_command, shell=True, check=True)
360   - return f'''Requirements installed successfully
361   - \n \n please wait installing requirments components...
362   - <meta http-equiv="refresh" content="1;url=/install-requirments-components" />'''
363   -
364   -@components_bp.route('/install-requirments-components')
365   -def install_requirements_components():
366   - # Откриття файлу requirements_components.txt
367   - requirements_file = 'requirements_components.txt'
368   - component_ids = None
369   - if os.path.isfile(requirements_file):
370   - with open('requirements_components.txt', 'r') as file:
371   - component_ids = file.read().splitlines()
372   - if component_ids:
373   - for component_id in component_ids:
374   - # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти
375   - response = requests.get(
376   - f'/install_components/{component_id}')
377   - return f'Requirements components installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
378   - else:
379   - return f'<meta http-equiv="refresh" content="1;url=/dashboard" />'
380   - # Опрацювання відповіді (за потреби)
381   -
382   -
383   -@components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET'])
384   -def remove_dependencies(component_id):
385   - # Знаходимо компоненту за її ID
386   - component = Component.query.get(component_id)
387   - if not component:
388   - return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
389   - #remove menu items
390   - component_name = component.name
391   - file_path = "components/menu.yml"
392   - remove_from_yaml_file(file_path, component_name)
393   -
394   - # remove routes
395   - file_path = 'routes.py'
396   - with open(file_path, 'r') as file:
397   - lines = file.readlines()
398   -
399   - updated_lines = [line for line in lines if line.strip() not in component.dependencies]
400   - with open(file_path, 'w') as file:
401   - file.writelines(updated_lines)
402   -
403   - component.installed = False
404   - db.session.commit()
405   -
406   - return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />'
407   -
408   -@components_bp.route('/add_dependencies/<string:component_id>', methods=['GET'])
409   -def add_dependencies(component_id):
410   -
411   - # Знаходимо компоненту за її ID
412   - component = Component.query.get(component_id)
413   - if not component:
414   - return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
415   -
416   - # Шлях до файлу, з якого потрібно видалити залежності
417   - file_path = 'routes.py'
418   - code = component.dependencies
419   - # Відкриття файлу у режимі дозапису
420   - with open(file_path, 'a') as file:
421   - # Запис нового коду у файл
422   - file.write(code)
423   -
424   - # Оновлюємо статус компоненти
425   - component.installed = True
426   - db.session.commit()
427   - return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
428   -
429   -@components_bp.route('/remove-component/<string:component_id>')
430   -def remove_component(component_id):
431   - # Шлях до головної папки проекту
432   - project_folder = 'components'
433   - component = Component.query.get(component_id)
434   - # Назва репозиторія
435   - repository_name = component.name
436   - # Шлях до папки репозиторія в межах проекту
437   - repository_folder = os.path.join(project_folder, repository_name)
438   - try:
439   - # Перевірка наявності папки репозиторія
440   - if os.path.exists(repository_folder):
441   - # Видалення папки репозиторія
442   - shutil.rmtree(repository_folder)
443   - # Видаляємо компоненту з бази
444   - if component:
445   - db.session.delete(component)
446   - db.session.commit()
447   -
448   - # Повертаємо повідомлення про успішне видалення
449   - return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
450   - except Exception as e:
451   - # Повертаємо повідомлення про помилку видалення
452   - return 'Error removing component: ' + str(e)
453   -
454   -@components_bp.route('/api/main-menu/')
455   -def project_menu():
456   - return k2.menu
... ... @@ -16,4 +16,5 @@
16 16 'cutpast': '0',
17 17 'enable': '0'
18 18 }
  19 + components = ''
  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 flask import request
  6 +from .k2cfg import k2
  7 +from .k2comp import Component
  8 +from flask_migrate import Migrate
  9 +import requests
  10 +import subprocess
  11 +from flask import current_app
  12 +import yaml
  13 +from functools import wraps
  14 +import os
  15 +import sys
  16 +
  17 +# initialize db
  18 +#migrate = Migrate(app, db)
  19 +
  20 +components_bp = Blueprint('components', __name__, template_folder='templates')
  21 +config = yaml.safe_load(open("db/first-login.yml"))
  22 +
  23 +
  24 +db = k2.db
  25 +
  26 +
  27 +def first_login_required(view_func):
  28 + @wraps(view_func)
  29 + def decorated_view(*args, **kwargs):
  30 + if 'username' not in session:
  31 + return redirect(url_for('components.first_login'))
  32 + return view_func(*args, **kwargs)
  33 + return decorated_view
  34 +
  35 +def append_to_yaml_file(file_path, data):
  36 + with open(file_path, 'r') as f:
  37 + existing_data = yaml.safe_load(f) or []
  38 +
  39 + if not existing_data:
  40 + start_id = 1
  41 + else:
  42 + start_id = max(item.get('id', 0) for item in existing_data) + 1
  43 +
  44 + for i, item in enumerate(data, start=start_id):
  45 + item['id'] = i
  46 + existing_data.append(item)
  47 +
  48 + with open(file_path, 'w') as f:
  49 + yaml.dump(existing_data, f, default_flow_style=False)
  50 +
  51 +
  52 +def remove_from_yaml_file(file_path, component_name):
  53 + with open(file_path, 'r') as f:
  54 + existing_data = yaml.safe_load(f) or []
  55 +
  56 + updated_data = [item for item in existing_data if item.get('component_name') != component_name]
  57 +
  58 + with open(file_path, 'w') as f:
  59 + yaml.dump(updated_data, f, default_flow_style=False)
  60 +
  61 +@components_bp.route('/api/languages', methods=['GET'])
  62 +def find_language():
  63 + components = Component.query.all()
  64 + languages_paths = []
  65 + # Додаємо головну директорію languages
  66 + languages_paths.append('languages')
  67 + # Знаходимо шляхи до директорій languages всередині папки components
  68 + for component in components:
  69 + component_languages_directory = 'components/' + component.name + '/' + component.name + '/languages'
  70 + languages_paths.append(component_languages_directory)
  71 + result = ';'.join(languages_paths)
  72 + print(result)
  73 + return result
  74 +
  75 +@components_bp.route('/api/add-to-menu', methods=['GET'])
  76 +def add_to_menu():
  77 + data = []
  78 + components = Component.query.all()
  79 + components_names = [component.name for component in components]
  80 + for components_names in components_names:
  81 + response = requests.get(f"{k2.domain}{components_names}/menu-admin-items")
  82 + print(response)
  83 + if response.status_code == 200:
  84 + data.append(response.json()[0])
  85 + else:
  86 + data
  87 + # add component_name key for menu items
  88 + for item in data:
  89 + item['component_name'] = components_names
  90 + k2.menu = data
  91 + return k2.menu
  92 +
  93 +@components_bp.route('/home', methods=['GET', 'POST'])
  94 +@first_login_required
  95 +def home():
  96 + return redirect('/dashboard')
  97 +
  98 +@components_bp.route('/first-login', methods=['GET', 'POST'])
  99 +def first_login():
  100 + if request.method == "POST":
  101 + username = request.form.get("username")
  102 + password = request.form.get("password")
  103 + for user in config["users"]:
  104 + if user["username"] == username and user["password"] == password:
  105 + session['username'] = username # Збереження ім'я користувача в сесії
  106 + return redirect(url_for('components.dashboard'))
  107 + return "Невірне ім'я користувача або пароль."
  108 + return render_template('first-login.html')
  109 +
  110 +
  111 +@components_bp.route('/change_language/<lang>')
  112 +def change_language(lang):
  113 + session['lang'] = lang
  114 + k2.current_language = lang
  115 + return redirect(url_for('components.dashboard'))
  116 +
  117 +@components_bp.route('/dashboard')
  118 +@first_login_required
  119 +def dashboard():
  120 + # Компоненти доступні для встановлення
  121 + try:
  122 + # GET-запит до API
  123 + response = requests.get(f'{k2.update_domain}api/components')
  124 + json_data = response.json()
  125 + # Перетворення JSON-об'єкту на масив
  126 + component_server = [item for item in json_data]
  127 + except:
  128 + component_server = None
  129 +
  130 + # Встановлені компоненти
  131 + components = Component.query.all()
  132 + components_names = [component.name for component in components]
  133 + # Отримання значення пошукового запиту з параметрів URL
  134 + search_query = request.args.get('search_query')
  135 + #print(search_query)
  136 + filtered_components = []
  137 + if search_query:
  138 + filtered_components = [component for component in component_server if
  139 + (search_query.lower() in component['name'].lower() if component['name'] else False) or
  140 + (search_query.lower() in component['description'].lower() if component[
  141 + 'description'] else False)]
  142 + else:
  143 + filtered_components = component_server
  144 + current_language = k2.current_language
  145 +
  146 + return render_template('dashboard.html', components=components,
  147 + components_names=components_names, component_server=filtered_components,
  148 + search_query=search_query, language=k2.menu )
  149 +
  150 +@components_bp.route('/show_components/<string:component_id>')
  151 +def show_components(component_id):
  152 + response = requests.get(f'{k2.update_domain}api/components')
  153 + json_data = response.json()
  154 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  155 + return render_template('component-info.html', selected_component=selected_component)
  156 +
  157 +@components_bp.route('/install_components_git/<string:component_id>')
  158 +def install_components_git(component_id):
  159 + # Шлях до головної папки проекту
  160 + project_folder = 'components'
  161 + #component = Component.get_repository_by_id(component_id)
  162 + response = requests.get(f'{k2.update_domain}api/components')
  163 + json_data = response.json()
  164 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  165 + # Назва репозиторія
  166 + repository_name = selected_component['name']
  167 + # Шлях до папки репозиторія в межах проекту
  168 + repository_folder = os.path.join(project_folder, repository_name)
  169 + # URL репозиторія
  170 +
  171 + git_repo_url = selected_component['git_link']
  172 + try:
  173 + # Перевірка наявності папки репозиторія
  174 + if not os.path.exists(repository_folder):
  175 + # Створення папки репозиторія
  176 + os.makedirs(repository_folder)
  177 + # Шлях до файлу __init__.py
  178 + init_file = os.path.join(repository_folder, '__init__.py')
  179 + # Перевірка наявності файлу __init__.py
  180 + if not os.path.exists(init_file):
  181 + # Створення пустого файлу __init__.py
  182 + open(init_file, 'a').close()
  183 + #підключення до приватного репозиторію
  184 + #os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW'
  185 + #git_repo_url_with_token = git_repo_url.replace('https://',
  186 + # f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@')
  187 +
  188 + # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія
  189 + command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url, '--target=' + repository_folder]
  190 + # Виконуємо команду встановлення
  191 + subprocess.check_call(command)
  192 +
  193 + # Шлях до файлу, до якого потрібно додати код
  194 + file_path = 'routes.py'
  195 + # Код, який потрібно додати
  196 + code = selected_component['dependencies']
  197 + # Відкриття файлу у режимі дозапису
  198 + with open(file_path, 'a') as file:
  199 + # Запис нового коду у файл
  200 + file.write('\n')
  201 + file.write(code)
  202 + file.write('\n')
  203 + component = Component.query.filter_by(name=selected_component['name']).first()
  204 + if not component:
  205 + new_component = Component(
  206 + name=selected_component['name'],
  207 + description=selected_component['description'],
  208 + version=selected_component['version'],
  209 + git_link=selected_component['git_link'],
  210 + dependencies=selected_component['dependencies'],
  211 + installed=True
  212 + )
  213 + # Add the new component to the database
  214 + db.session.add(new_component)
  215 + db.session.commit()
  216 +
  217 + # Повертаємо повідомлення про успішне встановлення
  218 + return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  219 + except subprocess.CalledProcessError as e:
  220 + return 'Error installing : ' + str(e)
  221 +
  222 +@components_bp.route('/install_components/<string:component_id>')
  223 +def install_component_from_archive(component_id):
  224 + # Шлях до головної папки проекту
  225 + project_folder = 'components'
  226 + # Отримати відповідну компоненту зі списку компонент
  227 + response = requests.get(f'{k2.update_domain}api/components')
  228 + json_data = response.json()
  229 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  230 + if selected_component is None:
  231 + return 'Component not found'
  232 + # Отримати посилання на архів компоненти та версію
  233 + archive_url = selected_component['latest_component_data']
  234 + version = selected_component['latest_version']
  235 + try:
  236 + # Створити шлях до папки компоненти згідно назви та версії
  237 + component_folder = os.path.join(project_folder)
  238 + os.makedirs(component_folder, exist_ok=True)
  239 + # Завантажити архів компоненти
  240 + response = requests.get(archive_url, stream=True)
  241 + response.raise_for_status()
  242 + # Шлях до завантаженого архіву
  243 + archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip")
  244 + # Встановити залежності з файлу requirements.txt
  245 +
  246 + # Зберегти архів на диск
  247 + with open(archive_path, "wb") as file:
  248 + for chunk in response.iter_content(chunk_size=8192):
  249 + file.write(chunk)
  250 + # Розпакувати архів
  251 + with zipfile.ZipFile(archive_path, "r") as zip_ref:
  252 + zip_ref.extractall(component_folder)
  253 +
  254 + # Видалити архів
  255 + os.remove(archive_path)
  256 +
  257 + # Шлях до файлу, до якого потрібно додати код
  258 + file_path = 'routes.py'
  259 + # Код, який потрібно додати
  260 + 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']}')'''
  261 + #selected_component['dependencies']
  262 +
  263 + # Відкриття файлу у режимі дозапису
  264 + with open(file_path, 'a') as file:
  265 + # Запис нового коду у файл
  266 + file.write('\n')
  267 + file.write(code)
  268 + file.write('\n')
  269 +
  270 + #Update database with the installed component
  271 + component = Component.query.filter_by(name=selected_component['name']).first()
  272 + if not component:
  273 + component = Component(
  274 + name=selected_component['name'],
  275 + description=selected_component['description'],
  276 + version=version,
  277 + git_link=selected_component['git_link'],
  278 + dependencies=code,
  279 + installed=True
  280 + )
  281 + db.session.add(component)
  282 + else:
  283 + component.version = version
  284 + component.git_link = selected_component['git_link']
  285 + component.dependencies = code
  286 + component.installed = True
  287 +
  288 + db.session.commit()
  289 +
  290 + #add language folders
  291 + k2.search_babel_translation_directories()
  292 + return f'''Component installed successfully: {selected_component["name"]} v{version} {k2.babel_translation_directories},
  293 + \n \n please wait installing requirments...
  294 + <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />'''
  295 +
  296 + except Exception as e:
  297 + return f'Error installing component: {str(e)}'
  298 +
  299 +@components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET'])
  300 +def install_requirments(selected_component_name):
  301 + #menu items api
  302 + response = requests.get(f"{k2.domain}{selected_component_name}/menu-items")
  303 + if response.status_code == 200:
  304 + data = response.json()
  305 +
  306 + else:
  307 + data = []
  308 + # add component_name key for menu items
  309 + for item in data:
  310 + item['component_name'] = selected_component_name
  311 + file_path = 'components/menu.yml'
  312 + append_to_yaml_file(file_path, data)
  313 + get_admin_menu()
  314 +
  315 + #install requirements
  316 + requirements_file = os.path.join('components', selected_component_name, "requirements.txt")
  317 + if os.path.isfile(requirements_file):
  318 + pip_command = f"{k2.venv_bin_path}/python -m pip install -r {requirements_file}"
  319 + subprocess.run(pip_command, shell=True, check=True)
  320 + return f'''Requirements installed successfully
  321 + \n \n please wait installing requirments components...
  322 + <meta http-equiv="refresh" content="1;url=/install-requirments-components" />'''
  323 +
  324 +@components_bp.route('/install-requirments-components')
  325 +def install_requirements_components():
  326 + # Откриття файлу requirements_components.txt
  327 + requirements_file = 'requirements_components.txt'
  328 + component_ids = None
  329 + if os.path.isfile(requirements_file):
  330 + with open('requirements_components.txt', 'r') as file:
  331 + component_ids = file.read().splitlines()
  332 + if component_ids:
  333 + for component_id in component_ids:
  334 + # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти
  335 + response = requests.get(
  336 + f'/install_components/{component_id}')
  337 + return f'Requirements components installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  338 + else:
  339 + return f'<meta http-equiv="refresh" content="1;url=/dashboard" />'
  340 + # Опрацювання відповіді (за потреби)
  341 +
  342 +@components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET'])
  343 +def remove_dependencies(component_id):
  344 + # Знаходимо компоненту за її ID
  345 + component = Component.query.get(component_id)
  346 + if not component:
  347 + return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
  348 + #remove menu items
  349 + component_name = component.name
  350 + file_path = "components/menu.yml"
  351 + remove_from_yaml_file(file_path, component_name)
  352 +
  353 + # remove routes
  354 + file_path = 'routes.py'
  355 + with open(file_path, 'r') as file:
  356 + lines = file.readlines()
  357 +
  358 + updated_lines = [line for line in lines if line.strip() not in component.dependencies]
  359 + with open(file_path, 'w') as file:
  360 + file.writelines(updated_lines)
  361 +
  362 + component.installed = False
  363 + db.session.commit()
  364 +
  365 + return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />'
  366 +
  367 +@components_bp.route('/add_dependencies/<string:component_id>', methods=['GET'])
  368 +def add_dependencies(component_id):
  369 +
  370 + # Знаходимо компоненту за її ID
  371 + component = Component.query.get(component_id)
  372 + if not component:
  373 + return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
  374 +
  375 + # Шлях до файлу, з якого потрібно видалити залежності
  376 + file_path = 'routes.py'
  377 + code = component.dependencies
  378 + # Відкриття файлу у режимі дозапису
  379 + with open(file_path, 'a') as file:
  380 + # Запис нового коду у файл
  381 + file.write(code)
  382 +
  383 + # Оновлюємо статус компоненти
  384 + component.installed = True
  385 + db.session.commit()
  386 + return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  387 +
  388 +@components_bp.route('/remove-component/<string:component_id>')
  389 +def remove_component(component_id):
  390 + # Шлях до головної папки проекту
  391 + project_folder = 'components'
  392 + component = Component.query.get(component_id)
  393 + # Назва репозиторія
  394 + repository_name = component.name
  395 + # Шлях до папки репозиторія в межах проекту
  396 + repository_folder = os.path.join(project_folder, repository_name)
  397 + try:
  398 + # Перевірка наявності папки репозиторія
  399 + if os.path.exists(repository_folder):
  400 + # Видалення папки репозиторія
  401 + shutil.rmtree(repository_folder)
  402 + # Видаляємо компоненту з бази
  403 + if component:
  404 + db.session.delete(component)
  405 + db.session.commit()
  406 +
  407 + # Повертаємо повідомлення про успішне видалення
  408 + return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  409 + except Exception as e:
  410 + # Повертаємо повідомлення про помилку видалення
  411 + return 'Error removing component: ' + str(e)
  412 +
  413 +@components_bp.route('/api/main-menu/')
  414 +def get_admin_menu():
  415 + requests.get(f"{k2.domain}api/add-to-menu")
  416 + return k2.menu
languages/babel_translation_directories.yml
1   -babel_translation_directories: languages;components/k2test/k2test/languages
  1 +babel_translation_directories: languages;components/k2test/k2test/languages;components/grid/grid/languages;components/adm/adm/languages
... ... @@ -8,7 +8,7 @@
8 8 # configure flask app
9 9 app = Flask(__name__)
10 10 app.config['SECRET_KEY'] = k2.secret_key
11   -
  11 +app.json.sort_keys = k2.json_sort_keys
12 12 #app.config.from_object(k2)
13 13  
14 14 # init db
... ... @@ -21,9 +21,6 @@
21 21 app.config['BABEL_TRANSLATION_DIRECTORIES'] = k2.babel_translation_directories
22 22 babel = Babel(app)
23 23 babel.init_app(app, locale_selector=k2.get_locale)
24   -
25   -#menu
26   -k2.get_menu_elenents()
27 24  
28 25 # flask routing
29 26 from routes import *
1   -from flask import Flask
2 1 #app = Flask(__name__)
3   -from main import app, babel
4   -from k2.k2inst import components_bp
  2 +from main import app
  3 +from k2.k2rout import components_bp
5 4 app.register_blueprint(components_bp)
6   -
7 5 from components.k2test.k2test.views import k2test
8 6 app.register_blueprint(k2test, url_prefix='/k2test')
9   -
10   -from components.adm.adm.views import adm
11   -app.register_blueprint(adm, url_prefix='/adm')
templates/dashboard.html
... ... @@ -112,7 +112,7 @@
112 112  
113 113  
114 114 <div class="container px-4 py-5" id="hanging-icons">
115   - <h2 class="pb-2 border-bottom">{{_('Components Shop')}}</h2>
  115 + <h2 class="pb-2 border-bottom">{{_('ADD Components')}}</h2>
116 116 <form action="{{ url_for('components.dashboard') }}" method="GET" class="search-form">
117 117 <div class="input-group">
118 118 <input type="text" name="search_query" class="form-control" placeholder="Search components">
templates/first-login.html
... ... @@ -64,7 +64,7 @@
64 64 <img class="logo" src="{{ url_for('static', filename='img/logo-k2.png')}}" alt="" width="250">
65 65 <h1>K2CloudERP-2.5.1.27</h1>
66 66  
67   - <form method="post" action="/login">
  67 + <form method="post" action="/first-login">
68 68 <div class="form-group">
69 69 <p><input type="text" name="username" placeholder="Ім'я користувача"></p>
70 70 </div>
templates/index.html
1   -<!DOCTYPE html>
2   -<html lang="">
3   - <head>
4   - <meta charset="utf-8" />
5   - <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6   - <meta name="viewport" content="width=device-width,initial-scale=1" />
7   - <title>Головна сторінка</title>
8   - <link rel="stylesheet" href="{{ url_for('static', filename='grid/css/chunk-vendors.3bee5491.css') }}">
9   - </head>
10   - <body>
11   - <h1>Index Main</h1>
12   - <div id="app"></div>
13   -
14   - <div>{{ name }}</div>
15   - {% for js_file in js_files %}
16   - <script src="{{ url_for('static', filename=js_file) }}"></script>
17   - {% endfor %}
18   - </body>
19   -</html>