Full app, v1.0. Contains web app and cli.
This commit is contained in:
parent
9f310f98db
commit
9f894671b0
42 changed files with 2245 additions and 0 deletions
46
.air.toml
Normal file
46
.air.toml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "areweplaying"
|
||||
cmd = "make build"
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
exclude_file = []
|
||||
exclude_regex = [".*_templ.go", "_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "templ", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
post_cmd = []
|
||||
pre_cmd = []
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -7,6 +7,16 @@
|
|||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
.env
|
||||
areweplaying
|
||||
areweplaying.*
|
||||
awp-cli
|
||||
awp-cli.*
|
||||
players.json
|
||||
.DS_Store
|
||||
|
||||
# air-related stuff
|
||||
tmp
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
|
|
|||
17
Makefile
Normal file
17
Makefile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
all: build
|
||||
|
||||
build:
|
||||
templ generate
|
||||
go build -o areweplaying cmd/web/*.go
|
||||
go build -o awp-cli cmd/cli/*.go
|
||||
|
||||
linuxbuild:
|
||||
templ generate
|
||||
GOOS=linux GOARCH=amd64 go build -o areweplaying.linux cmd/web/*.go
|
||||
GOOS=linux GOARCH=amd64 go build -o awp-cli.linux cmd/cli/*.go
|
||||
|
||||
clean:
|
||||
rm -rf areweplaying
|
||||
rm -rf areweplaying.*
|
||||
|
||||
test:
|
||||
82
cmd/cli/cmd/check.go
Normal file
82
cmd/cli/cmd/check.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
"github.com/hculpan/areweplaying/pkg/email"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func isAttending(body string) string {
|
||||
body = strings.ToLower(body)
|
||||
lines := strings.Fields(body)
|
||||
if strings.Contains(lines[0], "yes") {
|
||||
return "yes"
|
||||
} else if strings.Contains(lines[0], "no") {
|
||||
return "no"
|
||||
} else {
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// checkCmd represents the check command
|
||||
var checkCmd = &cobra.Command{
|
||||
Use: "check",
|
||||
Short: "Checks for new emails on player status",
|
||||
Long: `Checks at culpanvtt@gmail.com for any new
|
||||
emails sent by players to indicate if they
|
||||
will attend the next session.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
log.Default().Println("Checking for emails")
|
||||
emails, err := email.FetchEmails()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(emails) == 0 {
|
||||
log.Default().Println("No new emails")
|
||||
} else {
|
||||
session, err := data.ReadSessionData()
|
||||
if err != nil {
|
||||
log.Default().Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, email := range emails {
|
||||
if len(email.Body) > 0 {
|
||||
player := session.GetPlayerByEmail(email.FromAddress)
|
||||
if player != nil {
|
||||
attending := isAttending(email.Body)
|
||||
if attending == "yes" || attending == "no" {
|
||||
player.Attending = attending
|
||||
log.Default().Printf("Received player response for %s: %s", player.Name, player.Attending)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.PersistSession(session)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// checkCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// checkCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
42
cmd/cli/cmd/root.go
Normal file
42
cmd/cli/cmd/root.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "awp-cli",
|
||||
Short: "CLI utility for Are We Playing? web app",
|
||||
Long: `CLI utility for Are We Playing? web app`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.CompletionOptions.DisableDefaultCmd = true
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cli.yaml)")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
27
cmd/cli/main.go
Normal file
27
cmd/cli/main.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/hculpan/areweplaying/cmd/cli/cmd"
|
||||
"github.com/hculpan/areweplaying/pkg/utils"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
logFile := os.Getenv("CLI_LOG_FILE")
|
||||
if len(logFile) > 0 {
|
||||
utils.SetLogFile(logFile)
|
||||
}
|
||||
|
||||
cmd.Execute()
|
||||
}
|
||||
123
cmd/cli/main.go.bak
Normal file
123
cmd/cli/main.go.bak
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var username string
|
||||
var password string
|
||||
var fetchServer string
|
||||
var sendServer string
|
||||
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to load env: %s", err)
|
||||
}
|
||||
|
||||
username = os.Getenv("USERNAME")
|
||||
password = os.Getenv("PASSWORD")
|
||||
fetchServer = os.Getenv("IMAP_SERVER")
|
||||
sendServer = os.Getenv("SMTP_SERVER")
|
||||
port := 993
|
||||
|
||||
if len(username) == 0 || len(password) == 0 || len(fetchServer) == 0 || len(sendServer) == 0 {
|
||||
log.Fatal("missing configuration variables")
|
||||
}
|
||||
|
||||
imapClient, err := connectToServer(username, password, fetchServer, port)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer imapClient.Logout()
|
||||
|
||||
if err := fetchEmails(imapClient); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/*
|
||||
to := "harry@culpan.org"
|
||||
subject := "Test Email"
|
||||
body := "This is a test email sent from a Go-based email client."
|
||||
|
||||
if err := sendEmail(username, password, sendServer, 587, to, subject, body); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func fetchEmails(imapClient *client.Client) error {
|
||||
// Select the mailbox you want to read
|
||||
_, err := imapClient.Select("INBOX", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
criteria := imap.NewSearchCriteria()
|
||||
criteria.WithoutFlags = []string{"\\Seen"}
|
||||
uids, err := imapClient.Search(criteria)
|
||||
if err != nil {
|
||||
log.Printf("Search error: %s\n", err)
|
||||
}
|
||||
|
||||
if len(uids) > 0 {
|
||||
// Define the range of emails to fetch
|
||||
seqSet := new(imap.SeqSet)
|
||||
seqSet.AddNum(uids...)
|
||||
|
||||
// Fetch the required message attributes
|
||||
messages := make(chan *imap.Message, 10)
|
||||
section := &imap.BodySectionName{}
|
||||
items := []imap.FetchItem{section.FetchItem(), imap.FetchEnvelope}
|
||||
|
||||
go func() {
|
||||
if err := imapClient.Fetch(seqSet, items, messages); err != nil {
|
||||
log.Fatal("Fetch error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
for msg := range messages {
|
||||
fmt.Println("Subject:", msg.Envelope.Subject)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendEmail(username, password, server string, port int, to, subject, body string) error {
|
||||
auth := smtp.PlainAuth("", username, password, server)
|
||||
|
||||
msg := "From: " + username + "\r\n" +
|
||||
"To: " + to + "\r\n" +
|
||||
"Subject: " + subject + "\r\n" +
|
||||
"\r\n" +
|
||||
body
|
||||
|
||||
err := smtp.SendMail(server+":"+strconv.Itoa(port), auth, username, []string{to}, []byte(msg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func connectToServer(username, password, server string, port int) (*client.Client, error) {
|
||||
c, err := client.DialTLS(fmt.Sprintf("%s:%d", server, port), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.Login(username, password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
68
cmd/web/main.go
Normal file
68
cmd/web/main.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/hculpan/areweplaying/pkg/utils"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var appKey []byte
|
||||
|
||||
func main() {
|
||||
var port string
|
||||
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
port = "8080"
|
||||
}
|
||||
|
||||
port = os.Getenv("PORT")
|
||||
appKey = []byte(os.Getenv("APP_KEY"))
|
||||
if len(appKey) == 0 {
|
||||
log.Fatal("unable to load APP_KEY")
|
||||
}
|
||||
|
||||
logFile := os.Getenv("WEB_LOG_FILE")
|
||||
if len(logFile) > 0 {
|
||||
utils.SetLogFile(logFile)
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
workDir, _ := os.Getwd()
|
||||
filesDir := filepath.Join(workDir, "static")
|
||||
FileServer(r, "/static", http.Dir(filesDir))
|
||||
|
||||
routes(r)
|
||||
|
||||
log.Default().Printf("Starting up server on port :%s\n", port)
|
||||
http.ListenAndServe(fmt.Sprintf(":%s", port), r)
|
||||
}
|
||||
|
||||
// FileServer conveniently sets up a http.FileServer handler to serve
|
||||
// static files from a http.FileSystem.
|
||||
func FileServer(r chi.Router, path string, root http.FileSystem) {
|
||||
if strings.ContainsAny(path, "{}*") {
|
||||
panic("FileServer does not permit URL parameters.")
|
||||
}
|
||||
|
||||
if path != "/" && path[len(path)-1] != '/' {
|
||||
r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
|
||||
path += "/"
|
||||
}
|
||||
path += "*"
|
||||
|
||||
r.Get(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*")
|
||||
fs := http.StripPrefix(pathPrefix, http.FileServer(root))
|
||||
fs.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
156
cmd/web/routes.go
Normal file
156
cmd/web/routes.go
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
func routes(r *chi.Mux) {
|
||||
r.Post("/save-setup", func(w http.ResponseWriter, r *http.Request) {
|
||||
saveSetupHandler(w, r)
|
||||
})
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
comp := templates.MainPage()
|
||||
comp.Render(context.Background(), w)
|
||||
})
|
||||
|
||||
r.Post("/setup", func(w http.ResponseWriter, r *http.Request) {
|
||||
setupHandler(w, r)
|
||||
})
|
||||
|
||||
r.Get("/setup", func(w http.ResponseWriter, r *http.Request) {
|
||||
setupHandler(w, r)
|
||||
})
|
||||
|
||||
r.Post("/send-email", func(w http.ResponseWriter, r *http.Request) {
|
||||
sendEmailHandler(w, r)
|
||||
})
|
||||
|
||||
r.Get("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
if ValidateJWTFromCookie(r, appKey) {
|
||||
http.Redirect(w, r, "/setup", http.StatusSeeOther)
|
||||
}
|
||||
comp := templates.Login()
|
||||
comp.Render(context.Background(), w)
|
||||
})
|
||||
|
||||
r.Get("/send-reminder", func(w http.ResponseWriter, r *http.Request) {
|
||||
sendReminderHandler(w, r)
|
||||
})
|
||||
|
||||
r.Get("/sessioninfo", func(w http.ResponseWriter, r *http.Request) {
|
||||
session, dataErr := data.ReadSessionData()
|
||||
if dataErr != nil {
|
||||
http.Error(w, dataErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
playerName := r.URL.Query().Get("playerName")
|
||||
playerAttending := r.URL.Query().Get("playerAttending")
|
||||
|
||||
if len(playerName) > 0 && len(playerAttending) > 0 {
|
||||
if err := updatePlayerAttending(playerName, playerAttending, session); err != nil {
|
||||
log.Default().Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
comp := templates.PageBody(session)
|
||||
comp.Render(context.Background(), w)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func ValidateJWTFromCookie(r *http.Request, key []byte) bool {
|
||||
// Retrieve the JWT token from the cookie
|
||||
cookie, err := r.Cookie("jwt_token")
|
||||
if err != nil {
|
||||
// Cookie not found
|
||||
return false
|
||||
}
|
||||
|
||||
tokenString := cookie.Value
|
||||
|
||||
// Parse the token
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validate the algorithm used for the token
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return key, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if token is valid
|
||||
if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
// Here you can also add more checks on claims if needed
|
||||
// For example, check the issuer, subject, or expiration
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GenerateJWTAndStoreInCookie(w http.ResponseWriter, key []byte) error {
|
||||
// Create a new token object, specifying signing method and the claims you would like it to contain.
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"exp": time.Now().Add(90 * 24 * time.Hour).Unix(), // 90 days expiration
|
||||
})
|
||||
|
||||
// Sign and get the complete encoded token as a string using the secret
|
||||
tokenString, err := token.SignedString(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a cookie
|
||||
cookie := http.Cookie{
|
||||
Name: "jwt_token",
|
||||
Value: tokenString,
|
||||
Expires: time.Now().Add(90 * 24 * time.Hour),
|
||||
HttpOnly: true, // HttpOnly if you want to prevent access to the cookie from JavaScript
|
||||
}
|
||||
|
||||
// Set the cookie
|
||||
http.SetCookie(w, &cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updatePlayerAttending(name, attending string, session data.Session) error {
|
||||
for i, p := range session.Players {
|
||||
if p.Name == name {
|
||||
switch strings.ToLower(attending) {
|
||||
case "yes", "no":
|
||||
session.Players[i].Attending = strings.ToLower(attending)
|
||||
return data.PersistSession(session)
|
||||
case "toggle":
|
||||
newAttending := session.Players[i].Attending
|
||||
switch newAttending {
|
||||
case "unknown", "no":
|
||||
newAttending = "yes"
|
||||
case "yes":
|
||||
newAttending = "no"
|
||||
}
|
||||
session.Players[i].Attending = newAttending
|
||||
return data.PersistSession(session)
|
||||
default:
|
||||
return fmt.Errorf("unrecognized attending indicator %q", attending)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("player %q not found", name)
|
||||
}
|
||||
67
cmd/web/savesetuphandler.go
Normal file
67
cmd/web/savesetuphandler.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
func saveSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
nextSession := r.FormValue("nextSession")
|
||||
incDays := r.FormValue("incDays")
|
||||
sessionStatus := r.FormValue("sessionStatus")
|
||||
log.Default().Printf("sessionStatus = %s", sessionStatus)
|
||||
|
||||
session, dataErr := data.ReadSessionData()
|
||||
if dataErr != nil {
|
||||
http.Error(w, dataErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
msg := "Save successful!"
|
||||
err := updateSession(session, incDays, nextSession, sessionStatus)
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("Error in update: %s", err.Error())
|
||||
}
|
||||
|
||||
comp := templates.SaveSetup(msg)
|
||||
comp.Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func updateSession(session data.Session, incDays, nextSession, sessionStatus string) error {
|
||||
if val, err := strconv.Atoi(incDays); err == nil {
|
||||
session.IncrementDays = val
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
if nextSession == "nextSession" {
|
||||
if d, err := time.Parse(data.DATE_FORMAT, session.Date); err == nil {
|
||||
d = d.AddDate(0, 0, session.IncrementDays)
|
||||
session.Date = d.Format(data.DATE_FORMAT)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, p := range session.Players {
|
||||
if p.Gm {
|
||||
session.Players[i].Attending = "yes"
|
||||
} else {
|
||||
session.Players[i].Attending = "unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(sessionStatus) > 0 {
|
||||
session.Status = sessionStatus
|
||||
}
|
||||
|
||||
return data.PersistSession(session)
|
||||
}
|
||||
38
cmd/web/sendemailhandler.go
Normal file
38
cmd/web/sendemailhandler.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||
"github.com/hculpan/areweplaying/pkg/email"
|
||||
)
|
||||
|
||||
func sendEmailHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !ValidateJWTFromCookie(r, appKey) {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
r.ParseForm()
|
||||
to := r.FormValue("to")
|
||||
from := "culpanvtt@gmail.com"
|
||||
subject := r.FormValue("subject")
|
||||
body := r.FormValue("text")
|
||||
toArray := strings.Split(to, ",")
|
||||
for i := range toArray {
|
||||
toArray[i] = strings.Trim(toArray[i], " \t\n\r")
|
||||
}
|
||||
e := email.NewEmail(toArray, from, subject, body)
|
||||
|
||||
// log.Default().Printf("got email: To: %s, From: %s, Subject: %q, Body: %q", to, from, subject, body)
|
||||
err := email.SendEmail(e)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
comp := templates.SendEmail("Email sent!", "")
|
||||
comp.Render(context.Background(), w)
|
||||
}
|
||||
49
cmd/web/sendreminderhandler.go
Normal file
49
cmd/web/sendreminderhandler.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
func sendReminderHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !ValidateJWTFromCookie(r, appKey) {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
session, err := data.ReadSessionData()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
to := buildToList(session)
|
||||
subject := fmt.Sprintf("Game Reminder for %s", session.Date)
|
||||
text := fmt.Sprintf(
|
||||
`This is a game reminder for %s. Please respond with a "yes" or "no" to indicate
|
||||
if you plan to attend.
|
||||
|
||||
If you wish to check on the status of the game, you may do so at https://awp.culpanvtt.org.
|
||||
|
||||
Thank you,
|
||||
Your friendly "Are We Playing?" automated system`, session.Date)
|
||||
|
||||
comp := templates.SendReminder(to, subject, text)
|
||||
comp.Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func buildToList(session data.Session) string {
|
||||
emails := []string{}
|
||||
for _, player := range session.Players {
|
||||
if len(player.Email) > 0 {
|
||||
emails = append(emails, player.Email)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(emails, ", ")
|
||||
}
|
||||
31
cmd/web/setuphandler.go
Normal file
31
cmd/web/setuphandler.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
func setupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
session, dataErr := data.ReadSessionData()
|
||||
if dataErr != nil {
|
||||
http.Error(w, dataErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !ValidateJWTFromCookie(r, appKey) {
|
||||
r.ParseForm()
|
||||
pword := r.FormValue("password")
|
||||
if len(pword) == 0 || pword != session.Password {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
GenerateJWTAndStoreInCookie(w, appKey)
|
||||
}
|
||||
|
||||
comp := templates.Setup(session)
|
||||
comp.Render(context.Background(), w)
|
||||
}
|
||||
14
cmd/web/templates/header.templ
Normal file
14
cmd/web/templates/header.templ
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package templates
|
||||
|
||||
templ Header() {
|
||||
|
||||
<head>
|
||||
<title>Are We Playing?</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
|
||||
<script src="https://unpkg.com/htmx.org@1.9.10"
|
||||
integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
|
||||
crossorigin="anonymous"></script>
|
||||
</head>
|
||||
}
|
||||
53
cmd/web/templates/header_templ.go
Normal file
53
cmd/web/templates/header_templ.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func Header() templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<head><title>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Are We Playing?`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title><link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC\" crossorigin=\"anonymous\"><script src=\"https://unpkg.com/htmx.org@1.9.10\" integrity=\"sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC\" crossorigin=\"anonymous\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var3 := ``
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script></head>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
33
cmd/web/templates/index.templ
Normal file
33
cmd/web/templates/index.templ
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package templates
|
||||
|
||||
templ MainPage() {
|
||||
<html>
|
||||
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container mt-4" id="session-info" hx-get="/sessioninfo" hx-swap="innerHTML" hx-trigger="load"
|
||||
hx-target="#session-info">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="/login">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-gear text-secondary" viewBox="0 0 16 16">
|
||||
<path
|
||||
d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0" />
|
||||
<path
|
||||
d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src=" https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous">
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
}
|
||||
53
cmd/web/templates/index_templ.go
Normal file
53
cmd/web/templates/index_templ.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func MainPage() templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container mt-4\" id=\"session-info\" hx-get=\"/sessioninfo\" hx-swap=\"innerHTML\" hx-trigger=\"load\" hx-target=\"#session-info\"></div><div class=\"container\"><div class=\"d-flex justify-content-end\"><a href=\"/login\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-gear text-secondary\" viewBox=\"0 0 16 16\"><path d=\"M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0\"></path> <path d=\"M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z\"></path></svg></a></div></div><script src=\" https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM\" crossorigin=\"anonymous\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `
|
||||
`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
31
cmd/web/templates/login.templ
Normal file
31
cmd/web/templates/login.templ
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package templates
|
||||
|
||||
templ Login() {
|
||||
|
||||
<html>
|
||||
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container">
|
||||
<div class="row d-flex justify-content-center">
|
||||
<div class="col-4">
|
||||
<form action="/setup" method="POST">
|
||||
<h1 class="h3 mb-3 mt-4 fw-normal">Please sign in</h1>
|
||||
|
||||
<div class="form-floating">
|
||||
<input type="password" class="form-control mb-2" id="password" name="password"
|
||||
placeholder="Password" />
|
||||
<label for="floatingPassword">Password</label>
|
||||
</div>
|
||||
|
||||
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
}
|
||||
70
cmd/web/templates/login_templ.go
Normal file
70
cmd/web/templates/login_templ.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func Login() templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container\"><div class=\"row d-flex justify-content-center\"><div class=\"col-4\"><form action=\"/setup\" method=\"POST\"><h1 class=\"h3 mb-3 mt-4 fw-normal\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Please sign in`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><div class=\"form-floating\"><input type=\"password\" class=\"form-control mb-2\" id=\"password\" name=\"password\" placeholder=\"Password\"> <label for=\"floatingPassword\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var3 := `Password`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label></div><button class=\"w-100 btn btn-lg btn-primary\" type=\"submit\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var4 := `Sign in`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></form></div></div></div></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
50
cmd/web/templates/pagebody.templ
Normal file
50
cmd/web/templates/pagebody.templ
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package templates
|
||||
|
||||
import (
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
templ PageBody(session data.Session) {
|
||||
<div class="row">
|
||||
<div class="col h1 text-center">Next Session: { session.Date }</div>
|
||||
</div>
|
||||
<div class="row justify-content-center mt-4">
|
||||
<div class="col col-lg-3">
|
||||
<table class="table table-dark table-striped border border-secondary">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-1 text-center">Attending</th>
|
||||
<th scope="col" class="col-2 text-center">Player</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
for _, player := range session.Players {
|
||||
<tr>
|
||||
<td class="col col-lg-1 align-middle text-center" hx-get={ player.ToggleUrl } hx-swap="innerHTML"
|
||||
hx-target="#session-info" hx-trigger="click">
|
||||
if player.Attending == "yes" {
|
||||
<img src="/static/check_green.png" width="30" height="30" />
|
||||
} else if player.Attending == "no"{
|
||||
<img src="/static/check_red.png" width="30" height="30" />
|
||||
} else {
|
||||
<img src="/static/check_grey.png" width="30" height="30" />
|
||||
}
|
||||
</td>
|
||||
<td class="col col-lg-2 align-middle text-center" style="height: 50px;">{ player.Name }</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
if session.Status == "planned" {
|
||||
<div class="col h1 text-center text-success">Status: { session.Status }</div>
|
||||
} else if session.Status == "canceled" {
|
||||
<div class="col h1 text-center text-danger">Status: { session.Status }</div>
|
||||
} else {
|
||||
<div class="col h1 text-center">Status: { session.Status }</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
}
|
||||
200
cmd/web/templates/pagebody_templ.go
Normal file
200
cmd/web/templates/pagebody_templ.go
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import (
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
func PageBody(session data.Session) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"row\"><div class=\"col h1 text-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Next Session: `
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(session.Date)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/pagebody.templ`, Line: 8, Col: 64}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"row justify-content-center mt-4\"><div class=\"col col-lg-3\"><table class=\"table table-dark table-striped border border-secondary\"><thead><tr><th scope=\"col\" class=\"col-1 text-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var4 := `Attending`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</th><th scope=\"col\" class=\"col-2 text-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var5 := `Player`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</th></tr></thead> <tbody>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, player := range session.Players {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<tr><td class=\"col col-lg-1 align-middle text-center\" hx-get=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(player.ToggleUrl))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-swap=\"innerHTML\" hx-target=\"#session-info\" hx-trigger=\"click\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if player.Attending == "yes" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img src=\"/static/check_green.png\" width=\"30\" height=\"30\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else if player.Attending == "no" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img src=\"/static/check_red.png\" width=\"30\" height=\"30\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img src=\"/static/check_grey.png\" width=\"30\" height=\"30\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"col col-lg-2 align-middle text-center\" style=\"height: 50px;\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(player.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/pagebody.templ`, Line: 32, Col: 105}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td></tr>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</tbody></table></div></div><div class=\"row\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if session.Status == "planned" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col h1 text-center text-success\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var7 := `Status: `
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(session.Status)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/pagebody.templ`, Line: 41, Col: 73}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else if session.Status == "canceled" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col h1 text-center text-danger\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var9 := `Status: `
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(session.Status)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/pagebody.templ`, Line: 43, Col: 72}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col h1 text-center\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var11 := `Status: `
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(session.Status)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/pagebody.templ`, Line: 45, Col: 60}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
28
cmd/web/templates/save_setup.templ
Normal file
28
cmd/web/templates/save_setup.templ
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package templates
|
||||
|
||||
templ SaveSetup(status string) {
|
||||
<html>
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="/" class="btn btn-secondary"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8" />
|
||||
</svg>Back to Main Page</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<h1>{ status }</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class=" container">
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
}
|
||||
65
cmd/web/templates/save_setup_templ.go
Normal file
65
cmd/web/templates/save_setup_templ.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func SaveSetup(status string) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container\"><div class=\"row\"><div class=\"col-3\"><a href=\"/\" class=\"btn btn-secondary\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrow-left\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Back to Main Page`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div></div><div class=\"row mt-4\"><h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(status)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/save_setup.templ`, Line: 18, Col: 24}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1></div></div><footer class=\" container\"></footer></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
31
cmd/web/templates/sendemail.templ
Normal file
31
cmd/web/templates/sendemail.templ
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package templates
|
||||
|
||||
templ SendEmail(status string, msg string) {
|
||||
<html>
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="/" class="btn btn-secondary"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8" />
|
||||
</svg>Back to Main Page</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<h1>{ status }</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>{ msg }</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class=" container">
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
}
|
||||
78
cmd/web/templates/sendemail_templ.go
Normal file
78
cmd/web/templates/sendemail_templ.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func SendEmail(status string, msg string) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container\"><div class=\"row\"><div class=\"col-3\"><a href=\"/\" class=\"btn btn-secondary\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrow-left\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Back to Main Page`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div></div><div class=\"row mt-4\"><h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(status)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/sendemail.templ`, Line: 18, Col: 24}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1></div><div class=\"row\"><p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/sendemail.templ`, Line: 21, Col: 20}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p></div></div><footer class=\" container\"></footer></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
47
cmd/web/templates/sendreminder.templ
Normal file
47
cmd/web/templates/sendreminder.templ
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package templates
|
||||
|
||||
|
||||
templ SendReminder(to string, subject string, text string) {
|
||||
<html>
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="/" class="btn btn-secondary"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8" />
|
||||
</svg>Back to Main Page</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<h1>Send Reminder</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<form action="/send-email" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="toControl" class="form-label">To</label>
|
||||
<input type="text" id="toControl" name="to" value={to} />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="subjectControl" class="form-label">Subject</label>
|
||||
<input type="text" class="form-control" id="subjectControl" name="subject" value={ subject } />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="textControl" class="form-label">Text to send</label>
|
||||
<textarea class="form-control" id="subjectControl" name="text" rows="5">{ text }</textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Send Reminder</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class=" container">
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
}
|
||||
126
cmd/web/templates/sendreminder_templ.go
Normal file
126
cmd/web/templates/sendreminder_templ.go
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
func SendReminder(to string, subject string, text string) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container\"><div class=\"row\"><div class=\"col-3\"><a href=\"/\" class=\"btn btn-secondary\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrow-left\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Back to Main Page`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div></div><div class=\"row mt-4\"><h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var3 := `Send Reminder`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1></div><div class=\"row\"><form action=\"/send-email\" method=\"post\"><div class=\"mb-3\"><label for=\"toControl\" class=\"form-label\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var4 := `To`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"text\" id=\"toControl\" name=\"to\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(to))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></div><div class=\"mb-3\"><label for=\"subjectControl\" class=\"form-label\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var5 := `Subject`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"text\" class=\"form-control\" id=\"subjectControl\" name=\"subject\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(subject))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></div><div class=\"mb-3\"><label for=\"textControl\" class=\"form-label\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var6 := `Text to send`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <textarea class=\"form-control\" id=\"subjectControl\" name=\"text\" rows=\"5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `cmd/web/templates/sendreminder.templ`, Line: 33, Col: 98}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</textarea></div><button type=\"submit\" class=\"btn btn-primary\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var8 := `Send Reminder`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></form></div></div><footer class=\" container\"></footer></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
73
cmd/web/templates/setup.templ
Normal file
73
cmd/web/templates/setup.templ
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package templates
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
)
|
||||
|
||||
templ Setup(session data.Session) {
|
||||
<html>
|
||||
@Header()
|
||||
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="/" class="btn btn-secondary"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8" />
|
||||
</svg>Back to Main Page</a>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<a href="/send-reminder" class="btn btn-secondary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-envelope-plus" viewBox="0 0 16 16">
|
||||
<path
|
||||
d="M2 2a2 2 0 0 0-2 2v8.01A2 2 0 0 0 2 14h5.5a.5.5 0 0 0 0-1H2a1 1 0 0 1-.966-.741l5.64-3.471L8 9.583l7-4.2V8.5a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2zm3.708 6.208L1 11.105V5.383zM1 4.217V4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v.217l-7 4.2z" />
|
||||
<path
|
||||
d="M16 12.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0m-3.5-2a.5.5 0 0 0-.5.5v1h-1a.5.5 0 0 0 0 1h1v1a.5.5 0 0 0 1 0v-1h1a.5.5 0 0 0 0-1h-1v-1a.5.5 0 0 0-.5-.5" />
|
||||
</svg>
|
||||
Send Reminder
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<h1>Setup</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<form action="/save-setup" method="post">
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="nextSession" id="nextSession"
|
||||
name="nextSession" />
|
||||
<label class="form-check-label" for="nextSession">Change to next session</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="incrementDaysInput" class="form-label">Days to Increment</label>
|
||||
<input type="number" class="form-control" id="incrementDaysInput" name="incDays" min="1"
|
||||
style="max-width: 150px;" max="999" value={ strconv.Itoa(session.IncrementDays) } />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="sessionStatus" class="form-label">Session Status</label>
|
||||
<select class="form-select" aria-label="Default select example" name="sessionStatus"
|
||||
style="max-width: 150px;">
|
||||
<option selected></option>
|
||||
<option value="planned">Planned</option>
|
||||
<option value="canceled">Canceled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="sendEmail" id="sendEmail" name="sendEmail" />
|
||||
<label class="form-check-label" for="sendEmail">Send Email</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class=" container">
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
}
|
||||
146
cmd/web/templates/setup_templ.go
Normal file
146
cmd/web/templates/setup_templ.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.513
|
||||
package templates
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import (
|
||||
"github.com/hculpan/areweplaying/pkg/data"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func Setup(session data.Session) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = Header().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body class=\"bg-dark text-light\"><div class=\"container\"><div class=\"row\"><div class=\"col-3\"><a href=\"/\" class=\"btn btn-secondary\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrow-left\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var2 := `Back to Main Page`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"col-3\"><a href=\"/send-reminder\" class=\"btn btn-secondary\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-envelope-plus\" viewBox=\"0 0 16 16\"><path d=\"M2 2a2 2 0 0 0-2 2v8.01A2 2 0 0 0 2 14h5.5a.5.5 0 0 0 0-1H2a1 1 0 0 1-.966-.741l5.64-3.471L8 9.583l7-4.2V8.5a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2zm3.708 6.208L1 11.105V5.383zM1 4.217V4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v.217l-7 4.2z\"></path> <path d=\"M16 12.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0m-3.5-2a.5.5 0 0 0-.5.5v1h-1a.5.5 0 0 0 0 1h1v1a.5.5 0 0 0 1 0v-1h1a.5.5 0 0 0 0-1h-1v-1a.5.5 0 0 0-.5-.5\"></path></svg> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var3 := `Send Reminder`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div></div><div class=\"row mt-4\"><h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var4 := `Setup`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1></div><div class=\"row\"><form action=\"/save-setup\" method=\"post\"><div class=\"form-check mb-3\"><input class=\"form-check-input\" type=\"checkbox\" value=\"nextSession\" id=\"nextSession\" name=\"nextSession\"> <label class=\"form-check-label\" for=\"nextSession\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var5 := `Change to next session`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label></div><div class=\"mb-3\"><label for=\"incrementDaysInput\" class=\"form-label\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var6 := `Days to Increment`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"number\" class=\"form-control\" id=\"incrementDaysInput\" name=\"incDays\" min=\"1\" style=\"max-width: 150px;\" max=\"999\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(strconv.Itoa(session.IncrementDays)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></div><div class=\"mb-3\"><label for=\"sessionStatus\" class=\"form-label\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var7 := `Session Status`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <select class=\"form-select\" aria-label=\"Default select example\" name=\"sessionStatus\" style=\"max-width: 150px;\"><option selected></option> <option value=\"planned\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var8 := `Planned`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option> <option value=\"canceled\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var9 := `Canceled`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option></select></div><div class=\"form-check mb-3\"><input class=\"form-check-input\" type=\"checkbox\" value=\"sendEmail\" id=\"sendEmail\" name=\"sendEmail\"> <label class=\"form-check-label\" for=\"sendEmail\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var10 := `Send Email`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label></div><button type=\"submit\" class=\"btn btn-primary\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Var11 := `Save`
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></form></div></div><footer class=\" container\"></footer></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
16
exmaple_players.json
Normal file
16
exmaple_players.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"date": "Tuesday Jan 23, 2024 6:30pm",
|
||||
"players": [
|
||||
{
|
||||
"name": "Player1",
|
||||
"attending": "unknown"
|
||||
},
|
||||
{
|
||||
"name": "Player2",
|
||||
"attending": "yes"
|
||||
}
|
||||
],
|
||||
"inc_days": 7,
|
||||
"status": "planned",
|
||||
"password": "ABC123"
|
||||
}
|
||||
22
go.mod
Normal file
22
go.mod
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
module github.com/hculpan/areweplaying
|
||||
|
||||
go 1.21.6
|
||||
|
||||
require (
|
||||
github.com/a-h/templ v0.2.513
|
||||
github.com/go-chi/chi/v5 v5.0.11
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emersion/go-imap v1.2.1
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
||||
30
go.sum
Normal file
30
go.sum
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
github.com/a-h/templ v0.2.513 h1:ZmwGAOx4NYllnHy+FTpusc4+c5msoMpPIYX0Oy3dNqw=
|
||||
github.com/a-h/templ v0.2.513/go.mod h1:9gZxTLtRzM3gQxO8jr09Na0v8/jfliS97S9W5SScanM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
|
||||
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
||||
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
|
||||
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
31
pkg/data/data.go
Normal file
31
pkg/data/data.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package data
|
||||
|
||||
const (
|
||||
DATE_FORMAT string = "Monday Jan 2, 2006 3:04pm"
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
Name string `json:"name"`
|
||||
Attending string `json:"attending"`
|
||||
ToggleUrl string `json:"-"`
|
||||
Email string `json:"email"`
|
||||
Gm bool `json:"gm"`
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
Date string `json:"date"`
|
||||
Players []Player `json:"players"`
|
||||
IncrementDays int `json:"inc_days"`
|
||||
Status string `json:"status"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (s *Session) GetPlayerByEmail(addr string) *Player {
|
||||
for i, p := range s.Players {
|
||||
if addr == p.Email {
|
||||
return &s.Players[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
35
pkg/data/loaddata.go
Normal file
35
pkg/data/loaddata.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ReadSessionData() (Session, error) {
|
||||
var session Session
|
||||
data, err := os.ReadFile("players.json")
|
||||
if err != nil {
|
||||
return session, err
|
||||
}
|
||||
err = json.Unmarshal(data, &session)
|
||||
|
||||
if err == nil {
|
||||
for i, p := range session.Players {
|
||||
session.Players[i].ToggleUrl = "/sessioninfo?playerName=" + p.Name + "&playerAttending=toggle"
|
||||
}
|
||||
}
|
||||
|
||||
return session, err
|
||||
}
|
||||
|
||||
func PersistSession(session Session) error {
|
||||
// Convert the object to JSON
|
||||
jsonData, err := json.MarshalIndent(session, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write JSON data to file
|
||||
err = os.WriteFile("players.json", jsonData, 0644)
|
||||
return err
|
||||
}
|
||||
75
pkg/email/config.go
Normal file
75
pkg/email/config.go
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
const (
|
||||
IMAP_SERVICE EmailService = 993
|
||||
SMTP_SERVICE EmailService = 587
|
||||
)
|
||||
|
||||
type EmailService int
|
||||
|
||||
type Config struct {
|
||||
Username string
|
||||
Password string
|
||||
ImapServer string
|
||||
SmtpServer string
|
||||
}
|
||||
|
||||
func NewConfig(username, password, imapServer, smtpServer string) *Config {
|
||||
return &Config{
|
||||
Username: username,
|
||||
Password: password,
|
||||
ImapServer: imapServer,
|
||||
SmtpServer: smtpServer,
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfigFromEnv() (*Config, error) {
|
||||
var username string
|
||||
var password string
|
||||
var fetchServer string
|
||||
var sendServer string
|
||||
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading .env file: %s", err)
|
||||
}
|
||||
|
||||
username = os.Getenv("USERNAME")
|
||||
password = os.Getenv("PASSWORD")
|
||||
fetchServer = os.Getenv("IMAP_SERVER")
|
||||
sendServer = os.Getenv("SMTP_SERVER")
|
||||
|
||||
if len(username) == 0 || len(password) == 0 || len(fetchServer) == 0 || len(sendServer) == 0 {
|
||||
return nil, fmt.Errorf("missing configuration variables")
|
||||
}
|
||||
|
||||
return NewConfig(username, password, fetchServer, sendServer), nil
|
||||
}
|
||||
|
||||
func (c *Config) ConnectToServer(service EmailService) (*client.Client, error) {
|
||||
port := int(service)
|
||||
var host string
|
||||
if service == SMTP_SERVICE {
|
||||
host = c.SmtpServer
|
||||
} else {
|
||||
host = c.ImapServer
|
||||
}
|
||||
client, err := client.DialTLS(fmt.Sprintf("%s:%d", host, port), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := client.Login(c.Username, c.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
27
pkg/email/email.go
Normal file
27
pkg/email/email.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package email
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Email struct {
|
||||
ToAddress []string
|
||||
FromAddress string
|
||||
Subject string
|
||||
Body string
|
||||
}
|
||||
|
||||
func NewEmail(to []string, from, subject, body string) *Email {
|
||||
return &Email{
|
||||
ToAddress: to,
|
||||
FromAddress: from,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Email) String() string {
|
||||
bodyLength := len(e.Body)
|
||||
if bodyLength > 10 {
|
||||
bodyLength = 10
|
||||
}
|
||||
return fmt.Sprintf("To: %s, From: %s, Subject: %s, Body: %s", e.ToAddress, e.FromAddress, e.Subject, e.Body[:bodyLength])
|
||||
}
|
||||
100
pkg/email/fetch.go
Normal file
100
pkg/email/fetch.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/mail"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
)
|
||||
|
||||
func FetchEmails() ([]Email, error) {
|
||||
config, err := NewConfigFromEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imapClient, err := config.ConnectToServer(IMAP_SERVICE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer imapClient.Logout()
|
||||
|
||||
return fetchEmails(imapClient)
|
||||
}
|
||||
|
||||
func concatAddresses(addresses []*imap.Address) string {
|
||||
result := []string{}
|
||||
|
||||
for _, address := range addresses {
|
||||
if len(address.PersonalName) > 0 {
|
||||
result = append(result, fmt.Sprintf("%s <%s>", address.PersonalName, address.Address()))
|
||||
} else {
|
||||
result = append(result, address.Address())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return strings.Join(result, "; ")
|
||||
}
|
||||
|
||||
func fetchEmails(imapClient *client.Client) ([]Email, error) {
|
||||
result := []Email{}
|
||||
|
||||
// Select the mailbox you want to read
|
||||
_, err := imapClient.Select("INBOX", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
criteria := imap.NewSearchCriteria()
|
||||
criteria.WithoutFlags = []string{imap.SeenFlag}
|
||||
uids, err := imapClient.Search(criteria)
|
||||
if err != nil {
|
||||
log.Printf("Search error: %s\n", err)
|
||||
}
|
||||
|
||||
if len(uids) > 0 {
|
||||
// Define the range of emails to fetch
|
||||
seqSet := new(imap.SeqSet)
|
||||
seqSet.AddNum(uids...)
|
||||
|
||||
// Fetch the required message attributes
|
||||
messages := make(chan *imap.Message, 10)
|
||||
section := &imap.BodySectionName{}
|
||||
items := []imap.FetchItem{section.FetchItem(), imap.FetchEnvelope}
|
||||
|
||||
go func() {
|
||||
if err := imapClient.Fetch(seqSet, items, messages); err != nil {
|
||||
log.Fatal("Fetch error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
for msg := range messages {
|
||||
toAddress := concatAddresses(msg.Envelope.To)
|
||||
fromAddress := msg.Envelope.From[0].Address()
|
||||
r := msg.GetBody(section)
|
||||
if r == nil {
|
||||
return result, fmt.Errorf("server didn't returned message body")
|
||||
}
|
||||
m, err := mail.ReadMessage(r)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
body, err := io.ReadAll(m.Body)
|
||||
|
||||
email := NewEmail(
|
||||
[]string{toAddress},
|
||||
fromAddress,
|
||||
msg.Envelope.Subject,
|
||||
string(body),
|
||||
)
|
||||
result = append(result, *email)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
37
pkg/email/send.go
Normal file
37
pkg/email/send.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"net/smtp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SendEmail(email *Email) error {
|
||||
config, err := NewConfigFromEnv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = sendEmail(config.Username, config.Password, config.SmtpServer, int(SMTP_SERVICE), email.ToAddress, email.Subject, email.Body)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func sendEmail(username, password, server string, port int, to []string, subject, body string) error {
|
||||
auth := smtp.PlainAuth("", username, password, server)
|
||||
|
||||
msg := "From: " + username + "\r\n" +
|
||||
"To: " + strings.Join(to, ",") + "\r\n" +
|
||||
"Subject: " + subject + "\r\n" +
|
||||
"\r\n" +
|
||||
body
|
||||
|
||||
err := smtp.SendMail(server+":"+strconv.Itoa(port), auth, username, to, []byte(msg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
18
pkg/utils/utils.go
Normal file
18
pkg/utils/utils.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func SetLogFile(path string) error {
|
||||
logFile, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.SetOutput(logFile)
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile | log.Lmicroseconds)
|
||||
|
||||
return nil
|
||||
}
|
||||
BIN
static/check_green.png
Normal file
BIN
static/check_green.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
BIN
static/check_grey.png
Normal file
BIN
static/check_grey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
BIN
static/check_red.png
Normal file
BIN
static/check_red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
Loading…
Reference in a new issue