⚠️ WIP migrating tmp to patch
This commit is contained in:
parent
89ce1f361c
commit
fed315367a
13 changed files with 317 additions and 270 deletions
|
|
@ -34,7 +34,19 @@
|
|||
alt="Tao Bin Logo"
|
||||
/>
|
||||
</a>
|
||||
<!-- Redis Status -->
|
||||
<div class="p-2 rounded-lg border border-double border-black" [ngStyle]="redisStatus == 'Online'?{'background-color':'greenyellow'}:{'background-color':'tomato'}">
|
||||
<p class="text-center font-bold">{{redisStatus}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File Change Status -->
|
||||
<button *ngIf="showDetectChanges">
|
||||
|
||||
<h1 class="text-center font-extrabold text-2xl text-red-500 animate-pulse">Detect Changes! Click</h1>
|
||||
|
||||
</button>
|
||||
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center ml-3">
|
||||
<div class="flex flex-row">
|
||||
|
|
@ -155,3 +167,5 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Modal-->
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||
import { DatePipe, NgFor, NgIf, NgOptimizedImage } from '@angular/common';
|
||||
import { CommonModule, DatePipe, NgFor, NgIf, NgOptimizedImage } from '@angular/common';
|
||||
import { GoogleButtonComponent } from 'src/app/shared/googleButton/googleButton.component';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { User } from '../models/user.model';
|
||||
import { Subject, Subscription, map, share, takeUntil, timer } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { RecipeService } from '../services/recipe.service';
|
||||
import { AsyncStorage } from 'src/app/shared/helpers/asyncStorage';
|
||||
import { MergeComponent } from "../../features/merge/merge.component";
|
||||
|
||||
interface MenuItem {
|
||||
name: string;
|
||||
|
|
@ -13,17 +18,19 @@ interface MenuItem {
|
|||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterModule,
|
||||
NgFor,
|
||||
NgIf,
|
||||
GoogleButtonComponent,
|
||||
DatePipe,
|
||||
NgOptimizedImage,
|
||||
],
|
||||
selector: 'app-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterModule,
|
||||
NgFor,
|
||||
NgIf,
|
||||
GoogleButtonComponent,
|
||||
DatePipe,
|
||||
NgOptimizedImage,
|
||||
CommonModule,
|
||||
MergeComponent
|
||||
]
|
||||
})
|
||||
export class LayoutComponent implements OnInit, OnDestroy {
|
||||
current_department = this._router.snapshot.paramMap.get('department')!;
|
||||
|
|
@ -51,12 +58,17 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
|||
user: User | null = null;
|
||||
exit$ = new Subject<void>();
|
||||
|
||||
redisStatus:string = "Offline";
|
||||
showDetectChanges: boolean = false;
|
||||
|
||||
constructor(
|
||||
private _userService: UserService,
|
||||
private _router: ActivatedRoute
|
||||
private _router: ActivatedRoute,
|
||||
private _httpClient: HttpClient,
|
||||
private _recipeService: RecipeService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
async ngOnInit(): Promise<void> {
|
||||
this._userService.currentUser
|
||||
.pipe(takeUntil(this.exit$))
|
||||
.subscribe((user) => (this.user = user));
|
||||
|
|
@ -69,6 +81,32 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
|||
.subscribe((time) => {
|
||||
this.date = time;
|
||||
});
|
||||
|
||||
this._httpClient.get(environment.api + "/health/redis").subscribe((status) => {
|
||||
this.redisStatus = (status as any)["status"];
|
||||
});
|
||||
|
||||
// check if saves existed
|
||||
this._recipeService.getSavedTmp(
|
||||
await this._recipeService.getCurrentCountry(),
|
||||
this._recipeService.getCurrentFile()
|
||||
).subscribe({
|
||||
next: async (data: any) => {
|
||||
if(data != undefined && typeof data === 'object'){
|
||||
// check if attr exists
|
||||
if(data.files != null){
|
||||
this.showDetectChanges = true;
|
||||
await AsyncStorage.setItem("detectChanges", "true");
|
||||
} else {
|
||||
this.showDetectChanges = false;
|
||||
await AsyncStorage.setItem("detectChanges", "false");
|
||||
}
|
||||
} else {
|
||||
this.showDetectChanges = false;
|
||||
await AsyncStorage.setItem("detectChanges", "false");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ export class RecipeService {
|
|||
return this.tmp_files;
|
||||
}
|
||||
|
||||
constructor(private _httpClient: HttpClient, private _route: ActivatedRoute) {}
|
||||
constructor(
|
||||
private _httpClient: HttpClient,
|
||||
private _route: ActivatedRoute
|
||||
) {}
|
||||
|
||||
getRecipesDashboard(
|
||||
params: any = {
|
||||
|
|
@ -95,8 +98,9 @@ export class RecipeService {
|
|||
);
|
||||
}
|
||||
|
||||
async getRecipeDetail(productCode: string): Promise<Observable<RecipeDetail>> {
|
||||
|
||||
async getRecipeDetail(
|
||||
productCode: string
|
||||
): Promise<Observable<RecipeDetail>> {
|
||||
let asyncCountry = await this.getCurrentCountry(this.department!);
|
||||
console.log('get detail by asyncCountry', asyncCountry);
|
||||
|
||||
|
|
@ -115,8 +119,7 @@ export class RecipeService {
|
|||
|
||||
async getRecipeDetailMat(
|
||||
productCode: string
|
||||
): Promise<Observable<{ result: RecipeDetailMat[]; }>> {
|
||||
|
||||
): Promise<Observable<{ result: RecipeDetailMat[] }>> {
|
||||
let asyncCountry = await this.getCurrentCountry(this.department!);
|
||||
|
||||
return this._httpClient.get<{ result: RecipeDetailMat[] }>(
|
||||
|
|
@ -133,10 +136,8 @@ export class RecipeService {
|
|||
}
|
||||
|
||||
getCurrentFile(): string {
|
||||
|
||||
// TODO: get default from server
|
||||
|
||||
|
||||
const currentRecipeFile = localStorage.getItem('currentRecipeFile');
|
||||
if (currentRecipeFile) {
|
||||
return currentRecipeFile;
|
||||
|
|
@ -150,9 +151,7 @@ export class RecipeService {
|
|||
}
|
||||
|
||||
async getCurrentCountry(department?: string): Promise<string> {
|
||||
|
||||
if(department){
|
||||
|
||||
if (department) {
|
||||
// translate back to full name
|
||||
let fullname = getCountryMapSwitcher(department);
|
||||
|
||||
|
|
@ -167,7 +166,9 @@ export class RecipeService {
|
|||
|
||||
// const currentRecipeCountry = localStorage.getItem('currentRecipeCountry');
|
||||
|
||||
const currentRecipeCountry = await AsyncStorage.getItem<string>('currentRecipeCountry');
|
||||
const currentRecipeCountry = await AsyncStorage.getItem<string>(
|
||||
'currentRecipeCountry'
|
||||
);
|
||||
if (currentRecipeCountry) {
|
||||
return currentRecipeCountry;
|
||||
}
|
||||
|
|
@ -275,13 +276,37 @@ export class RecipeService {
|
|||
);
|
||||
}
|
||||
|
||||
async getRawRecipeOfProductCode(country: string, filename: string, productCode: string): Promise<Observable<{}>> {
|
||||
async getRawRecipeOfProductCode(
|
||||
country: string,
|
||||
filename: string,
|
||||
productCode: string
|
||||
): Promise<Observable<{}>> {
|
||||
return this._httpClient.get<{}>(
|
||||
environment.api + '/recipes/' + country + '/' + filename + '/' + productCode + '/raw_full',
|
||||
environment.api +
|
||||
'/recipes/' +
|
||||
country +
|
||||
'/' +
|
||||
filename +
|
||||
'/' +
|
||||
productCode +
|
||||
'/raw_full',
|
||||
{
|
||||
withCredentials: true,
|
||||
responseType: 'json',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async getPatchListOfCurrentFile(
|
||||
country: string,
|
||||
filename: string
|
||||
): Promise<Observable<any>> {
|
||||
|
||||
console.log("try get patches", country, filename);
|
||||
|
||||
return this._httpClient.get<any>(
|
||||
environment.api + '/recipes/patch/get/' + country + '/' + filename ,
|
||||
{ withCredentials: true, responseType: 'json' }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { MergeComponent } from '../merge/merge.component';
|
||||
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from 'src/environments/environment.development';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
|
@ -10,7 +10,7 @@ import { FetchLogService } from 'src/app/shared/services/fetch-log.service';
|
|||
standalone: true,
|
||||
templateUrl: './changelog.component.html',
|
||||
styleUrls: ['./changelog.component.css'],
|
||||
imports: [CommonModule, MergeComponent],
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class ChangelogComponent {
|
||||
public displayableLogs: string[] = [];
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MergeServiceService } from './merge-service.service';
|
||||
|
||||
describe('MergeServiceService', () => {
|
||||
let service: MergeServiceService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(MergeServiceService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MergeServiceService {
|
||||
|
||||
master_version: number = 0;
|
||||
dev_version: number = 0;
|
||||
output_path:string = "";
|
||||
changelog_path:string = "";
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
|
@ -1,55 +1 @@
|
|||
|
||||
<div class="flex-3 bg-stone-400 h-screen justify-centers items-center">
|
||||
|
||||
<h3 class="text-2xl text-center py-4 font-semibold">Merge 2 json</h3>
|
||||
|
||||
<div class="bg-stone-600 p-1 m-2 rounded-md">
|
||||
<div class="bg-stone-500 m-2 rounded-md">
|
||||
<p class="px-1 py-5 font-semibold">
|
||||
❓ What does this function do?
|
||||
</p>
|
||||
<div class="bg-stone-300 rounded">
|
||||
<p class="px-2 ">
|
||||
Apply changes from the `dev` version
|
||||
<br>into the `master` version
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-stone-200 p-1 m-2 rounded-md">
|
||||
<p class="px-2 py-4 text-md text-center font-bold">
|
||||
❗Beware❗
|
||||
<br>`master` = base version
|
||||
<br>`dev` = your version
|
||||
</p>
|
||||
</div>
|
||||
<form class="space-y-6 p-3 bg-stone-500 rounded" [formGroup]="mergeForm" (ngSubmit)="fetchMerge()">
|
||||
<div class="flex">
|
||||
<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" required>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<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" required>
|
||||
</div>
|
||||
|
||||
<!-- Output path -->
|
||||
<div class="flex">
|
||||
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="output_path">Output Path (.json)</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 (.json)</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>
|
||||
|
||||
<button class="button font-semibold bg-red-300 p-4 border border-collapse rounded-md" type="submit">Begin Merge</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<p>merge works!</p>
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MergeComponent } from './merge.component';
|
||||
|
||||
describe('MergeComponent', () => {
|
||||
let component: MergeComponent;
|
||||
let fixture: ComponentFixture<MergeComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [MergeComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(MergeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,90 +1,31 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MergeServiceService } from './merge-service.service';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { environment } from 'src/environments/environment.development';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ChangelogComponent } from '../changelog/changelog.component';
|
||||
import { FetchLogService } from 'src/app/shared/services/fetch-log.service';
|
||||
import { RecipeService } from 'src/app/core/services/recipe.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-merge',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, ChangelogComponent],
|
||||
imports: [CommonModule],
|
||||
templateUrl: './merge.component.html',
|
||||
styleUrls: ['./merge.component.css']
|
||||
})
|
||||
export class MergeComponent<T> {
|
||||
export class MergeComponent implements OnInit {
|
||||
|
||||
exceptionValues = [0, null, undefined]
|
||||
|
||||
mergeForm = this.formBuilder.group({
|
||||
master_version: 0,
|
||||
dev_version: 0,
|
||||
output_path: "",
|
||||
changelog_path: ""
|
||||
});
|
||||
|
||||
default_output_path = "cofffeemachineConfig/merge/"
|
||||
default_changelog_path = "cofffeemachineConfig/changelog/"
|
||||
|
||||
mergeLogs: Map<string, string> | void | undefined
|
||||
patchMap: any = {}
|
||||
|
||||
constructor(
|
||||
private targets: MergeServiceService,
|
||||
private formBuilder: FormBuilder,
|
||||
private httpClient: HttpClient,
|
||||
private chlog: ChangelogComponent
|
||||
){
|
||||
// Default fetching logs
|
||||
private _recipeService: RecipeService
|
||||
) { }
|
||||
|
||||
// fetch html
|
||||
// this.fetchLogsToDisplay("", true, false);
|
||||
// // fetch log file
|
||||
// this.fetchLogsToDisplay("", false, false);
|
||||
// // fetch json
|
||||
// this.mergeLogs = this.fetchLogsToDisplay("", false, true);
|
||||
async ngOnInit(): Promise<void> {
|
||||
(await this._recipeService.getPatchListOfCurrentFile(
|
||||
await this._recipeService.getCurrentCountry(),
|
||||
this._recipeService.getCurrentFile()
|
||||
)).subscribe({
|
||||
next: (data: any) => {
|
||||
this.patchMap = data;
|
||||
console.log("patches",this.patchMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private isException(value: any){
|
||||
return this.exceptionValues.includes(value)
|
||||
}
|
||||
|
||||
fetchMerge(){
|
||||
if(this.isException(this.mergeForm.value.master_version) || this.isException(this.mergeForm.value.dev_version)){
|
||||
return
|
||||
}
|
||||
this.targets.master_version = this.mergeForm.value.master_version!;
|
||||
this.targets.dev_version = this.mergeForm.value.dev_version!;
|
||||
this.targets.output_path = this.default_output_path + this.mergeForm.value.output_path!;
|
||||
this.targets.changelog_path = this.default_changelog_path + this.mergeForm.value.changelog_path!;
|
||||
|
||||
// TODO: Fetch merge. Modify this to websocket
|
||||
this.httpClient.post<T>(environment.api+"/merge", {
|
||||
master: this.targets.master_version,
|
||||
dev: this.targets.dev_version,
|
||||
output: this.targets.output_path,
|
||||
changelog: this.targets.changelog_path
|
||||
}, {
|
||||
withCredentials: true
|
||||
}).subscribe({
|
||||
next: (value: T) => {
|
||||
console.log(value)
|
||||
if(typeof value === "object" && value !== null){
|
||||
if("message" in value){
|
||||
// fetch html
|
||||
// this.fetchLogsToDisplay("", true, false);
|
||||
// fetch log file
|
||||
// this.fetchLogsToDisplay("", false, false);
|
||||
// fetch json
|
||||
this.mergeLogs = new FetchLogService(this.httpClient).fetchLogsToDisplay("", false, true,this.targets.changelog_path);
|
||||
this.chlog.fetchLoglist();
|
||||
this.chlog.translateLogDirToString();
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
|
||||
savedTmpfiles: any[] = [];
|
||||
saveTab: boolean = false;
|
||||
showSaveNoti: boolean = true;
|
||||
showSaveNoti: boolean = false;
|
||||
|
||||
department: string = this.route.parent!.snapshot.params['department'];
|
||||
copyList: any[] = [];
|
||||
|
|
@ -197,7 +197,7 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
})
|
||||
);
|
||||
|
||||
// FIXME: Lag assigned
|
||||
// : Lag assigned
|
||||
|
||||
this.recipesDashboard$.subscribe(async (data) => {
|
||||
this.currentVersion = data.configNumber;
|
||||
|
|
@ -241,37 +241,37 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
|
||||
// end of FIXME
|
||||
|
||||
this._recipeService
|
||||
.getSavedTmp(
|
||||
await this._recipeService.getCurrentCountry(this.department),
|
||||
this._recipeService.getCurrentFile()
|
||||
)
|
||||
.subscribe({
|
||||
next: (files: any) => {
|
||||
console.log('Obtain saves: ', typeof files, files);
|
||||
this.showSaveNoti = false;
|
||||
if (files != undefined && typeof files === 'object') {
|
||||
if (files.files != null) {
|
||||
console.log(
|
||||
'Obtain saves object: ',
|
||||
files.files[0],
|
||||
typeof files
|
||||
);
|
||||
this.savedTmpfiles = files.files;
|
||||
} else {
|
||||
this.showSaveNoti = false;
|
||||
this.savedTmpfiles = [];
|
||||
console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||
}
|
||||
// let svf = (document.getElementById('select_savefile_modal') as HTMLInputElement)!.checked;
|
||||
// console.log("isSavedModalOpened",svf)
|
||||
} else {
|
||||
this.showSaveNoti = false;
|
||||
this.savedTmpfiles = [];
|
||||
console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||
}
|
||||
},
|
||||
});
|
||||
// this._recipeService
|
||||
// .getSavedTmp(
|
||||
// await this._recipeService.getCurrentCountry(this.department),
|
||||
// this._recipeService.getCurrentFile()
|
||||
// )
|
||||
// .subscribe({
|
||||
// next: (files: any) => {
|
||||
// console.log('Obtain saves: ', typeof files, files);
|
||||
// this.showSaveNoti = false;
|
||||
// if (files != undefined && typeof files === 'object') {
|
||||
// if (files.files != null) {
|
||||
// console.log(
|
||||
// 'Obtain saves object: ',
|
||||
// files.files[0],
|
||||
// typeof files
|
||||
// );
|
||||
// this.savedTmpfiles = files.files;
|
||||
// } else {
|
||||
// this.showSaveNoti = false;
|
||||
// this.savedTmpfiles = [];
|
||||
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||
// }
|
||||
// // let svf = (document.getElementById('select_savefile_modal') as HTMLInputElement)!.checked;
|
||||
// // console.log("isSavedModalOpened",svf)
|
||||
// } else {
|
||||
// this.showSaveNoti = false;
|
||||
// this.savedTmpfiles = [];
|
||||
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
|
||||
(await this._materialService.getMaterialCodes())
|
||||
.pipe(
|
||||
|
|
|
|||
|
|
@ -135,3 +135,39 @@ func (r *RedisCli) SetKeyTimeout(key string, value interface{}, timeout int) err
|
|||
fmt.Println("error on EXPIRE ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *RedisCli) KeyList() ([]string, error) {
|
||||
// if cannot pass healthcheck, return err
|
||||
if err := r.HealthCheck(); err != nil {
|
||||
fmt.Println("HS> KEYS error ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keys := r.Client.Keys(context.Background(), "*")
|
||||
|
||||
return keys.Result()
|
||||
}
|
||||
|
||||
// list operations
|
||||
|
||||
func (r *RedisCli) GetList(key string) ([]string, error) {
|
||||
// if cannot pass healthcheck, return err
|
||||
if err := r.HealthCheck(); err != nil {
|
||||
fmt.Println("HS> List.GET error ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Client.LRange(context.Background(), key, 0, -1).Result()
|
||||
}
|
||||
|
||||
func (r *RedisCli) Add(key string, value interface{}) error {
|
||||
// if cannot pass healthcheck, return err
|
||||
if err := r.HealthCheck(); err != nil {
|
||||
fmt.Println("HS> List.ADD error ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err := r.Client.RPush(context.Background(), key, value)
|
||||
|
||||
return err.Err()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ func (rr *RecipeRouter) Route(r chi.Router) {
|
|||
|
||||
r.Get("/saved/{country}/{filename_version_only}", rr.getSavedRecipes)
|
||||
|
||||
r.Get("/patch/get/{country}/{filename}", rr.getSavedAsPatches)
|
||||
|
||||
r.Get("/departments", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
|
||||
|
|
@ -447,6 +449,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
|||
tempRecipe := models.Recipe01{}
|
||||
tempRecipe = tempRecipe.FromMap(changeMap)
|
||||
rr.data.SetValuesToRecipe(targetRecipe.Recipe01, tempRecipe)
|
||||
|
||||
rr.taoLogger.Log.Debug("ApplyChange", zap.Any("status", "passed"))
|
||||
|
||||
// check if changed
|
||||
|
|
@ -462,7 +465,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// gen hash
|
||||
commit_hash, err := data.HashCommit(8)
|
||||
rr.cache_db.SetToKey(commit_hash, targetRecipe)
|
||||
// rr.cache_db.SetToKey(commit_hash, targetRecipe)
|
||||
|
||||
commit := data.CommitLog{
|
||||
|
||||
|
|
@ -474,31 +477,68 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
|||
Relation: filename,
|
||||
}
|
||||
|
||||
// ------------------------ SKIP THIS ------------------------
|
||||
// TODO: save only changes.
|
||||
|
||||
// get new tempfile name if redis is connected;
|
||||
|
||||
productCodeNoSpl := strings.ReplaceAll(changes.ProductCode, "-", "")
|
||||
patchName := "Recipe_" + productCodeNoSpl + "-" + commit_hash + "_" + filename + ".patch"
|
||||
|
||||
// if cache service online
|
||||
if rr.cache_db.HealthCheck() == nil {
|
||||
// do change mode
|
||||
commit.Change_file = patchName
|
||||
commit.Relation = commit.Relation + "/patch"
|
||||
|
||||
// add to patch list of that filename
|
||||
// filename:patchlist
|
||||
err := rr.cache_db.Add(countryID+"."+filename+":patchList", commit.Id)
|
||||
|
||||
// add failed
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to add to patch list")))
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// this following codes do need users to pass update to each other
|
||||
// otherwise, the changes will diverge
|
||||
|
||||
file, _ := os.Create(temp_file_name)
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to create file")))
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// write to local if cannot connect
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
// full
|
||||
err = encoder.Encode(targetRecipe)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// partial
|
||||
// err = encoder.Encode(changes)
|
||||
|
||||
// put changes to redis
|
||||
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when write file")))
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// add to commit
|
||||
err = data.Insert(&commit)
|
||||
|
||||
file, _ := os.Create(temp_file_name)
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to create file")))
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
// full
|
||||
err = encoder.Encode(targetRecipe)
|
||||
|
||||
// partial
|
||||
// err = encoder.Encode(changes)
|
||||
|
||||
// put changes to redis
|
||||
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when write file")))
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = rr.cache_db.SetToKey(commit_hash+"_"+filename, changes)
|
||||
err = rr.cache_db.SetToKey(patchName, changes)
|
||||
// TODO: ^----- change this to patch
|
||||
|
||||
if err != nil {
|
||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipeCache", zap.Error(errors.WithMessage(err, "Error when write file")))
|
||||
|
|
@ -567,6 +607,64 @@ func (rr *RecipeRouter) getSavedRecipes(w http.ResponseWriter, r *http.Request)
|
|||
json.NewEncoder(w).Encode(map[string]interface{}{"files": commits})
|
||||
}
|
||||
|
||||
func (rr *RecipeRouter) getSavedAsPatches(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
filename := chi.URLParam(r, "filename")
|
||||
country := chi.URLParam(r, "country")
|
||||
|
||||
countryID, err := rr.data.GetCountryIDByName(country)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Country Name: %s not found!!!", country), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
patchList, err := rr.cache_db.GetList(countryID + "." + filename + ":patchList")
|
||||
if err != nil {
|
||||
// silent return, no patch
|
||||
return
|
||||
}
|
||||
|
||||
rr.taoLogger.Log.Debug("RecipeRouter.getSavedAsPatches", zap.Any("targetPatchOf", countryID+"."+filename+":patchList"), zap.Any("patchList", patchList))
|
||||
|
||||
// find patch content from patch list
|
||||
keys, err := rr.cache_db.KeyList()
|
||||
if err != nil {
|
||||
// keys found nothing
|
||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// loop through keys, if contain patch id
|
||||
patchMap := map[string]models.Recipe01{}
|
||||
for _, key := range keys {
|
||||
if strings.Contains(key, filename) && strings.Contains(key, "patch") {
|
||||
|
||||
// check if legit saved file from patchList
|
||||
for _, patchID := range patchList {
|
||||
if strings.Contains(key, patchID) {
|
||||
// get patch content
|
||||
var recipePatch models.Recipe01
|
||||
err := rr.cache_db.GetKeyTo(key, &recipePatch)
|
||||
if err != nil {
|
||||
// silent return, no patch
|
||||
return
|
||||
}
|
||||
|
||||
// append to patch list
|
||||
// patchContents = append(patchContents, recipePatch)
|
||||
patchMap[patchID] = recipePatch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(patchMap)
|
||||
|
||||
rr.taoLogger.Log.Debug("RecipeRouter.getSavedAsPatches", zap.Any("patchMap", patchMap))
|
||||
}
|
||||
|
||||
func (rr *RecipeRouter) getToppings(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
countryID := chi.URLParam(r, "country")
|
||||
|
|
@ -626,7 +724,7 @@ func (rr *RecipeRouter) getRawRecipeOfProductCode(w http.ResponseWriter, r *http
|
|||
productCode := chi.URLParam(r, "product_code")
|
||||
|
||||
// debug
|
||||
rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("countryID", countryID), zap.Any("filename", filename), zap.Any("productCode", productCode))
|
||||
// rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("countryID", countryID), zap.Any("filename", filename), zap.Any("productCode", productCode))
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
|
||||
|
|
@ -638,7 +736,7 @@ func (rr *RecipeRouter) getRawRecipeOfProductCode(w http.ResponseWriter, r *http
|
|||
}
|
||||
|
||||
// return recipe
|
||||
rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("recipe", recipe))
|
||||
// rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("recipe", recipe))
|
||||
|
||||
json.NewEncoder(w).Encode(recipe)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue