Add py api, WIP dl log

This commit is contained in:
pakintada@gmail.com 2023-09-20 13:35:36 +07:00
parent 35b8b3be57
commit b49b2235db
7 changed files with 159 additions and 111 deletions

View file

@ -67,6 +67,10 @@ const routes: Routes = [
}, },
], ],
}, },
{
path: 'log',
loadComponent: () => import('./features/changelog/changelog.component').then((m) => m.ChangelogComponent),
},
{ {
path: '**', path: '**',
pathMatch: 'full', pathMatch: 'full',

View file

@ -7,6 +7,8 @@ export class MergeServiceService {
master_version: number = 0; master_version: number = 0;
dev_version: number = 0; dev_version: number = 0;
output_path:string = "";
changelog_path:string = "";
constructor() { } constructor() { }
} }

View file

@ -26,12 +26,24 @@
<form class="space-y-6 p-3 bg-stone-500 rounded" [formGroup]="mergeForm" (ngSubmit)="fetchMerge()"> <form class="space-y-6 p-3 bg-stone-500 rounded" [formGroup]="mergeForm" (ngSubmit)="fetchMerge()">
<div class="flex"> <div class="flex">
<label class="flex-1 text-red-700 font-bold bg-yellow-100 rounded text-center" for="master_version">Master</label> <label class="flex-1 text-red-700 font-bold bg-yellow-100 rounded text-center" for="master_version">Master</label>
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="master_version" formControlName="master_version" type="text"> <input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="master_version" formControlName="master_version" type="text" required>
</div> </div>
<div class="flex"> <div class="flex">
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="dev_version">Dev</label> <label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="dev_version">Dev</label>
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="dev_version" formControlName="dev_version" type="text"> <input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="dev_version" formControlName="dev_version" type="text" required>
</div>
<!-- Output path -->
<div class="flex">
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="output_path">Output Path</label>
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="output_path" formControlName="output_path" type="text" required>
</div>
<!-- Changelog path -->
<div class="flex">
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="changelog_path">Changelog Path</label>
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="changelog_path" formControlName="changelog_path" type="text" required>
</div> </div>
<button class="button font-semibold bg-red-300 p-4 border border-collapse rounded-md" type="submit">Begin Merge</button> <button class="button font-semibold bg-red-300 p-4 border border-collapse rounded-md" type="submit">Begin Merge</button>

View file

@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { MergeServiceService } from './merge-service.service'; import { MergeServiceService } from './merge-service.service';
import { HttpClient } from '@angular/common/http';
@Component({ @Component({
selector: 'app-merge', selector: 'app-merge',
@ -17,13 +18,16 @@ export class MergeComponent {
mergeForm = this.formBuilder.group({ mergeForm = this.formBuilder.group({
master_version: 0, master_version: 0,
dev_version: 0 dev_version: 0,
output_path: "",
changelog_path: ""
}); });
constructor( constructor(
private targets: MergeServiceService, private targets: MergeServiceService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private httpClient: HttpClient,
){} ){}
private isException(value: any){ private isException(value: any){
@ -36,14 +40,47 @@ export class MergeComponent {
} }
this.targets.master_version = this.mergeForm.value.master_version!; this.targets.master_version = this.mergeForm.value.master_version!;
this.targets.dev_version = this.mergeForm.value.dev_version!; this.targets.dev_version = this.mergeForm.value.dev_version!;
this.targets.output_path = this.mergeForm.value.output_path!;
this.targets.changelog_path = this.mergeForm.value.changelog_path!;
// TODO: Fetch merge. Modify this to websocket // TODO: Fetch merge. Modify this to websocket
return fetch("http://localhost:3000/merge", {
method: "POST", this.httpClient.post("http://localhost:8080/merge", {
body: JSON.stringify({ master: this.targets.master_version,
master: this.targets.master_version, dev: this.targets.dev_version,
dev: this.targets.dev_version output: this.targets.output_path,
}) changelog: this.targets.changelog_path
}, {
withCredentials: true
}).subscribe({
next(value) {
console.log(value)
},
}) })
} }
downloadLogs(query: string){
let additionalParams:string = "?query=";
if(query != ""){
additionalParams += query
} else {
additionalParams = ""
}
this.httpClient.get("http://localhost:8080/dllog"+additionalParams, { responseType: 'blob' }).subscribe(
(data) => {
const blob = new Blob([data], { type: 'application/octet-stream' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'logfile.log';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
},
(error) => {
console.error('Error downloading log file: ',error);
}
)
}
} }

View file

@ -1,78 +1,22 @@
#!/usr/local/bin/python3
#!/usr/bin/python3
from __future__ import print_function
from functools import reduce
from operator import getitem
import os
import threading
import time
import sys
import subprocess
from io import StringIO
import datetime import datetime
from functools import reduce
import json import json
import string from operator import getitem
from datetime import datetime
import sys import sys
import os.path import os
import itertools
from google.auth.transport.requests import Request # /home/pakin/Codes/coffCfg/cofffeemachineConfig/coffeethai02_1550.json
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import google.auth
import UnifyGen
if sys.version_info[0] >= 3:
unicode = str
HomeDirectory = "/Users/wanloprungsiyangkul/"
CoffeeRecipeDirectory = "/Users/wanloprungsiyangkul/cofffeemachineConfig"
valid_len_product_code = len("12-01-02-0001")
def xl2int(s):
s = s.strip().upper()
return sum((ord(c)-ord('A')+1)*26**i
for i,c in enumerate(reversed(s)))
def GetDateTimeString(): def GetDateTimeString():
now = datetime.now() # current date and time now = datetime.datetime.now() # current date and time
date_time = now.strftime("%d-%b-%Y, %H:%M:%S") date_time = now.strftime("%d-%b-%Y, %H:%M:%S")
return date_time return date_time
HomeDirectory = "/home/pakin"
def ImportFileAndUpdateMenuName( recipe_version, menu_name_tsv, output_file): CoffeeRecipeDirectory = "/home/pakin/Codes/coffCfg/cofffeemachineConfig"
file_name_recipe = CoffeeRecipeDirectory + "/coffeethai02_" + str(recipe_version) + ".json" valid_len_product_code = len("12-01-02-0001")
print("file_name_recipe = " + file_name_recipe)
file_tsv = open( menu_name_tsv) #open requested file
with open( file_name_recipe, 'r') as JSON:
jdatclass = json.load(JSON)
print("configNumber =" + str( jdatclass["MachineSetting"]["configNumber"]))
jdatclass["Timestamp"] = GetDateTimeString()
Lines = file_tsv.readlines()
for line in Lines:
count += 1
sp = line.split('\t')
#for rp in jdatclass["Recipe01"]:
# if rp["productCode"] ==
with open( output_file, "w") as outfile_js:
json.dump( jdatclass, outfile_js,indent=4,ensure_ascii=False)
# events - save any action done by merge # events - save any action done by merge
events = [] events = []
@ -92,8 +36,6 @@ holdonPD = ""
def set_value_in_nested_map(key_list: list, value): def set_value_in_nested_map(key_list: list, value):
reduce(getitem, key_list[:-1], master_json)[key_list[-1]] = value reduce(getitem, key_list[:-1], master_json)[key_list[-1]] = value
# Get value of nested map by using keys from `key_list` with additional param `isMaster` for extra padding
# in case of different size of length between master and dev.
def get_value_in_nested_map(target_json: dict, key_list: list, isMaster=False): def get_value_in_nested_map(target_json: dict, key_list: list, isMaster=False):
if "Recipe01" in key_list: if "Recipe01" in key_list:
if isMaster: if isMaster:
@ -117,28 +59,24 @@ def decode_path(str_with_dot: str) -> list:
keylist.append(keyi) keylist.append(keyi)
return keylist return keylist
# Fetch the product code by giving the path and source
def fetch_pd(str_path: str, target_dict: dict) -> str: def fetch_pd(str_path: str, target_dict: dict) -> str:
keyList = decode_path(str_with_dot=str_path) keyList = decode_path(str_with_dot=str_path)
keyList.append("productCode") keyList.append("productCode")
# print("decode and append get : ",keyList) # print("decode and append get : ",keyList)
return get_value_in_nested_map(target_json=target_dict, key_list=keyList) return get_value_in_nested_map(target_json=target_dict, key_list=keyList)
# Fetch the material id by giving the path and source
def fetch_matId(str_path: str, target_dict:dict) -> str: def fetch_matId(str_path: str, target_dict:dict) -> str:
keyList = decode_path(str_with_dot=str_path) keyList = decode_path(str_with_dot=str_path)
keyList.append("materialPathId") keyList.append("materialPathId")
# print(keyList) # print(keyList)
return get_value_in_nested_map(target_json=target_dict, key_list=keyList) return get_value_in_nested_map(target_json=target_dict, key_list=keyList)
# Fetch the default id by giving the path and source
def fetch_defaultId(str_path: str, target_dict:dict) -> str: def fetch_defaultId(str_path: str, target_dict:dict) -> str:
keyList = decode_path(str_with_dot=str_path) keyList = decode_path(str_with_dot=str_path)
keyList.append("defaultIDSelect") keyList.append("defaultIDSelect")
# print(keyList) # print(keyList)
return get_value_in_nested_map(target_json=target_dict, key_list=keyList) return get_value_in_nested_map(target_json=target_dict, key_list=keyList)
# Fetch some parts of the path; Ex. Recipe01.8.recipes.0 --> Recipe01.8
def fetch_onlyMainMenuPath(str_with_dot: str): def fetch_onlyMainMenuPath(str_with_dot: str):
mainpath = decode_path(str_with_dot)[:2] mainpath = decode_path(str_with_dot)[:2]
# '.'.join(mainpath) # '.'.join(mainpath)
@ -219,9 +157,42 @@ def merge(args):
events.append(GetDateTimeString()+"\t[OUTPUT]\t\tFinished! write output to "+outfile_path+"\n") events.append(GetDateTimeString()+"\t[OUTPUT]\t\tFinished! write output to "+outfile_path+"\n")
events.append(GetDateTimeString()+"\t[LOG]\t\tLog is saved to "+changefile_path+"\n") events.append(GetDateTimeString()+"\t[LOG]\t\tLog is saved to "+changefile_path+"\n")
with open(changefile_path, "a+") as outlogfile: with open(changefile_path, "a+", encoding="utf-8") as outlogfile:
for event in events: for event in events:
outlogfile.write(event) outlogfile.write(event)
# Create html version
with open(changefile_path[:-3]+"html", "a+", encoding="utf-8") as outlogHtml:
for event in events:
# Create div
# print("Log as list: ",str(event).split("\t"))
html_string = "\t<div class=\"flex\">\n"
event_fraction = str(event).split("\t")
for i in event_fraction:
if i != "" and i != "\n" and i != "---":
if "|" in i and not i.endswith("|"):
# CHANGE
spl_text = i.split("|")
html_string += "\t\t<p>"+spl_text[0]+"</p>\n"
html_string += "\t\t<p>"+spl_text[1].replace("\n","")+"</p>\n"
elif ">>>" in i:
# INSERT
spl_text = i.split(">>>")
html_string += "\t\t<p>"+spl_text[0]+"</p>\n"
html_string += "\t\t<p>"+spl_text[1].replace("\n","")+"</p>\n"
elif i.endswith("|"):
html_string += "\t\t<p>"+i[:-1]+"</p>\n"
else:
# print("Default = ", i)
# Either version, status or others
html_string += "\t\t<p>"+i.replace("\n","")+"</p>\n"
html_string += "\t</div>\n"
outlogHtml.write(html_string)
# Merge dictionary - called by `merge`, using when the value is `dict` type # Merge dictionary - called by `merge`, using when the value is `dict` type
# original - main file to merge/append value into # original - main file to merge/append value into
@ -271,7 +242,7 @@ def merge_dicts(original:dict, updated:dict, path=""):
lc = last_change if last_change != "" else pre_timestamp lc = last_change if last_change != "" else pre_timestamp
try: try:
if debug == "debug": if debug == "debug":
print("Encounter path --> "+path, " | master: ",original[key]," dev: ", value) print("Encounter path --> "+current_path, " | master: ",original[key]," dev: ", value)
except: except:
pass pass
if "Recipe01" in current_path and not "recipes" in current_path: if "Recipe01" in current_path and not "recipes" in current_path:
@ -348,23 +319,13 @@ def merge_lists(original, updated, path=""):
pdadd += 1 pdadd += 1
original.append(item) original.append(item)
def main(): def main():
command_line = sys.argv[1] command_line = sys.argv[1]
if command_line == "name": print(sys.argv)
UnifyGen.GetFileSheet("menu-name", ".menu-name.tsv")
ImportFileAndUpdateMenuName( 529, ".menu-name.tsv", CoffeeRecipeDirectory + "/coffeethai02_530.json")
if command_line == "merge": if command_line == "merge":
dev_version = sys.argv[2]
merge(sys.argv[2:]) merge(sys.argv[2:])
if __name__ == "__main__": if __name__ == "__main__":
main() main()
#./import_price.py ~/cofffeemachineConfig/profile_MYR/profile_MYR_1.json ~/Downloads/MYS\ Taobin\ Menu\ with\ price.xlsx\ -\ 28_Mar_2023.tsv F ~/cofffeemachineConfig/profile_MYR/profile_MYR_1_3.json

View file

@ -9,6 +9,7 @@ import (
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"recipe-manager/config" "recipe-manager/config"
"recipe-manager/data" "recipe-manager/data"
"recipe-manager/routers" "recipe-manager/routers"
@ -77,9 +78,8 @@ func (s *Server) createHandler() {
AllowedOrigins: strings.Split(s.cfg.AllowedOrigins, ","), AllowedOrigins: strings.Split(s.cfg.AllowedOrigins, ","),
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
AllowCredentials: true, AllowCredentials: true,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, ExposedHeaders: []string{"Content-Type"},
MaxAge: 300, // Maximum value not ignored by any of major browsers AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
// Debug: true,
})) }))
database := data.NewData() database := data.NewData()
@ -92,6 +92,7 @@ func (s *Server) createHandler() {
// Protect Group // Protect Group
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(func(next http.Handler) http.Handler { r.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -121,11 +122,8 @@ func (s *Server) createHandler() {
}) })
}) })
// Recipe Router
rr := routers.NewRecipeRouter(database)
rr.Route(r)
r.Post("/merge", func(w http.ResponseWriter, r *http.Request) { r.Post("/merge", func(w http.ResponseWriter, r *http.Request) {
var targetMap map[string]interface{} var targetMap map[string]interface{}
err := json.NewDecoder(r.Body).Decode(&targetMap) err := json.NewDecoder(r.Body).Decode(&targetMap)
if err != nil { if err != nil {
@ -133,38 +131,72 @@ func (s *Server) createHandler() {
log.Fatalln("Merge request failed: ", err) log.Fatalln("Merge request failed: ", err)
return return
} }
log.Println(targetMap) repo_path := "cofffeemachineConfig/coffeethai02_"
master_version := targetMap["master"].(string) master_version := targetMap["master"].(string)
dev_version := targetMap["dev"].(string) dev_version := targetMap["dev"].(string)
output_path := targetMap["output"].(string)
changelog_path := targetMap["changelog"].(string)
// find target file in the cofffeemachineConfig // find target file in the cofffeemachineConfig
if _, err := os.Stat("coffeemachineConfig/coffeethai02_" + master_version + ".json"); err != nil { if _, err := os.Stat(repo_path + master_version + ".json"); err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
log.Fatalln("Merge request failed. Master file not found: ", err) log.Fatalln("Merge request failed. Master file not found: ", err)
return return
} }
if _, err := os.Stat("coffeemachineConfig/coffeethai02_" + dev_version + ".json"); err != nil { if _, err := os.Stat(repo_path + dev_version + ".json"); err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
log.Fatalln("Merge request failed. Dev file not found: ", err) log.Fatalln("Merge request failed. Dev file not found: ", err)
return return
} }
repo_path := "coffeemachineConfig/coffeethai02_"
master_path := repo_path + master_version + ".json" master_path := repo_path + master_version + ".json"
dev_path := repo_path + dev_version + ".json" dev_path := repo_path + dev_version + ".json"
// output path // // output path
output_path := "" // output_path := ""
// changelog path // // changelog path
changelog_path := "" // changelog_path := ""
// TODO: Call merge api if found // TODO: Call merge api if found
err = exec.Command("python", "merge", master_path, dev_path, output_path, changelog_path).Run()
// lookup for python exec
py_exec, err := exec.LookPath("python")
if err != nil {
log.Fatalln("Python error: ", err)
} else {
py_exec, err = filepath.Abs(py_exec)
}
log.Println("Found python exec: ", py_exec)
// target api file
merge_api, api_err := os.Open("./python_api/merge_recipe.py")
if api_err != nil {
log.Fatalln("Merge request failed. Python api error: ", api_err)
}
log.Println("Locate python api", merge_api.Name())
cmd := exec.Command(py_exec, merge_api.Name(), "merge", master_path, dev_path, output_path, changelog_path, "debug")
log.Println("Run merge command", cmd)
err = cmd.Run()
if err != nil { if err != nil {
log.Fatalln("Merge request failed. Python merge failed: ", err) log.Fatalln("Merge request failed. Python merge failed: ", err)
} }
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"message": "Merge success"})
}) })
r.Get("/dllog", func(w http.ResponseWriter, r *http.Request) {
})
// Recipe Router
rr := routers.NewRecipeRouter(database)
rr.Route(r)
}) })
r.NotFound(func(w http.ResponseWriter, r *http.Request) { r.NotFound(func(w http.ResponseWriter, r *http.Request) {