diff --git a/backend/app/api/api_v1/routers/kintone.py b/backend/app/api/api_v1/routers/kintone.py index 1203c0a..c7e9ad4 100644 --- a/backend/app/api/api_v1/routers/kintone.py +++ b/backend/app/api/api_v1/routers/kintone.py @@ -8,6 +8,141 @@ import app.core.config as c kinton_router = r = APIRouter() +def getfieldsfromexcel(df): + appname = df.iloc[0,2] + col=[] + for row in range(5,len(df)): + if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE: + continue + p=[] + for column in range(1,7): + if(not pd.isna(df.iloc[row,column])): + if(property[column-1]=="options"): + o=[] + for v in df.iloc[row,column].split(','): + o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}") + p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}") + elif(property[column-1]=="required"): + p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}") + else: + p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"") + col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}") + fields = ",".join(col).replace("False","false").replace("True","true") + return json.loads(f"{{{fields}}}") + +def getsettingfromexcel(df): + appname = df.iloc[0,2] + des = df.iloc[2,2] + return {"name":appname,"description":des} + +def getsettingfromkintone(app:str): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} + params = {"app":app} + url = f"{c.BASE_URL}{c.API_V1_STR}/app/settings.json" + r = httpx.get(url,headers=headers,params=params) + return r.json() + + +def analysesettings(excel,kintone): + updatesettings={} + updates = excel.keys() & kintone.keys() + for key in updates: + if excel[key] != kintone[key]: + updatesettings[key] = excel[key] + return updatesettings + +def createkintoneapp(name:str): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + data = {"name":name} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json" + r = httpx.post(url,headers=headers,data=json.dumps(data)) + return r.json() + +def updateappsettingstokintone(app:str,updates:dict): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/settings.json" + data = {"app":app} + data.update(updates) + r = httpx.put(url,headers=headers,data=json.dumps(data)) + return r.json() + +def addfieldstokintone(app:str,fields:dict,revision:str = None): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json" + if revision != None: + data = {"app":app,"revision":revision,"properties":fields} + else: + data = {"app":app,"properties":fields} + r = httpx.post(url,headers=headers,data=json.dumps(data)) + return r.json() + +def updatefieldstokintone(app:str,revision:str,fields:dict): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json" + data = {"app":app,"properties":fields} + r = httpx.put(url,headers=headers,data=json.dumps(data)) + return r.json() + +def deletefieldsfromkintone(app:str,revision:str,fields:dict): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json" + params = {"app":app,"revision":revision,"fields":fields} + #r = httpx.delete(url,headers=headers,content=json.dumps(params)) + r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params)) + return r.json() + +def deoployappfromkintone(app:str,revision:str): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} + url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json" + data = {"apps":[{"app":app,"revision":revision}],"revert": False} + r = httpx.post(url,headers=headers,data=json.dumps(data)) + return r.json + +def getfieldsfromkintone(app): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} + params = {"app":app} + url = f"{c.BASE_URL}{c.API_V1_STR}/app/form/fields.json" + r = httpx.get(url,headers=headers,params=params) + return r.json() + +def analysefields(excel,kintone): + updatefields={} + addfields={} + delfields=[] + updates = excel.keys() & kintone.keys() + adds = excel.keys() - kintone.keys() + dels = kintone.keys() - excel.keys() + for key in updates: + for p in property: + if excel[key].get(p) != None and kintone[key][p] != excel[key][p]: + updatefields[key] = excel[key] + break + for key in adds: + addfields[key] = excel[key] + for key in dels: + if kintone[key]["type"] in c.KINTONE_FIELD_TYPE: + delfields.append(key) + + return {"update":updatefields,"add":addfields,"del":delfields} + + +@r.post("/test",) +async def test(file:UploadFile= File(...),app:str=None): + if file.filename.endswith('.xlsx'): + try: + content = await file.read() + df = pd.read_excel(BytesIO(content)) + excel = getfieldsfromexcel(df) + if(app != None): + kintone = getfieldsfromkintone(app) + fields = analysefields(excel,kintone["properties"]) + except Exception as e: + raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}") + else: + raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file") + + return fields + @r.post("/upload",) async def upload(files:t.List[UploadFile] = File(...)): @@ -33,6 +168,18 @@ async def allapps(): r = httpx.get(url,headers=headers) return r.json() +@r.get("/appfields") +async def appfields(app:str): + return getfieldsfromkintone(app) + + +@r.get("/alljscs") +async def alljscs(app:str): + headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE} + url = f"{c.BASE_URL}{c.API_V1_STR}/app/customize.json" + params = {"app":app} + r = httpx.get(url,headers=headers,params=params) + return r.json() @r.post("/createapp",) async def createapp(name:str): @@ -55,97 +202,69 @@ async def createappfromexcel(files:t.List[UploadFile] = File(...)): if file.filename.endswith('.xlsx'): try: content = await file.read() - #アプリ名 df = pd.read_excel(BytesIO(content)) - # print(df) + #アプリ名 appname = df.iloc[0,2] - col=[] - for row in range(5,len(df)): - if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE: - continue - p=[] - for column in range(1,7): - if(not pd.isna(df.iloc[row,column])): - if(property[column-1]=="options"): - o=[] - for v in df.iloc[row,column].split(','): - o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}") - p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}") - elif(property[column-1]=="required"): - p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}") - else: - p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"") - col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}") - - headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} - data = {"name":appname} - url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json" - r = httpx.post(url,headers=headers,data=json.dumps(data)) - result1 = r.json() - if result1.get("app") != None: - url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json" - form = f"{{\"app\":{result1['app']},\"properties\":{{{','.join(col)}}}}}".replace("False","false").replace("True","true") - print(form) - data = json.loads(form) - r = httpx.post(url,headers=headers,data=json.dumps(data)) - result2 = r.json() - if result2.get("revision") != None: - url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json" - data = {"apps":[{"app":result1["app"],"revision":result2["revision"]}],"revert": False} - r = httpx.post(url,headers=headers,data=json.dumps(data)) + desc = df.iloc[2,2] + result = {"app":0,"revision":0,"msg":""} + fields = getfieldsfromexcel(df) + app = createkintoneapp(appname) + if app.get("app") != None: + result["app"] = app["app"] + app = updateappsettingstokintone(result["app"],{"description":desc}) + if app.get("revision") != None: + result["revision"] = app["revision"] + app = addfieldstokintone(result["app"],fields) + if app.get("revision") != None: + result["revision"] = app["revision"] + deoployappfromkintone(result["app"],result["revision"]) except Exception as e: raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}") else: raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file") - return {"app":result1["app"],"revision":result2["revision"]} + return result @r.post("/updateappfromexcel",) -async def updateappfromexcel(app:str,revision:str,files:t.List[UploadFile] = File(...)): +async def updateappfromexcel(app:str,files:t.List[UploadFile] = File(...)): for file in files: if file.filename.endswith('.xlsx'): try: content = await file.read() - #アプリ名 df = pd.read_excel(BytesIO(content)) - # print(df) - appname = df.iloc[0,2] - col=[] - for row in range(5,len(df)): - if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE: - continue - p=[] - for column in range(1,7): - if(not pd.isna(df.iloc[row,column])): - if(property[column-1]=="options"): - o=[] - for v in df.iloc[row,column].split(','): - o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}") - p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}") - elif(property[column-1]=="required"): - p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}") - else: - p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"") - col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}") - - headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"} - - url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json" - form = f"{{\"app\":{app},\"revision\": {revision},\"properties\":{{{','.join(col)}}}}}".replace("False","false").replace("True","true") - print(form) - data = json.loads(form) - r = httpx.put(url,headers=headers,data=json.dumps(data)) - result = r.json() - if result.get("revision") != None: - url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json" - data = {"apps":[{"app":app,"revision":result["revision"]}],"revert": False} - r = httpx.post(url,headers=headers,data=json.dumps(data)) + excel = getsettingfromexcel(df) + kintone= getsettingfromkintone(app) + settings = analysesettings(excel,kintone) + excel = getfieldsfromexcel(df) + kintone = getfieldsfromkintone(app) + revision = kintone["revision"] + fields = analysefields(excel,kintone["properties"]) + result = {"app":app,"revision":revision,"msg":"No Update"} + deploy = False + if len(fields["update"]) > 0: + result = updatefieldstokintone(app,revision,fields["update"]) + revision = result["revision"] + deploy = True + if len(fields["add"]) > 0: + result = addfieldstokintone(app,fields["add"],revision) + revision = result["revision"] + deploy = True + if len(fields["del"]) > 0: + result = deletefieldsfromkintone(app,revision,fields["del"]) + revision = result["revision"] + deploy = True + if len(settings) > 0: + result = updateappsettingstokintone(app,settings) + revision = result["revision"] + deploy = True + if deploy: + result = deoployappfromkintone(app,revision) except Exception as e: raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}") else: raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file") - return r.json() + return result