Merged PR 2: APP バージョン 履歴管理

- python3.12.4
- add app table
- flow domainid->domainurl add app flowhistory
This commit is contained in:
方 柏
2024-11-11 07:03:48 +00:00
committed by 小哲 馬
7 changed files with 169 additions and 18 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,7 @@
.vscode .vscode
.mypy_cache .mypy_cache
docker-stack.yml docker-stack.yml
backend/pyvenv.cfg
backend/Include/
backend/Scripts/

View File

@@ -1,4 +1,5 @@
from fastapi import Query, Request,Depends, APIRouter, UploadFile,HTTPException,File from fastapi import Query, Request,Depends, APIRouter, UploadFile,HTTPException,File
from app.core.operation import log_operation
from app.db import Base,engine from app.db import Base,engine
from app.db.session import get_db from app.db.session import get_db
from app.db.crud import * from app.db.crud import *
@@ -7,8 +8,69 @@ from typing import List, Optional
from app.core.auth import get_current_active_user,get_current_user from app.core.auth import get_current_active_user,get_current_user
from app.core.apiexception import APIException from app.core.apiexception import APIException
import httpx
import app.core.config as config
platform_router = r = APIRouter() platform_router = r = APIRouter()
@r.get(
"/apps",
response_model=List[AppList],
response_model_exclude_none=True,
)
async def apps_list(
request: Request,
user = Depends(get_current_user),
db=Depends(get_db),
):
try:
platformapps = get_apps(db)
domain = get_activedomain(db, user.id)
kintoneevn = config.KINTONE_ENV(domain)
headers={config.API_V1_AUTH_KEY:kintoneevn.API_V1_AUTH_VALUE}
url = f"{kintoneevn.BASE_URL}{config.API_V1_STR}/apps.json"
offset = 0
limit = 100
all_apps = []
while True:
r = httpx.get(f"{url}?limit={limit}&offset={offset}", headers=headers)
json_data = r.json()
apps = json_data.get("apps",[])
all_apps.extend(apps)
if len(apps)<limit:
break
offset += limit
tempapps = platformapps.copy()
for papp in tempapps:
exist = False
for kapp in all_apps:
if kapp['appId'] == papp.appid:
exist = True
break
if not exist:
platformapps.remove(papp)
return platformapps
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while get apps:",e)
@r.post("/apps", response_model=AppList, response_model_exclude_none=True)
async def apps_update(
request: Request,
app: AppVersion,
user=Depends(get_current_user),
db=Depends(get_db),
):
try:
return update_appversion(db, app,user.id)
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while get create app :",e)
@r.get( @r.get(
"/appsettings/{id}", "/appsettings/{id}",
response_model=App, response_model=App,
@@ -129,7 +191,7 @@ async def flow_list(
try: try:
domain = get_activedomain(db, user.id) domain = get_activedomain(db, user.id)
print("domain=>",domain) print("domain=>",domain)
flows = get_flows_by_app(db, domain.id, appid) flows = get_flows_by_app(db, domain.url, appid)
return flows return flows
except Exception as e: except Exception as e:
raise APIException('platform:flow',request.url._url,f"Error occurred while get flow by appid:",e) raise APIException('platform:flow',request.url._url,f"Error occurred while get flow by appid:",e)
@@ -144,7 +206,7 @@ async def flow_create(
): ):
try: try:
domain = get_activedomain(db, user.id) domain = get_activedomain(db, user.id)
return create_flow(db, domain.id, flow) return create_flow(db, domain.url, flow)
except Exception as e: except Exception as e:
raise APIException('platform:flow',request.url._url,f"Error occurred while create flow:",e) raise APIException('platform:flow',request.url._url,f"Error occurred while create flow:",e)

View File

@@ -5,7 +5,7 @@ import base64
PROJECT_NAME = "KintoneAppBuilder" PROJECT_NAME = "KintoneAppBuilder"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/dev" #SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/dev"
SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/postgres" SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://kabAdmin:P%40ssw0rd!@kintonetooldb.postgres.database.azure.com/dev_v2"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/test" #SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/test"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@ktune-prod-db.postgres.database.azure.com/postgres" #SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@ktune-prod-db.postgres.database.azure.com/postgres"
API_V1_STR = "/k/v1" API_V1_STR = "/k/v1"

View File

@@ -69,6 +69,46 @@ def edit_user(
db.refresh(db_user) db.refresh(db_user)
return db_user return db_user
def get_apps(
db: Session
) -> t.List[schemas.AppList]:
return db.query(models.App).all()
def update_appversion(db: Session, appedit: schemas.AppVersion,userid:int):
app = db.query(models.App).filter(and_(models.App.domainurl == appedit.domainurl,models.App.appid == appedit.appid)).first()
if app:
app.version = app.version + 1
db_app = app
appver = app.version
else:
appver = 1
db_app = models.App(
domainurl = appedit.domainurl,
appid=appedit.appid,
appname=appedit.appname,
version = 1,
updateuser= userid
)
db.add(db_app)
flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == appedit.domainurl,models.App.appid == appedit.appid))
for flow in flows:
db_flowhistory = models.FlowHistory(
flowid = flow.flowid,
appid = flow.appid,
eventid = flow.eventid,
domainurl = flow.domainurl,
name = flow.name,
content = flow.content,
createuser = userid,
version = appver
)
db.add(db_flowhistory)
db.commit()
db.refresh(db_app)
return db_app
def get_appsetting(db: Session, id: int): def get_appsetting(db: Session, id: int):
app = db.query(models.AppSetting).get(id) app = db.query(models.AppSetting).get(id)
@@ -125,12 +165,12 @@ def get_actions(db: Session):
return actions return actions
def create_flow(db: Session, domainid: int, flow: schemas.FlowBase): def create_flow(db: Session, domainurl: str, flow: schemas.FlowBase):
db_flow = models.Flow( db_flow = models.Flow(
flowid=flow.flowid, flowid=flow.flowid,
appid=flow.appid, appid=flow.appid,
eventid=flow.eventid, eventid=flow.eventid,
domainid=domainid, domainurl=domainurl,
name=flow.name, name=flow.name,
content=flow.content content=flow.content
) )
@@ -177,8 +217,8 @@ def get_flow(db: Session, flowid: str):
raise HTTPException(status_code=404, detail="Data not found") raise HTTPException(status_code=404, detail="Data not found")
return flow return flow
def get_flows_by_app(db: Session, domainid: int, appid: str): def get_flows_by_app(db: Session,domainurl: str, appid: str):
flows = db.query(models.Flow).filter(and_(models.Flow.domainid == domainid,models.Flow.appid == appid)).all() flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == domainurl,models.Flow.appid == appid)).all()
if not flows: if not flows:
raise Exception("Data not found") raise Exception("Data not found")
return flows return flows

