package service import ( "errors" "fmt" "strings" "teraclone/internal/cli" "teraclone/internal/store" ) type AppService struct { store *store.SQLiteStore } type User struct { ID int64 `json:"id"` Username string `json:"username"` Group string `json:"group"` Enabled bool `json:"enabled"` StatusLabel string `json:"statusLabel"` AccessSummary string `json:"accessSummary"` } type CreateUserInput struct { Username string `json:"username"` Password string `json:"password"` Group string `json:"group"` Enabled bool `json:"enabled"` } type UpdateUserInput struct { ID int64 `json:"id"` Username string `json:"username"` Password string `json:"password"` Group string `json:"group"` Enabled bool `json:"enabled"` } type Group struct { ID int64 `json:"id"` Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` PermissionSummary string `json:"permissionSummary"` } type CreateGroupInput struct { Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` } type UpdateGroupInput struct { ID int64 `json:"id"` Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` } func NewAppService(dbPath string) (*AppService, error) { sqliteStore, err := store.NewSQLiteStore(dbPath) if err != nil { return nil, err } return &AppService{store: sqliteStore}, nil } func (s *AppService) Greeting() string { return "hello from go server" } func (s *AppService) HealthStatus() string { return "ok" } func (s *AppService) NewTerminalSession() (*cli.TerminalSession, error) { return cli.NewTerminalSession() } func (s *AppService) Close() error { if s == nil { return nil } return s.store.Close() } func (s *AppService) RecordPageVisit(path string, title string) error { return s.store.RecordPageVisit(path, title) } func (s *AppService) RecordMockAction(action string, path string) error { return s.store.RecordMockAction(action, path) } func (s *AppService) RecentActivity(limit int) ([]store.ActivityRecord, error) { return s.store.RecentActivity(limit) } func (s *AppService) ListUsers() ([]User, error) { records, err := s.store.ListUsers() if err != nil { return nil, err } users := make([]User, 0, len(records)) for _, record := range records { users = append(users, mapUser(record)) } return users, nil } func (s *AppService) ListGroups() ([]Group, error) { records, err := s.store.ListGroups() if err != nil { return nil, err } groups := make([]Group, 0, len(records)) for _, record := range records { groups = append(groups, mapGroup(record)) } return groups, nil } func (s *AppService) GetGroup(id int64) (Group, error) { record, err := s.store.GetGroup(id) if err != nil { return Group{}, err } return mapGroup(record), nil } func (s *AppService) CreateGroup(input CreateGroupInput) (Group, error) { if err := validateGroupInput(input.Name, input.Permissions); err != nil { return Group{}, err } record, err := s.store.CreateGroup(store.CreateGroupParams{ Name: input.Name, Description: input.Description, Permissions: input.Permissions, }) if err != nil { return Group{}, err } return mapGroup(record), nil } func (s *AppService) UpdateGroup(input UpdateGroupInput) (Group, error) { if input.ID <= 0 { return Group{}, errors.New("invalid group id") } if err := validateGroupInput(input.Name, input.Permissions); err != nil { return Group{}, err } record, err := s.store.UpdateGroup(store.UpdateGroupParams{ ID: input.ID, Name: input.Name, Description: input.Description, Permissions: input.Permissions, }) if err != nil { return Group{}, err } return mapGroup(record), nil } func (s *AppService) DeleteGroup(id int64) error { if id <= 0 { return errors.New("invalid group id") } return s.store.DeleteGroup(id) } func (s *AppService) GetUser(id int64) (User, error) { record, err := s.store.GetUser(id) if err != nil { return User{}, err } return mapUser(record), nil } func (s *AppService) CreateUser(input CreateUserInput) (User, error) { group, err := s.store.GetGroupByName(strings.TrimSpace(input.Group)) if err != nil { return User{}, errors.New("group not found") } if err := validateUserInput(input.Username, input.Password, input.Group, true); err != nil { return User{}, err } record, err := s.store.CreateUser(store.CreateUserParams{ Username: input.Username, Password: input.Password, GroupName: group.Name, Enabled: input.Enabled, }) if err != nil { return User{}, err } return mapUser(record), nil } func (s *AppService) UpdateUser(input UpdateUserInput) (User, error) { if input.ID <= 0 { return User{}, errors.New("invalid user id") } group, err := s.store.GetGroupByName(strings.TrimSpace(input.Group)) if err != nil { return User{}, errors.New("group not found") } if err := validateUserInput(input.Username, input.Password, input.Group, false); err != nil { return User{}, err } record, err := s.store.UpdateUser(store.UpdateUserParams{ ID: input.ID, Username: input.Username, Password: input.Password, GroupName: group.Name, Enabled: input.Enabled, }) if err != nil { return User{}, err } return mapUser(record), nil } func (s *AppService) DeleteUser(id int64) error { if id <= 0 { return errors.New("invalid user id") } return s.store.DeleteUser(id) } func (s *AppService) AuthenticateUser(username string, password string) (User, error) { record, err := s.store.GetUserByUsername(strings.TrimSpace(username)) if err != nil { return User{}, err } if !record.Enabled { return User{}, errors.New("user is disabled") } if strings.TrimSpace(password) == "" || !store.VerifyPassword(password, record.PasswordHash) { return User{}, errors.New("invalid username or password") } return mapUser(record), nil } func mapUser(record store.UserRecord) User { return User{ ID: record.ID, Username: record.Username, Group: record.GroupName, Enabled: record.Enabled, StatusLabel: statusLabel(record.Enabled), AccessSummary: accessSummary(record.GroupName), } } func mapGroup(record store.GroupRecord) Group { return Group{ ID: record.ID, Name: record.Name, Description: record.Description, Permissions: record.Permissions, PermissionSummary: permissionSummary(record.Permissions), } } func validateUserInput(username string, password string, group string, passwordRequired bool) error { if strings.TrimSpace(username) == "" { return errors.New("username is required") } if passwordRequired && strings.TrimSpace(password) == "" { return errors.New("password is required") } if strings.TrimSpace(group) == "" { return errors.New("group is required") } return nil } func statusLabel(enabled bool) string { if enabled { return "사용" } return "중지" } func accessSummary(group string) string { switch strings.TrimSpace(group) { case "administrator": return "전체 허용" case "operator": return "운영 허용" case "guest": return "조회 허용" default: return "제한됨" } } func validateGroupInput(name string, permissions []string) error { if strings.TrimSpace(name) == "" { return errors.New("group name is required") } if len(permissions) == 0 { return errors.New("at least one permission is required") } return nil } func permissionSummary(permissions []string) string { if len(permissions) == 0 { return "권한 없음" } if len(permissions) == len(defaultPermissionOptions()) { return "모든 메뉴" } return fmt.Sprintf("권한 %d개", len(permissions)) } func defaultPermissionOptions() []string { return []string{"login", "network", "ports", "tools", "admin", "common", "status", "password", "operate"} }