Compare commits

..

8 Commits

Author SHA1 Message Date
xiaozhe.ma
055ec1aeaf merge with backend 2024-11-24 16:53:47 +09:00
方 柏
321f14b229 Merged PR 8: app&appversion&flowhistory&role&permission
app&appversion&flowhistory&role&permission
2024-11-23 10:49:59 +00:00
xiaozhe.ma
1626091e36 backend変更マージ 2024-11-23 18:36:01 +09:00
fa1d3b01b0 app&appversion&flowhistory&role&permission 2024-11-22 15:19:49 +09:00
xue jiahao
bf4abe3cad Fix select app 2024-11-22 12:45:37 +08:00
xue jiahao
3f98e17215 [feature] add new application 2024-11-20 16:05:18 +08:00
xiaozhe.ma
4563274789 backend bug fix 2024-11-20 15:09:45 +09:00
xue jiahao
3b9f08b43d Merged PR 6: [bugfix] id format error when saving flow
[bugfix] id format error when saving flow
2024-11-19 04:03:07 +00:00
14 changed files with 442 additions and 175 deletions

View File

@@ -25,11 +25,15 @@ async def login(
minutes=security.ACCESS_TOKEN_EXPIRE_MINUTES minutes=security.ACCESS_TOKEN_EXPIRE_MINUTES
) )
if user.is_superuser: if user.is_superuser:
permissions = "admin" roles = "super"
permissions = "ALL"
else: else:
permissions = "user" roles = ";".join(role.name for role in user.roles)
perlst = [perm.privilege for role in user.roles for perm in role.permissions]
permissions =";".join(list(set(perlst)))
access_token = security.create_access_token( access_token = security.create_access_token(
data={"sub": user.id, "permissions": permissions}, data={"sub": user.id, "roles":roles,"permissions": permissions ,},
expires_delta=access_token_expires, expires_delta=access_token_expires,
) )

View File