View File

@@ -1,5 +1,6 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey
from sqlalchemy.ext.declarative import as_declarative from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import relationship
from datetime import datetime from datetime import datetime
from app.core.security import chacha20Decrypt from app.core.security import chacha20Decrypt
@@ -20,6 +21,16 @@ class User(Base):
is_active = Column(Boolean, default=True) is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False) is_superuser = Column(Boolean, default=False)
class App(Base):
__tablename__ = "app"
domainurl = Column(String(200), nullable=False)
appname = Column(String(200), nullable=False)
appid = Column(String(100), index=True, nullable=False)
version = Column(Integer)
updateuser = Column(Integer,ForeignKey("user.id"))
user = relationship('User')
class AppSetting(Base): class AppSetting(Base):
__tablename__ = "appsetting" __tablename__ = "appsetting"
@@ -51,10 +62,22 @@ class Flow(Base):
flowid = Column(String(100), index=True, nullable=False) flowid = Column(String(100), index=True, nullable=False)
appid = Column(String(100), index=True, nullable=False) appid = Column(String(100), index=True, nullable=False)
eventid = Column(String(100), index=True, nullable=False) eventid = Column(String(100), index=True, nullable=False)
domainid = Column(Integer,ForeignKey("domain.id")) domainurl = Column(String(200))
name = Column(String(200)) name = Column(String(200))
content = Column(String) content = Column(String)
class FlowHistory(Base):
__tablename__ = "flowhistory"
flowid = Column(String(100), index=True, nullable=False)
appid = Column(String(100), index=True, nullable=False)
eventid = Column(String(100), index=True, nullable=False)
domainurl = Column(String(200))
name = Column(String(200))
content = Column(String)
createuser = Column(Integer,ForeignKey("user.id"))
version = Column(Integer)
class Tenant(Base): class Tenant(Base):
__tablename__ = "tenant" __tablename__ = "tenant"
@@ -108,6 +131,17 @@ class ErrorLog(Base):
location = Column(String(500)) location = Column(String(500))
content = Column(String(5000)) content = Column(String(5000))
class OperationLog(Base):
__tablename__ = "operationlog"
tenantid = Column(String(100))
domainurl = Column(String(200))
userid = Column(Integer,ForeignKey("user.id"))
operation = Column(String(200))
function = Column(String(200))
detail = Column(String(200))
user = relationship('User')
class KintoneFormat(Base): class KintoneFormat(Base):
__tablename__ = "kintoneformat" __tablename__ = "kintoneformat"

