experiment some thing spicy
This commit is contained in:
parent
ce28a757b1
commit
3411ae333d
18 changed files with 211 additions and 10 deletions
24
client/src/app/shared/atoms/textbox.component.ts
Normal file
24
client/src/app/shared/atoms/textbox.component.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
|
||||
import { FormComponent } from '../formBuilder/types/form.type';
|
||||
import { TextBox } from '../formBuilder/types/atoms-types';
|
||||
|
||||
@Component({
|
||||
selector: 'textbox',
|
||||
template: `
|
||||
<input
|
||||
class="form-control"
|
||||
[formControl]="form"
|
||||
[id]="field.id"
|
||||
[type]="field.body.label"
|
||||
[placeholder]="field.body.placeholder"
|
||||
/>
|
||||
`,
|
||||
})
|
||||
export class TextBoxComponent implements OnInit {
|
||||
@Input() field!: FormComponent;
|
||||
@Input() form!: FormControl;
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { FormComponent } from '../types/form.type';
|
||||
import { FormGroup, FormControl } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'field-builder',
|
||||
template: `
|
||||
<div class="form-group row" [formGroup]="form">
|
||||
<label class="col-md-3 form-control-label" [attr.for]="field.body.label">
|
||||
{{ field.body.label }}
|
||||
<strong
|
||||
class="text-danger"
|
||||
*ngIf="field.body.required && form.get(field.id)?.invalid"
|
||||
>*</strong
|
||||
>
|
||||
</label>
|
||||
<div class="col-md-9" [ngSwitch]="field.type">
|
||||
<textbox
|
||||
*ngSwitchCase="'text'"
|
||||
[field]="field"
|
||||
[form]="control"
|
||||
></textbox>
|
||||
<div
|
||||
class="alert alert-danger my-1 p-2 fadeInDown animated"
|
||||
*ngIf="!isValid && isDirty"
|
||||
>
|
||||
{{ field.body.label }} is required
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class FieldBuilderComponent implements OnInit {
|
||||
@Input({ required: true }) field!: FormComponent;
|
||||
@Input() form!: FormGroup;
|
||||
|
||||
get isValid() {
|
||||
return this.form.controls[this.field.id].valid;
|
||||
}
|
||||
get isDirty() {
|
||||
return this.form.controls[this.field.id].dirty;
|
||||
}
|
||||
|
||||
get control(): FormControl {
|
||||
return this.form.controls[this.field.id] as FormControl;
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
15
client/src/app/shared/formBuilder/form-id.ts
Normal file
15
client/src/app/shared/formBuilder/form-id.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export class FormID {
|
||||
private static CHARACTERS =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
private static BASE_ID = 'form-';
|
||||
|
||||
private static generateRandomString(length: number): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += this.CHARACTERS.charAt(
|
||||
Math.floor(Math.random() * this.CHARACTERS.length)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
19
client/src/app/shared/formBuilder/formBuilder.component.ts
Normal file
19
client/src/app/shared/formBuilder/formBuilder.component.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'form-builder',
|
||||
template: `
|
||||
<form [formGroup]="formGroup" class="form-horizontal">
|
||||
<div *ngFor="let field of fields">
|
||||
<field-builder [field]="field" [form]="formGroup"></field-builder>
|
||||
</div>
|
||||
<div class="form-row"></div>
|
||||
</form>
|
||||
`,
|
||||
})
|
||||
export class FormBuilderComponent {
|
||||
@Input() fields: any[] = [];
|
||||
@Input() formGroup!: FormGroup;
|
||||
constructor() {}
|
||||
}
|
||||
14
client/src/app/shared/formBuilder/formBuilder.module.ts
Normal file
14
client/src/app/shared/formBuilder/formBuilder.module.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormBuilderComponent } from './formBuilder.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { FieldBuilderComponent } from './field-builder/field-builder.component';
|
||||
import { TextBoxComponent } from '../atoms/textbox.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, ReactiveFormsModule],
|
||||
declarations: [FormBuilderComponent, FieldBuilderComponent, TextBoxComponent],
|
||||
exports: [FormBuilderComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class FormBuilderModule {}
|
||||
34
client/src/app/shared/formBuilder/types/atoms-types/index.ts
Normal file
34
client/src/app/shared/formBuilder/types/atoms-types/index.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
type TextBox = {
|
||||
type: 'text';
|
||||
body: {
|
||||
type: string;
|
||||
label: string;
|
||||
name: string;
|
||||
value: string;
|
||||
required: boolean;
|
||||
placeholder: string;
|
||||
};
|
||||
};
|
||||
|
||||
type CheckBox = {
|
||||
type: 'checkbox';
|
||||
body: {
|
||||
label: string;
|
||||
name: string;
|
||||
value: string;
|
||||
required: boolean;
|
||||
placeholder: string;
|
||||
};
|
||||
};
|
||||
|
||||
type DropDown = {
|
||||
type: 'dropdown';
|
||||
body: {
|
||||
label: string;
|
||||
items: string[];
|
||||
required: boolean;
|
||||
placeholder: string;
|
||||
};
|
||||
};
|
||||
|
||||
export { TextBox, CheckBox, DropDown };
|
||||
6
client/src/app/shared/formBuilder/types/form.type.ts
Normal file
6
client/src/app/shared/formBuilder/types/form.type.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { CheckBox, DropDown, TextBox } from './atoms-types';
|
||||
|
||||
export type FormComponent = (TextBox | CheckBox | DropDown) & {
|
||||
id: string;
|
||||
type: string;
|
||||
};
|
||||
|
|
@ -6,5 +6,16 @@
|
|||
{
|
||||
"path": "./server"
|
||||
}
|
||||
]
|
||||
],
|
||||
"settings": {
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"previewLimit": 50,
|
||||
"driver": "SQLite",
|
||||
"name": "Taobin Recipe Manager (Server)",
|
||||
"database": "${workspaceFolder:server}/data/database.db"
|
||||
}
|
||||
],
|
||||
"sqltools.useNodeRuntime": true
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 47004d38a2c9468fa5cdbadfaf792fb9bd234a1f
|
||||
Subproject commit 9fc8791818e56cc8bd9065beed223ec96844f146
|
||||
BIN
server/data/database.db
Normal file
BIN
server/data/database.db
Normal file
Binary file not shown.
0
server/data/migrations/20231127070350_init.down.sql
Normal file
0
server/data/migrations/20231127070350_init.down.sql
Normal file
10
server/data/migrations/20231127070350_init.up.sql
Normal file
10
server/data/migrations/20231127070350_init.up.sql
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
-- slqlite3
|
||||
-- create users table
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
8
server/data/sqlite.go
Normal file
8
server/data/sqlite.go
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package data
|
||||
|
||||
import "github.com/jmoiron/sqlx"
|
||||
|
||||
func NewSqliteDatabase() *sqlx.DB {
|
||||
db := sqlx.MustConnect("sqlite3", "./data/database.db")
|
||||
return db
|
||||
}
|
||||
|
|
@ -24,7 +24,11 @@ require (
|
|||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
||||
require github.com/gorilla/websocket v1.5.0 // indirect
|
||||
require (
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.18 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz
|
|||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
|
@ -150,6 +151,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
|
|
@ -161,8 +164,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
|
||||
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"recipe-manager/services/oauth"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
|
@ -87,6 +88,8 @@ func (ar *AuthRouter) Route(r chi.Router) {
|
|||
value.Add("redirect_to", redirect_to)
|
||||
}
|
||||
|
||||
Log.Info("User Log-In Success", zap.String("user", user.Name), zap.String("email", user.Email))
|
||||
|
||||
// redirect to frontend with token and refresh token
|
||||
w.Header().Add("set-cookie", "access_token="+token.AccessToken+"; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=3600")
|
||||
w.Header().Add("set-cookie", "refresh_token="+token.RefreshToken+"; Path=/; HttpOnly; SameSite=None; Secure")
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ func (rr *RecipeRouter) Route(r chi.Router) {
|
|||
// check if changed
|
||||
// Log.Debug("Check if changed", zap.Any("result", rr.data.GetRecipe01ByProductCode(changes.ProductCode)))
|
||||
|
||||
file, _ := os.Create(path.Join("./cofffeemachineConfig", countryID[:3], filename))
|
||||
file, _ := os.Create(path.Join("./cofffeemachineConfig", countryID, filename))
|
||||
if err != nil {
|
||||
Log.Error("Error when tried to create file", zap.Error(err))
|
||||
return
|
||||
|
|
@ -311,7 +311,7 @@ func (rr *RecipeRouter) Route(r chi.Router) {
|
|||
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
err = encoder.Encode(rr.data.GetCurrentRecipe())
|
||||
err = encoder.Encode(rr.data.GetRecipe(countryID, filename))
|
||||
|
||||
if err != nil {
|
||||
Log.Error("Error when write file", zap.Error(err))
|
||||
|
|
|
|||
|
|
@ -154,11 +154,6 @@ func (s *Server) createHandler() {
|
|||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "user", user)
|
||||
if user == nil {
|
||||
Log.Error("User is not authenticated or timed out", zap.Any("requester", user))
|
||||
} else {
|
||||
Log.Info("User is authenticated", zap.String("user", user.Name))
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue