chore: add ansible deploy simple logic, upgrade admin auth logic and docs
ci-agent / build (push) Failing after 1m55s

This commit is contained in:
d3m0k1d
2026-04-04 05:19:40 +03:00
parent 2a8faaa9fe
commit 10d899b50f
16 changed files with 3516 additions and 382 deletions
+222
View File
@@ -23,6 +23,7 @@ type AuthGroup struct {
// @Success 200 {object} repository.LoginResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /auth/login [post]
func (ag *AuthGroup) Login(c *gin.Context) {
var req repository.LoginRequest
@@ -37,6 +38,10 @@ func (ag *AuthGroup) Login(c *gin.Context) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
if errors.Is(err, repository.ErrAccountInactive) {
c.JSON(http.StatusForbidden, gin.H{"error": "account is not activated by admin"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to authenticate"})
return
}
@@ -168,6 +173,223 @@ func (ag *AuthGroup) DeleteMyToken(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "account deleted"})
}
// ActivateUser activates a user by login.
// @Summary Activate user
// @Description Activates a user account by login (admin only)
// @Tags auth
// @Param login path string true "Login of the user to activate"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login/activate [post]
func (ag *AuthGroup) ActivateUser(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
if err := ag.Repo.ActivateUserByLogin(login); err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to activate user"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "user activated"})
}
// DeactivateUser deactivates a user by login.
// @Summary Deactivate user
// @Description Deactivates a user account by login (admin only)
// @Tags auth
// @Param login path string true "Login of the user to deactivate"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login/deactivate [post]
func (ag *AuthGroup) DeactivateUser(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
if err := ag.Repo.DeactivateUserByLogin(login); err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to deactivate user"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "user deactivated"})
}
// ListInactiveUsers returns all users that are not activated.
// @Summary List inactive users
// @Description Returns list of all users waiting for activation
// @Tags auth
// @Produce json
// @Success 200 {array} repository.Tokens
// @Failure 500 {object} map[string]string
// @Router /auth/users/inactive [get]
func (ag *AuthGroup) ListInactiveUsers(c *gin.Context) {
tokens, err := ag.Repo.ListInactiveTokens()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list inactive users"})
return
}
c.JSON(http.StatusOK, tokens)
}
// GetUser returns a user by login.
// @Summary Get user by login
// @Description Returns a user by their login (admin only)
// @Tags auth
// @Produce json
// @Param login path string true "Login of the user"
// @Success 200 {object} repository.Tokens
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login [get]
func (ag *AuthGroup) GetUser(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
user, err := ag.Repo.GetTokenByLogin(login)
if err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get user"})
return
}
c.JSON(http.StatusOK, user)
}
// UpdateUser updates user's name and last name.
// @Summary Update user
// @Description Updates a user's name and last name (admin only)
// @Tags auth
// @Accept json
// @Param login path string true "Login of the user"
// @Param request body repository.TokenUpdate true "User data to update"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login [put]
func (ag *AuthGroup) UpdateUser(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
var update repository.TokenUpdate
if err := c.ShouldBindJSON(&update); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
return
}
if err := ag.Repo.UpdateToken(login, update); err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update user"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "user updated"})
}
// UpdateUserPermissions updates user's permissions and activation status.
// @Summary Update user permissions
// @Description Updates a user's permissions and activation status (admin only)
// @Tags auth
// @Accept json
// @Param login path string true "Login of the user"
// @Param request body repository.TokenUpdatePermissions true "Permissions to update"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login/permissions [put]
func (ag *AuthGroup) UpdateUserPermissions(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
var update repository.TokenUpdatePermissions
if err := c.ShouldBindJSON(&update); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
return
}
if err := ag.Repo.UpdatePermissions(login, update); err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update permissions"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "permissions updated"})
}
// ResetUserPassword resets a user's password.
// @Summary Reset user password
// @Description Resets a user's password to a new value (admin only)
// @Tags auth
// @Accept json
// @Param login path string true "Login of the user"
// @Param request body repository.TokenPasswordReset true "New password"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/users/:login/password [put]
func (ag *AuthGroup) ResetUserPassword(c *gin.Context) {
login := c.Param("login")
if login == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
return
}
var req repository.TokenPasswordReset
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
return
}
if err := ag.Repo.UpdatePassword(login, req.NewPassword); err != nil {
if errors.Is(err, repository.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to reset password"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "password reset"})
}
// getTokenFromHeader extracts the Bearer token from the Authorization header.
func getTokenFromHeader(c *gin.Context) string {
auth := c.GetHeader("Authorization")