wip
This commit is contained in:
parent
cc8c8ef967
commit
cdb16a9b60
9 changed files with 212 additions and 50 deletions
51
cmd.go
Normal file
51
cmd.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// rootCmd
|
||||
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.bottin.agendas.yaml)")
|
||||
|
||||
if err := BindFlags(rootCmd.PersistentFlags()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "agendas",
|
||||
//Args: cobra.(0),
|
||||
Short: "Gestion de distribution d'agendas",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
log.Println("Starting bottin agendas microservice")
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cfg, err := ParseConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
if args[0] == "debugConfig" {
|
||||
log.Println("debug: Printing current config")
|
||||
cfgAsBytes, err := json.MarshalIndent(cfg, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal("Cannot marshal config for printing:", err)
|
||||
}
|
||||
fmt.Println(string(cfgAsBytes))
|
||||
}
|
||||
}
|
||||
|
||||
if err := run(ctx, cfg); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
}
|
76
config.go
76
config.go
|
@ -1,7 +1,81 @@
|
|||
package main
|
||||
|
||||
import "git.agecem.com/bottin/bottin/v10/pkg/bottin"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.agecem.com/bottin/bottin/v10/pkg/bottin"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Bottin holds a client config to contact a bottin API server
|
||||
// Cannot be set using environment variables
|
||||
Bottin bottin.APIClientConfig
|
||||
|
||||
// TLS holds options for TLS / SSL / HTTPS
|
||||
TLS struct {
|
||||
// Cert holds the public certificate (or path to a file containing one) for user interface TLS
|
||||
Cert string
|
||||
|
||||
// Key holds the private key (or path to a file containing one) for user interface TLS
|
||||
Key string
|
||||
|
||||
// Enabled holds the TLS activation state
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// Credentials holds username-password pairs for basic authentication
|
||||
Credentials map[string]string
|
||||
|
||||
// Port holds the port on which to expose the user interface
|
||||
Port int
|
||||
}
|
||||
|
||||
func ParseConfig() (cfg Config, err error) {
|
||||
return cfg, viper.Unmarshal(&cfg)
|
||||
}
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := os.UserHomeDir()
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".bottin.agendas" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.SetConfigType("yaml")
|
||||
viper.SetConfigName(".bottin.agendas")
|
||||
}
|
||||
|
||||
// Read in env, will find matching viper bindings in flag.go [BindFlags]
|
||||
viper.SetEnvPrefix("AGENDAS")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
51
flag.go
Normal file
51
flag.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
configPort = "Port"
|
||||
defaultPort = 3333
|
||||
flagPort = "port"
|
||||
|
||||
configTLSEnabled = "TLS.Enabled"
|
||||
defaultTLSEnabled = true
|
||||
flagTLSEnabled = "tls-enabled"
|
||||
|
||||
configTLSCert = "TLS.Cert"
|
||||
defaultTLSCert = ""
|
||||
flagTLSCert = "tls-cert"
|
||||
|
||||
configTLSKey = "TLS.Key"
|
||||
defaultTLSKey = ""
|
||||
flagTLSKey = "tls-key"
|
||||
)
|
||||
|
||||
// BindClientFlags declares client-related flags and config options in the specified *pflag.FlagSet
|
||||
func BindFlags(set *pflag.FlagSet) error {
|
||||
// Credentials -> seulement par config
|
||||
|
||||
set.Int(flagPort, defaultPort, "User interface port")
|
||||
if err := viper.BindPFlag(configPort, set.Lookup(flagPort)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set.Bool(flagTLSEnabled, defaultTLSEnabled, "User interface TLS state")
|
||||
if err := viper.BindPFlag(configTLSEnabled, set.Lookup(flagTLSEnabled)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set.String(flagTLSKey, defaultTLSKey, "User interface TLS private key (or path to file)")
|
||||
if err := viper.BindPFlag(configTLSKey, set.Lookup(flagTLSKey)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set.String(flagTLSCert, defaultTLSCert, "User interface TLS certificate (or path to file)")
|
||||
if err := viper.BindPFlag(configTLSCert, set.Lookup(flagTLSCert)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
7
go.mod
7
go.mod
|
@ -6,13 +6,16 @@ require (
|
|||
codeberg.org/vlbeaudoin/voki/v3 v3.0.1
|
||||
git.agecem.com/bottin/bottin/v10 v10.4.1
|
||||
github.com/labstack/echo/v4 v4.13.3
|
||||
golang.org/x/term v0.27.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.19.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.1 // indirect
|
||||
|
@ -28,8 +31,6 @@ require (
|
|||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -2,6 +2,7 @@ codeberg.org/vlbeaudoin/voki/v3 v3.0.1 h1:pFjd/ZKsu4eOzRJYViE9F1S3RglSkAuIiqCo9I
|
|||
codeberg.org/vlbeaudoin/voki/v3 v3.0.1/go.mod h1:+6LMXosAu2ijNKV04sMwkeujpH+cghZU1fydqj2y95g=
|
||||
git.agecem.com/bottin/bottin/v10 v10.4.1 h1:mRZfqnLhGN9Qb+iQvfOvZM5pxXqSlkiXqIMX59zPAS8=
|
||||
git.agecem.com/bottin/bottin/v10 v10.4.1/go.mod h1:KTwlqY5XdVi9F7cpwy3hxYN1DQm+74tBv7Wc9rfKXuM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
|
@ -16,6 +17,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
|
@ -48,6 +51,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
|||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
|
@ -58,6 +62,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
|||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
|
@ -96,8 +102,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
|
|
44
main.go
44
main.go
|
@ -2,38 +2,16 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/vlbeaudoin/voki/v3"
|
||||
"git.agecem.com/bottin/bottin/v10/pkg/bottin"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// Entry
|
||||
|
||||
func init() {}
|
||||
|
||||
func main() {
|
||||
cfg := Config{}
|
||||
cfg.Bottin.Host = "api.bottin.agecem.com"
|
||||
cfg.Bottin.Port = 443
|
||||
cfg.Bottin.TLS.Enabled = true
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
fmt.Println("bottin password (no echo): ")
|
||||
password, err := term.ReadPassword(0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
cfg.Bottin.Key = string(password)
|
||||
|
||||
if err := run(ctx, cfg); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Start commandline parsing then call `run`
|
||||
Execute()
|
||||
}
|
||||
|
||||
func run(ctx context.Context, cfg Config) error {
|
||||
|
@ -41,23 +19,21 @@ func run(ctx context.Context, cfg Config) error {
|
|||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
var protocol string
|
||||
|
||||
if cfg.Bottin.TLS.Enabled {
|
||||
protocol = "https"
|
||||
} else {
|
||||
protocol = "http"
|
||||
}
|
||||
|
||||
bottinClient := bottin.APIClient{Caller: voki.New(
|
||||
http.DefaultClient,
|
||||
cfg.Bottin.Host,
|
||||
cfg.Bottin.Key,
|
||||
cfg.Bottin.Port,
|
||||
protocol,
|
||||
func() string {
|
||||
if cfg.Bottin.TLS.Enabled {
|
||||
return "https"
|
||||
} else {
|
||||
return "http"
|
||||
}
|
||||
}(),
|
||||
)}
|
||||
|
||||
if err := RunServer(ctx, &bottinClient); err != nil && err != http.ErrServerClosed {
|
||||
if err := RunServer(ctx, cfg, &bottinClient); err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
16
server.go
16
server.go
|
@ -4,12 +4,13 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.agecem.com/bottin/agendas/ui"
|
||||
"git.agecem.com/bottin/bottin/v10/pkg/bottin"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
)
|
||||
|
||||
func RunServer(ctx context.Context, bottinClient *bottin.APIClient) error {
|
||||
func RunServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
@ -20,14 +21,23 @@ func RunServer(ctx context.Context, bottinClient *bottin.APIClient) error {
|
|||
|
||||
e := echo.New()
|
||||
|
||||
e.Renderer = NewRenderer()
|
||||
e.Renderer = ui.NewRenderer()
|
||||
|
||||
e.Pre(middleware.AddTrailingSlash())
|
||||
|
||||
//TODO basic auth
|
||||
//TODO log successful basic auths username
|
||||
|
||||
e.GET("/", UIIndex(ctx, bottinClient))
|
||||
|
||||
e.GET("/membre/", UIReadMembre(ctx, bottinClient))
|
||||
|
||||
return e.Start(":3333")
|
||||
address := fmt.Sprintf(":%d", cfg.Port)
|
||||
|
||||
if cfg.TLS.Enabled {
|
||||
return e.StartTLS(address, cfg.TLS.Cert, cfg.TLS.Key)
|
||||
} else {
|
||||
return e.Start(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,3 @@ import "embed"
|
|||
|
||||
//go:embed *.html
|
||||
var htmlFS embed.FS
|
||||
|
||||
func HTMLFS() embed.FS {
|
||||
return htmlFS
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package main
|
||||
package ui
|
||||
|
||||
import (
|
||||
"io"
|
||||
"text/template"
|
||||
|
||||
"git.agecem.com/bottin/agendas/ui"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
|
@ -18,6 +17,6 @@ func (t *Renderer) Render(w io.Writer, name string, data any, c echo.Context) er
|
|||
|
||||
func NewRenderer() *Renderer {
|
||||
return &Renderer{
|
||||
templates: template.Must(template.ParseFS(ui.HTMLFS(), "*html")),
|
||||
templates: template.Must(template.ParseFS(htmlFS, "*html")),
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue