Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e262aea
Bug Fix: integration title display problem fixed in security plugins
Jul 13, 2023
640eca7
Merge pull request #58 from RavshanovUsmonbek/main
LifeDJIK Jul 20, 2023
f0f20c8
refactoring permissions and project steps
Aspect13 Jul 27, 2023
77b4d6b
Merge pull request #59 from Aspect13/feature/refactoring_1
Aspect13 Jul 27, 2023
76b0f7b
Update for s3 client
incx07 Aug 9, 2023
553aab7
Merge pull request #60 from incx07/feature/monitoring
hunkom Aug 29, 2023
fccc49e
added uid
incx07 Aug 29, 2023
172bd54
Merge branch 'carrier-io:main' into feature/integration_uid
incx07 Aug 30, 2023
8e4402c
Merge pull request #61 from incx07/feature/integration_uid
hunkom Sep 4, 2023
2693689
fix for integration_uid
incx07 Sep 5, 2023
b02d4c4
check up integration_uid type
incx07 Sep 5, 2023
3cdcc72
Merge pull request #62 from incx07/feature/integration_uid
hunkom Sep 6, 2023
5ff7b35
integration details by uid api
Aspect13 Oct 24, 2023
961774f
project_id is passed to check_connection
Jan 31, 2024
102e44e
Merge pull request #63 from RavshanovUsmonbek/main
arozumenko Jan 31, 2024
7d46e29
specify the use of project_id from request.json in auth decorator
LifeDJIK Jan 31, 2024
75b406b
Adding pagination and sorting for the integrations
dmotsnyiphotobox Feb 9, 2024
5ea734d
params fixed
daniilmotsniy Feb 9, 2024
48cf7a9
Merge pull request #64 from daniilmotsniy/main
Aspect13 Feb 9, 2024
60cdfda
Available integrations list
daniilmotsniy Feb 22, 2024
4712322
Merge pull request #65 from daniilmotsniy/main
Aspect13 Feb 22, 2024
bd98b24
integrations - set project id to found integration
Aspect13 Mar 14, 2024
2c053bc
integrations session management fix
Aspect13 Apr 17, 2024
81d3d8e
integration create with id fix
Aspect13 Apr 18, 2024
b961a2f
feat(DARK MODE): added dark mode;
KondratskiVD-BT Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions api/v1/available.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from flask import request

from tools import auth, api_tools


class ProjectAPI(api_tools.APIModeHandler):
...


class AdminAPI(api_tools.APIModeHandler):
...


class API(api_tools.APIBase):
url_params = [
'<int:project_id>',
'<string:mode>/<int:project_id>',
'<string:project_id>',
'<string:mode>/<string:project_id>'
]

mode_handlers = {
'default': ProjectAPI,
'administration': AdminAPI,
}

def get(self, **kwargs):
section = request.args.get('section')
if section:
return self.module.list_integrations_by_section(section), 200
return list(self.module.list_integrations()), 200
17 changes: 12 additions & 5 deletions api/v1/check_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,27 @@ class API(api_tools.APIBase):
'administration': AdminAPI,
}

@auth.decorators.check_api(["configuration.integrations.integrations.create",
"configuration.integrations.integrations.edit"
])
@auth.decorators.check_api(
[
"configuration.integrations.integrations.create",
"configuration.integrations.integrations.edit"
],
project_id_in_request_json=True
)
def post(self, integration_name: str, **kwargs):
integration = self.module.get_by_name(integration_name)
payload = request.json
if not integration:
return {'error': 'integration not found'}, 404
try:
settings = integration.settings_model.parse_obj(request.json)
settings = integration.settings_model.parse_obj(payload)
except ValidationError as e:
# return e.json(), 400
return e.errors(), 400

check_connection_response = settings.check_connection()
project_id = payload.get('project_id')
project_id = int(project_id) if project_id else project_id
check_connection_response = settings.check_connection(project_id)
if not request.json.get('save_action'):
if check_connection_response is True:
return 'OK', 200
Expand Down
8 changes: 4 additions & 4 deletions api/v1/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def post(self, integration_name: str):
try:
return IntegrationPD.from_orm(db_integration).dict(), 200
except ValidationError as e:
return e.errors(), 400
return e.errors(), 400

@auth.decorators.check_api({
"permissions": ["configuration.integrations.integrations.edit"],
Expand Down Expand Up @@ -108,7 +108,7 @@ def patch(self, project_id: int, integration_id: int):
"administration": {"admin": True, "viewer": False, "editor": False},
"default": {"admin": True, "viewer": False, "editor": False},
"developer": {"admin": False, "viewer": False, "editor": False},
}})
}})
def delete(self, project_id: int, integration_id: int):
with db.with_project_schema_session(project_id) as tenant_session:
db_integration = tenant_session.query(IntegrationProject).filter(
Expand Down Expand Up @@ -197,7 +197,7 @@ def patch(self, integration_id: int, **kwargs):
"administration": {"admin": True, "viewer": False, "editor": False},
"default": {"admin": True, "viewer": False, "editor": False},
"developer": {"admin": False, "viewer": False, "editor": False},
}})
}})
def delete(self, integration_id: int, **kwargs):
IntegrationAdmin.query.filter(IntegrationAdmin.id == integration_id).delete()
IntegrationAdmin.commit()
Expand All @@ -216,4 +216,4 @@ class API(api_tools.APIBase):
mode_handlers = {
'default': ProjectAPI,
'administration': AdminAPI,
}
}
23 changes: 23 additions & 0 deletions api/v1/integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ def get(self, **kwargs):
], 200