@@ -156,10 +156,10 @@ def getsettingfromexcel(df):
des = df.iloc[2,2] des = df.iloc[2,2]
return {"name":appname,"description":des} return {"name":appname,"description":des}
def getsettingfromkintone(app:str,c:config.KINTONE_ENV): def getsettingfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
params = {"app":app} params = {"app":app}
url = f"{c.BASE_URL}{config.API_V1_STR}/app/settings.json" url = f"{env.BASE_URL}{config.API_V1_STR}/app/settings.json"
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
@@ -171,24 +171,24 @@ def analysesettings(excel,kintone):
updatesettings[key] = excel[key] updatesettings[key] = excel[key]
return updatesettings return updatesettings
def createkintoneapp(name:str,c:config.KINTONE_ENV): def createkintoneapp(name:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
data = {"name":name} data = {"name":name}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app.json"
r = httpx.post(url,headers=headers,data=json.dumps(data)) r = httpx.post(url,headers=headers,data=json.dumps(data))
return r.json() return r.json()
def updateappsettingstokintone(app:str,updates:dict,c:config.KINTONE_ENV): def updateappsettingstokintone(app:str,updates:dict,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/settings.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/settings.json"
data = {"app":app} data = {"app":app}
data.update(updates) data.update(updates)
r = httpx.put(url,headers=headers,data=json.dumps(data)) r = httpx.put(url,headers=headers,data=json.dumps(data))
return r.json() return r.json()
def addfieldstokintone(app:str,fields:dict,c:config.KINTONE_ENV,revision:str = None): def addfieldstokintone(app:str,fields:dict,env:config.KINTONE_ENV,revision:str = None):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
if revision != None: if revision != None:
data = {"app":app,"revision":revision,"properties":fields} data = {"app":app,"revision":revision,"properties":fields}
else: else:
@@ -197,43 +197,43 @@ def addfieldstokintone(app:str,fields:dict,c:config.KINTONE_ENV,revision:str = N
r.raise_for_status() r.raise_for_status()
return r.json() return r.json()
def updatefieldstokintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV): def updatefieldstokintone(app:str,revision:str,fields:dict,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
data = {"app":app,"properties":fields} data = {"app":app,"properties":fields}
r = httpx.put(url,headers=headers,data=json.dumps(data)) r = httpx.put(url,headers=headers,data=json.dumps(data))
return r.json() return r.json()
def deletefieldsfromkintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV): def deletefieldsfromkintone(app:str,revision:str,fields:dict,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
params = {"app":app,"revision":revision,"fields":fields} params = {"app":app,"revision":revision,"fields":fields}
#r = httpx.delete(url,headers=headers,content=json.dumps(params)) #r = httpx.delete(url,headers=headers,content=json.dumps(params))
r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params)) r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params))
return r.json() return r.json()
def deoployappfromkintone(app:str,revision:str,c:config.KINTONE_ENV): def deoployappfromkintone(app:str,revision:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json"
data = {"apps":[{"app":app,"revision":revision}],"revert": False} data = {"apps":[{"app":app,"revision":revision}],"revert": False}
r = httpx.post(url,headers=headers,data=json.dumps(data)) r = httpx.post(url,headers=headers,data=json.dumps(data))
return r.json return r.json
# 既定項目に含めるアプリのフィールドのみ取得する # 既定項目に含めるアプリのフィールドのみ取得する
# スペース、枠線、ラベルを含まない # スペース、枠線、ラベルを含まない
def getfieldsfromkintone(app:str,c:config.KINTONE_ENV): def getfieldsfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
params = {"app":app} params = {"app":app}
url = f"{c.BASE_URL}{config.API_V1_STR}/app/form/fields.json" url = f"{env.BASE_URL}{config.API_V1_STR}/app/form/fields.json"
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
# フォームに配置するフィールドのみ取得する # フォームに配置するフィールドのみ取得する
# スペース、枠線、ラベルも含める # スペース、枠線、ラベルも含める
def getformfromkintone(app:str,c:config.KINTONE_ENV): def getformfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
params = {"app":app} params = {"app":app}
url = f"{c.BASE_URL}{config.API_V1_STR}/form.json" url = f"{env.BASE_URL}{config.API_V1_STR}/form.json"
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
@@ -286,10 +286,10 @@ def analysefields(excel,kintone):
return {"update":updatefields,"add":addfields,"del":delfields} return {"update":updatefields,"add":addfields,"del":delfields}
def getprocessfromkintone(app:str,c:config.KINTONE_ENV): def getprocessfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
params = {"app":app} params = {"app":app}
url = f"{c.BASE_URL}{config.API_V1_STR}/app/status.json" url = f"{env.BASE_URL}{config.API_V1_STR}/app/status.json"
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
@@ -374,24 +374,24 @@ def getkintoneorgs(c:config.KINTONE_ENV):
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
def uploadkintonefiles(file,c:config.KINTONE_ENV): def uploadkintonefiles(file,env:config.KINTONE_ENV):
if (file.endswith('alc_runtime.js') and config.DEPLOY_MODE == "DEV"): if (file.endswith('alc_runtime.js') and config.DEPLOY_MODE == "DEV"):
return {'fileKey':file} return {'fileKey':file}
upload_files = {'file': open(file,'rb')} upload_files = {'file': open(file,'rb')}
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
data ={'name':'file','filename':os.path.basename(file)} data ={'name':'file','filename':os.path.basename(file)}
url = f"{c.BASE_URL}/k/v1/file.json" url = f"{env.BASE_URL}/k/v1/file.json"
r = httpx.post(url,headers=headers,data=data,files=upload_files) r = httpx.post(url,headers=headers,data=data,files=upload_files)
#{"name":data['filename'],'fileKey':r['fileKey']} #{"name":data['filename'],'fileKey':r['fileKey']}
return r.json() return r.json()
def updateappjscss(app,uploads,c:config.KINTONE_ENV): def updateappjscss(app,uploads,env:config.KINTONE_ENV):
dsjs = [] dsjs = []
dscss = [] dscss = []
#mobile側 #mobile側
mbjs = [] mbjs = []
mbcss = [] mbcss = []
customize = getappcustomize(app, c) customize = getappcustomize(app, env)
current_js = customize['desktop'].get('js', []) current_js = customize['desktop'].get('js', [])
current_css = customize['desktop'].get('css', []) current_css = customize['desktop'].get('css', [])
current_mobile_js = customize['mobile'].get('js', []) current_mobile_js = customize['mobile'].get('js', [])
@@ -430,16 +430,16 @@ def updateappjscss(app,uploads,c:config.KINTONE_ENV):
ds ={'js':dsjs,'css':dscss} ds ={'js':dsjs,'css':dscss}
mb ={'js':mbjs,'css':mbcss} mb ={'js':mbjs,'css':mbcss}
data = {'app':app,'scope':'ALL','desktop':ds,'mobile':mb,'revision':customize["revision"]} data = {'app':app,'scope':'ALL','desktop':ds,'mobile':mb,'revision':customize["revision"]}
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/customize.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
print(json.dumps(data)) print(json.dumps(data))
r = httpx.put(url,headers=headers,data=json.dumps(data)) r = httpx.put(url,headers=headers,data=json.dumps(data))
return r.json() return r.json()
#kintone カスタマイズ情報 #kintone カスタマイズ情報
def getappcustomize(app,c:config.KINTONE_ENV): def getappcustomize(app,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/customize.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
params = {"app":app} params = {"app":app}
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
@@ -451,9 +451,9 @@ def getTempPath(filename):
fpath = os.path.join(rootdir,"Temp",filename) fpath = os.path.join(rootdir,"Temp",filename)
return fpath return fpath
def createappjs(domainid,app): def createappjs(domain_url,app):
db = SessionLocal() db = SessionLocal()
flows = get_flows_by_app(db,domainid,app) flows = get_flows_by_app(db,domain_url,app)
db.close() db.close()
content={} content={}
for flow in flows: for flow in flows:
@@ -521,7 +521,7 @@ async def upload(request:Request,files:t.List[UploadFile] = File(...)):
return {"files": [file.filename for file in files]} return {"files": [file.filename for file in files]}
@r.post("/updatejscss") @r.post("/updatejscss")
async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env = Depends(getkintoneenv)): async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env:config.KINTONE_ENV = Depends(getkintoneenv)):
try: try:
jscs=[] jscs=[]
for file in files: for file in files:
@@ -542,21 +542,21 @@ async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env
raise APIException('kintone:updatejscss',request.url._url, f"Error occurred while update js/css {file.filename} is not an Excel file",e) raise APIException('kintone:updatejscss',request.url._url, f"Error occurred while update js/css {file.filename} is not an Excel file",e)
@r.get("/app") @r.get("/app")
async def app(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def app(request:Request,app:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
try: try:
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/app.json" url = f"{env.BASE_URL}{config.API_V1_STR}/app.json"
params ={"id":app} params ={"id":app}
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
except Exception as e: except Exception as e:
raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAME}->{app}):",e) raise APIException('kintone:app',request.url._url, f"Error occurred while get app({env.DOMAIN_NAME}->{app}):",e)
@r.get("/allapps") @r.get("/allapps")
async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def allapps(request:Request,env:config.KINTONE_ENV=Depends(getkintoneenv)):
try: try:
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/apps.json" url = f"{env.BASE_URL}{config.API_V1_STR}/apps.json"
offset = 0 offset = 0
limit = 100 limit = 100
all_apps = [] all_apps = []
@@ -572,17 +572,17 @@ async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)):
return {"apps": all_apps} return {"apps": all_apps}
except Exception as e: except Exception as e:
raise APIException('kintone:allapps', request.url._url, f"Error occurred while get allapps({c.DOMAIN_NAME}):", e) raise APIException('kintone:allapps', request.url._url, f"Error occurred while get allapps({env.DOMAIN_NAME}):", e)
@r.get("/appfields") @r.get("/appfields")
async def appfields(request:Request,app:str,env = Depends(getkintoneenv)): async def appfields(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
try: try:
return getfieldsfromkintone(app,env) return getfieldsfromkintone(app,env)
except Exception as e: except Exception as e:
raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAME}->{app}):",e) raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAME}->{app}):",e)
@r.get("/allfields") @r.get("/allfields")
async def allfields(request:Request,app:str,env = Depends(getkintoneenv)): async def allfields(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
try: try:
field_resp = getfieldsfromkintone(app,env) field_resp = getfieldsfromkintone(app,env)
form_resp = getformfromkintone(app,env) form_resp = getformfromkintone(app,env)
@@ -591,38 +591,38 @@ async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAME}->{app}):",e) raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAME}->{app}):",e)
@r.get("/appprocess") @r.get("/appprocess")
async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)): async def appprocess(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
try: try:
return getprocessfromkintone(app,env) return getprocessfromkintone(app,env)
except Exception as e: except Exception as e:
raise APIException('kintone:appprocess',request.url._url, f"Error occurred while get app process({env.DOMAIN_NAME}->{app}):",e) raise APIException('kintone:appprocess',request.url._url, f"Error occurred while get app process({env.DOMAIN_NAME}->{app}):",e)
@r.get("/alljscss") @r.get("/alljscss")
async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def alljscs(request:Request,app:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
try: try:
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/app/customize.json" url = f"{env.BASE_URL}{config.API_V1_STR}/app/customize.json"
params = {"app":app} params = {"app":app}
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
except Exception as e: except Exception as e:
raise APIException('kintone:alljscss',request.url._url, f"Error occurred while get app js/css({c.DOMAIN_NAME}->{app}):",e) raise APIException('kintone:alljscss',request.url._url, f"Error occurred while get app js/css({env.DOMAIN_NAME}->{app}):",e)
@r.post("/createapp",) @r.post("/createapp",)
async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def createapp(request:Request,name:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
try: try:
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
data = {"name":name} data = {"name":name}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app.json"
r = httpx.post(url,headers=headers,data=json.dumps(data)) r = httpx.post(url,headers=headers,data=json.dumps(data))
result = r.json() result = r.json()
if result.get("app") != None: if result.get("app") != None:
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json" url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json"
data = {"apps":[result],"revert": False} data = {"apps":[result],"revert": False}
r = httpx.post(url,headers=headers,data=json.dumps(data)) r = httpx.post(url,headers=headers,data=json.dumps(data))
return r.json return r.json
except Exception as e: except Exception as e:
raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({c.DOMAIN_NAME}->{name}):",e) raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({env.DOMAIN_NAME}->{name}):",e)
@r.post("/createappfromexcel",) @r.post("/createappfromexcel",)
@@ -761,7 +761,7 @@ async def createjstokintone(request:Request,app:str,env:config.KINTONE_ENV = Dep
try: try:
jscs=[] jscs=[]
files=[] files=[]
files.append(createappjs(env.DOMAIN_ID, app)) files.append(createappjs(env.BASE_URL, app))
files.append(getTempPath('alc_runtime.js')) files.append(getTempPath('alc_runtime.js'))
files.append(getTempPath('alc_runtime.css')) files.append(getTempPath('alc_runtime.css'))
for file in files: for file in files:

View File

@@ -23,7 +23,7 @@ platform_router = r = APIRouter()
) )
async def apps_list( async def apps_list(
request: Request, request: Request,
user = Depends(get_current_user), user = Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -60,7 +60,7 @@ async def apps_list(
async def apps_update( async def apps_update(
request: Request, request: Request,
app: AppVersion, app: AppVersion,
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -68,7 +68,21 @@ async def apps_update(
except Exception as e: except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while get create app :",e) raise APIException('platform:apps',request.url._url,f"Error occurred while get create app :",e)
@r.delete(
"/apps/{domainurl}/{appid}", response_model_exclude_none=True
)
async def apps_delete(
request: Request,
domainurl:str,
appid: str,
user=Depends(get_current_active_user),
db=Depends(get_db),
):
try:
return delete_apps(db, domainurl,appid)
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while delete apps({domainurl}:{appid}):",e)
@r.get( @r.get(
"/appsettings/{id}", "/appsettings/{id}",
response_model=App, response_model=App,
@@ -183,7 +197,7 @@ async def flow_details(
async def flow_list( async def flow_list(
request: Request, request: Request,
appid: str, appid: str,
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -198,8 +212,8 @@ async def flow_list(
@r.post("/flow", response_model=Flow, response_model_exclude_none=True) @r.post("/flow", response_model=Flow, response_model_exclude_none=True)
async def flow_create( async def flow_create(
request: Request, request: Request,
flow: FlowBase, flow: FlowIn,
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -214,11 +228,14 @@ async def flow_create(
) )
async def flow_edit( async def flow_edit(
request: Request, request: Request,
flow: FlowBase, flowid: str,
flow: FlowIn,
user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
return edit_flow(db, flow) domain = get_activedomain(db, user.id)
return edit_flow(db,domain.url, flow,user.id)
except Exception as e: except Exception as e:
raise APIException('platform:flow',request.url._url,f"Error occurred while edit flow:",e) raise APIException('platform:flow',request.url._url,f"Error occurred while edit flow:",e)
@@ -256,7 +273,7 @@ async def domain_details(
async def domain_create( async def domain_create(
request: Request, request: Request,
domain: DomainBase, domain: DomainBase,
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -271,10 +288,11 @@ async def domain_create(
async def domain_edit( async def domain_edit(
request: Request, request: Request,
domain: DomainBase, domain: DomainBase,
user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
return edit_domain(db, domain) return edit_domain(db, domain,user.id)
except Exception as e: except Exception as e:
raise APIException('platform:domain',request.url._url,f"Error occurred while edit domain:",e) raise APIException('platform:domain',request.url._url,f"Error occurred while edit domain:",e)
@@ -300,7 +318,7 @@ async def domain_delete(
async def userdomain_details( async def userdomain_details(
request: Request, request: Request,
userId: Optional[int] = Query(None, alias="userId"), userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -348,7 +366,7 @@ async def userdomain_delete(
async def get_useractivedomain( async def get_useractivedomain(
request: Request, request: Request,
userId: Optional[int] = Query(None, alias="userId"), userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:
@@ -368,7 +386,7 @@ async def update_activeuserdomain(
request: Request, request: Request,
domainid:int, domainid:int,
userId: Optional[int] = Query(None, alias="userId"), userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_user), user=Depends(get_current_active_user),
db=Depends(get_db), db=Depends(get_db),
): ):
try: try:

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter, Request, Depends, Response, encoders from fastapi import APIRouter, Request, Depends, Response, Security, encoders
import typing as t import typing as t
from app.db.session import get_db from app.db.session import get_db
@@ -8,9 +8,11 @@ from app.db.crud import (
create_user, create_user,
delete_user, delete_user,
edit_user, edit_user,
assign_userrole,
get_roles,
) )
from app.db.schemas import UserCreate, UserEdit, User, UserOut from app.db.schemas import UserCreate, UserEdit, User, UserOut,Role
from app.core.auth import get_current_active_user, get_current_active_superuser from app.core.auth import get_current_user,get_current_active_user, get_current_active_superuser
users_router = r = APIRouter() users_router = r = APIRouter()
@@ -23,14 +25,14 @@ users_router = r = APIRouter()
async def users_list( async def users_list(
response: Response, response: Response,
db=Depends(get_db), db=Depends(get_db),
current_user=Depends(get_current_active_superuser), current_user=Depends(get_current_active_user),
): ):
""" """
Get all users Get all users
""" """
users = get_users(db) users = get_users(db,current_user.is_superuser)
# This is necessary for react-admin to work # This is necessary for react-admin to work
response.headers["Content-Range"] = f"0-9/{len(users)}" #response.headers["Content-Range"] = f"0-9/{len(users)}"
return users return users
@@ -105,3 +107,30 @@ async def user_delete(
Delete existing user Delete existing user
""" """
return delete_user(db, user_id) return delete_user(db, user_id)
@r.post("/userrole",
response_model=User,
response_model_exclude_none=True,)
async def assign_role(
request: Request,
userid:int,
roles:t.List[int],
db=Depends(get_db)
):
return assign_userrole(db,userid,roles)
@r.get(
"/roles",
response_model=t.List[Role],
response_model_exclude_none=True,
)
async def roles_list(
response: Response,
db=Depends(get_db),
current_user=Security(get_current_active_user, scopes=["role_list"]),
):
roles = get_roles(db)
return roles

View File

@@ -1,5 +1,6 @@
from fastapi.security import SecurityScopes
import jwt import jwt
from fastapi import Depends, HTTPException, status from fastapi import Depends, HTTPException, Request, Security, status
from jwt import PyJWTError from jwt import PyJWTError
from app.db import models, schemas, session from app.db import models, schemas, session
@@ -7,7 +8,7 @@ from app.db.crud import get_user_by_email, create_user,get_user
from app.core import security from app.core import security
async def get_current_user( async def get_current_user(security_scopes: SecurityScopes,
db=Depends(session.get_db), token: str = Depends(security.oauth2_scheme) db=Depends(session.get_db), token: str = Depends(security.oauth2_scheme)
): ):
credentials_exception = HTTPException( credentials_exception = HTTPException(
@@ -16,13 +17,21 @@ async def get_current_user(
headers={"WWW-Authenticate": "Bearer"}, headers={"WWW-Authenticate": "Bearer"},
) )
try: try:
payload = jwt.decode( payload = jwt.decode(
token, security.SECRET_KEY, algorithms=[security.ALGORITHM] token, security.SECRET_KEY, algorithms=[security.ALGORITHM]
) )
id: int = payload.get("sub") id: int = payload.get("sub")
if id is None: if id is None:
raise credentials_exception raise credentials_exception
permissions: str = payload.get("permissions") permissions: str = payload.get("permissions")
if not permissions =="ALL":
for scope in security_scopes.scopes:
if scope not in permissions.split(";"):
raise HTTPException(
status_code=403, detail="The user doesn't have enough privileges"
)
token_data = schemas.TokenData(id = id, permissions=permissions) token_data = schemas.TokenData(id = id, permissions=permissions)
except PyJWTError: except PyJWTError:
raise credentials_exception raise credentials_exception

View File

@@ -1,3 +1,4 @@
from datetime import datetime
from fastapi import HTTPException, status from fastapi import HTTPException, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy import and_ from sqlalchemy import and_
@@ -19,9 +20,12 @@ def get_user_by_email(db: Session, email: str) -> schemas.UserBase:
def get_users( def get_users(
db: Session, skip: int = 0, limit: int = 100 db: Session, super:bool
) -> t.List[schemas.UserOut]: ) -> t.List[schemas.UserOut]:
return db.query(models.User).offset(skip).limit(limit).all() if super:
return db.query(models.User).all()
else:
return db.query(models.User).filter(models.User.is_superuser == False)
def create_user(db: Session, user: schemas.UserCreate): def create_user(db: Session, user: schemas.UserCreate):
@@ -69,28 +73,48 @@ def edit_user(
db.refresh(db_user) db.refresh(db_user)
return db_user return db_user
def get_roles(
db: Session
) -> t.List[schemas.Role]:
return db.query(models.Role).all()
def assign_userrole( db: Session, user_id: int, roles: t.List[int]):
db_user = db.query(models.User).get(user_id)
if db_user:
for role in db_user.roles:
db_user.roles.remove(role)
for roleid in roles:
role = db.query(models.Role).get(roleid)
if role:
db_user.roles.append(role)
db.commit()
db.refresh(db_user)
return db_user
def get_apps( def get_apps(
db: Session, db: Session,
domain_url:str domainurl:str
) -> t.List[schemas.AppList]: ) -> t.List[schemas.AppList]:
return db.query(models.App).filter(models.App.domainurl == domain_url).all() return db.query(models.App).filter(models.App.domainurl == domainurl).all()
def update_appversion(db: Session, appedit: schemas.AppVersion,userid:int): 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() db_app = db.query(models.App).filter(and_(models.App.domainurl == appedit.domainurl,models.App.appid == appedit.appid)).first()
if app: if not db_app:
app.version = app.version + 1 raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
db_app = app
appver = app.version db_app.version = db_app.version + 1
else: appversion = models.AppVersion(
appver = 1
db_app = models.App(
domainurl = appedit.domainurl, domainurl = appedit.domainurl,
appid=appedit.appid, appid=appedit.appid,
appname=appedit.appname, appname=db_app.appname,
version = 1, version = db_app.version,
updateuser= userid versionname = appedit.versionname,
) comment = appedit.comment,
updateuserid = userid,
createuserid = userid
)
db.add(appversion)
db.add(db_app) db.add(db_app)
flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == appedit.domainurl,models.App.appid == appedit.appid)) flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == appedit.domainurl,models.App.appid == appedit.appid))
@@ -103,7 +127,9 @@ def update_appversion(db: Session, appedit: schemas.AppVersion,userid:int):
name = flow.name, name = flow.name,
content = flow.content, content = flow.content,
createuser = userid, createuser = userid,
version = appver version = db_app.version,
updateuserid = userid,
createuserid = userid
) )
db.add(db_flowhistory) db.add(db_flowhistory)
@@ -111,6 +137,17 @@ def update_appversion(db: Session, appedit: schemas.AppVersion,userid:int):
db.refresh(db_app) db.refresh(db_app)
return db_app return db_app
def delete_apps(db: Session, domainurl: str,appid: str ):
db_app = db.query(models.App).filter(and_(models.App.domainurl == domainurl,models.App.appid ==appid)).first()
if not db_app:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="App not found")
db.delete(db_app)
db_flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == domainurl,models.Flow.appid ==appid))
for flow in db_flows:
db.delete(flow)
db.commit()
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)
if not app: if not app:
@@ -166,16 +203,28 @@ def get_actions(db: Session):
return actions return actions
def create_flow(db: Session, domainurl: str, flow: schemas.FlowBase): def create_flow(db: Session, domainurl: str, flow: schemas.FlowIn,userid:int):
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,
domainurl=domainurl, domainurl=domainurl,
name=flow.name, name=flow.name,
content=flow.content content=flow.content,
createuserid = userid,
updateuserid = userid
) )
db.add(db_flow) db.add(db_flow)
db_app = db.query(models.App).filter(and_(models.App.domainurl == domainurl,models.App.appid == flow.appid)).first()
if not db_app:
db_app = models.App(
domainurl = domainurl,
appid=flow.appid,
appname=flow.appname,
version = 0,
createuserid= userid,
updateuserid = userid
)
db.commit() db.commit()
db.refresh(db_flow) db.refresh(db_flow)
return db_flow return db_flow
@@ -190,16 +239,20 @@ def delete_flow(db: Session, flowid: str):
def edit_flow( def edit_flow(
db: Session, flow: schemas.FlowBase db: Session, domainurl: str, flow: schemas.FlowIn,userid:int
) -> schemas.Flow: ) -> schemas.Flow:
db_flow = get_flow(db, flow.flowid) db_flow = get_flow(db, flow.flowid)
if not db_flow: if not db_flow:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Flow not found") #見つからない時新規作成
update_data = flow.dict(exclude_unset=True) return create_flow(db,domainurl,flow,userid)
for key, value in update_data.items(): db_flow.appid =flow.appid
setattr(db_flow, key, value) db_flow.eventid=flow.eventid
db_flow.domainurl=domainurl
db_flow.name=flow.name
db_flow.content=flow.content
db_flow.updateuserid = userid
db.add(db_flow) db.add(db_flow)
db.commit() db.commit()
db.refresh(db_flow) db.refresh(db_flow)
@@ -214,8 +267,8 @@ def get_flows(db: Session, flowid: str):
def get_flow(db: Session, flowid: str): def get_flow(db: Session, flowid: str):
flow = db.query(models.Flow).filter(models.Flow.flowid == flowid).first() flow = db.query(models.Flow).filter(models.Flow.flowid == flowid).first()
if not flow: # if not flow:
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,domainurl: str, appid: str): def get_flows_by_app(db: Session,domainurl: str, appid: str):
@@ -231,7 +284,9 @@ def create_domain(db: Session, domain: schemas.DomainBase,userid:int):
name=domain.name, name=domain.name,
url=domain.url, url=domain.url,
kintoneuser=domain.kintoneuser, kintoneuser=domain.kintoneuser,
kintonepwd=domain.kintonepwd kintonepwd=domain.kintonepwd,
createuserid = userid,
updateuserid = userid
) )
db.add(db_domain) db.add(db_domain)
db.flush() db.flush()
@@ -250,18 +305,19 @@ def delete_domain(db: Session,id: int):
def edit_domain( def edit_domain(
db: Session, domain: schemas.DomainBase db: Session, domain: schemas.DomainBase,userid:int
) -> schemas.Domain: ) -> schemas.Domain:
domain.encrypt_kintonepwd() domain.encrypt_kintonepwd()
db_domain = db.query(models.Domain).get(domain.id) db_domain = db.query(models.Domain).get(domain.id)
if not db_domain: if not db_domain:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found") raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
update_data = domain.dict(exclude_unset=True) db_domain.tenantid = domain.tenantid
db_domain.name=domain.name
for key, value in update_data.items(): db_domain.url=domain.url
if key != "id" and not (key == "kintonepwd" and (value is None or value == "")): db_domain.kintoneuser=domain.kintoneuser
setattr(db_domain, key, value) db_domain.kintonepwd = domain.kintonepwd
print(str(db_domain)) db_domain.updateuserid = userid
db_domain.update_time = datetime.now
db.add(db_domain) db.add(db_domain)
db.commit() db.commit()
db.refresh(db_domain) db.refresh(db_domain)

View File

@@ -1,8 +1,8 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey,Table
from sqlalchemy.ext.declarative import as_declarative from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from datetime import datetime from datetime import datetime
from app.db.session import Base
from app.core.security import chacha20Decrypt from app.core.security import chacha20Decrypt
@as_declarative() @as_declarative()
@@ -11,6 +11,21 @@ class Base:
create_time = Column(DateTime, default=datetime.now) create_time = Column(DateTime, default=datetime.now)
update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now) update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
userrole = Table(
"userrole",
Base.metadata,
Column("userid",Integer,ForeignKey("user.id")),
Column("roleid",Integer,ForeignKey("role.id")),
)
rolepermission = Table(
"rolepermission",
Base.metadata,
Column("roleid",Integer,ForeignKey("role.id")),
Column("permissionid",Integer,ForeignKey("permission.id")),
)
class User(Base): class User(Base):
__tablename__ = "user" __tablename__ = "user"
@@ -20,6 +35,25 @@ class User(Base):
hashed_password = Column(String(200), nullable=False) hashed_password = Column(String(200), nullable=False)
is_active = Column(Boolean, default=True) is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False) is_superuser = Column(Boolean, default=False)
roles = relationship("Role",secondary=userrole,back_populates="users")
class Role(Base):
__tablename__ = "role"
name = Column(String(100))
description = Column(String(255))
users = relationship("User",secondary=userrole,back_populates="roles")
permissions = relationship("Permission",secondary=rolepermission,back_populates="roles")
class Permission(Base):
__tablename__ = "permission"
menu = Column(String(100))
function = Column(String(255))
privilege = Column(String(100))
roles = relationship("Role",secondary=rolepermission,back_populates="permissions")
class App(Base): class App(Base):
__tablename__ = "app" __tablename__ = "app"
@@ -28,8 +62,25 @@ class App(Base):
appname = Column(String(200), nullable=False) appname = Column(String(200), nullable=False)
appid = Column(String(100), index=True, nullable=False) appid = Column(String(100), index=True, nullable=False)
version = Column(Integer) version = Column(Integer)
updateuser = Column(Integer,ForeignKey("user.id")) createuserid = Column(Integer,ForeignKey("user.id"))
user = relationship('User') updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class AppVersion(Base):
__tablename__ = "appversion"
domainurl = Column(String(200), nullable=False)
appname = Column(String(200), nullable=False)
appid = Column(String(100), index=True, nullable=False)
version = Column(Integer)
versionname = Column(String(200), nullable=False)
comment = Column(String(200), nullable=False)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class AppSetting(Base): class AppSetting(Base):
__tablename__ = "appsetting" __tablename__ = "appsetting"
@@ -64,7 +115,11 @@ class Flow(Base):
eventid = Column(String(100), index=True, nullable=False) eventid = Column(String(100), index=True, nullable=False)
domainurl = Column(String(200)) domainurl = Column(String(200))
name = Column(String(200)) name = Column(String(200))
content = Column(String) content = Column(String)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class FlowHistory(Base): class FlowHistory(Base):
__tablename__ = "flowhistory" __tablename__ = "flowhistory"
@@ -75,8 +130,11 @@ class FlowHistory(Base):
domainurl = Column(String(200)) domainurl = Column(String(200))
name = Column(String(200)) name = Column(String(200))
content = Column(String) content = Column(String)
createuser = Column(Integer,ForeignKey("user.id"))
version = Column(Integer) version = Column(Integer)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class Tenant(Base): class Tenant(Base):
__tablename__ = "tenant" __tablename__ = "tenant"
@@ -98,7 +156,10 @@ class Domain(Base):
def decrypt_kintonepwd(self): def decrypt_kintonepwd(self):
decrypted_pwd = chacha20Decrypt(self.kintonepwd) decrypted_pwd = chacha20Decrypt(self.kintonepwd)
return decrypted_pwd return decrypted_pwd
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class UserDomain(Base): class UserDomain(Base):
__tablename__ = "userdomain" __tablename__ = "userdomain"

View File

@@ -8,13 +8,26 @@ class Base(BaseModel):
create_time: datetime create_time: datetime
update_time: datetime update_time: datetime
class Permission(BaseModel):
id: int
menu:str
function:str
privilege:str
class Role(BaseModel):
id: int
name:str
description:str
permissions:t.List[Permission] = []
class UserBase(BaseModel): class UserBase(BaseModel):
email: str email: str
is_active: bool = True is_active: bool = True
is_superuser: bool = False is_superuser: bool = False
first_name: str = None first_name: str = None
last_name: str = None last_name: str = None
roles:t.List[Role] = []
class UserOut(UserBase): class UserOut(UserBase):
pass pass
@@ -54,13 +67,16 @@ class AppList(Base):
domainurl: str domainurl: str
appname: str appname: str
appid:str appid:str
updateuser: UserOut
version:int version:int
user:UserOut
class AppVersion(BaseModel): class AppVersion(BaseModel):
domainurl: str domainurl: str
appname: str appname: str
versionname: str
comment:str
appid:str appid:str
class TokenData(BaseModel): class TokenData(BaseModel):
id:int = 0 id:int = 0
@@ -106,9 +122,11 @@ class Action(BaseModel):
class ConfigDict: class ConfigDict:
orm_mode = True orm_mode = True
class FlowBase(BaseModel): class FlowIn(BaseModel):
flowid: str flowid: str
# domainurl:str
appid: str appid: str
appname:str
eventid: str eventid: str
name: str = None name: str = None
content: str = None content: str = None

View File

@@ -17,28 +17,38 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, onMounted, reactive, watchEffect } from 'vue' import { ref, onMounted, reactive, watchEffect, PropType } from 'vue'
import { api } from 'boot/axios'; import { api } from 'boot/axios';
interface IAppDisplay {
id: string;
name: string;
description: string;
createdate: string;
}
export default { export default {
name: 'AppSelectBox', name: 'AppSelectBox',
props: { props: {
name: String, name: String,
type: String, type: String,
filter: String, filter: String,
filterInitRowsFunc: {
type: Function as PropType<(app: IAppDisplay) => boolean>,
},
updateSelectApp: { updateSelectApp: {
type: Function type: Function
} }
}, },
setup(props) { setup(props) {
const columns = [ const columns = [
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true }, { name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true, sort: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10) },
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' }, { name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false }, { name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' } { name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
] ]
const isLoaded = ref(false); const isLoaded = ref(false);
const rows: any[] = reactive([]); const rows = reactive<IAppDisplay[]>([]);
const selected = ref([]) const selected = ref([])
watchEffect(()=>{ watchEffect(()=>{
@@ -49,12 +59,16 @@ export default {
onMounted(() => { onMounted(() => {
api.get('api/v1/allapps').then(res => { api.get('api/v1/allapps').then(res => {
res.data.apps.forEach((item: any) => { res.data.apps.forEach((item: any) => {
rows.push({ const row : IAppDisplay = {
id: item.appId, id: item.appId,
name: item.name, name: item.name,
description: item.description, description: item.description,
createdate: dateFormat(item.createdAt) createdate: dateFormat(item.createdAt)
}); }
if (props.filterInitRowsFunc && !props.filterInitRowsFunc(row)) {
return;
}
rows.push(row);
}); });
isLoaded.value = true; isLoaded.value = true;
}); });

View File

@@ -12,7 +12,7 @@
<slot></slot> <slot></slot>
</q-card-section> </q-card-section>
<q-card-actions v-if="!disableBtn" align="right" class="text-primary"> <q-card-actions v-if="!disableBtn" align="right" class="text-primary">
<q-btn flat label="確定" v-close-popup @click="CloseDialogue('OK')" /> <q-btn flat label="確定" :loading="okBtnLoading" :v-close-popup="okBtnAutoClose" @click="CloseDialogue('OK')" />
<q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" /> <q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
@@ -30,6 +30,11 @@ export default {
height:String, height:String,
minWidth:String, minWidth:String,
minHeight:String, minHeight:String,
okBtnLoading:Boolean,
okBtnAutoClose:{
type: Boolean,
default: true
},
disableBtn:{ disableBtn:{
type: Boolean, type: Boolean,
default: false default: false

View File

@@ -8,7 +8,7 @@
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination"> <q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">
<template v-slot:top> <template v-slot:top>
<q-btn disabled color="primary" :disable="loading" label="新規" @click="addRow" /> <q-btn color="primary" :disable="loading" label="新規" @click="showAddAppDialog" />
<q-space /> <q-space />
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索"> <q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
<template v-slot:append> <template v-slot:append>
@@ -26,15 +26,24 @@
<template v-slot:body-cell-actions="p"> <template v-slot:body-cell-actions="p">
<q-td :props="p"> <q-td :props="p">
<q-btn-group flat> <q-btn-group flat>
<q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="editFlow(p.row)" /> <q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="toEditFlowPage(p.row)" />
<q-btn disabled flat color="primary" padding="xs" size="1em" icon="history" @click="showHistory(p.row)" /> <q-btn disabled flat color="primary" padding="xs" size="1em" icon="history" @click="showHistory(p.row)" />
<q-btn disabled flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" /> <q-btn disabled flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" />
</q-btn-group> </q-btn-group>
</q-td> </q-td>
</template> </template>
</q-table> </q-table>
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeSelectAppDialog" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
<template v-slot:toolbar>
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="filter" :filterInitRowsFunc="filterInitRows" />
</show-dialog>
</div> </div>
</template> </template>
@@ -46,9 +55,12 @@ import { useFlowEditorStore } from 'stores/flowEditor';
import { router } from 'src/router'; import { router } from 'src/router';
import { date } from 'quasar' import { date } from 'quasar'
import { IManagedApp } from 'src/types/AppTypes'; import { IManagedApp } from 'src/types/AppTypes';
import ShowDialog from 'src/components/ShowDialog.vue';
import AppSelectBox from 'src/components/AppSelectBox.vue';
interface IAppDisplay{ interface IAppDisplay{
id:string; id:string;
sortId: number;
name:string; name:string;
url:string; url:string;
user:string; user:string;
@@ -65,7 +77,7 @@ const columns = [
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true }, { name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
{ name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true}, { name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true},
{ name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true}, { name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true},
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true}, { name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
{ name: 'actions', label: '操作', field: 'actions' } { name: 'actions', label: '操作', field: 'actions' }
]; ];
@@ -73,21 +85,21 @@ const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
const loading = ref(false); const loading = ref(false);
const filter = ref(''); const filter = ref('');
const rows = ref<IAppDisplay[]>([]); const rows = ref<IAppDisplay[]>([]);
const rowIds = new Set<string>();
const store = useFlowEditorStore(); const store = useFlowEditorStore();
const appDialog = ref();
const showSelectApp=ref(false);
const isAdding = ref(false);
const getApps = async () => { const getApps = async () => {
loading.value = true; loading.value = true;
rowIds.clear();
const result = await api.get('api/apps'); const result = await api.get('api/apps');
rows.value = result.data.map((item: IManagedApp) => { rows.value = result.data.map((item: IManagedApp) => {
return { rowIds.add(item.appid);
id: item.appid, return appToAppDisplay(item)
name: item.appname, }).sort((a: IAppDisplay, b: IAppDisplay) => a.sortId - b.sortId); // set default order
url: `${item.domainurl}/k/${item.appid}`,
user: `${item.user.first_name} ${item.user.last_name}` ,
updatetime:date.formatDate(item.update_time, 'YYYY/MM/DD HH:mm'),
version: Number(item.version)
}
}).sort((a: IAppDisplay, b: IAppDisplay) => numberStringSorting(a.id, b.id)); // set default order
loading.value = false; loading.value = false;
} }
@@ -100,8 +112,22 @@ watch(() => authStore.currentDomain.id, async () => {
await getApps(); await getApps();
}); });
const addRow = () => { const filterInitRows = (row: {id: string}) => {
return return !rowIds.has(row.id);
}
const showAddAppDialog = () => {
showSelectApp.value = true;
}
const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
showSelectApp.value = true;
if (val == 'OK' && appDialog.value.selected[0]) {
isAdding.value = true;
toEditFlowPage(appDialog.value.selected[0]);
}
showSelectApp.value = false;
isAdding.value = false;
} }
const removeRow = (app:IAppDisplay) => { const removeRow = (app:IAppDisplay) => {
@@ -112,7 +138,19 @@ const showHistory = (app:IAppDisplay) => {
return return
} }
const editFlow = (app:IAppDisplay) => { const appToAppDisplay = (app: IManagedApp) => {
return {
id: app.appid,
sortId: parseInt(app.appid, 10),
name: app.appname,
url: `${app.domainurl}/k/${app.appid}`,
user: `${app.updateuser.first_name} ${app.updateuser.last_name}` ,
updatetime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
version: app.version
}
}
const toEditFlowPage = (app:IAppDisplay) => {
store.setApp({ store.setApp({
appId: app.id, appId: app.id,
name: app.name name: app.name

View File

@@ -328,8 +328,22 @@ const fetchData = async () => {
} }
const fetchAppById = async(id: string) => { const fetchAppById = async(id: string) => {
const result = await api.get('api/apps'); try {
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp; const result = await api.get('api/apps');
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
} catch (e) {
console.error(e);
const result = await api.get(`api/v1/app?app=${id}`);
const data = result?.data;
if (data?.message) {
$q.notify({
type: 'negative',
caption: "エラー",
message: data.message
});
}
return { appid: data.appId, appname: data.name };
}
} }
const onClearFilter=()=>{ const onClearFilter=()=>{

View File

@@ -128,6 +128,7 @@ export const useFlowEditorStore = defineStore('flowEditor', {
const jsonData = { const jsonData = {
flowid: isNew ? flow.createNewId() : flow.id, flowid: isNew ? flow.createNewId() : flow.id,
appid: this.appInfo?.appId, appid: this.appInfo?.appId,
appname: this.appInfo?.name,
eventid: root?.name, eventid: root?.name,
name: root?.subTitle, name: root?.subTitle,
content: JSON.stringify(flow), content: JSON.stringify(flow),

View File

@@ -1,14 +1,14 @@
interface IUser { interface IUser {
first_name: string; first_name: string;
last_name: string; last_name: string;
email: string; email: string;
} }
export interface IManagedApp { export interface IManagedApp {
appid: string; appid: string;
appname: string; appname: string;
domainurl: string; domainurl: string;
version: string; version: string;
user: IUser; updateuser: IUser;
update_time: string; update_time: string;
} }