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 /habits/{id}", loginRequired(postHabitsIDHandler))
126 http.HandleFunc("POST /delete/{id}", loginRequired(postDeleteIDHandler))
127 http.HandleFunc("POST /ack/{id}", loginRequired(postAckIDHandler))
128
129 // Auth
130 http.HandleFunc("GET /register", getRegisterHandler)
131 http.HandleFunc("GET /login", getLoginHandler)
132 http.HandleFunc("GET /reset-password", getResetPasswordHandler)
133 http.HandleFunc("GET /reset-password-confirm", getResetPasswordConfirmHandler)
134 http.HandleFunc("GET /logout", logoutHandler)
135 http.HandleFunc("POST /login", postLoginHandler)
136 http.HandleFunc("POST /register", postRegisterHandler)
137 http.HandleFunc("POST /reset-password", postResetPasswordHandler)
138 http.HandleFunc("POST /reset-password-confirm", postResetPasswordConfirmHandler)
139
140 // Static
141 http.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
142
143 // Start serving
144 log.Println("Port: " + port)
145 log.Println("Server started: " + baseUrl)
146 log.Fatal(http.ListenAndServe(":"+port, nil))
147}