Refactor checkin table to attendance table
Signed-off-by: Asai Neko <sugar@sne.moe>
This commit is contained in:
263
data/attendance.go
Normal file
263
data/attendance.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/meilisearch/meilisearch-go"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Attendance struct {
|
||||
Id uint `json:"id" gorm:"primarykey;autoIncrement"`
|
||||
UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueIndex;not null"`
|
||||
AttendanceId uuid.UUID `json:"attendance_id" gorm:"type:uuid;uniqueIndex;not null"`
|
||||
EventId uuid.UUID `json:"event_id" gorm:"type:uuid;uniqueIndex:unique_event_user;not null"`
|
||||
UserId uuid.UUID `json:"user_id" gorm:"type:uuid;uniqueIndex:unique_event_user;not null"`
|
||||
Role string `json"role" gorm:"not null"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
type AttendanceSearchDoc struct {
|
||||
AttendanceId string `json:"attendance_id"`
|
||||
EventId string `json:"event_id"`
|
||||
UserId string `json:"user_id"`
|
||||
Role string `json:"role"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
func (self *Attendance) GetAttendance(userId, eventId uuid.UUID) (*Attendance, error) {
|
||||
var checkin Attendance
|
||||
|
||||
err := Database.
|
||||
Where("user_id = ? AND event_id = ?", userId, eventId).
|
||||
First(&checkin).Error
|
||||
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &checkin, err
|
||||
}
|
||||
|
||||
type AttendanceUsers struct {
|
||||
UserId uuid.UUID `json:"user_id"`
|
||||
Role string `json:"role"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
func (self *Attendance) GetUsersByEventID(eventID uuid.UUID) (*[]AttendanceUsers, error) {
|
||||
var result []AttendanceUsers
|
||||
|
||||
err := Database.
|
||||
Model(&Attendance{}).
|
||||
Select("user_id, checkin_at").
|
||||
Where("event_id = ?", eventID).
|
||||
Order("checkin_at ASC").
|
||||
Scan(&result).Error
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type AttendanceEvent struct {
|
||||
EventId uuid.UUID `json:"event_id"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
func (self *Attendance) GetEventsByUserID(userID uuid.UUID) (*[]AttendanceEvent, error) {
|
||||
var result []AttendanceEvent
|
||||
|
||||
err := Database.
|
||||
Model(&Attendance{}).
|
||||
Select("event_id, checkin_at").
|
||||
Where("user_id = ?", userID).
|
||||
Order("checkin_at ASC").
|
||||
Scan(&result).Error
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (self *Attendance) Create() error {
|
||||
self.UUID = uuid.New()
|
||||
self.AttendanceId = uuid.New()
|
||||
|
||||
// DB transaction for strong consistency
|
||||
err := Database.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&self).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.UpdateSearchIndex(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Attendance) Update(attendanceId uuid.UUID, checkinTime *time.Time) (*Attendance, error) {
|
||||
var attendance Attendance
|
||||
|
||||
err := Database.Transaction(func(tx *gorm.DB) error {
|
||||
// Lock the row for update
|
||||
if err := tx.
|
||||
Where("attendance_id = ?", attendanceId).
|
||||
First(&attendance).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updates := map[string]any{}
|
||||
|
||||
if checkinTime != nil {
|
||||
updates["checkin_at"] = *checkinTime
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := tx.
|
||||
Model(&attendance).
|
||||
Updates(updates).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reload to ensure struct is up to date
|
||||
return tx.
|
||||
Where("attendance_id = ?", attendanceId).
|
||||
First(&attendance).Error
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync to MeiliSearch (eventual consistency)
|
||||
if err := attendance.UpdateSearchIndex(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &attendance, nil
|
||||
}
|
||||
|
||||
func (self *Attendance) SearchUsersByEvent(eventID string) (*meilisearch.SearchResponse, error) {
|
||||
index := MeiliSearch.Index("attendance")
|
||||
|
||||
return index.Search("", &meilisearch.SearchRequest{
|
||||
Filter: "event_id = \"" + eventID + "\"",
|
||||
Sort: []string{"checkin_at:asc"},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Attendance) SearchEventsByUser(userID string) (*meilisearch.SearchResponse, error) {
|
||||
index := MeiliSearch.Index("attendance")
|
||||
|
||||
return index.Search("", &meilisearch.SearchRequest{
|
||||
Filter: "user_id = \"" + userID + "\"",
|
||||
Sort: []string{"checkin_at:asc"},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Attendance) UpdateSearchIndex() error {
|
||||
doc := AttendanceSearchDoc{
|
||||
AttendanceId: self.AttendanceId.String(),
|
||||
EventId: self.EventId.String(),
|
||||
UserId: self.UserId.String(),
|
||||
CheckinAt: self.CheckinAt,
|
||||
}
|
||||
|
||||
index := MeiliSearch.Index("attendance")
|
||||
|
||||
primaryKey := "attendance_id"
|
||||
opts := &meilisearch.DocumentOptions{
|
||||
PrimaryKey: &primaryKey,
|
||||
}
|
||||
|
||||
if _, err := index.UpdateDocuments([]AttendanceSearchDoc{doc}, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Attendance) DeleteSearchIndex() error {
|
||||
index := MeiliSearch.Index("attendance")
|
||||
_, err := index.DeleteDocument(self.AttendanceId.String(), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *Attendance) GenCheckinCode(eventId uuid.UUID) (*string, error) {
|
||||
ctx := context.Background()
|
||||
ttl := viper.GetDuration("ttl.checkin_code_ttl")
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
for {
|
||||
code := fmt.Sprintf("%06d", rng.Intn(900000)+100000)
|
||||
ok, err := Redis.SetNX(
|
||||
ctx,
|
||||
"checkin_code:"+code,
|
||||
"user_id:"+self.UserId.String()+":event_id:"+eventId.String(),
|
||||
ttl,
|
||||
).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
return &code, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Attendance) VerifyCheckinCode(checkinCode string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
val, err := Redis.Get(ctx, "checkin_code:"+checkinCode).Result()
|
||||
if err != nil {
|
||||
return errors.New("invalid or expired checkin code")
|
||||
}
|
||||
|
||||
// Expected format: user_id:<uuid>:event_id:<uuid>
|
||||
parts := strings.Split(val, ":")
|
||||
if len(parts) != 4 {
|
||||
return errors.New("invalid checkin code format")
|
||||
}
|
||||
|
||||
userIdStr := parts[1]
|
||||
eventIdStr := parts[3]
|
||||
|
||||
userId, err := uuid.Parse(userIdStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eventId, err := uuid.Parse(eventIdStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attendanceData, err := self.GetAttendance(userId, eventId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time := time.Now()
|
||||
_, err = self.Update(attendanceData.AttendanceId, &time)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
281
data/checkin.go
281
data/checkin.go
@@ -1,281 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/meilisearch/meilisearch-go"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Checkin struct {
|
||||
Id uint `json:"id" gorm:"primarykey;autoIncrement"`
|
||||
UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueIndex;not null"`
|
||||
CheckinId uuid.UUID `json:"checkin_id" gorm:"type:uuid;uniqueIndex;not null"`
|
||||
EventId uuid.UUID `json:"event_id" gorm:"type:uuid;uniqueIndex:unique_event_user;not null"`
|
||||
UserId uuid.UUID `json:"user_id" gorm:"type:uuid;uniqueIndex:unique_event_user;not null"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
type CheckinSearchDoc struct {
|
||||
CheckinId string `json:"checkin_id"`
|
||||
EventId string `json:"event_id"`
|
||||
UserId string `json:"user_id"`
|
||||
CheckinAt time.Time `json:"checkin_at"`
|
||||
}
|
||||
|
||||
func (self *Checkin) GetCheckin(userId, eventId uuid.UUID) (*Checkin, error) {
|
||||
var checkin Checkin
|
||||
|
||||
err := Database.
|
||||
Where("user_id = ? AND event_id = ?", userId, eventId).
|
||||
First(&checkin).Error
|
||||
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &checkin, err
|
||||
}
|
||||
|
||||
type CheckinUsers struct {
|
||||
UserId uuid.UUID `json:"user_id"`
|
||||
CheckinTime time.Time `json:"checkin_time"`
|
||||
}
|
||||
|
||||
func (self *Checkin) GetUsersByEventID(eventID uuid.UUID) (*[]CheckinUsers, error) {
|
||||
var result []CheckinUsers
|
||||
|
||||
err := Database.
|
||||
Model(&Checkin{}).
|
||||
Select("user_id, checkin_time").
|
||||
Where("event_id = ?", eventID).
|
||||
Order("checkin_time ASC").
|
||||
Scan(&result).Error
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type CheckinEvent struct {
|
||||
EventId uuid.UUID `json:"event_id"`
|
||||
CheckinTime time.Time `json:"checkin_time"`
|
||||
}
|
||||
|
||||
func (self *Checkin) GetEventsByUserID(userID uuid.UUID) (*[]CheckinEvent, error) {
|
||||
var result []CheckinEvent
|
||||
|
||||
err := Database.
|
||||
Model(&Checkin{}).
|
||||
Select("event_id, checkin_time").
|
||||
Where("user_id = ?", userID).
|
||||
Order("checkin_time ASC").
|
||||
Scan(&result).Error
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (self *Checkin) CreateCheckin() error {
|
||||
self.UUID = uuid.New()
|
||||
self.CheckinId = uuid.New()
|
||||
|
||||
// DB transaction for strong consistency
|
||||
err := Database.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&self).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.UpdateSearchIndex(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type CheckinUpdateInput struct {
|
||||
CheckinTime *time.Time
|
||||
}
|
||||
|
||||
func (self *Checkin) UpdateCheckin(checkinID uuid.UUID, input CheckinUpdateInput) (*Checkin, error) {
|
||||
var checkin Checkin
|
||||
|
||||
err := Database.Transaction(func(tx *gorm.DB) error {
|
||||
// Lock the row for update
|
||||
if err := tx.
|
||||
Where("checkin_id = ?", checkinID).
|
||||
First(&checkin).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updates := map[string]any{}
|
||||
|
||||
if input.CheckinTime != nil {
|
||||
updates["checkin_time"] = *input.CheckinTime
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := tx.
|
||||
Model(&checkin).
|
||||
Updates(updates).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reload to ensure struct is up to date
|
||||
return tx.
|
||||
Where("checkin_id = ?", checkinID).
|
||||
First(&checkin).Error
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync to MeiliSearch (eventual consistency)
|
||||
if err := checkin.UpdateSearchIndex(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &checkin, nil
|
||||
}
|
||||
|
||||
func (self *Checkin) SearchUsersByEvent(eventID string) (*meilisearch.SearchResponse, error) {
|
||||
index := MeiliSearch.Index("checkin")
|
||||
|
||||
return index.Search("", &meilisearch.SearchRequest{
|
||||
Filter: "event_id = \"" + eventID + "\"",
|
||||
Sort: []string{"checkin_time:asc"},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Checkin) SearchEventsByUser(userID string) (*meilisearch.SearchResponse, error) {
|
||||
index := MeiliSearch.Index("checkin")
|
||||
|
||||
return index.Search("", &meilisearch.SearchRequest{
|
||||
Filter: "user_id = \"" + userID + "\"",
|
||||
Sort: []string{"checkin_time:asc"},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Checkin) UpdateSearchIndex() error {
|
||||
doc := CheckinSearchDoc{
|
||||
CheckinId: self.CheckinId.String(),
|
||||
EventId: self.EventId.String(),
|
||||
UserId: self.UserId.String(),
|
||||
CheckinAt: self.CheckinAt,
|
||||
}
|
||||
|
||||
index := MeiliSearch.Index("checkin")
|
||||
|
||||
primaryKey := "checkin_id"
|
||||
opts := &meilisearch.DocumentOptions{
|
||||
PrimaryKey: &primaryKey,
|
||||
}
|
||||
|
||||
if _, err := index.UpdateDocuments([]CheckinSearchDoc{doc}, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Checkin) DeleteSearchIndex() error {
|
||||
index := MeiliSearch.Index("checkin")
|
||||
_, err := index.DeleteDocument(self.CheckinId.String(), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *Checkin) GenCheckinCode(eventId uuid.UUID) (*string, error) {
|
||||
ctx := context.Background()
|
||||
ttl := viper.GetDuration("ttl.checkin_code_ttl")
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
for {
|
||||
code := fmt.Sprintf("%06d", rng.Intn(900000)+100000)
|
||||
ok, err := Redis.SetNX(
|
||||
ctx,
|
||||
"checkin_code:"+code,
|
||||
"user_id:"+self.UserId.String()+":event_id:"+eventId.String(),
|
||||
ttl,
|
||||
).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
return &code, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Checkin) VerifyCheckinCode(checkinCode string) (*uuid.UUID, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
val, err := Redis.Get(ctx, "checkin_code:"+checkinCode).Result()
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid or expired checkin code")
|
||||
}
|
||||
|
||||
// Expected format: user_id:<uuid>:event_id:<uuid>
|
||||
parts := strings.Split(val, ":")
|
||||
if len(parts) != 4 {
|
||||
return nil, errors.New("invalid checkin code format")
|
||||
}
|
||||
|
||||
userIdStr := parts[1]
|
||||
eventIdStr := parts[3]
|
||||
|
||||
userId, err := uuid.Parse(userIdStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eventId, err := uuid.Parse(eventIdStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// DB transaction: ensure checkin is created atomically
|
||||
err = Database.Transaction(func(tx *gorm.DB) error {
|
||||
checkin := &Checkin{
|
||||
UUID: uuid.New(),
|
||||
CheckinId: uuid.New(),
|
||||
UserId: userId,
|
||||
EventId: eventId,
|
||||
CheckinAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := tx.Create(checkin).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync search index after commit
|
||||
go func(c *Checkin) {
|
||||
_ = c.UpdateSearchIndex()
|
||||
}(checkin)
|
||||
|
||||
// Consume the code (one-time use)
|
||||
Redis.Del(ctx, "checkin_code:"+checkinCode)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &userId, nil
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func Init() {
|
||||
}
|
||||
|
||||
// Auto migrate
|
||||
err = db.AutoMigrate(&User{}, &Event{})
|
||||
err = db.AutoMigrate(&User{}, &Event{}, &Attendance{})
|
||||
if err != nil {
|
||||
log.Error("[Database] Error migrating database: ", err)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func (self *Event) UpdateEventById(eventId uuid.UUID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Event) CreateEvent() error {
|
||||
func (self *Event) Create() error {
|
||||
self.UUID = uuid.New()
|
||||
self.EventId = uuid.New()
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ type User struct {
|
||||
UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueindex;not null"`
|
||||
UserId uuid.UUID `json:"user_id" gorm:"type:uuid;uniqueindex;not null"`
|
||||
Email string `json:"email" gorm:"type:varchar(255);uniqueindex;not null"`
|
||||
Type string `json:"type" gorm:"type:varchar(32);index;not null"`
|
||||
Nickname string `json:"nickname"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Avatar string `json:"avatar"`
|
||||
@@ -134,7 +133,6 @@ func (self *User) UpdateSearchIndex() error {
|
||||
doc := UserSearchDoc{
|
||||
UserId: self.UserId.String(),
|
||||
Email: self.Email,
|
||||
Type: self.Type,
|
||||
Nickname: self.Nickname,
|
||||
Subtitle: self.Subtitle,
|
||||
Avatar: self.Avatar,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func Info(c *gin.Context) {
|
||||
event := new(data.Event)
|
||||
eventData := new(data.Event)
|
||||
eventIdOrig, ok := c.GetQuery("event_id")
|
||||
if !ok {
|
||||
c.JSON(400, gin.H{
|
||||
@@ -26,7 +26,7 @@ func Info(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err = event.GetEventById(eventId)
|
||||
event, err := eventData.GetEventById(eventId)
|
||||
if err != nil {
|
||||
c.JSON(404, gin.H{
|
||||
"status": "event id not found",
|
||||
@@ -35,9 +35,8 @@ func Info(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"name": event.Name,
|
||||
"start_time": event.StartTime,
|
||||
"end_time": event.EndTime,
|
||||
"joined_users": event.JoinedUsers,
|
||||
"name": event.Name,
|
||||
"start_time": event.StartTime,
|
||||
"end_time": event.EndTime,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func Checkin(c *gin.Context) {
|
||||
data := new(data.Checkin)
|
||||
data := new(data.Attendance)
|
||||
userId, ok := c.Get("user_id")
|
||||
if !ok {
|
||||
c.JSON(401, gin.H{
|
||||
@@ -71,8 +71,8 @@ func CheckinSubmit(c *gin.Context) {
|
||||
}
|
||||
c.ShouldBindJSON(&req)
|
||||
|
||||
checkinData := new(data.Checkin)
|
||||
userId, err := checkinData.VerifyCheckinCode(req.ChekinCode)
|
||||
attendanceData := new(data.Attendance)
|
||||
err := attendanceData.VerifyCheckinCode(req.ChekinCode)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"status": "error verify checkin code",
|
||||
|
||||
@@ -29,7 +29,6 @@ func Info(c *gin.Context) {
|
||||
c.JSON(200, gin.H{
|
||||
"user_id": user.UserId,
|
||||
"email": user.Email,
|
||||
"type": user.Type,
|
||||
"nickname": user.Nickname,
|
||||
"subtitle": user.Subtitle,
|
||||
"avatar": user.Avatar,
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"nixcn-cms/data"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Query(c *gin.Context) {
|
||||
@@ -28,35 +25,20 @@ func Query(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
checkinData := new(data.Checkin)
|
||||
checkin, err := checkinData.GetCheckin(userId.(uuid.UUID), eventId)
|
||||
attendanceData := new(data.Attendance)
|
||||
attendance, err := attendanceData.GetAttendance(userId.(uuid.UUID), eventId)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"status": "database error"})
|
||||
return
|
||||
} else if checkin == nil {
|
||||
} else if attendance == nil {
|
||||
c.JSON(404, gin.H{"status": "event checkin record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
checkinTime := time.Now()
|
||||
checkinData.EventId = eventId
|
||||
checkinData.UserId = userId.(uuid.UUID)
|
||||
checkinData.CheckinAt = checkinTime
|
||||
err = checkinData.CreateCheckin()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
c.JSON(409, gin.H{
|
||||
"status": "already checked in",
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(500, gin.H{
|
||||
"status": "database error",
|
||||
})
|
||||
} else if attendance.CheckinAt.IsZero() {
|
||||
c.JSON(200, gin.H{"checkin_at": nil})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"checkin_time": checkinTime,
|
||||
"checkin_at": attendance.CheckinAt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,10 +36,6 @@ func Update(c *gin.Context) {
|
||||
user.Email = ReqInfo.Email
|
||||
user.Nickname = ReqInfo.Nickname
|
||||
user.Subtitle = ReqInfo.Subtitle
|
||||
// Cant change user type under permission 2
|
||||
if user.PermissionLevel >= 2 {
|
||||
user.Type = ReqInfo.Type
|
||||
}
|
||||
|
||||
// Update user info
|
||||
user.UpdateByUserID(userId.(uuid.UUID))
|
||||
|
||||
Reference in New Issue
Block a user