View File

@@ -28,21 +28,21 @@ class UserCreate(UserBase):
is_active:bool is_active:bool
is_superuser:bool is_superuser:bool
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class UserEdit(UserBase): class UserEdit(UserBase):
password: t.Optional[str] = None password: t.Optional[str] = None
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class User(UserBase): class User(UserBase):
id: int id: int
class Config: class ConfigDict:
orm_mode = True orm_mode = True
@@ -50,6 +50,17 @@ class Token(BaseModel):
access_token: str access_token: str
token_type: str token_type: str
class AppList(Base):
domainurl: str
appname: str
appid:str
version:int
user:UserOut
class AppVersion(BaseModel):
domainurl: str
appname: str
appid:str
class TokenData(BaseModel): class TokenData(BaseModel):
id:int = 0 id:int = 0
@@ -68,7 +79,7 @@ class AppBase(BaseModel):
class App(AppBase): class App(AppBase):
id: int id: int
class Config: class ConfigDict:
orm_mode = True orm_mode = True
@@ -79,7 +90,7 @@ class Kintone(BaseModel):
desc: str = None desc: str = None
content: str = None content: str = None
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class Action(BaseModel): class Action(BaseModel):
@@ -92,7 +103,7 @@ class Action(BaseModel):
categoryid: int = None categoryid: int = None
nosort: int nosort: int
categoryname : str =None categoryname : str =None
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class FlowBase(BaseModel): class FlowBase(BaseModel):
@@ -107,11 +118,11 @@ class Flow(Base):
flowid: str flowid: str
appid: str appid: str
eventid: str eventid: str
domainid: int domainurl: str
name: str = None name: str = None
content: str = None content: str = None
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class DomainBase(BaseModel): class DomainBase(BaseModel):
@@ -133,7 +144,7 @@ class Domain(Base):
url: str url: str
kintoneuser: str kintoneuser: str
kintonepwd: str kintonepwd: str
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class Event(Base): class Event(Base):
@@ -145,7 +156,7 @@ class Event(Base):
mobile: bool mobile: bool
eventgroup: bool eventgroup: bool
class Config: class ConfigDict:
orm_mode = True orm_mode = True
class ErrorCreate(BaseModel): class ErrorCreate(BaseModel):

Binary file not shown.