commit 55a4a1285de5ae830dd75181502966b8555057e6 Author: Stevan Freeborn Date: Fri Jul 31 08:06:29 2026 -0500 feat: implemented initial login command diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..307cc61 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,19 @@ +# Copyright (c) 2026 Stevan Freeborn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ab778f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# gator + +This is a blog aggregator that was built as part of a [boot.dev](https://boot.dev) course. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6dd3d99 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/StevanFreeborn/gator + +go 1.26.3 diff --git a/internal/command/command.go b/internal/command/command.go new file mode 100644 index 0000000..318b57f --- /dev/null +++ b/internal/command/command.go @@ -0,0 +1,76 @@ +package command + +import ( + "fmt" + + "github.com/StevanFreeborn/gator/internal/state" +) + +type Command struct { + Name string + Handler CommandHandler +} + +type CommandHandler func(s *state.State) error + +func newCommand(name string, handler CommandHandler) *Command { + return &Command{ + Name: name, + Handler: handler, + } +} + +type CommandRegistry struct { + commands map[string]*Command +} + +func (c *CommandRegistry) register(cmd *Command) error { + c.commands[cmd.Name] = cmd + return nil +} + +func NewRegistry() *CommandRegistry { + cr := CommandRegistry{ + commands: map[string]*Command{}, + } + + commands := []*Command{ + loginCommand(), + } + + for _, cmd := range commands { + cr.register(cmd) + } + + return &cr +} + +func (c *CommandRegistry) RunCommand(cmdName string, s *state.State) error { + cmd, found := c.commands[cmdName] + + if !found { + return fmt.Errorf("No '%s' registered", cmdName) + } + + return cmd.Handler(s) +} + +func loginCommand() *Command { + return newCommand("login", func(s *state.State) error { + if len(s.Arguments) == 0 { + return fmt.Errorf("Did not receive expected username argument") + } + + username := s.Arguments[0] + + err := s.Config.SetUser(username) + + if err != nil { + return err + } + + fmt.Printf("Current user set to '%s'\n", username) + + return nil + }) +} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..97974fa --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,92 @@ +package config + +import ( + "encoding/json" + "fmt" + "os" + "path" +) + +const GATOR_CONFIG_FILE = ".gatorconfig.json" + +type Config struct { + DbUrl string `json:"db_url"` + CurrentUserName string `json:"current_user_name"` +} + +func Read() (*Config, error) { + config := Config{} + + configFilePath, err := getConfigPath() + + if err != nil { + return nil, err + } + + data, err := os.ReadFile(configFilePath) + + if err != nil { + return nil, err + } + + err = json.Unmarshal(data, &config) + + if err != nil { + return nil, err + } + + return &config, nil +} + +// TODO: I don't think there should be +// hidden I/O in this method call +func (c *Config) SetUser(currentUserName string) error { + c.CurrentUserName = currentUserName + return writeFile(c) +} + +func (c *Config) String() string { + return fmt.Sprintf("Config { DbUrl = %s, CurrentUserName = %s }", c.DbUrl, c.CurrentUserName) +} + +func writeFile(config *Config) error { + data, err := json.Marshal(config) + + if err != nil { + return err + } + + configFilePath, err := getConfigPath() + + if err != nil { + return err + } + + file, err := os.Create(configFilePath) + + if err != nil { + return err + } + + defer file.Close() + + _, err = file.Write(data) + + if err != nil { + return err + } + + return nil +} + +func getConfigPath() (string, error) { + homeDir, err := os.UserHomeDir() + + if err != nil { + return "", err + } + + configFilePath := path.Join(homeDir, GATOR_CONFIG_FILE) + + return configFilePath, nil +} diff --git a/internal/state/state.go b/internal/state/state.go new file mode 100644 index 0000000..d04d9d2 --- /dev/null +++ b/internal/state/state.go @@ -0,0 +1,12 @@ +package state + +import "github.com/StevanFreeborn/gator/internal/config" + +type State struct { + Config *config.Config + Arguments []string +} + +func NewState(c *config.Config, args []string) *State { + return &State{Config: c, Arguments: args} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..19eb4a9 --- /dev/null +++ b/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "os" + + "github.com/StevanFreeborn/gator/internal/command" + "github.com/StevanFreeborn/gator/internal/config" + "github.com/StevanFreeborn/gator/internal/state" +) + +func main() { + if len(os.Args) < 2 { + fmt.Println("Not enough arguments provided. Usage: ") + os.Exit(1) + } + + c, err := config.Read() + + if err != nil { + fmt.Printf("Error reading config file: %s", err) + } + + cmd := os.Args[1] + args := os.Args[2:] + + s := state.NewState(c, args) + + registry := command.NewRegistry() + err = registry.RunCommand(cmd, s) + + if err != nil { + fmt.Printf("Error running '%s' command: %s\n", cmd, err) + os.Exit(2) + } + + os.Exit(0) +} diff --git a/sql/schema/001_users.sql b/sql/schema/001_users.sql new file mode 100644 index 0000000..eb16433 --- /dev/null +++ b/sql/schema/001_users.sql @@ -0,0 +1,9 @@ +-- TODO: Finish writing SQL migration +-- for users table +-- +goose Up +CREATE TABLE users ( + id UUID +); + +-- +goose Down +DROP TABLE users;