Archived
Template
1
0
This repository has been archived on 2023-12-20. You can view files and clone it, but cannot push or open issues or pull requests.
Files
golang-base-project/main.go

154 lines
5.1 KiB
Go
Raw Normal View History

2021-12-12 14:56:13 +01:00
package baseproject
import (
"embed"
2022-01-29 10:21:05 +01:00
"fmt"
"github.com/BurntSushi/toml"
2021-12-12 14:56:13 +01:00
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
2022-01-29 10:21:05 +01:00
"github.com/nicksnyder/go-i18n/v2/i18n"
2021-12-12 14:56:13 +01:00
"github.com/uberswe/golang-base-project/middleware"
"github.com/uberswe/golang-base-project/routes"
2022-01-29 10:21:05 +01:00
"golang.org/x/text/language"
2021-12-12 14:56:13 +01:00
"html/template"
"io/fs"
"log"
"math/rand"
2021-12-12 14:56:13 +01:00
"net/http"
"time"
2021-12-12 14:56:13 +01:00
)
// staticFS is an embedded file system
2021-12-12 14:56:13 +01:00
//go:embed dist/*
var staticFS embed.FS
// Run is the main function that runs the entire package and starts the webserver, this is called by /cmd/base/main.go
2021-12-12 14:56:13 +01:00
func Run() {
// When generating random strings we need to provide a seed otherwise we always get the same strings the next time our application starts
rand.Seed(time.Now().UnixNano())
// We load environment variables, these are only read when the application launches
2021-12-12 14:56:13 +01:00
conf := loadEnvVariables()
2022-01-29 10:21:05 +01:00
// Translations
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
languages := []string{
"en",
"sv",
}
for _, l := range languages {
_, err := bundle.LoadMessageFile(fmt.Sprintf("active.%s.toml", l))
if err != nil {
log.Fatalln(err)
}
}
// We connect to the database using the configuration generated from the environment variables.
2021-12-12 14:56:13 +01:00
db, err := connectToDatabase(conf)
if err != nil {
log.Fatalln(err)
}
// Once a database connection is established we run any needed migrations
2021-12-12 14:56:13 +01:00
err = migrateDatabase(db)
if err != nil {
log.Fatalln(err)
}
// t will hold all our html templates used to render pages
var t *template.Template
2021-12-12 14:56:13 +01:00
// We parse and load the html files into our t variable
2021-12-12 14:56:13 +01:00
t, err = loadTemplates()
if err != nil {
log.Fatalln(err)
}
// A gin Engine instance with the default configuration
2021-12-12 14:56:13 +01:00
r := gin.Default()
// We create a new cookie store with a key used to secure cookies with HMAC
2021-12-12 14:56:13 +01:00
store := cookie.NewStore([]byte(conf.CookieSecret))
// We define our session middleware to be used globally on all routes
2021-12-12 14:56:13 +01:00
r.Use(sessions.Sessions("golang_base_project_session", store))
// We pase our template variable t to the gin engine so it can be used to render html pages
2021-12-12 14:56:13 +01:00
r.SetHTMLTemplate(t)
// our assets are only located in a section of our file system. so we create a sub file system.
2021-12-12 14:56:13 +01:00
subFS, err := fs.Sub(staticFS, "dist/assets")
if err != nil {
log.Fatalln(err)
}
// All static assets are under the /assets path so we make this its own group called assets
assets := r.Group("/assets")
// This middleware sets the Cache-Control header and is applied to the assets group only
assets.Use(middleware.Cache(conf.CacheMaxAge))
// All requests to /assets will use the sub fil system which contains all our static assets
assets.StaticFS("/", http.FS(subFS))
2021-12-12 14:56:13 +01:00
// Session middleware is applied to all groups after this point.
2021-12-12 14:56:13 +01:00
r.Use(middleware.Session(db))
// A General middleware is defined to add default headers to improve site security
2021-12-12 14:56:13 +01:00
r.Use(middleware.General())
// A new instance of the routes controller is created
2022-01-29 10:21:05 +01:00
controller := routes.New(db, conf, bundle)
2021-12-12 14:56:13 +01:00
// Any request to / will call controller.Index
2021-12-12 14:56:13 +01:00
r.GET("/", controller.Index)
// We want to handle both POST and GET requests on the /search route. We define both but use the same function to handle the requests.
2021-12-12 14:56:13 +01:00
r.GET("/search", controller.Search)
r.POST("/search", controller.Search)
2022-01-29 12:31:01 +01:00
r.Any("/search/:page", controller.Search)
r.Any("/search/:page/:query", controller.Search)
// We define our 404 handler for when a page can not be found
2021-12-12 14:56:13 +01:00
r.NoRoute(controller.NoRoute)
// noAuth is a group for routes which should only be accessed if the user is not authenticated
2021-12-12 14:56:13 +01:00
noAuth := r.Group("/")
noAuth.Use(middleware.NoAuth())
noAuth.GET("/login", controller.Login)
noAuth.GET("/register", controller.Register)
noAuth.GET("/activate/resend", controller.ResendActivation)
noAuth.GET("/activate/:token", controller.Activate)
noAuth.GET("/user/password/forgot", controller.ForgotPassword)
noAuth.GET("/user/password/reset/:token", controller.ResetPassword)
// We make a separate group for our post requests on the same endpoints so that we can define our throttling middleware on POST requests only.
2021-12-12 14:56:13 +01:00
noAuthPost := noAuth.Group("/")
noAuthPost.Use(middleware.Throttle(conf.RequestsPerMinute))
noAuthPost.POST("/login", controller.LoginPost)
noAuthPost.POST("/register", controller.RegisterPost)
noAuthPost.POST("/activate/resend", controller.ResendActivationPost)
noAuthPost.POST("/user/password/forgot", controller.ForgotPasswordPost)
noAuthPost.POST("/user/password/reset/:token", controller.ResetPasswordPost)
// the admin group handles routes that should only be accessible to authenticated users
2021-12-12 14:56:13 +01:00
admin := r.Group("/")
admin.Use(middleware.Auth())
admin.Use(middleware.Sensitive())
admin.GET("/admin", controller.Admin)
// We need to handle post from the login redirect
admin.POST("/admin", controller.Admin)
admin.GET("/logout", controller.Logout)
// This starts our webserver, our application will not stop running or go past this point unless
// an error occurs or the web server is stopped for some reason. It is designed to run forever.
2021-12-12 14:56:13 +01:00
err = r.Run(conf.Port)
if err != nil {
log.Fatalln(err)
}
}