package router import ( "crypto/rand" "database/sql" "encoding/hex" "net/http" "strconv" "time" "go.jolheiser.com/invitea/api" "go.jolheiser.com/invitea/database" "go.jolheiser.com/invitea/static" "code.gitea.io/sdk/gitea" "github.com/go-chi/chi/v5" "github.com/rs/zerolog/log" ) type Routes struct { DB *database.Queries Gitea *gitea.Client GiteaURL string } func (ro *Routes) Index(w http.ResponseWriter, r *http.Request) { var isAdmin bool if ia, ok := r.Context().Value("isAdmin").(bool); ok { isAdmin = ia } dbInvites, err := ro.DB.ListInvites(r.Context()) if err != nil { log.Err(err).Msg("") } if err := static.Templates.ExecuteTemplate(w, "index.tmpl", map[string]any{ "isAdmin": isAdmin, "username": r.Context().Value("username"), "invites": api.InvitesFromDB(dbInvites...), }); err != nil { log.Err(err).Msg("") } } func (ro *Routes) IndexPost(w http.ResponseWriter, r *http.Request) { action := r.FormValue("action") if action == "" { http.Redirect(w, r, "/", http.StatusBadRequest) return } switch action { case "delete": id, err := strconv.ParseInt(r.FormValue("id"), 10, 64) if err != nil { http.Error(w, "invalid ID", http.StatusBadRequest) return } if err := ro.DB.DeleteInvite(r.Context(), id); err != nil { log.Err(err).Msg("could not delete invite") http.Error(w, "could not delete invite", http.StatusInternalServerError) return } case "create": u := r.FormValue("uses") var uses int64 if u != "" { var err error if uses, err = strconv.ParseInt(u, 10, 64); err != nil { http.Error(w, "invalid uses", http.StatusBadRequest) return } } e := r.FormValue("expiration") var expiration int64 if e != "" { ex, err := time.Parse("2006-01-02", e) if err != nil { http.Error(w, "invalid expiration", http.StatusBadRequest) return } expiration = ex.Unix() } code := make([]byte, 5) if _, err := rand.Read(code); err != nil { log.Err(err).Msg("could not generate code") http.Error(w, "could not generate code", http.StatusInternalServerError) return } if _, err := ro.DB.CreateInvite(r.Context(), database.CreateInviteParams{ Code: hex.EncodeToString(code), Total: sql.NullInt64{ Int64: uses, Valid: true, }, Expiration: sql.NullInt64{ Int64: expiration, Valid: true, }, }); err != nil { log.Err(err).Msg("could not create invite") http.Error(w, "could not create invite", http.StatusInternalServerError) return } } http.Redirect(w, r, "/", http.StatusSeeOther) } func (ro *Routes) Invite(w http.ResponseWriter, r *http.Request) { code := chi.URLParam(r, "code") dbInvite, err := ro.DB.GetInvite(r.Context(), code) if err != nil { log.Err(err).Str("code", code).Msg("could not get invite") http.NotFound(w, r) return } invite := api.InviteFromDB(dbInvite) if !invite.Valid() { http.NotFound(w, r) return } if err := static.Templates.ExecuteTemplate(w, "invite.tmpl", map[string]any{ "invite": invite, }); err != nil { log.Err(err).Msg("") } } func (ro *Routes) InvitePost(w http.ResponseWriter, r *http.Request) { code := chi.URLParam(r, "code") dbInvite, err := ro.DB.GetInvite(r.Context(), code) if err != nil { log.Err(err).Msg(code) http.NotFound(w, r) return } invite := api.InviteFromDB(dbInvite) if !invite.Valid() { http.NotFound(w, r) return } username := r.FormValue("username") password := r.FormValue("password") email := r.FormValue("email") var b bool if _, _, err := ro.Gitea.AdminCreateUser(gitea.CreateUserOption{ Username: username, Email: email, Password: password, MustChangePassword: &b, }); err != nil { log.Err(err).Msg("could not create user") http.Error(w, "could not create user", http.StatusInternalServerError) return } if err := ro.DB.UpdateInvite(r.Context(), database.UpdateInviteParams{ ID: dbInvite.ID, Uses: dbInvite.Uses + 1, }); err != nil { log.Err(err).Msg("could not update invite") http.Error(w, "could not update invite", http.StatusInternalServerError) return } http.Redirect(w, r, ro.GiteaURL+"/user/login", http.StatusSeeOther) }