Implement admin media approval endpoints and add JWT role-based auth - NOT TESTED
This commit is contained in:
@@ -43,7 +43,7 @@ func (j *JwtTokenGenerator) GinMiddleware() gin.HandlerFunc {
|
|||||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = jwt.Parse(token.Value, func(t *jwt.Token) (interface{}, error) {
|
t, err := jwt.Parse(token.Value, func(t *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, jwt.ErrSignatureInvalid
|
return nil, jwt.ErrSignatureInvalid
|
||||||
}
|
}
|
||||||
@@ -53,6 +53,11 @@ func (j *JwtTokenGenerator) GinMiddleware() gin.HandlerFunc {
|
|||||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
claims, ok := t.Claims.(jwt.MapClaims)
|
||||||
|
if !ok || claims["role"] != "admin" { // Check role, only if its admin let it go
|
||||||
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
5
internal/models/requestModels/approveMedia.go
Normal file
5
internal/models/requestModels/approveMedia.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package requestmodels
|
||||||
|
|
||||||
|
type ApproveMediaInput struct {
|
||||||
|
MediaId string `json:"mediaId" binding:"required"`
|
||||||
|
}
|
5
internal/models/requestModels/rejectMedia.go
Normal file
5
internal/models/requestModels/rejectMedia.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package requestmodels
|
||||||
|
|
||||||
|
type RejectMediaInput struct {
|
||||||
|
MediaId string `json:"mediaId" binding:"required"`
|
||||||
|
}
|
@@ -4,7 +4,6 @@ import (
|
|||||||
"CatsOfMastodonBotGo/internal"
|
"CatsOfMastodonBotGo/internal"
|
||||||
handlers_admin "CatsOfMastodonBotGo/internal/web/handlers/admin"
|
handlers_admin "CatsOfMastodonBotGo/internal/web/handlers/admin"
|
||||||
handlers_api "CatsOfMastodonBotGo/internal/web/handlers/api"
|
handlers_api "CatsOfMastodonBotGo/internal/web/handlers/api"
|
||||||
handlers_home "CatsOfMastodonBotGo/internal/web/handlers/home"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -14,21 +13,18 @@ func SetupRouter(appContext *internal.AppContext) *gin.Engine {
|
|||||||
|
|
||||||
|
|
||||||
adminDashboardHandler := handlers_admin.NewAdminDashboardHandler(appContext)
|
adminDashboardHandler := handlers_admin.NewAdminDashboardHandler(appContext)
|
||||||
homePageHandler := handlers_home.NewMainPageHandler(appContext)
|
|
||||||
apiHandler := handlers_api.NewApiEndpointHandler(appContext)
|
apiHandler := handlers_api.NewApiEndpointHandler(appContext)
|
||||||
|
|
||||||
admin := r.Group("/admin")
|
admin := r.Group("/admin")
|
||||||
|
|
||||||
admin.GET("/", adminDashboardHandler.AdminHomePage)
|
// My man, this is done way more efficient and fast in .NET, specially the authentication part
|
||||||
admin.POST("/login", adminDashboardHandler.Login)
|
admin.POST("/login", adminDashboardHandler.Login)
|
||||||
admin.POST("/approve", adminDashboardHandler.ApproveMedia)
|
admin.POST("/approve", appContext.Jwt.GinMiddleware() ,adminDashboardHandler.ApproveMedia)
|
||||||
admin.POST("/reject", adminDashboardHandler.RejectMedia)
|
admin.POST("/reject" ,appContext.Jwt.GinMiddleware() , adminDashboardHandler.RejectMedia)
|
||||||
|
|
||||||
api := r.Group("/api")
|
api := r.Group("/api")
|
||||||
|
|
||||||
api.GET("/post/random", apiHandler.GetRandomPost)
|
api.GET("/post/random", apiHandler.GetRandomPost)
|
||||||
|
|
||||||
r.GET("/", homePageHandler.HomePageHandler)
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@@ -88,6 +88,8 @@ func (ps *PostService) InsertNewAccounts(newAccounts []models.Account) int {
|
|||||||
return int(ps.db.Clauses(clause.OnConflict{UpdateAll: true}).Create(&newAccounts).RowsAffected)
|
return int(ps.db.Clauses(clause.OnConflict{UpdateAll: true}).Create(&newAccounts).RowsAffected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From this point on, its for the api endpoints
|
||||||
|
|
||||||
func (ps *PostService) GetRandomPost() models.Post {
|
func (ps *PostService) GetRandomPost() models.Post {
|
||||||
var post models.Post
|
var post models.Post
|
||||||
ps.db.
|
ps.db.
|
||||||
@@ -98,6 +100,18 @@ func (ps *PostService) GetRandomPost() models.Post {
|
|||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ps *PostService) ApproveMedia(mediaId string) bool {
|
||||||
|
return ps.db.Model(&models.MediaAttachment{}).
|
||||||
|
Where("id = ?", mediaId).
|
||||||
|
Update("approved", true).RowsAffected > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *PostService) RejectMedia(mediaId string) bool {
|
||||||
|
return ps.db.Model(&models.MediaAttachment{}).
|
||||||
|
Where("id = ?", mediaId).
|
||||||
|
Update("rejected", true).RowsAffected > 0
|
||||||
|
}
|
||||||
|
|
||||||
func arrayContains(arr []string, str string) bool {
|
func arrayContains(arr []string, str string) bool {
|
||||||
for _, a := range arr {
|
for _, a := range arr {
|
||||||
if a == str {
|
if a == str {
|
||||||
|
@@ -19,34 +19,43 @@ func NewAdminDashboardHandler(appContext *internal.AppContext) *AdminDashboardHa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (appContext *AdminDashboardHandler) AdminHomePage(c *gin.Context) {
|
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"YouAreOn": "AdminDashboardHomePage",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (appContext *AdminDashboardHandler) ApproveMedia(c *gin.Context) {
|
func (appContext *AdminDashboardHandler) ApproveMedia(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{
|
var input requestmodels.ApproveMediaInput
|
||||||
"YouAreOn": "ApproveMedia",
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if appContext.AppContext.PostService.ApproveMedia(input.MediaId) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Media approved successfully"})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to approve media"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (appContext *AdminDashboardHandler) RejectMedia(c *gin.Context) {
|
func (appContext *AdminDashboardHandler) RejectMedia(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{
|
var input requestmodels.RejectMediaInput
|
||||||
"YouAreOn": "RejectMedia",
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if appContext.AppContext.PostService.RejectMedia(input.MediaId) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Media rejected successfully"})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reject media"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
||||||
|
|
||||||
var input requestmodels.LoginInput
|
var input requestmodels.LoginInput
|
||||||
|
|
||||||
|
// Validate data
|
||||||
if err := c.ShouldBindJSON(&input); err != nil {
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.Password == appContext.AppContext.AdminPassword {
|
if input.Password == appContext.AppContext.AdminPassword { // Its more than enough for this project
|
||||||
token, err := appContext.AppContext.Jwt.GenerateToken(map[string]interface{}{"role": "admin"})
|
token, err := appContext.AppContext.Jwt.GenerateToken(map[string]interface{}{"role": "admin"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token generation failed"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token generation failed"})
|
||||||
@@ -60,6 +69,10 @@ func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
|||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
"YouAreOn": "Unauthorized",
|
"YouAreOn": "Unauthorized",
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"YouAreOn": "Login",
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +0,0 @@
|
|||||||
package handlers_home
|
|
||||||
|
|
||||||
import (
|
|
||||||
"CatsOfMastodonBotGo/internal"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MainPageHandler struct {
|
|
||||||
AppContext *internal.AppContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMainPageHandler(appContext *internal.AppContext) *MainPageHandler {
|
|
||||||
return &MainPageHandler{
|
|
||||||
AppContext: appContext,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (appContext *MainPageHandler) HomePageHandler(c *gin.Context) {
|
|
||||||
c.Data(200, "text/html; charset=utf-8", []byte(`<p>Welcome to CatsOfMastodonBotGo - <a href="https://git.mahdium.ir/mahdium/CatsOfMastodon">The main project</a>, writen in C# is available at that link - This is only my attempt to port it to Go for learning purposes</p>`))
|
|
||||||
}
|
|
Reference in New Issue
Block a user