all repos — well-binge @ 4690b04bb57834544694aa1b0d740fe746ec7236

Create positive, recurring habits.

src/app/init.go (view raw)

  1package app
  2
  3import (
  4	"log"
  5	"net/http"
  6	"os"
  7	"path/filepath"
  8	"strings"
  9	"time"
 10
 11	"github.com/birabittoh/auth-boilerplate/src/auth"
 12	"github.com/birabittoh/auth-boilerplate/src/email"
 13	"github.com/birabittoh/myks"
 14	"github.com/glebarez/sqlite"
 15	"github.com/joho/godotenv"
 16	"github.com/utking/extemplate"
 17	"gorm.io/gorm"
 18)
 19
 20type key int
 21
 22type User struct {
 23	gorm.Model
 24	Username     string `gorm:"unique"`
 25	Email        string `gorm:"unique"`
 26	PasswordHash string
 27	Salt         string
 28
 29	Habits []Habit
 30}
 31
 32type Habit struct {
 33	gorm.Model
 34	UserID   uint
 35	Name     string
 36	Days     uint
 37	LastAck  *time.Time
 38	Negative bool
 39	Disabled bool
 40
 41	User User
 42	Acks []Ack
 43}
 44
 45type Ack struct {
 46	gorm.Model
 47	HabitID uint
 48
 49	Habit Habit
 50}
 51
 52const (
 53	dataDir = "data"
 54	dbName  = "app.db"
 55)
 56
 57var (
 58	db *gorm.DB
 59	g  *auth.Auth
 60	m  *email.Client
 61	xt *extemplate.Extemplate
 62
 63	baseUrl             string
 64	port                string
 65	registrationEnabled = true
 66
 67	ks           = myks.New[uint](0)
 68	durationDay  = 24 * time.Hour
 69	durationWeek = 7 * durationDay
 70)
 71
 72const userContextKey key = 0
 73
 74func Main() {
 75	err := godotenv.Load()
 76	if err != nil {
 77		log.Println("Error loading .env file")
 78	}
 79
 80	port = os.Getenv("APP_PORT")
 81	if port == "" {
 82		port = "3000"
 83	}
 84
 85	baseUrl = os.Getenv("APP_BASE_URL")
 86	if baseUrl == "" {
 87		baseUrl = "http://localhost:" + port
 88	}
 89
 90	e := strings.ToLower(os.Getenv("APP_REGISTRATION_ENABLED"))
 91	if e == "false" || e == "0" {
 92		registrationEnabled = false
 93	}
 94
 95	// Init auth and email
 96	m = loadEmailConfig()
 97	g = auth.NewAuth(os.Getenv("APP_PEPPER"), auth.DefaultMaxPasswordLength)
 98	if g == nil {
 99		log.Fatal("Could not init authentication.")
100	}
101
102	os.MkdirAll(dataDir, os.ModePerm)
103	dbPath := filepath.Join(dataDir, dbName) + "?_pragma=foreign_keys(1)"
104	db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
105	if err != nil {
106		log.Fatal(err)
107	}
108
109	db.AutoMigrate(&User{}, &Habit{}, &Ack{})
110
111	// Init template engine
112	xt = extemplate.New()
113	err = xt.ParseDir("templates", []string{".tmpl"})
114	if err != nil {
115		log.Fatal(err)
116	}
117
118	// App
119	http.HandleFunc("GET /", getIndexHandler)
120	http.HandleFunc("GET /habits", loginRequired(getHabitsHandler))
121	http.HandleFunc("GET /habits/{id}", loginRequired(getHabitsIDHandler))
122	http.HandleFunc("GET /new/positive", loginRequired(getNewPositiveHandler))
123	http.HandleFunc("GET /new/negative", loginRequired(getNewNegativeHandler))
124	http.HandleFunc("POST /new", loginRequired(postNewHandler))
125	http.HandleFunc("POST /ack/{id}", loginRequired(postAckIDHandler))
126
127	// Auth
128	http.HandleFunc("GET /register", getRegisterHandler)
129	http.HandleFunc("GET /login", getLoginHandler)
130	http.HandleFunc("GET /reset-password", getResetPasswordHandler)
131	http.HandleFunc("GET /reset-password-confirm", getResetPasswordConfirmHandler)
132	http.HandleFunc("GET /logout", logoutHandler)
133	http.HandleFunc("POST /login", postLoginHandler)
134	http.HandleFunc("POST /register", postRegisterHandler)
135	http.HandleFunc("POST /reset-password", postResetPasswordHandler)
136	http.HandleFunc("POST /reset-password-confirm", postResetPasswordConfirmHandler)
137
138	// Static
139	http.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
140
141	// Start serving
142	log.Println("Port: " + port)
143	log.Println("Server started: " + baseUrl)
144	log.Fatal(http.ListenAndServe(":"+port, nil))
145}