@@ -26,7 +26,8 @@ func (c *DatabaseController) RegisterRoutes(router *gin.RouterGroup) {
2626 router .POST ("/databases/test-connection-direct" , c .TestDatabaseConnectionDirect )
2727 router .POST ("/databases/:id/copy" , c .CopyDatabase )
2828 router .GET ("/databases/notifier/:id/is-using" , c .IsNotifierUsing )
29-
29+ router .POST ("/databases/is-readonly" , c .IsUserReadOnly )
30+ router .POST ("/databases/create-readonly-user" , c .CreateReadOnlyUser )
3031}
3132
3233// CreateDatabase
@@ -330,3 +331,76 @@ func (c *DatabaseController) CopyDatabase(ctx *gin.Context) {
330331
331332 ctx .JSON (http .StatusCreated , copiedDatabase )
332333}
334+
335+ // IsUserReadOnly
336+ // @Summary Check if database user is read-only
337+ // @Description Check if current database credentials have only read (SELECT) privileges
338+ // @Tags databases
339+ // @Accept json
340+ // @Produce json
341+ // @Security BearerAuth
342+ // @Param request body Database true "Database configuration to check"
343+ // @Success 200 {object} IsReadOnlyResponse
344+ // @Failure 400 {object} map[string]string
345+ // @Failure 401 {object} map[string]string
346+ // @Failure 403 {object} map[string]string
347+ // @Router /databases/is-readonly [post]
348+ func (c * DatabaseController ) IsUserReadOnly (ctx * gin.Context ) {
349+ user , ok := users_middleware .GetUserFromContext (ctx )
350+ if ! ok {
351+ ctx .JSON (http .StatusUnauthorized , gin.H {"error" : "User not authenticated" })
352+ return
353+ }
354+
355+ var request Database
356+ if err := ctx .ShouldBindJSON (& request ); err != nil {
357+ ctx .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
358+ return
359+ }
360+
361+ isReadOnly , err := c .databaseService .IsUserReadOnly (user , & request )
362+ if err != nil {
363+ ctx .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
364+ return
365+ }
366+
367+ ctx .JSON (http .StatusOK , IsReadOnlyResponse {IsReadOnly : isReadOnly })
368+ }
369+
370+ // CreateReadOnlyUser
371+ // @Summary Create read-only database user
372+ // @Description Create a new PostgreSQL user with read-only privileges for backup operations
373+ // @Tags databases
374+ // @Accept json
375+ // @Produce json
376+ // @Security BearerAuth
377+ // @Param request body Database true "Database configuration to create user for"
378+ // @Success 200 {object} CreateReadOnlyUserResponse
379+ // @Failure 400 {object} map[string]string
380+ // @Failure 401 {object} map[string]string
381+ // @Failure 403 {object} map[string]string
382+ // @Router /databases/create-readonly-user [post]
383+ func (c * DatabaseController ) CreateReadOnlyUser (ctx * gin.Context ) {
384+ user , ok := users_middleware .GetUserFromContext (ctx )
385+ if ! ok {
386+ ctx .JSON (http .StatusUnauthorized , gin.H {"error" : "User not authenticated" })
387+ return
388+ }
389+
390+ var request Database
391+ if err := ctx .ShouldBindJSON (& request ); err != nil {
392+ ctx .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
393+ return
394+ }
395+
396+ username , password , err := c .databaseService .CreateReadOnlyUser (user , & request )
397+ if err != nil {
398+ ctx .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
399+ return
400+ }
401+
402+ ctx .JSON (http .StatusOK , CreateReadOnlyUserResponse {
403+ Username : username ,
404+ Password : password ,
405+ })
406+ }
0 commit comments