test update some permissions

This commit is contained in:
Kenta420 2023-12-08 14:46:07 +07:00
parent ac64335d5b
commit 25ce65e425
15 changed files with 582 additions and 493 deletions

View file

@ -1,4 +1,4 @@
import { NgModule, inject } from '@angular/core'; import {inject, NgModule} from '@angular/core';
import { import {
ActivatedRouteSnapshot, ActivatedRouteSnapshot,
CanActivateFn, CanActivateFn,
@ -7,8 +7,9 @@ import {
RouterStateSnapshot, RouterStateSnapshot,
Routes, Routes,
} from '@angular/router'; } from '@angular/router';
import { UserService } from './core/services/user.service'; import {UserService} from './core/services/user.service';
import { map } from 'rxjs'; import {map} from 'rxjs';
import {UserPermissions} from "./core/auth/userPermissions";
const authGuard: CanActivateFn = ( const authGuard: CanActivateFn = (
route: ActivatedRouteSnapshot, route: ActivatedRouteSnapshot,
@ -31,13 +32,38 @@ const authGuard: CanActivateFn = (
); );
}; };
const loginGuard: CanActivateFn = ( const permissionsGuard: (...requiredPermissions: UserPermissions[]) => CanActivateFn = (...requiredPermissions) => (
route: ActivatedRouteSnapshot, route: ActivatedRouteSnapshot,
state: RouterStateSnapshot state: RouterStateSnapshot
) => { ) => {
const userService: UserService = inject(UserService); const userService: UserService = inject(UserService);
const router: Router = inject(Router); const router: Router = inject(Router);
const user = userService.getCurrentUser()
if (user == null)
return router.createUrlTree(['/login'], {
queryParams: {
redirectUrl: state.url,
},
});
if (requiredPermissions.every(permission => user.permissions.includes(permission))) {
return true
}
return router.createUrlTree(['/unauthorized'], {
queryParams: {
redirectUrl: state.url,
},
});
}
const loginGuard: CanActivateFn = (
route: ActivatedRouteSnapshot
) => {
const userService: UserService = inject(UserService);
const router: Router = inject(Router);
return userService.isAuthenticated.pipe( return userService.isAuthenticated.pipe(
map((isAuth) => { map((isAuth) => {
if (!isAuth) { if (!isAuth) {
@ -83,15 +109,15 @@ const routes: Routes = [
import('./features/recipes/recipes.component').then( import('./features/recipes/recipes.component').then(
(m) => m.RecipesComponent (m) => m.RecipesComponent
), ),
canActivate: [authGuard], canActivate: [authGuard, permissionsGuard(UserPermissions.THAI_PERMISSION, UserPermissions.SUPER_ADMIN)],
}, },
{ {
path: 'recipe/:productCode', path: 'recipe/:productCode',
loadComponent: () => loadComponent: () =>
import( import(
'./features/recipes/recipe-details/recipe-details.component' './features/recipes/recipe-details/recipe-details.component'
).then((m) => m.RecipeDetailsComponent), ).then((m) => m.RecipeDetailsComponent),
canActivate: [authGuard], canActivate: [authGuard, permissionsGuard(UserPermissions.THAI_PERMISSION, UserPermissions.SUPER_ADMIN)],
}, },
// { // {
// path: 'log', // path: 'log',
@ -100,9 +126,17 @@ const routes: Routes = [
// (m) => m.ChangelogComponent // (m) => m.ChangelogComponent
// ), // ),
// }, // },
{
path: 'unauthorized',
loadComponent: () => import('./core/auth/unauthorized.component').then((m) => m.UnauthorizedComponent)
},
{
path: 'notfound',
loadComponent: () => import('./core/notfound.component').then((m) => m.NotfoundComponent)
},
{ {
path: '**', path: '**',
redirectTo: 'recipes', redirectTo: 'notfound',
}, },
], ],
}, },
@ -112,4 +146,5 @@ const routes: Routes = [
imports: [RouterModule.forRoot(routes)], imports: [RouterModule.forRoot(routes)],
exports: [RouterModule], exports: [RouterModule],
}) })
export class AppRoutingModule {} export class AppRoutingModule {
}

View file

@ -0,0 +1,31 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-unauthorized',
standalone: true,
template: `
<div class="flex pt-[100px] justify-center h-screen">
<h1 class="text-2xl font-bold text-center text-red-500">
Unauthorized, You 🫵🏻 not have permissions
</h1>
</div>`
})
export class UnauthorizedComponent implements OnInit {
constructor(
private router: Router,
private activatedRoute: ActivatedRoute
) { }
ngOnInit(): void {
const redirectUrl = this.activatedRoute.snapshot.queryParams['redirectUrl'];
if (redirectUrl) {
this.router.navigate([redirectUrl]).catch(() => {
// redirect to login page
void this.router.navigate(['/login']);
});
}
}
}

View file

@ -0,0 +1,12 @@
export enum UserPermissions {
NO_PERMISSION,
THAI_PERMISSION = 1 << 0,
MALAY_PERMISSION = 1 << 1,
AUS_PERMISSION = 1 << 2,
SUPER_ADMIN = 1 << 3
}
export function getPermissions(perms: number) : UserPermissions[] {
return Object.values(UserPermissions)
.filter(permission => typeof permission === 'number' && (perms & permission) !== 0) as UserPermissions[];
}

View file

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common'; import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { UserService } from '../services/user.service'; import { UserService } from '../services/user.service';
import {getPermissions} from "../auth/userPermissions";
@Component({ @Component({
selector: 'app-callback', selector: 'app-callback',
@ -19,18 +19,19 @@ export class CallbackComponent implements OnInit {
this.route.queryParams.subscribe((params) => { this.route.queryParams.subscribe((params) => {
console.log(params); console.log(params);
if (params['email'] && params['name'] && params['picture']) { if (params['email'] && params['name'] && params['picture'] && params['permissions']) {
this.userService.setAuth({ this.userService.setAuth({
email: params['email'], email: params['email'],
name: params['name'], name: params['name'],
picture: params['picture'], picture: params['picture'],
permissions: getPermissions(params['permissions'])
}); });
} }
if (params['redirect_to']) { if (params['redirect_to']) {
this.router.navigate([params['redirect_to']]); void this.router.navigate([params['redirect_to']]);
} else { } else {
this.router.navigate(['/']); void this.router.navigate(['/']);
} }
}); });
} }

View file

@ -1,5 +1,8 @@
import {UserPermissions} from "../auth/userPermissions";
export interface User { export interface User {
email: string; email: string;
name: string; name: string;
picture: string; picture: string;
permissions: UserPermissions[];
} }

View file

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-notfound',
standalone: true,
template: `<h1>Not Found!!!</h1>`
})
export class NotfoundComponent {
}

View file

@ -2,10 +2,9 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { import {
BehaviorSubject, BehaviorSubject,
Observable,
distinctUntilChanged, distinctUntilChanged,
map, map,
tap,
} from 'rxjs'; } from 'rxjs';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -31,6 +30,10 @@ export class UserService {
} }
} }
getCurrentUser(): User | null {
return this.currentUserSubject.value
}
logout(): void { logout(): void {
this.purgeAuth(); this.purgeAuth();
// post to api /revoke with cookie // post to api /revoke with cookie
@ -43,21 +46,6 @@ export class UserService {
}); });
} }
getCurrentUser(): Observable<{ user: User }> {
return this.http
.get<{ user: User }>(environment.api + '/auth/user', {
withCredentials: true,
})
.pipe(
tap({
next: ({ user }) => {
this.setAuth(user);
},
error: () => this.purgeAuth(),
})
);
}
setAuth(user: User): void { setAuth(user: User): void {
window.localStorage.setItem('user', JSON.stringify(user)); window.localStorage.setItem('user', JSON.stringify(user));
void this.currentUserSubject.next(user); void this.currentUserSubject.next(user);

View file

@ -2,7 +2,7 @@ import { CommonModule, DatePipe } from '@angular/common';
import { Component, EventEmitter, OnInit } from '@angular/core'; import { Component, EventEmitter, OnInit } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Observable, first } from 'rxjs'; import {Observable, first, map} from 'rxjs';
import { RecipeService } from 'src/app/core/services/recipe.service'; import { RecipeService } from 'src/app/core/services/recipe.service';
import { ConfirmModal } from 'src/app/shared/modal/confirm/confirm-modal.component'; import { ConfirmModal } from 'src/app/shared/modal/confirm/confirm-modal.component';
import { animate, style, transition, trigger } from '@angular/animations'; import { animate, style, transition, trigger } from '@angular/animations';
@ -11,8 +11,7 @@ import {
RecipeDetail, RecipeDetail,
RecipeDetailMat, RecipeDetailMat,
} from 'src/app/core/models/recipe.model'; } from 'src/app/core/models/recipe.model';
import { Action, ActionRecord } from 'src/app/shared/actionRecord/actionRecord'; import { ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
import { isEqual } from 'lodash';
import { UserService } from 'src/app/core/services/user.service'; import { UserService } from 'src/app/core/services/user.service';
@Component({ @Component({
@ -119,10 +118,9 @@ export class RecipeDetailsComponent implements OnInit {
// get username // get username
let username:string = "" let username:string = ""
this._userService.getCurrentUser().subscribe((user) => { this._userService.currentUser.pipe(map((user) => {
username = user.user.name; if (user)
username = user.name;
let to_send = { let to_send = {
edit_by: username, edit_by: username,
@ -152,8 +150,8 @@ export class RecipeDetailsComponent implements OnInit {
} }
); );
console.log('Sending changes'); console.log('Sending changes');
this._router.navigate(['/recipes']); void this._router.navigate(['/recipes']);
}) }))
@ -198,6 +196,6 @@ export class RecipeDetailsComponent implements OnInit {
onRecipeListFormChange(repl: unknown[]) { onRecipeListFormChange(repl: unknown[]) {
console.log('Recipe List Form Changed', repl); console.log('Recipe List Form Changed', repl);
this.repl = repl as never[]; this.repl = repl as never[];
this.isValueChanged ||= repl != undefined ? true : false; this.isValueChanged ||= repl != undefined;
} }
} }

Binary file not shown.

View file

@ -42,7 +42,7 @@ func DynamicCompare(s interface{}, u interface{}) (bool, error) {
return t == u, nil return t == u, nil
case float64: case float64:
u, ok := u.(float64) u, ok := u.(float64)
// Log.Debug("[helpers] DynamicCompare", zap.Any("u", u), zap.Any("ok", ok), zap.Any("test_compare*(t==u)", t == u)) // Log.Debug("[helpers] DynamicCompare", zap.Any("user", u), zap.Any("ok", ok), zap.Any("test_compare*(t==u)", t == u))
if t == u { if t == u {
return t == u, nil return t == u, nil

View file

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"errors"
"log" "log"
"os" "os"
"os/signal" "os/signal"
@ -22,7 +23,7 @@ func main() {
go func() { go func() {
<-shutdownCtx.Done() <-shutdownCtx.Done()
if shutdownCtx.Err() == context.DeadlineExceeded { if errors.Is(shutdownCtx.Err(), context.DeadlineExceeded) {
log.Println("Shutdown timeout, force exit") log.Println("Shutdown timeout, force exit")
cancel() cancel()
} }

View file

@ -1,19 +1,87 @@
package middlewares package middlewares
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"golang.org/x/oauth2"
"net/http" "net/http"
"recipe-manager/enums/permissions" "recipe-manager/enums/permissions"
"recipe-manager/models" "recipe-manager/models"
"recipe-manager/services/oauth"
"recipe-manager/services/user"
) )
func Authorize(p []permissions.Permission, nextRoute http.HandlerFunc) http.HandlerFunc { // ========================== ValidatePermissions =========================================
func Authorize(oauthService oauth.OAuthService, userService user.UserService, nextRoute http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(*models.User) token := &oauth2.Token{}
if cookie, err := r.Cookie("access_token"); err == nil {
token.AccessToken = cookie.Value
}
userInfo, err := oauthService.GetUserInfo(r.Context(), token)
if err != nil {
// if have refresh token, set refresh token to token
if cookie, err := r.Cookie("refresh_token"); err == nil {
token.RefreshToken = cookie.Value
}
newToken, err := oauthService.RefreshToken(r.Context(), token)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
userInfo, err = oauthService.GetUserInfo(r.Context(), newToken)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// set new token to cookie
w.Header().Add("set-cookie", fmt.Sprintf("access_token=%s; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=3600", newToken.AccessToken))
}
if userInfo != nil {
userFromDB, err := userService.GetUserByEmail(r.Context(), userInfo.Email)
if err != nil {
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
}
if userFromDB != nil {
userInfo.ID = userFromDB.ID
userInfo.Name = userFromDB.Name
if userFromDB.Picture != "" {
userInfo.Picture = userFromDB.Picture
}
userInfo.Permissions = userFromDB.Permissions
}
}
ctx := context.WithValue(r.Context(), "user", userInfo)
nextRoute.ServeHTTP(w, r.WithContext(ctx))
}
}
// ========================== Permissions =========================================
func ValidatePermissions(p []permissions.Permission, nextRoute http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
u := r.Context().Value("user").(*models.User)
for _, pm := range p { for _, pm := range p {
if !user.Permissions.IsHavePermission(pm) { if !u.Permissions.IsHavePermission(pm) {
// If not have permission response unauthorized // If not have permission response unauthorized
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
err := json.NewEncoder(w).Encode("Unauthorized") err := json.NewEncoder(w).Encode("Unauthorized")
@ -28,10 +96,10 @@ func Authorize(p []permissions.Permission, nextRoute http.HandlerFunc) http.Hand
} }
} }
func OwnOrAuthorize(p []permissions.Permission, nextRoute http.HandlerFunc) http.HandlerFunc { func ValidateOwnerOrPermissions(p []permissions.Permission, nextRoute http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
reqUserID := chi.URLParam(r, "id") reqUserID := chi.URLParam(r, "id")
user := r.Context().Value("user").(*models.User) u := r.Context().Value("user").(*models.User)
if reqUserID == "" { if reqUserID == "" {
// If not have permission response unauthorized // If not have permission response unauthorized
@ -43,11 +111,11 @@ func OwnOrAuthorize(p []permissions.Permission, nextRoute http.HandlerFunc) http
return return
} }
if reqUserID == user.ID { if reqUserID == u.ID {
nextRoute.ServeHTTP(w, r) nextRoute.ServeHTTP(w, r)
return return
} }
Authorize(p, nextRoute) ValidatePermissions(p, nextRoute)
} }
} }

View file

@ -27,14 +27,14 @@ func (ur *UserRouter) Route(r chi.Router) {
// Users // Users
r.Route("/users", func(r chi.Router) { r.Route("/users", func(r chi.Router) {
r.Get("/", middlewares.Authorize([]permissions.Permission{permissions.SuperAdmin}, ur.getUsers)) r.Get("/", middlewares.ValidatePermissions([]permissions.Permission{permissions.SuperAdmin}, ur.getUsers))
r.Post("/", middlewares.Authorize([]permissions.Permission{permissions.SuperAdmin}, ur.createUser)) r.Post("/", middlewares.ValidatePermissions([]permissions.Permission{permissions.SuperAdmin}, ur.createUser))
}) })
// User // User
r.Route("/user", func(r chi.Router) { r.Route("/user", func(r chi.Router) {
r.Get("/{id}", middlewares.OwnOrAuthorize([]permissions.Permission{permissions.SuperAdmin}, ur.getUser)) r.Get("/{id}", middlewares.ValidateOwnerOrPermissions([]permissions.Permission{permissions.SuperAdmin}, ur.getUser))
}) })
} }
@ -56,7 +56,7 @@ func (ur *UserRouter) createUser(w http.ResponseWriter, r *http.Request) {
ur.taoLogger.Log.Error("UserRouter.CreateUser", zap.Error(err)) ur.taoLogger.Log.Error("UserRouter.CreateUser", zap.Error(err))
} }
ur.taoLogger.Log.Info("UserRouter.CreateUser", zap.Reflect("u", u)) ur.taoLogger.Log.Info("UserRouter.CreateUser", zap.Reflect("user", u))
if err := ur.userService.CreateNewUser(ctx, u.Name, u.Email, u.Picture, u.Permissions); err != nil { if err := ur.userService.CreateNewUser(ctx, u.Name, u.Email, u.Picture, u.Permissions); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

View file

@ -14,6 +14,7 @@ import (
"recipe-manager/config" "recipe-manager/config"
"recipe-manager/data" "recipe-manager/data"
"recipe-manager/enums/permissions" "recipe-manager/enums/permissions"
"recipe-manager/middlewares"
"recipe-manager/models" "recipe-manager/models"
"recipe-manager/routers" "recipe-manager/routers"
"recipe-manager/services/logger" "recipe-manager/services/logger"
@ -29,7 +30,6 @@ import (
"github.com/go-chi/cors" "github.com/go-chi/cors"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/oauth2"
) )
var ( var (
@ -116,7 +116,7 @@ func (s *Server) createHandler() {
})) }))
// Recipe Service // Recipe Service
recipeService := recipe.NewRecipeService(s.data) recipeService := recipe.NewRecipeService(s.data, s.taoLogger)
// User Service // User Service
userService := user.NewUserService(s.cfg, s.database, s.taoLogger) userService := user.NewUserService(s.cfg, s.database, s.taoLogger)
@ -134,63 +134,7 @@ func (s *Server) createHandler() {
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 middlewares.Authorize(s.oauth, userService, next)
token := &oauth2.Token{}
if cookie, err := r.Cookie("access_token"); err == nil {
token.AccessToken = cookie.Value
}
userInfo, err := s.oauth.GetUserInfo(r.Context(), token)
if err != nil {
// if have refresh token, set refresh token to token
if cookie, err := r.Cookie("refresh_token"); err == nil {
token.RefreshToken = cookie.Value
}
newToken, err := s.oauth.RefreshToken(r.Context(), token)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
userInfo, err = s.oauth.GetUserInfo(r.Context(), newToken)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// set new token to cookie
w.Header().Add("set-cookie", fmt.Sprintf("access_token=%s; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=3600", newToken.AccessToken))
}
if userInfo != nil {
userFromDB, err := userService.GetUserByEmail(r.Context(), userInfo.Email)
if err != nil {
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
}
if userFromDB != nil {
userInfo.ID = userFromDB.ID
userInfo.Name = userFromDB.Name
if userFromDB.Picture != "" {
userInfo.Picture = userFromDB.Picture
}
userInfo.Permissions = userFromDB.Permissions
}
}
ctx := context.WithValue(r.Context(), "user", userInfo)
next.ServeHTTP(w, r.WithContext(ctx))
})
}) })
r.Post("/merge", func(w http.ResponseWriter, r *http.Request) { r.Post("/merge", func(w http.ResponseWriter, r *http.Request) {
@ -198,10 +142,10 @@ func (s *Server) createHandler() {
// locking // locking
if !pyAPIhandler(w, r) { if !pyAPIhandler(w, r) {
s.taoLogger.Log.Warn("Merge - u tried to access while another u is requesting merge", s.taoLogger.Log.Warn("Merge - u tried to access while another u is requesting merge",
zap.String("u", r.Context().Value("u").(*models.User).Name)) zap.String("user", r.Context().Value("user").(*models.User).Name))
return return
} else { } else {
s.taoLogger.Log.Debug("Merge - u has access", zap.String("u", r.Context().Value("u").(*models.User).Name)) s.taoLogger.Log.Debug("Merge - u has access", zap.String("user", r.Context().Value("user").(*models.User).Name))
} }
var targetMap map[string]interface{} var targetMap map[string]interface{}
@ -234,8 +178,8 @@ func (s *Server) createHandler() {
dev_path := repo_path + dev_version + ".json" dev_path := repo_path + dev_version + ".json"
// Get who's requesting // Get who's requesting
u := r.Context().Value("u").(*models.User) u := r.Context().Value("user").(*models.User)
s.taoLogger.Log.Info("Request merge by", zap.String("u", u.Name)) s.taoLogger.Log.Info("Request merge by", zap.String("user", u.Name))
// lookup for python exec // lookup for python exec
pyExec, err := exec.LookPath("python") pyExec, err := exec.LookPath("python")

View file

@ -12,10 +12,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
var (
Log = logger.GetInstance()
)
type RecipeService interface { type RecipeService interface {
GetRecipeDashboard(request *contracts.RecipeDashboardRequest) (contracts.RecipeDashboardResponse, error) GetRecipeDashboard(request *contracts.RecipeDashboardRequest) (contracts.RecipeDashboardResponse, error)
GetRecipeOverview(request *contracts.RecipeOverviewRequest) (contracts.RecipeOverviewResponse, error) GetRecipeOverview(request *contracts.RecipeOverviewRequest) (contracts.RecipeOverviewResponse, error)
@ -25,13 +21,14 @@ type RecipeService interface {
} }
type recipeService struct { type recipeService struct {
db *data.Data db *data.Data
taoLogger *logger.TaoLogger
} }
// GetRecipeDetail implements RecipeService. // GetRecipeDetail implements RecipeService.
func (rs *recipeService) GetRecipeDetail(request *contracts.RecipeDetailRequest) (contracts.RecipeDetailResponse, error) { func (rs *recipeService) GetRecipeDetail(request *contracts.RecipeDetailRequest) (contracts.RecipeDetailResponse, error) {
Log.Debug("GetRecipeDetail", zap.Any("request", request)) rs.taoLogger.Log.Debug("GetRecipeDetail", zap.Any("request", request))
recipe, err := rs.db.GetRecipe01ByProductCode(request.Filename, request.Country, request.ProductCode) recipe, err := rs.db.GetRecipe01ByProductCode(request.Filename, request.Country, request.ProductCode)
@ -40,7 +37,7 @@ func (rs *recipeService) GetRecipeDetail(request *contracts.RecipeDetailRequest)
} }
// DEBUG: picture // DEBUG: picture
Log.Debug("GetRecipeDetail", zap.String("picture", recipe.UriData)) rs.taoLogger.Log.Debug("GetRecipeDetail", zap.String("picture", recipe.UriData))
result := contracts.RecipeDetailResponse{ result := contracts.RecipeDetailResponse{
Name: recipe.Name, Name: recipe.Name,
@ -143,7 +140,7 @@ func (rs *recipeService) GetRecipeOverview(request *contracts.RecipeOverviewRequ
result := contracts.RecipeOverviewResponse{} result := contracts.RecipeOverviewResponse{}
if request.Search != "" { if request.Search != "" {
searchResult := []models.Recipe01{} var searchResult []models.Recipe01
for _, v := range recipeFilter { for _, v := range recipeFilter {
if strings.Contains(strings.ToLower(v.ProductCode), strings.ToLower(request.Search)) || if strings.Contains(strings.ToLower(v.ProductCode), strings.ToLower(request.Search)) ||
strings.Contains(strings.ToLower(v.Name), strings.ToLower(request.Search)) || strings.Contains(strings.ToLower(v.Name), strings.ToLower(request.Search)) ||
@ -155,7 +152,7 @@ func (rs *recipeService) GetRecipeOverview(request *contracts.RecipeOverviewRequ
} }
if len(request.MatIds) > 0 { if len(request.MatIds) > 0 {
matIdsFiltered := []models.Recipe01{} var matIdsFiltered []models.Recipe01
for _, v := range recipeFilter { for _, v := range recipeFilter {
for _, matID := range request.MatIds { for _, matID := range request.MatIds {
for _, recipe := range v.Recipes { for _, recipe := range v.Recipes {
@ -197,8 +194,9 @@ func (rs *recipeService) GetRecipeOverview(request *contracts.RecipeOverviewRequ
return result, nil return result, nil
} }
func NewRecipeService(db *data.Data) RecipeService { func NewRecipeService(db *data.Data, taoLogger *logger.TaoLogger) RecipeService {
return &recipeService{ return &recipeService{
db: db, db: db,
taoLogger: taoLogger,
} }
} }