package models import ( "errors" "fmt" "strings" "time" "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/log" ) // UserNote table where users can write private notes about each other. type UserNote struct { ID uint64 `gorm:"primaryKey"` UserID uint64 `gorm:"index"` // author ID AboutUserID uint64 `gorm:"index"` // target user ID Message string CreatedAt time.Time UpdatedAt time.Time } // GetNoteBetweenUsers finds the existing note or creates an empty model if not found. func GetNoteBetweenUsers(currentUser *User, user *User) *UserNote { var ( note = &UserNote{} result = DB.Model(note).Where( "user_id = ? AND about_user_id = ?", currentUser.ID, user.ID, ).First(¬e) ) if result.Error != nil { note = &UserNote{ UserID: currentUser.ID, AboutUserID: user.ID, } } return note } // GetNote finds a user note by its ID. func GetNote(id uint64) (*UserNote, error) { p := &UserNote{} result := DB.First(&p, id) return p, result.Error } // CountNotesAboutUser returns the number of notes (the current user) has about the other user. // // For regular user, will return zero or one; for admins, will return the total count of notes // left by any other users about this user. func CountNotesAboutUser(currentUser *User, user *User) int64 { var ( wheres = []string{} placeholders = []interface{}{} count int64 ) if currentUser.HasAdminScope(config.ScopeUserNotes) { wheres = append(wheres, "about_user_id = ?") placeholders = append(placeholders, user.ID) } else { wheres = append(wheres, "user_id = ? AND about_user_id = ?") placeholders = append(placeholders, currentUser.ID, user.ID) } query := DB.Model(&UserNote{}).Where( strings.Join(wheres, " AND "), placeholders..., ).Count(&count) if query.Error != nil { log.Error("CountNotesAboutUser(%s, %s): %s", currentUser.Username, user.Username, query.Error) } return count } // PaginateUserNotes shows all notes written by users about the target user. func PaginateUserNotes(user *User, pager *Pagination) ([]*UserNote, error) { var ( notes = []*UserNote{} wheres = []string{} placeholders = []interface{}{} ) wheres = append(wheres, "about_user_id = ?") placeholders = append(placeholders, user.ID) query := DB.Joins("JOIN users ON users.id = user_notes.user_id").Where( strings.Join(wheres, " AND "), placeholders..., ).Order( "users.is_admin desc, " + pager.Sort, ) query.Model(&UserNote{}).Count(&pager.Total) result := query.Offset( pager.GetOffset(), ).Limit(pager.PerPage).Find(¬es) return notes, result.Error } // PaginateMyUserNotes shows all notes written by the current user about others. func PaginateMyUserNotes(currentUser *User, search string, pager *Pagination) ([]*UserNote, error) { var ( notes = []*UserNote{} wheres = []string{} placeholders = []interface{}{} ilike = "%" + search + "%" ) wheres = append(wheres, "user_notes.user_id = ?") placeholders = append(placeholders, currentUser.ID) // Searching? if search != "" { wheres = append(wheres, "(users.username ILIKE ? OR user_notes.message ILIKE ?)") placeholders = append(placeholders, ilike, ilike) } query := DB.Joins("JOIN users ON users.id = user_notes.about_user_id").Where( strings.Join(wheres, " AND "), placeholders..., ).Order( pager.Sort, ) query.Model(&UserNote{}).Count(&pager.Total) result := query.Offset( pager.GetOffset(), ).Limit(pager.PerPage).Find(¬es) return notes, result.Error } // PaginateAdminUserNotes shows all notes written by any admin user account on nonshy. func PaginateAdminUserNotes(search string, pager *Pagination) ([]*UserNote, error) { var ( adminUserIDs = []uint64{} notes = []*UserNote{} wheres = []string{} placeholders = []interface{}{} ilike = "%" + search + "%" ) // Get all the admin users. adminUsers, err := ListAdminUsers() if err != nil { return nil, fmt.Errorf("couldn't get admin users: %s", err) } for _, user := range adminUsers { adminUserIDs = append(adminUserIDs, user.ID) } // Filter to notes written by admin users. wheres = append(wheres, "user_notes.user_id IN ?") placeholders = append(placeholders, adminUserIDs) // Searching? if search != "" { wheres = append(wheres, "(users.username ILIKE ? OR user_notes.message ILIKE ?)") placeholders = append(placeholders, ilike, ilike) } query := DB.Joins("JOIN users ON users.id = user_notes.about_user_id").Where( strings.Join(wheres, " AND "), placeholders..., ).Order( pager.Sort, ) query.Model(&UserNote{}).Count(&pager.Total) result := query.Offset( pager.GetOffset(), ).Limit(pager.PerPage).Find(¬es) return notes, result.Error } // Save the note. func (p *UserNote) Save() error { if p.ID == 0 { return DB.Create(p).Error } return DB.Save(p).Error } var ErrNoUserNoteToDelete = errors.New("you had no user note to delete") // Delete the DB entry. func (p *UserNote) Delete() error { if p.ID == 0 { return ErrNoUserNoteToDelete } return DB.Delete(p).Error }