You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
5.6 KiB

package user
import (
"database/sql"
"fmt"
"net/http"
"strconv"
"time"
"github.com/asaskevich/govalidator"
"github.com/gin-gonic/gin"
"github.com/imdotdev/im.dev/server/internal/email"
"github.com/imdotdev/im.dev/server/pkg/common"
"github.com/imdotdev/im.dev/server/pkg/config"
"github.com/imdotdev/im.dev/server/pkg/db"
"github.com/imdotdev/im.dev/server/pkg/log"
"github.com/imdotdev/im.dev/server/pkg/models"
"github.com/matcornic/hermes/v2"
)
var logger = log.RootLogger.New("logger", "user")
type Session struct {
Token string `json:"token"`
User *models.User `json:"user"`
CreateTime time.Time `json:"createTime"`
}
func Login(c *gin.Context) {
user := &models.User{}
c.Bind(&user)
err := user.Query("", "", user.Email)
if err != nil {
if err == sql.ErrNoRows {
c.JSON(http.StatusNotFound, common.RespError("邮箱不存在"))
return
}
logger.Error("login error", "error", err)
c.JSON(http.StatusInternalServerError, common.RespInternalError())
return
}
// delete old session
token := getToken(c)
deleteSession(token)
token = strconv.FormatInt(time.Now().UnixNano(), 10)
session := &Session{
Token: token,
User: user,
CreateTime: time.Now(),
}
err = storeSession(session)
if err != nil {
c.JSON(500, common.RespInternalError())
return
}
_, err = db.Conn.Exec(`UPDATE user SET last_seen_at=? WHERE id=?`, time.Now(), user.ID)
if err != nil {
logger.Warn("set last login date error", "error", err)
}
c.JSON(http.StatusOK, common.RespSuccess(session))
}
func LoginEmail(c *gin.Context) {
user := &models.User{}
c.Bind(&user)
if !govalidator.IsEmail(user.Email) {
c.JSON(http.StatusBadRequest, common.RespError("邮件格式不合法"))
return
}
fmt.Println(user.Email)
e := hermes.Email{
Body: hermes.Body{
Title: "Hello there",
Name: "",
Intros: []string{
fmt.Sprintf("Welcome to %s! We're very excited to have you on board.", config.Data.Common.AppName),
},
Actions: []hermes.Action{
{
Instructions: "To get started, please click here:",
Button: hermes.Button{
Color: "#22BC66", // Optional action button color
Text: "Confirm your account",
Link: config.Data.UI.Domain,
},
},
},
Outros: []string{
"Need help, or have questions? Just reply to this email, we'd love to help.",
},
},
}
emailBody, err := email.H.GenerateHTML(e)
emailMsg := &email.EmailMessage{
To: []string{user.Email},
From: fmt.Sprintf("%s <%s>", config.Dynamic.SMTP.FromName, config.Dynamic.SMTP.FromAddress),
Subject: fmt.Sprintf("Sign in to %s", config.Data.Common.AppName),
Body: emailBody,
}
err = email.Send(emailMsg)
if err != nil {
logger.Warn("send login email error", "error", err)
c.JSON(http.StatusBadRequest, common.RespError(err.Error()))
return
}
// err := user.Query("", "", user.Email)
// if err != nil {
// if err == sql.ErrNoRows {
// c.JSON(http.StatusNotFound, common.RespError("邮箱不存在"))
// return
// }
// logger.Error("login error", "error", err)
// c.JSON(http.StatusInternalServerError, common.RespInternalError())
// return
// }
// // delete old session
// token := getToken(c)
// deleteSession(token)
// token = strconv.FormatInt(time.Now().UnixNano(), 10)
// session := &Session{
// Token: token,
// User: user,
// CreateTime: time.Now(),
// }
// err = storeSession(session)
// if err != nil {
// c.JSON(500, common.RespInternalError())
// return
// }
// _, err = db.Conn.Exec(`UPDATE user SET last_seen_at=? WHERE id=?`, time.Now(), user.ID)
// if err != nil {
// logger.Warn("set last login date error", "error", err)
// }
c.JSON(http.StatusOK, common.RespSuccess(nil))
}
// Logout ...
func Logout(c *gin.Context) {
token := getToken(c)
// 删除用户的session
deleteSession(token)
c.JSON(http.StatusOK, common.RespSuccess(nil))
}
func getToken(c *gin.Context) string {
return c.Request.Header.Get("X-Token")
}
func deleteSession(sid string) {
q := `DELETE FROM sessions WHERE sid=?`
_, err := db.Conn.Exec(q, sid)
if err != nil {
logger.Warn("delete session error", "error", err)
}
}
func storeSession(s *Session) error {
q := `insert into sessions (user_id,sid) VALUES (?,?)`
_, err := db.Conn.Exec(q, s.User.ID, s.Token)
if err != nil {
logger.Warn("store session error", "error", err)
return err
}
return nil
}
func CurrentUser(c *gin.Context) *models.User {
token := getToken(c)
createTime, _ := strconv.ParseInt(token, 10, 64)
if createTime != 0 {
// check whether token is expired
if (time.Now().Unix() - createTime/1e9) > config.Data.User.SessionExpire {
return nil
}
}
sess := loadSession(token)
if sess == nil {
// 用户未登陆或者session失效
return nil
}
return sess.User
}
func GetSession(c *gin.Context) *Session {
token := getToken(c)
createTime, _ := strconv.ParseInt(token, 10, 64)
if createTime != 0 {
// check whether token is expired
if (time.Now().Unix() - createTime/1e9) > config.Data.User.SessionExpire {
return nil
}
}
sess := loadSession(token)
if sess == nil {
// 用户未登陆或者session失效
return nil
}
return sess
}
func loadSession(sid string) *Session {
var userid string
q := `SELECT user_id FROM sessions WHERE sid=?`
err := db.Conn.QueryRow(q, sid).Scan(&userid)
if err != nil {
if err != sql.ErrNoRows {
logger.Warn("query session error", "error", err)
}
return nil
}
user := &models.User{}
err = user.Query(userid, "", "")
if err != nil {
logger.Warn("query user error", "error", err)
return nil
}
return &Session{
Token: sid,
User: user,
}
}