render html change templ
This commit is contained in:
parent
cff64975d7
commit
e9876b0c6f
5
Makefile
5
Makefile
@ -30,10 +30,13 @@ migratedown:
|
|||||||
sqlc:
|
sqlc:
|
||||||
sqlc generate
|
sqlc generate
|
||||||
|
|
||||||
|
templ:
|
||||||
|
templ generate
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v -cover ./...
|
go test -v -cover ./...
|
||||||
|
|
||||||
server:
|
server:
|
||||||
go run main.go
|
go run main.go
|
||||||
|
|
||||||
.PHONY: network redis postgres createdb dropdb psql migrateup migratedown sqlc test server
|
.PHONY: network redis postgres createdb dropdb psql migrateup migratedown sqlc templ test server
|
||||||
7
assets/css/bootstrap.min.css
vendored
Normal file
7
assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
assets/css/bootstrap.min.css.map
Normal file
1
assets/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
100
assets/css/index.css
Normal file
100
assets/css/index.css
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
@charset "utf-8";
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
/* 禁用空格键的滚动 */
|
||||||
|
scroll-behavior: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-content {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-items {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-wh {
|
||||||
|
padding: 0.2rem 1.6rem;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand-fs {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 2.2rem;
|
||||||
|
height: 2.2rem;
|
||||||
|
fill: currentColor;
|
||||||
|
/* color: #f44336; */
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oauth {
|
||||||
|
align-items: center;
|
||||||
|
list-style-type: none;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oauth li {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
max-width: 1280px;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .title a {
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-box {
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(229, 246, 253);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-box .tip-icon {
|
||||||
|
width: 24px;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-box .tip-icon svg {
|
||||||
|
fill: currentColor;
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-box .tip-info p {
|
||||||
|
letter-spacing: 0.00938em;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: rgb(1, 67, 97);
|
||||||
|
margin-bottom: 0;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
7
assets/js/bootstrap.bundle.min.js
vendored
Normal file
7
assets/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
assets/js/bootstrap.bundle.min.js.map
Normal file
1
assets/js/bootstrap.bundle.min.js.map
Normal file
File diff suppressed because one or more lines are too long
7
assets/js/bootstrap.min.js
vendored
Normal file
7
assets/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
assets/js/bootstrap.min.js.map
Normal file
1
assets/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
2
assets/js/jquery.min.js
vendored
Normal file
2
assets/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module github.com/zhang2092/go-url-shortener
|
|||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/a-h/templ v0.2.793
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/csrf v1.7.2
|
github.com/gorilla/csrf v1.7.2
|
||||||
github.com/gorilla/handlers v1.5.2
|
github.com/gorilla/handlers v1.5.2
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -1,5 +1,7 @@
|
|||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY=
|
||||||
|
github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
@ -12,6 +14,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
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/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/gorilla/securecookie"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
AuthorizeCookie = "authorize"
|
|
||||||
ContextUser ctxKey = "context_user"
|
|
||||||
)
|
|
||||||
|
|
||||||
var secureCookie *securecookie.SecureCookie
|
|
||||||
|
|
||||||
type ctxKey string
|
|
||||||
|
|
||||||
type Authorize struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func genId() string {
|
|
||||||
return uuid.Must(uuid.NewRandom()).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetSecureCookie(sc *securecookie.SecureCookie) {
|
|
||||||
secureCookie = sc
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/zhang2092/go-url-shortener/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HomeView(templates fs.FS, store db.Store) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ctx := r.Context()
|
|
||||||
user := withUser(ctx)
|
|
||||||
result, err := store.ListUrlByUser(ctx, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
renderLayout(w, r, templates, nil, "home.html.tmpl")
|
|
||||||
}
|
|
||||||
renderLayout(w, r, templates, result, "home.html.tmpl")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/gorilla/csrf"
|
|
||||||
"github.com/zhang2092/go-url-shortener/pkg/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// renderLayout 渲染方法 带框架
|
|
||||||
func renderLayout(w http.ResponseWriter, r *http.Request, templates fs.FS, data any, tmpl string) {
|
|
||||||
t := template.New(filepath.Base(tmpl))
|
|
||||||
t = t.Funcs(template.FuncMap{
|
|
||||||
"csrfField": func() template.HTML {
|
|
||||||
return csrf.TemplateField(r)
|
|
||||||
},
|
|
||||||
"currentUser": func() *Authorize {
|
|
||||||
return withUser(r.Context())
|
|
||||||
},
|
|
||||||
"genShortUrl": func(url string) string {
|
|
||||||
scheme := "http://"
|
|
||||||
if r.TLS != nil {
|
|
||||||
scheme = "https://"
|
|
||||||
}
|
|
||||||
return scheme + r.Host + "/" + url
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
tpl := template.Must(t.Clone())
|
|
||||||
tpl, err := tpl.ParseFS(templates, tmpl, "base/header.html.tmpl", "base/footer.html.tmpl")
|
|
||||||
if err != nil {
|
|
||||||
logger.Logger.Errorf("template parse: %s, %v", tmpl, err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tpl.Execute(w, data); err != nil {
|
|
||||||
logger.Logger.Errorf("template execute: %s, %v", tmpl, err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
internal/.DS_Store
vendored
Normal file
BIN
internal/.DS_Store
vendored
Normal file
Binary file not shown.
@ -2,32 +2,23 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zhang2092/go-url-shortener/db"
|
"github.com/google/uuid"
|
||||||
"github.com/zhang2092/go-url-shortener/pkg/cookie"
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
pwd "github.com/zhang2092/go-url-shortener/pkg/password"
|
"github.com/zhang2092/go-url-shortener/internal/middleware"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/pkg/cookie"
|
||||||
|
pwd "github.com/zhang2092/go-url-shortener/internal/pkg/password"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type registerPageData struct {
|
func RegisterView(w http.ResponseWriter, r *http.Request) {
|
||||||
Summary string
|
templ.Register(w, r, &model.RegisterPageData{})
|
||||||
Email string
|
|
||||||
EmailMsg string
|
|
||||||
Username string
|
|
||||||
UsernameMsg string
|
|
||||||
Password string
|
|
||||||
PasswordMsg string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterView(templates fs.FS) http.HandlerFunc {
|
func Register(store db.Store) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
renderRegister(w, r, templates, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Register(templates fs.FS, store db.Store) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
@ -41,7 +32,7 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
password := r.PostFormValue("password")
|
password := r.PostFormValue("password")
|
||||||
resp, ok := viladatorRegister(email, username, password)
|
resp, ok := viladatorRegister(email, username, password)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderRegister(w, r, templates, resp)
|
templ.Register(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +43,7 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
arg := &db.CreateUserParams{
|
arg := &db.CreateUserParams{
|
||||||
ID: genId(),
|
ID: uuid.Must(uuid.NewRandom()).String(),
|
||||||
Username: username,
|
Username: username,
|
||||||
HashedPassword: hashedPassword,
|
HashedPassword: hashedPassword,
|
||||||
Email: email,
|
Email: email,
|
||||||
@ -62,12 +53,12 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if store.IsUniqueViolation(err) {
|
if store.IsUniqueViolation(err) {
|
||||||
resp.Summary = "邮箱或名称已经存在"
|
resp.Summary = "邮箱或名称已经存在"
|
||||||
renderRegister(w, r, templates, resp)
|
templ.Register(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Summary = "请求网络错误,请刷新重试"
|
resp.Summary = "请求网络错误,请刷新重试"
|
||||||
renderRegister(w, r, templates, resp)
|
templ.Register(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,26 +66,16 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type loginPageData struct {
|
func LoginView(w http.ResponseWriter, r *http.Request) {
|
||||||
Summary string
|
templ.Login(w, r, &model.LoginPageData{})
|
||||||
Email string
|
|
||||||
EmailMsg string
|
|
||||||
Password string
|
|
||||||
PasswordMsg string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginView(templates fs.FS) http.HandlerFunc {
|
func Login(store db.Store) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
renderLogin(w, r, templates, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Login(templates fs.FS, store db.Store) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
renderLogin(w, r, templates, registerPageData{Summary: "请求网络错误,请刷新重试"})
|
templ.Login(w, r, &model.LoginPageData{Summary: "请求网络错误,请刷新重试"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +83,7 @@ func Login(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
password := r.PostFormValue("password")
|
password := r.PostFormValue("password")
|
||||||
resp, ok := viladatorLogin(email, password)
|
resp, ok := viladatorLogin(email, password)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderLogin(w, r, templates, resp)
|
templ.Login(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,26 +92,26 @@ func Login(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if store.IsNoRows(sql.ErrNoRows) {
|
if store.IsNoRows(sql.ErrNoRows) {
|
||||||
resp.Summary = "邮箱或密码错误"
|
resp.Summary = "邮箱或密码错误"
|
||||||
renderLogin(w, r, templates, resp)
|
templ.Login(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Summary = "请求网络错误,请刷新重试"
|
resp.Summary = "请求网络错误,请刷新重试"
|
||||||
renderLogin(w, r, templates, resp)
|
templ.Login(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pwd.BcryptComparePassword(user.HashedPassword, password)
|
err = pwd.BcryptComparePassword(user.HashedPassword, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Summary = "邮箱或密码错误"
|
resp.Summary = "邮箱或密码错误"
|
||||||
renderLogin(w, r, templates, resp)
|
templ.Login(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
encoded, err := secureCookie.Encode(AuthorizeCookie, &Authorize{ID: user.ID, Name: user.Username})
|
encoded, err := middleware.Encode(middleware.AuthorizeCookie, &middleware.Authorize{ID: user.ID, Name: user.Username})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Summary = "请求网络错误,请刷新重试(cookie)"
|
resp.Summary = "请求网络错误,请刷新重试(cookie)"
|
||||||
renderLogin(w, r, templates, resp)
|
templ.Login(w, r, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,24 +121,16 @@ func Login(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Logout(templates fs.FS) http.HandlerFunc {
|
func Logout() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
cookie.DeleteCookie(w, cookie.AuthorizeName)
|
cookie.DeleteCookie(w, cookie.AuthorizeName)
|
||||||
http.Redirect(w, r, "/login", http.StatusFound)
|
http.Redirect(w, r, "/login", http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRegister(w http.ResponseWriter, r *http.Request, templates fs.FS, data any) {
|
func viladatorRegister(email, username, password string) (*model.RegisterPageData, bool) {
|
||||||
renderLayout(w, r, templates, data, "user/register.html.tmpl")
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderLogin(w http.ResponseWriter, r *http.Request, templates fs.FS, data any) {
|
|
||||||
renderLayout(w, r, templates, data, "user/login.html.tmpl")
|
|
||||||
}
|
|
||||||
|
|
||||||
func viladatorRegister(email, username, password string) (registerPageData, bool) {
|
|
||||||
ok := true
|
ok := true
|
||||||
resp := registerPageData{
|
resp := &model.RegisterPageData{
|
||||||
Email: email,
|
Email: email,
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
@ -179,9 +152,9 @@ func viladatorRegister(email, username, password string) (registerPageData, bool
|
|||||||
return resp, ok
|
return resp, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func viladatorLogin(email, password string) (loginPageData, bool) {
|
func viladatorLogin(email, password string) (*model.LoginPageData, bool) {
|
||||||
ok := true
|
ok := true
|
||||||
errs := loginPageData{
|
errs := &model.LoginPageData{
|
||||||
Email: email,
|
Email: email,
|
||||||
Password: password,
|
Password: password,
|
||||||
}
|
}
|
||||||
22
internal/handler/home.go
Normal file
22
internal/handler/home.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/middleware"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HomeView(store db.Store) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
user := middleware.GetUser(ctx)
|
||||||
|
result, err := store.ListUrlByUser(ctx, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
templ.Home(w, r, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
templ.Home(w, r, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,37 +1,36 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/zhang2092/go-url-shortener/db"
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
"github.com/zhang2092/go-url-shortener/service"
|
"github.com/zhang2092/go-url-shortener/internal/middleware"
|
||||||
"github.com/zhang2092/go-url-shortener/shortener"
|
"github.com/zhang2092/go-url-shortener/internal/service"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/shortener"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateShortUrlView(templates fs.FS) http.HandlerFunc {
|
func CreateShortUrlView(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
templ.CreateUrl(w, r, "")
|
||||||
renderLayout(w, r, templates, nil, "short_url/create.html.tmpl")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateShortUrl(templates fs.FS, store db.Store) http.HandlerFunc {
|
func CreateShortUrl(store db.Store) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
renderCreateShortUrl(w, r, templates, map[string]string{"Error": "请求参数错误"})
|
templ.CreateUrl(w, r, "请求参数错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
user := withUser(ctx)
|
user := middleware.GetUser(ctx)
|
||||||
longUrl := r.PostFormValue("long_url")
|
longUrl := r.PostFormValue("long_url")
|
||||||
shortUrl, err := shortener.GenerateShortLink(longUrl, user.ID)
|
shortUrl, err := shortener.GenerateShortLink(longUrl, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renderCreateShortUrl(w, r, templates, map[string]string{"Error": "生成短路径错误"})
|
templ.CreateUrl(w, r, "生成短路径错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,13 +41,13 @@ func CreateShortUrl(templates fs.FS, store db.Store) http.HandlerFunc {
|
|||||||
ExpireAt: time.Now().Add(time.Hour * 6),
|
ExpireAt: time.Now().Add(time.Hour * 6),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renderCreateShortUrl(w, r, templates, map[string]string{"Error": "短路径存储错误"})
|
templ.CreateUrl(w, r, "短路径存储错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = service.SaveUrlMapping(shortUrl, longUrl, user.ID)
|
err = service.SaveUrlMapping(shortUrl, longUrl, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renderCreateShortUrl(w, r, templates, map[string]string{"Error": "短路径存储错误"})
|
templ.CreateUrl(w, r, "短路径存储错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,18 +81,10 @@ func HandleShortUrlRedirect(w http.ResponseWriter, r *http.Request) {
|
|||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
shorUrl := vars["shortUrl"]
|
shorUrl := vars["shortUrl"]
|
||||||
link, err := service.RetrieveInitialUrl(shorUrl)
|
link, err := service.RetrieveInitialUrl(shorUrl)
|
||||||
if err != nil {
|
if err != nil || len(link) == 0 {
|
||||||
http.Error(w, "failed to get url", http.StatusInternalServerError)
|
RespondErr(w, "短链已经失效", nil)
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(link) == 0 {
|
|
||||||
http.Error(w, "short url get to long url is empty", http.StatusInternalServerError)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, link, http.StatusFound)
|
http.Redirect(w, r, link, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderCreateShortUrl(w http.ResponseWriter, r *http.Request, templates fs.FS, data any) {
|
|
||||||
renderLayout(w, r, templates, data, "short_url/create.html.tmpl")
|
|
||||||
}
|
|
||||||
@ -9,7 +9,7 @@ var (
|
|||||||
rxPhone = regexp.MustCompile(`^(13|14|15|16|17|18|19)\d{9}$`)
|
rxPhone = regexp.MustCompile(`^(13|14|15|16|17|18|19)\d{9}$`)
|
||||||
rxEmail = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
|
rxEmail = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
|
||||||
rxUsername = regexp.MustCompile(`^[a-z0-9A-Z]{6,20}$`) // 6到20位(字母,数字)
|
rxUsername = regexp.MustCompile(`^[a-z0-9A-Z]{6,20}$`) // 6到20位(字母,数字)
|
||||||
//rxPassword = regexp.MustCompile(`^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{8,18}$`) // 最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
|
// rxPassword = regexp.MustCompile(`^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{8,18}$`) // 最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateRxPhone(phone string) bool {
|
func ValidateRxPhone(phone string) bool {
|
||||||
@ -1,13 +1,37 @@
|
|||||||
package handler
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthorizeCookie = "authorize"
|
||||||
|
ContextUser ctxKey = "context_user"
|
||||||
|
)
|
||||||
|
|
||||||
|
var secureCookie *securecookie.SecureCookie
|
||||||
|
|
||||||
|
type ctxKey string
|
||||||
|
|
||||||
|
type Authorize struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSecureCookie(sc *securecookie.SecureCookie) {
|
||||||
|
secureCookie = sc
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encode(name string, value any) (string, error) {
|
||||||
|
return secureCookie.Encode(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
func MyAuthorize(next http.Handler) http.Handler {
|
func MyAuthorize(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
u := withUser(r.Context())
|
u := GetUser(r.Context())
|
||||||
if u == nil {
|
if u == nil {
|
||||||
http.Redirect(w, r, "/login", http.StatusFound)
|
http.Redirect(w, r, "/login", http.StatusFound)
|
||||||
return
|
return
|
||||||
@ -25,6 +49,11 @@ func SetUser(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cookie == nil || len(cookie.Value) == 0 {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
u := Authorize{}
|
u := Authorize{}
|
||||||
err = secureCookie.Decode(AuthorizeCookie, cookie.Value, &u)
|
err = secureCookie.Decode(AuthorizeCookie, cookie.Value, &u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -38,7 +67,7 @@ func SetUser(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUser(ctx context.Context) *Authorize {
|
func GetUser(ctx context.Context) *Authorize {
|
||||||
val := ctx.Value(ContextUser)
|
val := ctx.Value(ContextUser)
|
||||||
if u, ok := val.(Authorize); ok {
|
if u, ok := val.(Authorize); ok {
|
||||||
return &u
|
return &u
|
||||||
BIN
internal/templ/.DS_Store
vendored
Normal file
BIN
internal/templ/.DS_Store
vendored
Normal file
Binary file not shown.
67
internal/templ/auth/login.templ
Normal file
67
internal/templ/auth/login.templ
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ Login(r *http.Request, page string, form *model.LoginPageData) {
|
||||||
|
@base.Base(page) {
|
||||||
|
<div class="container">
|
||||||
|
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
||||||
|
<h1>登录</h1>
|
||||||
|
<div class="col-sm-4 py-md-5">
|
||||||
|
<form action="/login" method="post">
|
||||||
|
@templ.Raw(funcs.CsrfField(r))
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">邮箱</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
id="email"
|
||||||
|
value={ form.Email }
|
||||||
|
aria-describedby="emailValid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
if form.EmailMsg != "" {
|
||||||
|
<small id="emailValid" style="color: #f44336;" class="form-text">{ form.EmailMsg }</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">密码</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
value={ form.Password }
|
||||||
|
aria-describedby="passwordValid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
if form.PasswordMsg!= "" {
|
||||||
|
<small id="passwordValid" style="color: #f44336;" class="form-text">{ form.PasswordMsg }</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
||||||
|
</form>
|
||||||
|
if form.Summary!= "" {
|
||||||
|
<div class="py-md-5" style="color: #f44336;">
|
||||||
|
{ form.Summary }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
168
internal/templ/auth/login_templ.go
Normal file
168
internal/templ/auth/login_templ.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package auth
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Login(r *http.Request, page string, form *model.LoginPageData) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"container\"><div class=\"flex flex-column align-items row py-md-5 mt-md-5\"><h1>登录</h1><div class=\"col-sm-4 py-md-5\"><form action=\"/login\" method=\"post\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(funcs.CsrfField(r)).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">邮箱</span></div><input type=\"email\" name=\"email\" class=\"form-control\" required id=\"email\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(form.Email)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/login.templ`, Line: 29, Col: 27}
|
||||||
|
}
|
||||||
|
_, 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("\" aria-describedby=\"emailValid\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.EmailMsg != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<small id=\"emailValid\" style=\"color: #f44336;\" class=\"form-text\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(form.EmailMsg)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/login.templ`, Line: 34, Col: 88}
|
||||||
|
}
|
||||||
|
_, 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("</small>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">密码</span></div><input type=\"password\" name=\"password\" class=\"form-control\" required id=\"password\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(form.Password)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/login.templ`, Line: 48, Col: 30}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" aria-describedby=\"passwordValid\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.PasswordMsg != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<small id=\"passwordValid\" style=\"color: #f44336;\" class=\"form-text\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(form.PasswordMsg)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/login.templ`, Line: 53, Col: 94}
|
||||||
|
}
|
||||||
|
_, 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("</small>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><button type=\"submit\" class=\"btn btn-primary btn-block\">提交</button></form>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.Summary != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"py-md-5\" style=\"color: #f44336;\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(form.Summary)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/login.templ`, Line: 60, Col: 21}
|
||||||
|
}
|
||||||
|
_, 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("</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base.Base(page).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
86
internal/templ/auth/register.templ
Normal file
86
internal/templ/auth/register.templ
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ Register(r *http.Request, page string, form *model.RegisterPageData) {
|
||||||
|
@base.Base(page) {
|
||||||
|
<div class="container">
|
||||||
|
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
||||||
|
<h1>注册</h1>
|
||||||
|
<div class="col-sm-4 py-md-5">
|
||||||
|
<form action="/register" method="post">
|
||||||
|
@templ.Raw(funcs.CsrfField(r))
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">邮箱</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
id="email"
|
||||||
|
value={ form.Email }
|
||||||
|
aria-describedby="emailValid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
if form.Email!="" {
|
||||||
|
<small id="emailValid" style="color: #f44336;" class="form-text">{ form.EmailMsg }</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">名称</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
id="username"
|
||||||
|
value={ form.Username }
|
||||||
|
aria-describedby="usernameValid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
if form.Username!="" {
|
||||||
|
<small id="usernameValid" style="color: #f44336;" class="form-text">{ form.UsernameMsg }</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">密码</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
value={ form.Password }
|
||||||
|
aria-describedby="passwordValid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
if form.Password!="" {
|
||||||
|
<small id="passwordValid" style="color: #f44336;" class="form-text">{ form.PasswordMsg }</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
||||||
|
</form>
|
||||||
|
if form.Summary != "" {
|
||||||
|
<div class="py-md-5" style="color: #f44336;">
|
||||||
|
{ form.Summary }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
204
internal/templ/auth/register_templ.go
Normal file
204
internal/templ/auth/register_templ.go
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package auth
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Register(r *http.Request, page string, form *model.RegisterPageData) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"container\"><div class=\"flex flex-column align-items row py-md-5 mt-md-5\"><h1>注册</h1><div class=\"col-sm-4 py-md-5\"><form action=\"/register\" method=\"post\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(funcs.CsrfField(r)).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">邮箱</span></div><input type=\"email\" name=\"email\" class=\"form-control\" required id=\"email\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(form.Email)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 29, Col: 27}
|
||||||
|
}
|
||||||
|
_, 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("\" aria-describedby=\"emailValid\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.Email != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<small id=\"emailValid\" style=\"color: #f44336;\" class=\"form-text\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(form.EmailMsg)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 34, Col: 88}
|
||||||
|
}
|
||||||
|
_, 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("</small>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">名称</span></div><input type=\"text\" name=\"username\" class=\"form-control\" required id=\"username\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(form.Username)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 48, Col: 30}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" aria-describedby=\"usernameValid\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.Username != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<small id=\"usernameValid\" style=\"color: #f44336;\" class=\"form-text\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(form.UsernameMsg)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 53, Col: 94}
|
||||||
|
}
|
||||||
|
_, 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("</small>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">密码</span></div><input type=\"password\" name=\"password\" class=\"form-control\" required id=\"password\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(form.Password)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 67, Col: 30}
|
||||||
|
}
|
||||||
|
_, 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("\" aria-describedby=\"passwordValid\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.Password != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<small id=\"passwordValid\" style=\"color: #f44336;\" class=\"form-text\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(form.PasswordMsg)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 72, Col: 94}
|
||||||
|
}
|
||||||
|
_, 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("</small>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><button type=\"submit\" class=\"btn btn-primary btn-block\">提交</button></form>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if form.Summary != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"py-md-5\" style=\"color: #f44336;\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(form.Summary)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/auth/register.templ`, Line: 79, Col: 21}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||||
|
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></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base.Base(page).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
59
internal/templ/base/base.templ
Normal file
59
internal/templ/base/base.templ
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/css"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ Base(page string) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||||
|
<link rel="shortcut icon" href="/assets/favicon.ico" type="image/x-icon"/>
|
||||||
|
<link rel="stylesheet" href="/assets/css/bootstrap.min.css"/>
|
||||||
|
<link rel="stylesheet" href="/assets/css/index.css"/>
|
||||||
|
switch page {
|
||||||
|
case "home":
|
||||||
|
@css.HomeCSS()
|
||||||
|
}
|
||||||
|
<title>URL段地址服务</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<nav class="navbar navbar-light bg-light navbar-wh">
|
||||||
|
<a class="navbar-brand navbar-brand-fs" href="/">
|
||||||
|
URL段地址服务
|
||||||
|
</a>
|
||||||
|
<ul class="flex oauth">
|
||||||
|
{{ auth := funcs.GetAuthorize(ctx) }}
|
||||||
|
if auth != nil {
|
||||||
|
<li style="font-size: 12px;">
|
||||||
|
欢迎您: { auth.Name }
|
||||||
|
</li>
|
||||||
|
<li style="font-size: 12px;">
|
||||||
|
<a href="/logout" class="btn btn-primary btn-sm">退出</a>
|
||||||
|
</li>
|
||||||
|
} else {
|
||||||
|
<li>
|
||||||
|
<a href="/login" class="btn btn-outline-primary btn-sm">登录</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/register" class="btn btn-primary btn-sm">注册</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{ children... }
|
||||||
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
|
switch page {
|
||||||
|
case "home":
|
||||||
|
@js.HomeJS()
|
||||||
|
}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
105
internal/templ/base/base_templ.go
Normal file
105
internal/templ/base/base_templ.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package base
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/css"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Base(page string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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("<!doctype html><html lang=\"zh-CN\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"><link rel=\"shortcut icon\" href=\"/assets/favicon.ico\" type=\"image/x-icon\"><link rel=\"stylesheet\" href=\"/assets/css/bootstrap.min.css\"><link rel=\"stylesheet\" href=\"/assets/css/index.css\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
switch page {
|
||||||
|
case "home":
|
||||||
|
templ_7745c5c3_Err = css.HomeCSS().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<title>URL段地址服务</title></head><body><div class=\"wrapper\"><nav class=\"navbar navbar-light bg-light navbar-wh\"><a class=\"navbar-brand navbar-brand-fs\" href=\"/\">URL段地址服务</a><ul class=\"flex oauth\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
auth := funcs.GetAuthorize(ctx)
|
||||||
|
if auth != nil {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<li style=\"font-size: 12px;\">欢迎您: ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(auth.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/base/base.templ`, Line: 34, Col: 30}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li style=\"font-size: 12px;\"><a href=\"/logout\" class=\"btn btn-primary btn-sm\">退出</a></li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<li><a href=\"/login\" class=\"btn btn-outline-primary btn-sm\">登录</a></li><li><a href=\"/register\" class=\"btn btn-primary btn-sm\">注册</a></li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</ul></nav></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script src=\"/assets/js/jquery.min.js\"></script><script src=\"/assets/js/bootstrap.bundle.min.js\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
switch page {
|
||||||
|
case "home":
|
||||||
|
templ_7745c5c3_Err = js.HomeJS().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
23
internal/templ/css/home.templ
Normal file
23
internal/templ/css/home.templ
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package css
|
||||||
|
|
||||||
|
templ HomeCSS() {
|
||||||
|
<style>
|
||||||
|
.my_table {
|
||||||
|
display: block;
|
||||||
|
max-width: 1280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my_table tr {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my_table tr td {
|
||||||
|
display: inline-block;
|
||||||
|
word-wrap: break-word;
|
||||||
|
padding: 2px 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
40
internal/templ/css/home_templ.go
Normal file
40
internal/templ/css/home_templ.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package css
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
func HomeCSS() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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("<style>\n .my_table {\n display: block;\n max-width: 1280px;\n }\n\n .my_table tr {\n display: inline-block;\n width: 100%;\n border: 1px solid #eee;\n border-collapse: collapse;\n }\n\n .my_table tr td {\n display: inline-block;\n word-wrap: break-word;\n padding: 2px 5px;\n }\n</style>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
10
internal/templ/err/404.templ
Normal file
10
internal/templ/err/404.templ
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package err
|
||||||
|
|
||||||
|
import "github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
|
||||||
|
templ Error404() {
|
||||||
|
@base.Base("404") {
|
||||||
|
<h1>404</h1>
|
||||||
|
<p>当前短路径已经失效</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
60
internal/templ/err/404_templ.go
Normal file
60
internal/templ/err/404_templ.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package err
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
|
||||||
|
func Error404() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h1>404</h1><p>当前短路径已经失效</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base.Base("404").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
11
internal/templ/funcs/authorize.go
Normal file
11
internal/templ/funcs/authorize.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package funcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAuthorize(ctx context.Context) *middleware.Authorize {
|
||||||
|
return middleware.GetUser(ctx)
|
||||||
|
}
|
||||||
12
internal/templ/funcs/csrf.go
Normal file
12
internal/templ/funcs/csrf.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package funcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/csrf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CsrfField(r *http.Request) template.HTML {
|
||||||
|
return csrf.TemplateField(r)
|
||||||
|
}
|
||||||
51
internal/templ/home/home.templ
Normal file
51
internal/templ/home/home.templ
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package home
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ Home(r *http.Request, page string, data []*db.UserRelateUrl) {
|
||||||
|
@base.Base(page) {
|
||||||
|
<div class="container-fluid flex justify-content">
|
||||||
|
<div class="main">
|
||||||
|
<h3 style="margin-top: 20px;margin-bottom: 10px;">
|
||||||
|
短地址列表
|
||||||
|
<a
|
||||||
|
class="btn btn-primary"
|
||||||
|
href="/create-short-url"
|
||||||
|
>添加</a>
|
||||||
|
</h3>
|
||||||
|
<table class="my_table" style="display: block;">
|
||||||
|
<tr>
|
||||||
|
<th width="600px">原地址</th>
|
||||||
|
<th width="320px">短地址</th>
|
||||||
|
<th width="80px">是否有效</th>
|
||||||
|
<th width="80px">删除</th>
|
||||||
|
</tr>
|
||||||
|
for _, item := range data {
|
||||||
|
<tr>
|
||||||
|
<td width="600px">{ item.OriginUrl }</td>
|
||||||
|
<td width="320px"><a target="_blank" href={ templ.URL(item.ShortUrl) }>{ item.ShortUrl }</a></td>
|
||||||
|
<td width="80px">
|
||||||
|
if item.Status == 0 {
|
||||||
|
<code>YES</code>
|
||||||
|
} else {
|
||||||
|
<code>NO</code>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td width="80px">
|
||||||
|
if item.Status == 0 {
|
||||||
|
<button data-short-url={ item.ShortUrl } class="btn btn-danger deleteShortUrl">删除</button>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
@templ.Raw(funcs.CsrfField(r))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
156
internal/templ/home/home_templ.go
Normal file
156
internal/templ/home/home_templ.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package home
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Home(r *http.Request, page string, data []*db.UserRelateUrl) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"container-fluid flex justify-content\"><div class=\"main\"><h3 style=\"margin-top: 20px;margin-bottom: 10px;\">短地址列表 <a class=\"btn btn-primary\" href=\"/create-short-url\">添加</a></h3><table class=\"my_table\" style=\"display: block;\"><tr><th width=\"600px\">原地址</th><th width=\"320px\">短地址</th><th width=\"80px\">是否有效</th><th width=\"80px\">删除</th></tr>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, item := range data {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<tr><td width=\"600px\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(item.OriginUrl)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/home/home.templ`, Line: 30, Col: 41}
|
||||||
|
}
|
||||||
|
_, 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("</td><td width=\"320px\"><a target=\"_blank\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 templ.SafeURL = templ.URL(item.ShortUrl)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.ShortUrl)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/home/home.templ`, Line: 31, Col: 93}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></td><td width=\"80px\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if item.Status == 0 {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<code>YES</code>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<code>NO</code>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td width=\"80px\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if item.Status == 0 {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button data-short-url=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(item.ShortUrl)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templ/home/home.templ`, Line: 41, Col: 47}
|
||||||
|
}
|
||||||
|
_, 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("\" class=\"btn btn-danger deleteShortUrl\">删除</button>")
|
||||||
|
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("</table>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(funcs.CsrfField(r)).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base.Base(page).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
28
internal/templ/js/home.templ
Normal file
28
internal/templ/js/home.templ
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package js
|
||||||
|
|
||||||
|
templ HomeJS() {
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('.deleteShortUrl').click(function () {
|
||||||
|
let csrfToken = $('input[name="csrf_token"]').val()
|
||||||
|
let u = $(this).attr('data-short-url')
|
||||||
|
$.ajax({
|
||||||
|
url: '/delete-short-url/' + u,
|
||||||
|
type: 'POST',
|
||||||
|
cache: false,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
headers: {
|
||||||
|
"X-CSRF-Token": csrfToken
|
||||||
|
},
|
||||||
|
success: function (res) {
|
||||||
|
if (res.success) {
|
||||||
|
alert('删除成功');
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert('删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
40
internal/templ/js/home_templ.go
Normal file
40
internal/templ/js/home_templ.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package js
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
func HomeJS() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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("<script type=\"text/javascript\">\n $('.deleteShortUrl').click(function () {\n let csrfToken = $('input[name=\"csrf_token\"]').val()\n let u = $(this).attr('data-short-url')\n $.ajax({\n url: '/delete-short-url/' + u,\n type: 'POST',\n cache: false,\n processData: false,\n contentType: false,\n headers: {\n \"X-CSRF-Token\": csrfToken\n },\n success: function (res) {\n if (res.success) {\n alert('删除成功');\n window.location.reload();\n } else {\n alert('删除失败');\n }\n }\n })\n });\n</script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
19
internal/templ/model/auth.go
Normal file
19
internal/templ/model/auth.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type LoginPageData struct {
|
||||||
|
Summary string
|
||||||
|
Email string
|
||||||
|
EmailMsg string
|
||||||
|
Password string
|
||||||
|
PasswordMsg string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterPageData struct {
|
||||||
|
Summary string
|
||||||
|
Email string
|
||||||
|
EmailMsg string
|
||||||
|
Username string
|
||||||
|
UsernameMsg string
|
||||||
|
Password string
|
||||||
|
PasswordMsg string
|
||||||
|
}
|
||||||
38
internal/templ/templ.go
Normal file
38
internal/templ/templ.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package templ
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/auth"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/err"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/home"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/model"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Login(w http.ResponseWriter, r *http.Request, form *model.LoginPageData) {
|
||||||
|
checkErr(w, auth.Login(r, "login", form).Render(r.Context(), w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(w http.ResponseWriter, r *http.Request, form *model.RegisterPageData) {
|
||||||
|
checkErr(w, auth.Register(r, "register", form).Render(r.Context(), w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Home(w http.ResponseWriter, r *http.Request, data []*db.UserRelateUrl) {
|
||||||
|
checkErr(w, home.Home(r, "home", data).Render(r.Context(), w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateUrl(w http.ResponseWriter, r *http.Request, errorMsg string) {
|
||||||
|
checkErr(w, url.CreateUrl(r, "create_url", errorMsg).Render(r.Context(), w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error404(w http.ResponseWriter, r *http.Request) {
|
||||||
|
checkErr(w, err.Error404().Render(r.Context(), w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(w http.ResponseWriter, err error) {
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
34
internal/templ/url/url.templ
Normal file
34
internal/templ/url/url.templ
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package url
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ CreateUrl(r *http.Request, page string, errorMsg string) {
|
||||||
|
@base.Base(page) {
|
||||||
|
<div class="container">
|
||||||
|
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
||||||
|
<h1>创建短路径</h1>
|
||||||
|
<div class="col-sm-4 py-md-5">
|
||||||
|
<form action="/create-short-url" method="post">
|
||||||
|
@templ.Raw(funcs.CsrfField(r))
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">原路径</span>
|
||||||
|
</div>
|
||||||
|
<input type="text" name="long_url" class="form-control" required id="long_url"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">创建</button>
|
||||||
|
</form>
|
||||||
|
if errorMsg != "" {
|
||||||
|
<div class="py-md-5" style="color: #f44336;"></div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
82
internal/templ/url/url_templ.go
Normal file
82
internal/templ/url/url_templ.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.2.793
|
||||||
|
package url
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/base"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/templ/funcs"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateUrl(r *http.Request, page string, errorMsg string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
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_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"container\"><div class=\"flex flex-column align-items row py-md-5 mt-md-5\"><h1>创建短路径</h1><div class=\"col-sm-4 py-md-5\"><form action=\"/create-short-url\" method=\"post\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ.Raw(funcs.CsrfField(r)).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"form-group\"><div class=\"input-group\"><div class=\"input-group-prepend\"><span class=\"input-group-text\">原路径</span></div><input type=\"text\" name=\"long_url\" class=\"form-control\" required id=\"long_url\"></div></div><button type=\"submit\" class=\"btn btn-primary btn-block\">创建</button></form>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if errorMsg != "" {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"py-md-5\" style=\"color: #f44336;\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base.Base(page).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
50
main.go
50
main.go
@ -18,17 +18,15 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/zhang2092/go-url-shortener/db"
|
"github.com/zhang2092/go-url-shortener/internal/db"
|
||||||
"github.com/zhang2092/go-url-shortener/handler"
|
"github.com/zhang2092/go-url-shortener/internal/handler"
|
||||||
"github.com/zhang2092/go-url-shortener/pkg/logger"
|
"github.com/zhang2092/go-url-shortener/internal/middleware"
|
||||||
"github.com/zhang2092/go-url-shortener/service"
|
"github.com/zhang2092/go-url-shortener/internal/pkg/logger"
|
||||||
|
"github.com/zhang2092/go-url-shortener/internal/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed web/template
|
//go:embed assets
|
||||||
var templateFS embed.FS
|
var assetsFS embed.FS
|
||||||
|
|
||||||
//go:embed web/static
|
|
||||||
var staticFS embed.FS
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var local bool
|
var local bool
|
||||||
@ -43,14 +41,8 @@ func main() {
|
|||||||
|
|
||||||
logger.NewLogger()
|
logger.NewLogger()
|
||||||
|
|
||||||
// Set up templates
|
// Set up assets
|
||||||
templates, err := fs.Sub(templateFS, "web/template")
|
assets, err := fs.Sub(assetsFS, "assets")
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up statics
|
|
||||||
statics, err := fs.Sub(staticFS, "web/static")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -71,11 +63,11 @@ func main() {
|
|||||||
|
|
||||||
hashKey := securecookie.GenerateRandomKey(32)
|
hashKey := securecookie.GenerateRandomKey(32)
|
||||||
blockKey := securecookie.GenerateRandomKey(32)
|
blockKey := securecookie.GenerateRandomKey(32)
|
||||||
handler.SetSecureCookie(securecookie.New(hashKey, blockKey))
|
middleware.SetSecureCookie(securecookie.New(hashKey, blockKey))
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(mux.CORSMethodMiddleware(router))
|
router.Use(mux.CORSMethodMiddleware(router))
|
||||||
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics))))
|
router.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(http.FS(assets))))
|
||||||
|
|
||||||
csrfMiddleware := csrf.Protect(
|
csrfMiddleware := csrf.Protect(
|
||||||
[]byte(securecookie.GenerateRandomKey(32)),
|
[]byte(securecookie.GenerateRandomKey(32)),
|
||||||
@ -85,24 +77,24 @@ func main() {
|
|||||||
csrf.CookieName("authorize_csrf"),
|
csrf.CookieName("authorize_csrf"),
|
||||||
)
|
)
|
||||||
router.Use(csrfMiddleware)
|
router.Use(csrfMiddleware)
|
||||||
router.Use(handler.SetUser)
|
router.Use(middleware.SetUser)
|
||||||
|
|
||||||
router.Handle("/register", hds.MethodHandler{
|
router.Handle("/register", hds.MethodHandler{
|
||||||
http.MethodGet: http.Handler(handler.RegisterView(templates)),
|
http.MethodGet: http.HandlerFunc(handler.RegisterView),
|
||||||
http.MethodPost: http.Handler(handler.Register(templates, store)),
|
http.MethodPost: http.Handler(handler.Register(store)),
|
||||||
})
|
})
|
||||||
router.Handle("/login", hds.MethodHandler{
|
router.Handle("/login", hds.MethodHandler{
|
||||||
http.MethodGet: http.Handler(handler.LoginView(templates)),
|
http.MethodGet: http.HandlerFunc(handler.LoginView),
|
||||||
http.MethodPost: http.Handler(handler.Login(templates, store)),
|
http.MethodPost: http.Handler(handler.Login(store)),
|
||||||
})
|
})
|
||||||
router.Handle("/logout", handler.Logout(templates)).Methods(http.MethodGet)
|
router.Handle("/logout", handler.Logout()).Methods(http.MethodGet)
|
||||||
|
|
||||||
subRouter := router.PathPrefix("/").Subrouter()
|
subRouter := router.PathPrefix("/").Subrouter()
|
||||||
subRouter.Use(handler.MyAuthorize)
|
subRouter.Use(middleware.MyAuthorize)
|
||||||
subRouter.Handle("/", handler.HomeView(templates, store)).Methods(http.MethodGet)
|
subRouter.Handle("/", handler.HomeView(store)).Methods(http.MethodGet)
|
||||||
subRouter.Handle("/create-short-url", hds.MethodHandler{
|
subRouter.Handle("/create-short-url", hds.MethodHandler{
|
||||||
http.MethodGet: http.Handler(handler.CreateShortUrlView(templates)),
|
http.MethodGet: http.HandlerFunc(handler.CreateShortUrlView),
|
||||||
http.MethodPost: http.Handler(handler.CreateShortUrl(templates, store)),
|
http.MethodPost: http.Handler(handler.CreateShortUrl(store)),
|
||||||
})
|
})
|
||||||
subRouter.Handle("/delete-short-url/{shortUrl}", handler.DeleteShortUrl(store)).Methods(http.MethodPost)
|
subRouter.Handle("/delete-short-url/{shortUrl}", handler.DeleteShortUrl(store)).Methods(http.MethodPost)
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
<!-- <!doctype html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<link rel="stylesheet" href="/statics/css/bootstrap.min.css" />
|
|
||||||
<title>HLS流媒体</title>
|
|
||||||
{{block "css" .}}{{end}}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="wrapper"> -->
|
|
||||||
{{define "footer"}}
|
|
||||||
</div>
|
|
||||||
<script src="/static/js/jquery.min.js"></script>
|
|
||||||
<script src="/static/js/bootstrap.bundle.min.js"></script>
|
|
||||||
{{block "js" .}}{{end}}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
{{end}}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
{{define "header"}}
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<link rel="shortcut icon" href="/statics/favicon.ico" type="image/x-icon" />
|
|
||||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
|
|
||||||
<link rel="stylesheet" href="/static/css/index.css" />
|
|
||||||
{{block "css" .}}{{end}}
|
|
||||||
<title>URL段地址服务</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="wrapper">
|
|
||||||
<nav class="navbar navbar-light bg-light navbar-wh">
|
|
||||||
<a class="navbar-brand navbar-brand-fs" href="/">
|
|
||||||
URL段地址服务
|
|
||||||
</a>
|
|
||||||
<ul class="flex oauth">
|
|
||||||
{{if currentUser}}
|
|
||||||
<li style="font-size: 12px;">
|
|
||||||
欢迎您: {{ currentUser.Name }}
|
|
||||||
</li>
|
|
||||||
<li style="font-size: 12px;">
|
|
||||||
<a href="/logout" class="btn btn-primary btn-sm">退出</a>
|
|
||||||
</li>
|
|
||||||
{{else}}
|
|
||||||
<li>
|
|
||||||
<a href="/login" class="btn btn-outline-primary btn-sm">登录</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/register" class="btn btn-primary btn-sm">注册</a>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{{end}}
|
|
||||||
<!-- </div>
|
|
||||||
<script src="/statics/js/jquery.slim.min.js"></script>
|
|
||||||
<script src="/statics/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html> -->
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container-fluid flex justify-content">
|
|
||||||
<div class="main">
|
|
||||||
<h3 style="margin-top: 20px;margin-bottom: 10px;">短地址列表 <a class="btn btn-primary"
|
|
||||||
href="/create-short-url">添加</a></h3>
|
|
||||||
<table class="my_table" style="display: block;">
|
|
||||||
<tr>
|
|
||||||
<th width="600px">原地址</th>
|
|
||||||
<th width="320px">短地址</th>
|
|
||||||
<th width="80px">是否有效</th>
|
|
||||||
<th width="80px">删除</th>
|
|
||||||
</tr>
|
|
||||||
{{range .}}
|
|
||||||
<tr>
|
|
||||||
<td width="600px">{{.OriginUrl}}</td>
|
|
||||||
<td width="320px"><a target="_blank" href="{{genShortUrl .ShortUrl}}">{{genShortUrl .ShortUrl}}</a></td>
|
|
||||||
<td width="80px">
|
|
||||||
{{if eq .Status 0}}
|
|
||||||
<code>YES</code>
|
|
||||||
{{else}}
|
|
||||||
<code>NO</code>
|
|
||||||
{{end}}
|
|
||||||
</td>
|
|
||||||
<td width="80px">
|
|
||||||
{{if eq .Status 0}}
|
|
||||||
<button data-short-url="{{.ShortUrl}}" class="btn btn-danger deleteShortUrl">删除</button>
|
|
||||||
{{end}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
|
||||||
{{ csrfField }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{define "css"}}
|
|
||||||
<style>
|
|
||||||
.my_table {
|
|
||||||
display: block;
|
|
||||||
max-width: 1280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my_table tr {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my_table tr td {
|
|
||||||
display: inline-block;
|
|
||||||
word-wrap: break-word;
|
|
||||||
padding: 2px 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{end}}
|
|
||||||
{{define "js"}}
|
|
||||||
<script>
|
|
||||||
$('.deleteShortUrl').click(function () {
|
|
||||||
let csrfToken = $('input[name="csrf_token"]').val()
|
|
||||||
let u = $(this).attr('data-short-url')
|
|
||||||
$.ajax({
|
|
||||||
url: '/delete-short-url/' + u,
|
|
||||||
type: 'POST',
|
|
||||||
cache: false,
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
headers: {
|
|
||||||
"X-CSRF-Token": csrfToken
|
|
||||||
},
|
|
||||||
success: function (res) {
|
|
||||||
if (res.success) {
|
|
||||||
alert('删除成功');
|
|
||||||
window.location.reload();
|
|
||||||
} else {
|
|
||||||
alert('删除失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
||||||
{{template "footer" .}}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container">
|
|
||||||
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
|
||||||
<h1>创建短路径</h1>
|
|
||||||
<div class="col-sm-4 py-md-5">
|
|
||||||
<form action="/create-short-url" method="post">
|
|
||||||
{{ csrfField }}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">原路径</span>
|
|
||||||
</div>
|
|
||||||
<input type="text" name="long_url" class="form-control" required id="long_url">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">创建</button>
|
|
||||||
</form>
|
|
||||||
{{if .}}
|
|
||||||
<div class="py-md-5" style="color: #f44336;">
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "footer" .}}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container">
|
|
||||||
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
|
||||||
<h1>登录</h1>
|
|
||||||
<div class="col-sm-4 py-md-5">
|
|
||||||
<form action="/login" method="post">
|
|
||||||
{{ csrfField }}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">邮箱</span>
|
|
||||||
</div>
|
|
||||||
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
|
||||||
aria-describedby="emailValid">
|
|
||||||
</div>
|
|
||||||
{{if .EmailMsg}}
|
|
||||||
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailMsg}}</small>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">密码</span>
|
|
||||||
</div>
|
|
||||||
<input type="password" name="password" class="form-control" required id="password"
|
|
||||||
value="{{.Password}}" aria-describedby="passwordValid">
|
|
||||||
</div>
|
|
||||||
{{if .PasswordMsg}}
|
|
||||||
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordMsg}}</small>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
|
||||||
</form>
|
|
||||||
{{if .Summary}}
|
|
||||||
<div class="py-md-5" style="color: #f44336;">
|
|
||||||
{{.Summary}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "footer" .}}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container">
|
|
||||||
<div class="flex flex-column align-items row py-md-5 mt-md-5">
|
|
||||||
<h1>注册</h1>
|
|
||||||
<div class="col-sm-4 py-md-5">
|
|
||||||
<form action="/register" method="post">
|
|
||||||
{{ csrfField }}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">邮箱</span>
|
|
||||||
</div>
|
|
||||||
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
|
||||||
aria-describedby="emailValid">
|
|
||||||
</div>
|
|
||||||
{{if .EmailMsg}}
|
|
||||||
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailMsg}}</small>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">名称</span>
|
|
||||||
</div>
|
|
||||||
<input type="text" name="username" class="form-control" required id="username"
|
|
||||||
value="{{.Username}}" aria-describedby="usernameValid">
|
|
||||||
</div>
|
|
||||||
{{if .UsernameMsg}}
|
|
||||||
<small id="usernameValid" style="color: #f44336;" class="form-text">{{.UsernameMsg}}</small>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text">密码</span>
|
|
||||||
</div>
|
|
||||||
<input type="password" name="password" class="form-control" required id="password"
|
|
||||||
value="{{.Password}}" aria-describedby="passwordValid">
|
|
||||||
</div>
|
|
||||||
{{if .PasswordMsg}}
|
|
||||||
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordMsg}}</small>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
|
||||||
</form>
|
|
||||||
{{if .Summary}}
|
|
||||||
<div class="py-md-5" style="color: #f44336;">
|
|
||||||
{{.Summary}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "footer" .}}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user