✨ Abuse report system
This commit is contained in:
		@@ -27,6 +27,7 @@ var AutoMaintainRange = []any{
 | 
			
		||||
	&models.ApiKey{},
 | 
			
		||||
	&models.SignRecord{},
 | 
			
		||||
	&models.PreferenceNotification{},
 | 
			
		||||
	&models.AbuseReport{},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunMigration(source *gorm.DB) error {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								pkg/internal/models/reports.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pkg/internal/models/reports.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ReportStatusPending   = "pending"
 | 
			
		||||
	ReportStatusReviewing = "reviewing"
 | 
			
		||||
	ReportStatusConfirmed = "confirmed"
 | 
			
		||||
	ReportStatusRejected  = "rejected"
 | 
			
		||||
	ReportStatusProcessed = "processed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AbuseReport struct {
 | 
			
		||||
	BaseModel
 | 
			
		||||
 | 
			
		||||
	Resource  string  `json:"resource"`
 | 
			
		||||
	Reason    string  `json:"reason"`
 | 
			
		||||
	Status    string  `json:"status"`
 | 
			
		||||
	AccountID uint    `json:"account_id"`
 | 
			
		||||
	Account   Account `json:"account"`
 | 
			
		||||
}
 | 
			
		||||
@@ -30,6 +30,17 @@ func MapAPIs(app *fiber.App, baseURL string) {
 | 
			
		||||
			preferences.Put("/notifications", updateNotificationPreference)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reports := api.Group("/reports").Name("Reports API")
 | 
			
		||||
		{
 | 
			
		||||
			abuse := reports.Group("/abuse").Name("Abuse Reports")
 | 
			
		||||
			{
 | 
			
		||||
				abuse.Get("/", listAbuseReports)
 | 
			
		||||
				abuse.Get("/:id", getAbuseReport)
 | 
			
		||||
				abuse.Put("/:id/status", updateAbuseReportStatus)
 | 
			
		||||
				abuse.Post("/", createAbuseReport)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		api.Get("/users/lookup", lookupAccount)
 | 
			
		||||
		api.Get("/users/search", searchAccount)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								pkg/internal/server/api/reports.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								pkg/internal/server/api/reports.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
 | 
			
		||||
	"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
 | 
			
		||||
	"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
 | 
			
		||||
	"github.com/gofiber/fiber/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func listAbuseReports(c *fiber.Ctx) error {
 | 
			
		||||
	if err := exts.EnsureAuthenticated(c); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	user := c.Locals("user").(models.Account)
 | 
			
		||||
 | 
			
		||||
	reports, err := services.ListAbuseReport(user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fiber.NewError(fiber.StatusBadRequest, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.JSON(reports)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAbuseReport(c *fiber.Ctx) error {
 | 
			
		||||
	id, _ := c.ParamsInt("id")
 | 
			
		||||
	report, err := services.GetAbuseReport(uint(id))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.JSON(report)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func updateAbuseReportStatus(c *fiber.Ctx) error {
 | 
			
		||||
	if err := exts.EnsureGrantedPerm(c, "DealAbuseReport", true); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Status string `json:"status" validate:"required"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := exts.BindAndValidate(c, &data); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id, _ := c.ParamsInt("id")
 | 
			
		||||
 | 
			
		||||
	if err := services.UpdateAbuseReportStatus(uint(id), data.Status); err != nil {
 | 
			
		||||
		return fiber.NewError(fiber.StatusBadRequest, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.SendStatus(fiber.StatusOK)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createAbuseReport(c *fiber.Ctx) error {
 | 
			
		||||
	if err := exts.EnsureAuthenticated(c); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	user := c.Locals("user").(models.Account)
 | 
			
		||||
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Resource string `json:"resource" validate:"required"`
 | 
			
		||||
		Reason   string `json:"reason" validate:"required,min=16,max=4096"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := exts.BindAndValidate(c, &data); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	report, err := services.NewAbuseReport(data.Resource, data.Reason, user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fiber.NewError(fiber.StatusBadRequest, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.JSON(report)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								pkg/internal/services/reports.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								pkg/internal/services/reports.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
 | 
			
		||||
	"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func ListAbuseReport(account models.Account) ([]models.AbuseReport, error) {
 | 
			
		||||
	var reports []models.AbuseReport
 | 
			
		||||
	err := database.C.
 | 
			
		||||
		Where("account_id = ?", account.ID).
 | 
			
		||||
		Find(&reports).Error
 | 
			
		||||
	return reports, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetAbuseReport(id uint) (models.AbuseReport, error) {
 | 
			
		||||
	var report models.AbuseReport
 | 
			
		||||
	err := database.C.
 | 
			
		||||
		Where("id = ?", id).
 | 
			
		||||
		First(&report).Error
 | 
			
		||||
	return report, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateAbuseReportStatus(id uint, status string) error {
 | 
			
		||||
	var report models.AbuseReport
 | 
			
		||||
	err := database.C.
 | 
			
		||||
		Where("id = ?", id).
 | 
			
		||||
		Preload("Account").
 | 
			
		||||
		First(&report).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	report.Status = status
 | 
			
		||||
	account := report.Account
 | 
			
		||||
 | 
			
		||||
	err = database.C.Save(&report).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	NewNotification(models.Notification{
 | 
			
		||||
		Topic:     "reports.feedback",
 | 
			
		||||
		Title:     "Abuse report status has been changed.",
 | 
			
		||||
		Body:      fmt.Sprintf("The report created by you with ID #%d's status has been changed to %s", id, status),
 | 
			
		||||
		Account:   account,
 | 
			
		||||
		AccountID: account.ID,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAbuseReport(resource string, reason string, account models.Account) (models.AbuseReport, error) {
 | 
			
		||||
	var report models.AbuseReport
 | 
			
		||||
	if err := database.C.
 | 
			
		||||
		Where(
 | 
			
		||||
			"resource = ? AND account_id = ? AND status IN ?",
 | 
			
		||||
			resource,
 | 
			
		||||
			account.ID,
 | 
			
		||||
			[]string{models.ReportStatusPending, models.ReportStatusReviewing},
 | 
			
		||||
		).First(&report).Error; err == nil {
 | 
			
		||||
		return report, fmt.Errorf("you already reported this resource and it still in process")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	report = models.AbuseReport{
 | 
			
		||||
		Resource:  resource,
 | 
			
		||||
		Reason:    reason,
 | 
			
		||||
		AccountID: account.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := database.C.Create(&report).Error
 | 
			
		||||
	return report, err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user