render html change templ
This commit is contained in:
		
							parent
							
								
									cff64975d7
								
							
						
					
					
						commit
						e9876b0c6f
					
				
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
								
							| @ -30,10 +30,13 @@ migratedown: | ||||
| sqlc: | ||||
| 	sqlc generate | ||||
| 
 | ||||
| templ: | ||||
| 	templ generate | ||||
| 
 | ||||
| test: | ||||
| 	go test -v -cover ./... | ||||
| 
 | ||||
| server: | ||||
| 	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 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/a-h/templ v0.2.793 | ||||
| 	github.com/google/uuid v1.6.0 | ||||
| 	github.com/gorilla/csrf v1.7.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/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/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= | ||||
| 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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= | ||||
| 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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| 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 ( | ||||
| 	"database/sql" | ||||
| 	"io/fs" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/zhang2092/go-url-shortener/db" | ||||
| 	"github.com/zhang2092/go-url-shortener/pkg/cookie" | ||||
| 	pwd "github.com/zhang2092/go-url-shortener/pkg/password" | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/db" | ||||
| 	"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 { | ||||
| 	Summary     string | ||||
| 	Email       string | ||||
| 	EmailMsg    string | ||||
| 	Username    string | ||||
| 	UsernameMsg string | ||||
| 	Password    string | ||||
| 	PasswordMsg string | ||||
| func RegisterView(w http.ResponseWriter, r *http.Request) { | ||||
| 	templ.Register(w, r, &model.RegisterPageData{}) | ||||
| } | ||||
| 
 | ||||
| func RegisterView(templates fs.FS) 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 { | ||||
| func Register(store db.Store) http.HandlerFunc { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		defer r.Body.Close() | ||||
| 
 | ||||
| @ -41,7 +32,7 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 		password := r.PostFormValue("password") | ||||
| 		resp, ok := viladatorRegister(email, username, password) | ||||
| 		if !ok { | ||||
| 			renderRegister(w, r, templates, resp) | ||||
| 			templ.Register(w, r, resp) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -52,7 +43,7 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 		} | ||||
| 
 | ||||
| 		arg := &db.CreateUserParams{ | ||||
| 			ID:             genId(), | ||||
| 			ID:             uuid.Must(uuid.NewRandom()).String(), | ||||
| 			Username:       username, | ||||
| 			HashedPassword: hashedPassword, | ||||
| 			Email:          email, | ||||
| @ -62,12 +53,12 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 		if err != nil { | ||||
| 			if store.IsUniqueViolation(err) { | ||||
| 				resp.Summary = "邮箱或名称已经存在" | ||||
| 				renderRegister(w, r, templates, resp) | ||||
| 				templ.Register(w, r, resp) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			resp.Summary = "请求网络错误,请刷新重试" | ||||
| 			renderRegister(w, r, templates, resp) | ||||
| 			templ.Register(w, r, resp) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -75,26 +66,16 @@ func Register(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type loginPageData struct { | ||||
| 	Summary     string | ||||
| 	Email       string | ||||
| 	EmailMsg    string | ||||
| 	Password    string | ||||
| 	PasswordMsg string | ||||
| func LoginView(w http.ResponseWriter, r *http.Request) { | ||||
| 	templ.Login(w, r, &model.LoginPageData{}) | ||||
| } | ||||
| 
 | ||||
| func LoginView(templates fs.FS) 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 { | ||||
| func Login(store db.Store) http.HandlerFunc { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		defer r.Body.Close() | ||||
| 
 | ||||
| 		if err := r.ParseForm(); err != nil { | ||||
| 			renderLogin(w, r, templates, registerPageData{Summary: "请求网络错误,请刷新重试"}) | ||||
| 			templ.Login(w, r, &model.LoginPageData{Summary: "请求网络错误,请刷新重试"}) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -102,7 +83,7 @@ func Login(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 		password := r.PostFormValue("password") | ||||
| 		resp, ok := viladatorLogin(email, password) | ||||
| 		if !ok { | ||||
| 			renderLogin(w, r, templates, resp) | ||||
| 			templ.Login(w, r, resp) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -111,26 +92,26 @@ func Login(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 		if err != nil { | ||||
| 			if store.IsNoRows(sql.ErrNoRows) { | ||||
| 				resp.Summary = "邮箱或密码错误" | ||||
| 				renderLogin(w, r, templates, resp) | ||||
| 				templ.Login(w, r, resp) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			resp.Summary = "请求网络错误,请刷新重试" | ||||
| 			renderLogin(w, r, templates, resp) | ||||
| 			templ.Login(w, r, resp) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		err = pwd.BcryptComparePassword(user.HashedPassword, password) | ||||
| 		if err != nil { | ||||
| 			resp.Summary = "邮箱或密码错误" | ||||
| 			renderLogin(w, r, templates, resp) | ||||
| 			templ.Login(w, r, resp) | ||||
| 			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 { | ||||
| 			resp.Summary = "请求网络错误,请刷新重试(cookie)" | ||||
| 			renderLogin(w, r, templates, resp) | ||||
| 			templ.Login(w, r, resp) | ||||
| 			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) { | ||||
| 		cookie.DeleteCookie(w, cookie.AuthorizeName) | ||||
| 		http.Redirect(w, r, "/login", http.StatusFound) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func renderRegister(w http.ResponseWriter, r *http.Request, templates fs.FS, data any) { | ||||
| 	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) { | ||||
| func viladatorRegister(email, username, password string) (*model.RegisterPageData, bool) { | ||||
| 	ok := true | ||||
| 	resp := registerPageData{ | ||||
| 	resp := &model.RegisterPageData{ | ||||
| 		Email:    email, | ||||
| 		Username: username, | ||||
| 		Password: password, | ||||
| @ -179,9 +152,9 @@ func viladatorRegister(email, username, password string) (registerPageData, bool | ||||
| 	return resp, ok | ||||
| } | ||||
| 
 | ||||
| func viladatorLogin(email, password string) (loginPageData, bool) { | ||||
| func viladatorLogin(email, password string) (*model.LoginPageData, bool) { | ||||
| 	ok := true | ||||
| 	errs := loginPageData{ | ||||
| 	errs := &model.LoginPageData{ | ||||
| 		Email:    email, | ||||
| 		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 | ||||
| 
 | ||||
| import ( | ||||
| 	"io/fs" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gorilla/mux" | ||||
| 	"github.com/zhang2092/go-url-shortener/db" | ||||
| 	"github.com/zhang2092/go-url-shortener/service" | ||||
| 	"github.com/zhang2092/go-url-shortener/shortener" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/db" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/middleware" | ||||
| 	"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 { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		renderLayout(w, r, templates, nil, "short_url/create.html.tmpl") | ||||
| 	} | ||||
| func CreateShortUrlView(w http.ResponseWriter, r *http.Request) { | ||||
| 	templ.CreateUrl(w, r, "") | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 		defer r.Body.Close() | ||||
| 
 | ||||
| 		if err := r.ParseForm(); err != nil { | ||||
| 			renderCreateShortUrl(w, r, templates, map[string]string{"Error": "请求参数错误"}) | ||||
| 			templ.CreateUrl(w, r, "请求参数错误") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		ctx := r.Context() | ||||
| 		user := withUser(ctx) | ||||
| 		user := middleware.GetUser(ctx) | ||||
| 		longUrl := r.PostFormValue("long_url") | ||||
| 		shortUrl, err := shortener.GenerateShortLink(longUrl, user.ID) | ||||
| 		if err != nil { | ||||
| 			renderCreateShortUrl(w, r, templates, map[string]string{"Error": "生成短路径错误"}) | ||||
| 			templ.CreateUrl(w, r, "生成短路径错误") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -42,13 +41,13 @@ func CreateShortUrl(templates fs.FS, store db.Store) http.HandlerFunc { | ||||
| 			ExpireAt:  time.Now().Add(time.Hour * 6), | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			renderCreateShortUrl(w, r, templates, map[string]string{"Error": "短路径存储错误"}) | ||||
| 			templ.CreateUrl(w, r, "短路径存储错误") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		err = service.SaveUrlMapping(shortUrl, longUrl, user.ID) | ||||
| 		if err != nil { | ||||
| 			renderCreateShortUrl(w, r, templates, map[string]string{"Error": "短路径存储错误"}) | ||||
| 			templ.CreateUrl(w, r, "短路径存储错误") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| @ -82,18 +81,10 @@ func HandleShortUrlRedirect(w http.ResponseWriter, r *http.Request) { | ||||
| 	vars := mux.Vars(r) | ||||
| 	shorUrl := vars["shortUrl"] | ||||
| 	link, err := service.RetrieveInitialUrl(shorUrl) | ||||
| 	if err != nil { | ||||
| 		http.Error(w, "failed to get url", http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 	if len(link) == 0 { | ||||
| 		http.Error(w, "short url get to long url is empty", http.StatusInternalServerError) | ||||
| 	if err != nil || len(link) == 0 { | ||||
| 		RespondErr(w, "短链已经失效", nil) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	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}$`) | ||||
| 	rxEmail    = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`) | ||||
| 	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 { | ||||
| @ -1,13 +1,37 @@ | ||||
| package handler | ||||
| package middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"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 { | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		u := withUser(r.Context()) | ||||
| 		u := GetUser(r.Context()) | ||||
| 		if u == nil { | ||||
| 			http.Redirect(w, r, "/login", http.StatusFound) | ||||
| 			return | ||||
| @ -25,6 +49,11 @@ func SetUser(next http.Handler) http.Handler { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if cookie == nil || len(cookie.Value) == 0 { | ||||
| 			next.ServeHTTP(w, r) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		u := Authorize{} | ||||
| 		err = secureCookie.Decode(AuthorizeCookie, cookie.Value, &u) | ||||
| 		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) | ||||
| 	if u, ok := val.(Authorize); ok { | ||||
| 		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/securecookie" | ||||
| 	"github.com/joho/godotenv" | ||||
| 	"github.com/zhang2092/go-url-shortener/db" | ||||
| 	"github.com/zhang2092/go-url-shortener/handler" | ||||
| 	"github.com/zhang2092/go-url-shortener/pkg/logger" | ||||
| 	"github.com/zhang2092/go-url-shortener/service" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/db" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/handler" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/middleware" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/pkg/logger" | ||||
| 	"github.com/zhang2092/go-url-shortener/internal/service" | ||||
| ) | ||||
| 
 | ||||
| //go:embed web/template | ||||
| var templateFS embed.FS | ||||
| 
 | ||||
| //go:embed web/static | ||||
| var staticFS embed.FS | ||||
| //go:embed assets | ||||
| var assetsFS embed.FS | ||||
| 
 | ||||
| func main() { | ||||
| 	var local bool | ||||
| @ -43,14 +41,8 @@ func main() { | ||||
| 
 | ||||
| 	logger.NewLogger() | ||||
| 
 | ||||
| 	// Set up templates | ||||
| 	templates, err := fs.Sub(templateFS, "web/template") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Set up statics | ||||
| 	statics, err := fs.Sub(staticFS, "web/static") | ||||
| 	// Set up assets | ||||
| 	assets, err := fs.Sub(assetsFS, "assets") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| @ -71,11 +63,11 @@ func main() { | ||||
| 
 | ||||
| 	hashKey := securecookie.GenerateRandomKey(32) | ||||
| 	blockKey := securecookie.GenerateRandomKey(32) | ||||
| 	handler.SetSecureCookie(securecookie.New(hashKey, blockKey)) | ||||
| 	middleware.SetSecureCookie(securecookie.New(hashKey, blockKey)) | ||||
| 
 | ||||
| 	router := mux.NewRouter() | ||||
| 	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( | ||||
| 		[]byte(securecookie.GenerateRandomKey(32)), | ||||
| @ -85,24 +77,24 @@ func main() { | ||||
| 		csrf.CookieName("authorize_csrf"), | ||||
| 	) | ||||
| 	router.Use(csrfMiddleware) | ||||
| 	router.Use(handler.SetUser) | ||||
| 	router.Use(middleware.SetUser) | ||||
| 
 | ||||
| 	router.Handle("/register", hds.MethodHandler{ | ||||
| 		http.MethodGet:  http.Handler(handler.RegisterView(templates)), | ||||
| 		http.MethodPost: http.Handler(handler.Register(templates, store)), | ||||
| 		http.MethodGet:  http.HandlerFunc(handler.RegisterView), | ||||
| 		http.MethodPost: http.Handler(handler.Register(store)), | ||||
| 	}) | ||||
| 	router.Handle("/login", hds.MethodHandler{ | ||||
| 		http.MethodGet:  http.Handler(handler.LoginView(templates)), | ||||
| 		http.MethodPost: http.Handler(handler.Login(templates, store)), | ||||
| 		http.MethodGet:  http.HandlerFunc(handler.LoginView), | ||||
| 		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.Use(handler.MyAuthorize) | ||||
| 	subRouter.Handle("/", handler.HomeView(templates, store)).Methods(http.MethodGet) | ||||
| 	subRouter.Use(middleware.MyAuthorize) | ||||
| 	subRouter.Handle("/", handler.HomeView(store)).Methods(http.MethodGet) | ||||
| 	subRouter.Handle("/create-short-url", hds.MethodHandler{ | ||||
| 		http.MethodGet:  http.Handler(handler.CreateShortUrlView(templates)), | ||||
| 		http.MethodPost: http.Handler(handler.CreateShortUrl(templates, store)), | ||||
| 		http.MethodGet:  http.HandlerFunc(handler.CreateShortUrlView), | ||||
| 		http.MethodPost: http.Handler(handler.CreateShortUrl(store)), | ||||
| 	}) | ||||
| 	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