class PromptLibAPI(api_tools.APIModeHandler):
AI_SECTION: str = 'ai'

@auth.decorators.check_api({
"permissions": ["configuration.integrations.integrations.view"],
"recommended_roles": {
"administration": {"admin": True, "viewer": True, "editor": True},
"default": {"admin": True, "viewer": True, "editor": True},
"developer": {"admin": True, "viewer": False, "editor": False},
}})
def get(self, project_id: int):
sort_order = request.args.get('sort_order', 'asc')
sort_by = request.args.get('sort_by', 'name')
offset = int(request.args.get('offset', 0))
limit = int(request.args.get('limit', 10_000))
return [
i.dict() for i in self.module.get_sorted_paginated_integrations_by_section(
self.AI_SECTION, project_id, sort_order, sort_by, offset, limit
)
], 200


class API(api_tools.APIBase):
url_params = [
'<int:project_id>',
Expand All @@ -59,4 +81,5 @@ class API(api_tools.APIBase):
mode_handlers = {
'default': ProjectAPI,
'administration': AdminAPI,
'prompt_lib': PromptLibAPI,
}
Empty file added events/__init__.py
Empty file.
37 changes: 37 additions & 0 deletions events/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from sqlalchemy import Boolean

from ..models.integration import IntegrationAdmin, IntegrationDefault
from ..models.pd.integration import SecretField

from tools import rpc_tools, VaultClient, db

from pylon.core.tools import web, log


def _usecret_field(integration_db, project_id):
settings = integration_db.settings
secret_access_key = SecretField.parse_obj(settings['secret_access_key'])
settings['secret_access_key'] = secret_access_key.unsecret(project_id=project_id)
return settings


class Event:
@web.event('project_created')
def create_default_s3_for_new_project(self, context, event, project: dict, **kwargs) -> None:
log.info('Creating default integration for project %s', project)
project_id = project['id']
if integration_db := IntegrationAdmin.query.filter(
IntegrationAdmin.name == 's3_integration',
IntegrationAdmin.config['is_shared'].astext.cast(Boolean) == True,
IntegrationAdmin.is_default == True,
).one_or_none():
with db.with_project_schema_session(project_id) as tenant_session:
default_integration = IntegrationDefault(
name=integration_db.name,
project_id=None,
integration_id=integration_db.id,
is_default=True,
section=integration_db.section
)
tenant_session.add(default_integration)
tenant_session.commit()
49 changes: 12 additions & 37 deletions models/integration.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pylon.core.tools import log
from sqlalchemy import Integer, Column, String, Boolean, UniqueConstraint, Index
from sqlalchemy.dialects.postgresql import JSON
from uuid import uuid4

from tools import db_tools, db, rpc_tools
from ..models.pd.integration import IntegrationBase
Expand All @@ -19,15 +20,15 @@ class IntegrationAdmin(db_tools.AbstractBaseMixin, db.Base, rpc_tools.RpcMixin,
)
id = Column(Integer, primary_key=True)
name = Column(String(64), unique=False)
# project_id = Column(Integer, unique=False, nullable=True)
# mode = Column(String(64), unique=False, default='default')
settings = Column(JSON, unique=False, default={})
is_default = Column(Boolean, default=False, nullable=False)
section = Column(String(64), unique=False, nullable=False)
# description = Column(String(256), unique=False, nullable=True, default='Default integration')
config = Column(JSON, unique=False, default={})
task_id = Column(String(256), unique=False, nullable=True)
status = Column(String(256), unique=False, nullable=False, default='success')
# ALTER TABLE "Project-1"."integration" ADD COLUMN uid VARCHAR(128)
# ALTER TABLE "Project-1"."integration" ALTER COLUMN uid NOT NULL
uid = Column(String(128), unique=True, nullable=False)

def make_default(self):
IntegrationAdmin.query.filter(
Expand All @@ -45,6 +46,8 @@ def set_task_id(self, task_id: str):
self.insert()

def insert(self):
if not self.uid:
self.uid = str(uuid4())
if not IntegrationAdmin.query.filter(
IntegrationAdmin.name == self.name,
IntegrationAdmin.is_default == True,
Expand All @@ -66,50 +69,24 @@ def process_secret_fields(self):

class IntegrationProject(db_tools.AbstractBaseMixin, db.Base, rpc_tools.RpcMixin, rpc_tools.EventManagerMixin):
__tablename__ = "integration"
# __table_args__ = (
# Index(
# 'ix_project_default_uc', # Index name
# 'project_id', 'name', # Columns which are part of the index
# unique=True,
# postgresql_where=Column('is_default') # The condition
# )
# )
__table_args__ = {'schema': 'tenant'}

id = Column(Integer, primary_key=True)
name = Column(String(64), unique=False)
project_id = Column(Integer, unique=False, nullable=True)
# mode = Column(String(64), unique=False, default='default')
settings = Column(JSON, unique=False, default={})
is_default = Column(Boolean, default=False, nullable=False)
section = Column(String(64), unique=False, nullable=False)
# description = Column(String(256), unique=False, nullable=True, default='Default integration')
config = Column(JSON, unique=False, default={})
task_id = Column(String(256), unique=False, nullable=True)
status = Column(String(256), unique=False, nullable=False, default='success')


# def make_default(self, session):
# default_integration = session.query(IntegrationProject).filter(
# IntegrationProject.project_id == self.project_id,
# IntegrationProject.name == self.name,
# IntegrationProject.is_default == True,
# IntegrationProject.id != self.id
# ).one_or_none()
# if default_integration:
# default_integration.is_default = False
# self.is_default = True
# # super().insert()
# session.commit()

# def set_task_id(self, session, task_id: str):
# session.query(IntegrationProject).filter(
# IntegrationProject.id == self.id
# ).update({IntegrationProject.task_id: task_id})
# # self.insert()
# session.commit()
# ALTER TABLE "Project-1"."integration" ADD COLUMN uid VARCHAR(128)
# ALTER TABLE "Project-1"."integration" ALTER COLUMN uid NOT NULL
uid = Column(String(128), unique=True, nullable=False)

def insert(self, session):
if not self.uid:
self.uid = str(uuid4())
session.add(self)
session.commit()
inherited_integration = IntegrationAdmin.query.filter(
Expand All @@ -122,7 +99,6 @@ def insert(self, session):
).one_or_none()
if not inherited_integration and not default_integration:
self.rpc.call.integrations_make_default_integration(self, self.project_id)
# super().insert(session)
self.process_secret_fields(session)
self.event_manager.fire_event(f'{self.name}_created_or_updated', self.to_json())

Expand All @@ -133,7 +109,6 @@ def process_secret_fields(self, session):
session.query(IntegrationProject).filter(
IntegrationProject.id == self.id
).update({IntegrationProject.settings: settings})
# super().insert()
session.commit()


Expand All @@ -154,4 +129,4 @@ class IntegrationDefault(db_tools.AbstractBaseMixin, db.Base, rpc_tools.RpcMixin
integration_id = Column(Integer, unique=False, nullable=False)
project_id = Column(Integer, unique=False, nullable=True)
is_default = Column(Boolean, default=False, nullable=False)
section = Column(String(64), unique=False, nullable=False)
section = Column(String(64), unique=False, nullable=False)
23 changes: 8 additions & 15 deletions models/pd/integration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Optional, Union
from uuid import uuid4

from pydantic import BaseModel, validator, constr
from pylon.core.tools import log
Expand All @@ -18,13 +19,19 @@ class IntegrationBase(BaseModel):
config: dict
task_id: Optional[str]
status: Optional[str] = 'success'
# mode: str
uid: str

class Config:
orm_mode = True


class IntegrationPD(IntegrationBase):
@validator('uid', pre=True, always=True)
def set_uid(cls, value: Optional[str]):
if not value:
return str(uuid4())
return value

@validator("settings")
def validate_settings(cls, value, values):
integration = rpc_tools.RpcMixin().rpc.call.integrations_get_by_name(
Expand All @@ -44,11 +51,6 @@ def validate_section(cls, value, values):
return rpc_tools.RpcMixin().rpc.call.integrations_register_section(name=value)
return section

# @validator("config")
# def validate_config(cls, value, values):
# assert value.get('name'), 'ensure this value has at least 1 characters'
# return value

@validator("config")
def validate_description(cls, value, values):
if not value.get('name'):
Expand All @@ -57,15 +59,6 @@ def validate_description(cls, value, values):
return value


# class IntegrationProjectPD(IntegrationPD):
# pass
# @validator("is_default")
# def validate_is_default(cls, value, values):
# if rpc_tools.RpcMixin().rpc.call.integrations_is_default(values['project_id'], values):
# return True
# return False


class IntegrationDefaultPD(BaseModel):
id: int
name: str
Expand Down
5 changes: 3 additions & 2 deletions module.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
from pylon.core.tools import log # pylint: disable=E0611,E0401
from pylon.core.tools import module

from .models.integration import IntegrationAdmin # pylint: disable=E0611,E0401
from .models.pd.integration import IntegrationBase
# from .models.integration import IntegrationAdmin # pylint: disable=E0611,E0401
# from .models.pd.integration import IntegrationBase

from .init_db import init_db

Expand All @@ -46,6 +46,7 @@ def init(self):
self.descriptor.init_blueprint()
self.descriptor.init_api()
self.descriptor.init_slots()
self.descriptor.init_events()

theme.register_subsection(
'configuration', 'integrations',
Expand Down
Loading