Добавлен дашборд пользователя
This commit is contained in:
parent
e6f29479e8
commit
71602bb120
@ -8,7 +8,12 @@ import (
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/register", handlers.RegisterFormHandler)
|
||||
http.HandleFunc("/login", handlers.LoginHandler)
|
||||
http.HandleFunc("/logout", handlers.LogoutHandler)
|
||||
|
||||
log.Println("Сервер запущен на :8080")
|
||||
http.HandleFunc("/dashboard", handlers.AuthMiddleware(handlers.DashboardHandler))
|
||||
|
||||
// Запуск сервера
|
||||
log.Println("Клиент запущен на :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
@ -1,16 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"log"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := pocketbase.New()
|
||||
app := pocketbase.New()
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := app.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
8
go.mod
8
go.mod
@ -24,14 +24,14 @@ require (
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/image v0.25.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/oauth2 v0.28.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
|
16
go.sum
16
go.sum
@ -64,8 +64,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
@ -78,16 +78,16 @@ golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
|
149
handlers/dashboard.go
Normal file
149
handlers/dashboard.go
Normal file
@ -0,0 +1,149 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"pocketbaseSigner/models"
|
||||
)
|
||||
|
||||
|
||||
func DashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Метод не поддерживается", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Получаем токен из cookie
|
||||
cookie, err := r.Cookie("pb_auth")
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Получаем ID пользователя из cookie
|
||||
userIdCookie, err := r.Cookie("user_id")
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при получении ID пользователя: %v", err)
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Получаем данные пользователя
|
||||
url := "http://localhost:8090/api/collections/users/records/" + userIdCookie.Value
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании запроса: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", cookie.Value)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при получении данных пользователя: %v", err)
|
||||
http.Error(w, "Ошибка при получении данных", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при чтении ответа: %v", err)
|
||||
http.Error(w, "Ошибка при обработке данных", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем статус ответа
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("Ошибка при получении данных пользователя: %s", string(body))
|
||||
http.Error(w, "Ошибка при получении данных пользователя", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var userData models.UserData
|
||||
if err := json.Unmarshal(body, &userData); err != nil {
|
||||
log.Printf("Ошибка при разборе JSON: %v", err)
|
||||
http.Error(w, "Ошибка при обработке данных", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Отображаем dashboard
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
dashboardHTML := `
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Личный кабинет</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.user-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.logout-btn {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.logout-btn:hover {
|
||||
background: #c82333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Личный кабинет</h1>
|
||||
<form action="/logout" method="POST">
|
||||
<button type="submit" class="logout-btn">Выйти</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<h2>Информация о пользователе</h2>
|
||||
<p><strong>Email:</strong> ` + userData.Email + `</p>
|
||||
<p><strong>Имя:</strong> ` + userData.FirstName + `</p>
|
||||
<p><strong>Фамилия:</strong> ` + userData.LastName + `</p>
|
||||
<p><strong>Телефон:</strong> ` + userData.Phone + `</p>
|
||||
<p><strong>Дата регистрации:</strong> ` + userData.Created + `</p>
|
||||
<p><strong>Последнее обновление:</strong> ` + userData.Updated + `</p>
|
||||
<p><strong>Статус верификации:</strong> ` + formatVerified(userData.Verified) + `</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
w.Write([]byte(dashboardHTML))
|
||||
}
|
||||
|
||||
func formatVerified(verified bool) string {
|
||||
if verified {
|
||||
return "Подтвержден"
|
||||
}
|
||||
return "Не подтвержден"
|
||||
}
|
124
handlers/login.go
Normal file
124
handlers/login.go
Normal file
@ -0,0 +1,124 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"pocketbaseSigner/models"
|
||||
)
|
||||
|
||||
//1. добавить в хэндлере регистрации переход на логин хэндлер
|
||||
//2. реализовать логин
|
||||
//3. приступить к миддлвейру
|
||||
|
||||
|
||||
func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
http.ServeFile(w, r, "./web/login_form.html")
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
http.Error(w, "Ошибка при обработке формы", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if r.FormValue("email") == "" || r.FormValue("password") == "" {
|
||||
http.Error(w, "Email и пароль обязательны!", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Создаем структуру для запроса
|
||||
loginData := map[string]string{
|
||||
"identity": r.FormValue("email"),
|
||||
"password": r.FormValue("password"),
|
||||
}
|
||||
|
||||
// Преобразуем в JSON
|
||||
jsonData, err := json.Marshal(loginData)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании JSON: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
url := "http://localhost:8090/api/collections/users/auth-with-password"
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании запроса: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при отправке запроса: %v", err)
|
||||
http.Error(w, "Ошибка при подключении к серверу", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при чтении ответа: %v", err)
|
||||
http.Error(w, "Ошибка при обработке ответа", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем статус ответа
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("Ошибка авторизации: %s", string(body))
|
||||
http.Error(w, "Неверный email или пароль", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Парсим ответ для получения токена
|
||||
var authResp models.AuthResponse
|
||||
if err := json.Unmarshal(body, &authResp); err != nil {
|
||||
log.Printf("Ошибка при разборе JSON: %v", err)
|
||||
http.Error(w, "Ошибка при обработке ответа", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем наличие токена в ответе
|
||||
if authResp.Token == "" {
|
||||
log.Printf("Токен отсутствует в ответе: %s", string(body))
|
||||
http.Error(w, "Ошибка авторизации: токен не получен", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Логируем успешную авторизацию
|
||||
log.Printf("Успешная авторизация пользователя: %s", authResp.Token)
|
||||
|
||||
// Сохраняем токен в cookie
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "pb_auth",
|
||||
Value: authResp.Token,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
})
|
||||
|
||||
// Сохраняем ID пользователя в отдельную cookie
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "user_id",
|
||||
Value: authResp.Record.ID,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
})
|
||||
|
||||
// Перенаправляем на dashboard
|
||||
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
||||
}
|
||||
}
|
31
handlers/logout.go
Normal file
31
handlers/logout.go
Normal file
@ -0,0 +1,31 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Метод не поддерживается", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Удаляем cookie с токеном
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "pb_auth",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
})
|
||||
|
||||
// Удаляем cookie с ID пользователя
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "user_id",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
})
|
||||
|
||||
// Перенаправляем на страницу логина
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
}
|
45
handlers/middleware.go
Normal file
45
handlers/middleware.go
Normal file
@ -0,0 +1,45 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Получаем токен из cookie
|
||||
cookie, err := r.Cookie("pb_auth")
|
||||
if err != nil {
|
||||
// Если токена нет, перенаправляем на страницу логина
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем валидность токена через PocketBase
|
||||
req, err := http.NewRequest("POST", "http://localhost:8090/api/collections/users/auth-refresh", nil)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании запроса: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", cookie.Value)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при проверке токена: %v", err)
|
||||
http.Error(w, "Ошибка при проверке авторизации", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Если токен невалиден, перенаправляем на страницу логина
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Если токен валиден, продолжаем выполнение
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
@ -1,91 +1,93 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"pocketbaseSigner/models"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"pocketbaseSigner/models"
|
||||
)
|
||||
|
||||
|
||||
func RegisterFormHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
http.ServeFile(w, r, "./web/register_form.html")
|
||||
return
|
||||
}
|
||||
if r.Method == http.MethodGet {
|
||||
http.ServeFile(w, r, "./web/register_form.html")
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
http.Error(w, "Ошибка при обработке формы", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if r.Method == http.MethodPost {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
http.Error(w, "Ошибка при обработке формы", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.UserForm{
|
||||
Email: r.FormValue("email"),
|
||||
Password: r.FormValue("password"),
|
||||
PasswordConfirm: r.FormValue("password_confirm"),
|
||||
FirstName: r.FormValue("firstname"),
|
||||
LastName: r.FormValue("lastname"),
|
||||
Phone: r.FormValue("phone"),
|
||||
}
|
||||
user := models.RegisterForm{
|
||||
Email: r.FormValue("email"),
|
||||
Password: r.FormValue("password"),
|
||||
PasswordConfirm: r.FormValue("password_confirm"),
|
||||
FirstName: r.FormValue("firstname"),
|
||||
LastName: r.FormValue("lastname"),
|
||||
Phone: r.FormValue("phone"),
|
||||
}
|
||||
|
||||
// нужно для маршалинга потому что переменные с маленькой буквы потеряются
|
||||
// если все переменные делать с большой буквы, то pocketbase не примет
|
||||
dataMap := map[string]string{
|
||||
"email": user.Email,
|
||||
"password": user.Password,
|
||||
"passwordConfirm": user.PasswordConfirm,
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Phone": user.Phone,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(dataMap)
|
||||
// Проверяем совпадение паролей
|
||||
if r.FormValue("password") != r.FormValue("password_confirm") {
|
||||
http.Error(w, "Пароли не совпали", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем обязательные поля
|
||||
if user.Email == "" || user.Password == "" {
|
||||
http.Error(w, "Email и пароль обязательны!", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if r.FormValue("password") != r.FormValue("password_confirm") {
|
||||
http.Error(w, "Пароли не совпали", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Проверка
|
||||
if user.Email == "" || user.Password == "" {
|
||||
http.Error(w, "Email и пароль обязательны!", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Подготавливаем данные для отправки
|
||||
dataMap := map[string]string{
|
||||
"email": user.Email,
|
||||
"password": user.Password,
|
||||
"passwordConfirm": user.PasswordConfirm,
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Phone": user.Phone,
|
||||
}
|
||||
|
||||
log.Printf("Получен пользователь: %+v\n", user)
|
||||
fmt.Println(json.Marshal(user))
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
data, err := json.Marshal(dataMap)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании JSON: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
url:= "http://localhost:8090/api/collections/users/records"
|
||||
fmt.Println(bytes.NewBuffer(data))
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Отправляем данные пользователя: %+v\n", user)
|
||||
|
||||
fmt.Println(bytes.NewBuffer(data))
|
||||
fmt.Println()
|
||||
url := "http://localhost:8090/api/collections/users/records"
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при создании запроса: %v", err)
|
||||
http.Error(w, "Внутренняя ошибка сервера", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
fmt.Println(req)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка при отправке запроса: %v", err)
|
||||
http.Error(w, "Ошибка при подключении к серверу", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
http.Error(w, "Данные отправлены", http.StatusOK)
|
||||
// Проверяем статус ответа
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("Ошибка при регистрации: %v", resp.StatusCode)
|
||||
http.Error(w, "Ошибка при регистрации", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// Перенаправляем на страницу логина после успешной регистрации
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
}
|
12
models/auth.go
Normal file
12
models/auth.go
Normal file
@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
type AuthResponse struct {
|
||||
Record struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"FirstName"`
|
||||
LastName string `json:"LastName"`
|
||||
Phone string `json:"Phone"`
|
||||
} `json:"record"`
|
||||
Token string `json:"token"`
|
||||
}
|
15
models/forms.go
Normal file
15
models/forms.go
Normal file
@ -0,0 +1,15 @@
|
||||
package models
|
||||
|
||||
type RegisterForm struct {
|
||||
Email string
|
||||
Password string
|
||||
PasswordConfirm string
|
||||
FirstName string
|
||||
LastName string
|
||||
Phone string
|
||||
}
|
||||
|
||||
type LoginForm struct{
|
||||
Email string
|
||||
Password string
|
||||
}
|
@ -1,17 +1,24 @@
|
||||
package models
|
||||
|
||||
type UserForm struct {
|
||||
Email string
|
||||
Password string
|
||||
PasswordConfirm string
|
||||
FirstName string
|
||||
LastName string
|
||||
Phone string
|
||||
}
|
||||
|
||||
type UserResponse struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
}
|
||||
|
||||
type UserData struct {
|
||||
CollectionId string `json:"collectionId"`
|
||||
CollectionName string `json:"collectionName"`
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"FirstName"`
|
||||
LastName string `json:"LastName"`
|
||||
Phone string `json:"Phone"`
|
||||
EmailVisibility bool `json:"emailVisibility"`
|
||||
Verified bool `json:"verified"`
|
||||
Avatar string `json:"avatar"`
|
||||
Created string `json:"created"`
|
||||
Updated string `json:"updated"`
|
||||
}
|
Binary file not shown.
BIN
pb_data/data.db
BIN
pb_data/data.db
Binary file not shown.
84
web/login_form.html
Normal file
84
web/login_form.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Регистрация / Авторизация</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f4f4f4;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
.form-container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
.form-container h2 {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="tel"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="form-container">
|
||||
<h1>Сервис подписи файлов</h1>
|
||||
<h2>Авторизация</h2>
|
||||
<form method="POST" action="/login">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Пароль:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">войти</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -96,7 +96,11 @@
|
||||
<input type="password" id="password_confirm" name="password_confirm" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">Войти</button>
|
||||
<button type="submit">Зарегистрироваться</button>
|
||||
</form>
|
||||
<br>
|
||||
<form method="GET" action="/login">
|
||||
<button type="submit">Уже зарегистрирован, хочу авторизоваться</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user