311 lines
9.1 KiB
Go
311 lines
9.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"homework-manager/internal/middleware"
|
|
"homework-manager/internal/models"
|
|
"homework-manager/internal/service"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type ProfileHandler struct {
|
|
authService *service.AuthService
|
|
totpService *service.TOTPService
|
|
notificationService *service.NotificationService
|
|
appName string
|
|
}
|
|
|
|
func NewProfileHandler(notificationService *service.NotificationService) *ProfileHandler {
|
|
return &ProfileHandler{
|
|
authService: service.NewAuthService(),
|
|
totpService: service.NewTOTPService(),
|
|
notificationService: notificationService,
|
|
appName: "Super-HomeworkManager",
|
|
}
|
|
}
|
|
|
|
func (h *ProfileHandler) getUserID(c *gin.Context) uint {
|
|
userID, _ := c.Get(middleware.UserIDKey)
|
|
return userID.(uint)
|
|
}
|
|
|
|
func (h *ProfileHandler) Show(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
name, _ := c.Get(middleware.UserNameKey)
|
|
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|
|
|
|
func (h *ProfileHandler) Update(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
name := c.PostForm("name")
|
|
|
|
err := h.authService.UpdateProfile(userID, name)
|
|
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
|
|
if err != nil {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"error": "プロフィールの更新に失敗しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"success": "プロフィールを更新しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": user.Name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|
|
|
|
func (h *ProfileHandler) ChangePassword(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
oldPassword := c.PostForm("old_password")
|
|
newPassword := c.PostForm("new_password")
|
|
confirmPassword := c.PostForm("confirm_password")
|
|
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
name, _ := c.Get(middleware.UserNameKey)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
|
|
if newPassword != confirmPassword {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"passwordError": "新しいパスワードが一致しません",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
if len(newPassword) < 8 {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"passwordError": "パスワードは8文字以上で入力してください",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
err := h.authService.ChangePassword(userID, oldPassword, newPassword)
|
|
if err != nil {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"passwordError": "現在のパスワードが正しくありません",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"passwordSuccess": "パスワードを変更しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|
|
|
|
func (h *ProfileHandler) UpdateNotificationSettings(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
name, _ := c.Get(middleware.UserNameKey)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
|
|
settings := &models.UserNotificationSettings{
|
|
TelegramEnabled: c.PostForm("telegram_enabled") == "on",
|
|
TelegramChatID: c.PostForm("telegram_chat_id"),
|
|
NotifyOnCreate: c.PostForm("notify_on_create") == "on",
|
|
}
|
|
|
|
err := h.notificationService.UpdateUserSettings(userID, settings)
|
|
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
|
|
if err != nil {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"notifyError": "通知設定の更新に失敗しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"notifySuccess": "通知設定を更新しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|
|
|
|
const totpPendingSecretKey = "totp_pending_secret"
|
|
|
|
func (h *ProfileHandler) ShowTOTPSetup(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
|
|
setupData, err := h.totpService.GenerateSecret(user.Email, h.appName)
|
|
if err != nil {
|
|
RenderHTML(c, http.StatusOK, "totp_setup.html", gin.H{
|
|
"title": "2段階認証の設定",
|
|
"error": "シークレットの生成に失敗しました",
|
|
})
|
|
return
|
|
}
|
|
|
|
session := sessions.Default(c)
|
|
session.Set(totpPendingSecretKey, setupData.Secret)
|
|
session.Save()
|
|
|
|
RenderHTML(c, http.StatusOK, "totp_setup.html", gin.H{
|
|
"title": "2段階認証の設定",
|
|
"secret": setupData.Secret,
|
|
"qrCode": setupData.QRCodeB64,
|
|
"otpAuthURL": setupData.OTPAuthURL,
|
|
})
|
|
}
|
|
|
|
func (h *ProfileHandler) EnableTOTP(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
|
|
session := sessions.Default(c)
|
|
secret, ok := session.Get(totpPendingSecretKey).(string)
|
|
if !ok || secret == "" {
|
|
c.Redirect(http.StatusFound, "/profile/totp/setup")
|
|
return
|
|
}
|
|
|
|
renderSetupError := func(msg string) {
|
|
data := gin.H{
|
|
"title": "2段階認証の設定",
|
|
"error": msg,
|
|
"secret": secret,
|
|
}
|
|
if setupData, err := h.totpService.SetupDataFromSecret(secret, user.Email, h.appName); err == nil {
|
|
data["qrCode"] = setupData.QRCodeB64
|
|
data["otpAuthURL"] = setupData.OTPAuthURL
|
|
}
|
|
RenderHTML(c, http.StatusOK, "totp_setup.html", data)
|
|
}
|
|
|
|
password := c.PostForm("password")
|
|
if _, err := h.authService.Login(user.Email, password); err != nil {
|
|
renderSetupError("パスワードが正しくありません")
|
|
return
|
|
}
|
|
|
|
code := c.PostForm("totp_code")
|
|
if !h.totpService.Validate(secret, code) {
|
|
renderSetupError("認証コードが正しくありません。もう一度試してください")
|
|
return
|
|
}
|
|
|
|
if err := h.authService.EnableTOTP(userID, secret); err != nil {
|
|
RenderHTML(c, http.StatusOK, "totp_setup.html", gin.H{
|
|
"title": "2段階認証の設定",
|
|
"error": "2段階認証の有効化に失敗しました",
|
|
})
|
|
return
|
|
}
|
|
|
|
session.Delete(totpPendingSecretKey)
|
|
session.Save()
|
|
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
name, _ := c.Get(middleware.UserNameKey)
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
user, _ = h.authService.GetUserByID(userID)
|
|
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"totpSuccess": "2段階認証を有効化しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|
|
|
|
func (h *ProfileHandler) DisableTOTP(c *gin.Context) {
|
|
userID := h.getUserID(c)
|
|
role, _ := c.Get(middleware.UserRoleKey)
|
|
name, _ := c.Get(middleware.UserNameKey)
|
|
user, _ := h.authService.GetUserByID(userID)
|
|
notifySettings, _ := h.notificationService.GetUserSettings(userID)
|
|
|
|
password := c.PostForm("password")
|
|
if _, err := h.authService.Login(user.Email, password); err != nil {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"totpError": "パスワードが正しくありません",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := h.authService.DisableTOTP(userID); err != nil {
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"totpError": "2段階認証の無効化に失敗しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
return
|
|
}
|
|
|
|
user, _ = h.authService.GetUserByID(userID)
|
|
RenderHTML(c, http.StatusOK, "profile.html", gin.H{
|
|
"title": "プロフィール",
|
|
"user": user,
|
|
"totpSuccess": "2段階認証を無効化しました",
|
|
"isAdmin": role == "admin",
|
|
"userName": name,
|
|
"notifySettings": notifySettings,
|
|
})
|
|
}
|