Update: documentation for the Chaoscenter Authentication REST API (#5012)

* fix: update swagger details

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* feat: add authentication api document

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* feat: add auth api documentation using redoc

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* remove auto generated files

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* fix: update response objects

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* chore: add new docs

Signed-off-by: namkyu1999 <lak9348@gmail.com>

* chore: passed tests

Signed-off-by: namkyu1999 <lak9348@gmail.com>

---------

Signed-off-by: namkyu1999 <lak9348@gmail.com>
This commit is contained in:
Namkyu Park 2025-03-28 13:56:13 +09:00 committed by GitHub
parent 49972737cc
commit e9db75b884
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1236 additions and 2876 deletions

View File

@ -97,7 +97,7 @@ type ErrServerError struct {
After annotating your API and defining your responses, run the following command in your project root to generate the `swagger.yaml` file:
```bash
swag init
swag init --parseDependency true
```
This command scans your project and creates a Swagger specification from your annotations.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
package response
import "github.com/gin-gonic/gin"
import (
"github.com/gin-gonic/gin"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities"
)
type Response struct {
Response string
@ -32,7 +35,7 @@ type CapabilitiesResponse struct {
}
type MessageResponse struct {
Message string
Message string `json:"message"`
}
type NewApiToken struct {
@ -134,3 +137,53 @@ type ErrProjectNotFoundstruct struct {
Code int `json:"code" example:"400"`
Message string `json:"message" example:"project does not exist"`
}
type ReadinessAPIStatus struct {
DataBase string `json:"database"`
Collections string `json:"collections"`
}
type APIStatus struct {
Status string `json:"status"`
}
type UserWithProject struct {
Data entities.UserWithProject `json:"data"`
}
type Project struct {
Data entities.Project `json:"data"`
}
type Projects struct {
Data []*entities.Project `json:"data"`
}
type ListProjectResponse struct {
Data entities.ListProjectResponse `json:"data"`
}
type ProjectStats struct {
Data []*entities.ProjectStats `json:"data"`
}
type Members struct {
Data []*entities.Member `json:"data"`
}
type Member struct {
Data entities.Member `json:"data"`
}
type ListInvitationResponse struct {
Data []entities.ListInvitationResponse `json:"data"`
}
type ProjectRole struct {
Role string `json:"role"`
}
type ProjectIDWithMessage struct {
Message string `json:"message"`
ProjectID string `json:"projectID"`
}

View File

@ -16,6 +16,8 @@ import (
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.CapabilitiesResponse{}
// @Router /capabilities [get]
//
// GetCapabilities returns the capabilities of the Auth Server.
func GetCapabilities() gin.HandlerFunc {
return func(c *gin.Context) {
capabilities := new(response.CapabilitiesResponse)

View File

@ -3,7 +3,7 @@ package rest
import (
"net/http"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities"
response "github.com/litmuschaos/litmus/chaoscenter/authentication/api/handlers"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services"
"github.com/gin-gonic/gin"
@ -20,32 +20,26 @@ func contains(s []string, str string) bool {
return false
}
type ReadinessAPIStatus struct {
DataBase string `json:"database"`
Collections string `json:"collections"`
}
// Status godoc
//
// @Description Status will request users list and return, if successful, an http code 200.
// @Description Status will request users list and return, if successful, a http code 200.
// @Tags MiscRouter
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.APIStatus{}
// @Router /status [get]
//
// Status will request users list and return, if successful,
// an http code 200
// Status will request users list and return, if successful, a http code 200
func Status(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
_, err := service.GetUsers()
if err != nil {
log.Error(err)
c.JSON(http.StatusInternalServerError, entities.APIStatus{Status: "down"})
c.JSON(http.StatusInternalServerError, response.APIStatus{Status: "down"})
return
}
c.JSON(http.StatusOK, entities.APIStatus{Status: "up"})
c.JSON(http.StatusOK, response.APIStatus{Status: "up"})
}
}
@ -56,37 +50,39 @@ func Status(service services.ApplicationService) gin.HandlerFunc {
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.ReadinessAPIStatus{}
// @Router /readiness [get]
//
// Readiness will return the status of the database and collections
func Readiness(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var (
db_flag = "up"
col_flag = "up"
dbFlag = "up"
colFlag = "up"
)
dbs, err := service.ListDataBase()
if !contains(dbs, "auth") {
db_flag = "down"
dbFlag = "down"
}
if err != nil {
log.Error(err)
c.JSON(http.StatusInternalServerError, ReadinessAPIStatus{"down", "unknown"})
c.JSON(http.StatusInternalServerError, response.ReadinessAPIStatus{DataBase: "down", Collections: "unknown"})
return
}
cols, err := service.ListCollection()
if !contains(cols, "project") || !contains(cols, "users") {
col_flag = "down"
colFlag = "down"
}
if err != nil {
log.Error(err)
c.JSON(http.StatusInternalServerError, ReadinessAPIStatus{db_flag, "down"})
c.JSON(http.StatusInternalServerError, response.ReadinessAPIStatus{DataBase: dbFlag, Collections: "down"})
return
}
c.JSON(http.StatusOK, ReadinessAPIStatus{db_flag, col_flag})
c.JSON(http.StatusOK, response.ReadinessAPIStatus{DataBase: dbFlag, Collections: colFlag})
}
}

View File

@ -1,12 +1,14 @@
package rest
import (
"errors"
"net/http"
"time"
response "github.com/litmuschaos/litmus/chaoscenter/authentication/api/handlers"
"github.com/litmuschaos/litmus/chaoscenter/authentication/api/presenter"
"github.com/litmuschaos/litmus/chaoscenter/authentication/api/types"
project_utils "github.com/litmuschaos/litmus/chaoscenter/authentication/api/utils"
projectUtils "github.com/litmuschaos/litmus/chaoscenter/authentication/api/utils"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/utils"
@ -20,8 +22,9 @@ import (
)
// GetUserWithProject godoc
//
// @Summary Get user with project.
// @Description Return users who has a project.
// @Description Return users who have a project.
// @Tags ProjectRouter
// @Param username path string true "Username"
// @Accept json
@ -29,16 +32,16 @@ import (
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 400 {object} response.ErrUserNotFound
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.UserWithProject{}
// @Router /get_user_with_project/:username [get]
//
// GetUserWithProject returns user and project details based on username
func GetUserWithProject(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
username := c.Param("username")
// Validating logged in user
// Must be either requesting info from the logged in user
// Validating logged-in user
// Must be either requesting info from the logged-in user
// or any user if it has the admin role
role := c.MustGet("role").(string)
if c.MustGet("username").(string) != username && role != string(entities.RoleAdmin) {
@ -55,29 +58,30 @@ func GetUserWithProject(service services.ApplicationService) gin.HandlerFunc {
return
}
request := project_utils.GetProjectFilters(c)
request := projectUtils.GetProjectFilters(c)
request.UserID = user.ID
response, err := service.GetProjectsByUserID(request)
res, err := service.GetProjectsByUserID(request)
if err != nil {
log.Error(err)
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
outputUser := &entities.UserWithProject{
outputUser := entities.UserWithProject{
Username: user.Username,
ID: user.ID,
Email: user.Email,
Name: user.Name,
Projects: response.Projects,
Projects: res.Projects,
}
c.JSON(http.StatusOK, gin.H{"data": outputUser})
c.JSON(http.StatusOK, response.UserWithProject{Data: outputUser})
}
}
// GetProject godoc
//
// @Summary Get user with project.
// @Description Return a project.
// @Tags ProjectRouter
@ -86,9 +90,9 @@ func GetUserWithProject(service services.ApplicationService) gin.HandlerFunc {
// @Produce json
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Project{}
// @Router /get_project/:project_id [get]
//
// GetProject queries the project with a given projectID from the database
func GetProject(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
@ -113,7 +117,7 @@ func GetProject(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{"data": project})
c.JSON(http.StatusOK, response.Project{Data: *project})
}
}
@ -125,16 +129,16 @@ func GetProject(service services.ApplicationService) gin.HandlerFunc {
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.ListProjectResponse{}
// @Router /list_projects [get]
//
// GetProjectsByUserID queries the project with a given userID from the database and returns it in the appropriate format
func GetProjectsByUserID(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
request := project_utils.GetProjectFilters(c)
request := projectUtils.GetProjectFilters(c)
response, err := service.GetProjectsByUserID(request)
if response == nil || (response.TotalNumberOfProjects != nil && *response.TotalNumberOfProjects == 0) {
res, err := service.GetProjectsByUserID(request)
if res == nil || (res.TotalNumberOfProjects != nil && *res.TotalNumberOfProjects == 0) {
c.JSON(http.StatusOK, gin.H{
"message": "No projects found",
})
@ -146,7 +150,7 @@ func GetProjectsByUserID(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{"data": response})
c.JSON(http.StatusOK, response.ListProjectResponse{Data: *res})
}
}
@ -158,10 +162,10 @@ func GetProjectsByUserID(service services.ApplicationService) gin.HandlerFunc {
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.ProjectStats{}
// @Router /get_projects_stats [get]
//
// GetProjectStats is used to retrive stats related to projects in the DB
// GetProjectStats is used to retrieve stats related to projects in the DB
func GetProjectStats(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
role := c.MustGet("role").(string)
@ -181,7 +185,7 @@ func GetProjectStats(service services.ApplicationService) gin.HandlerFunc {
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{"data": project})
c.JSON(http.StatusOK, response.ProjectStats{Data: project})
}
}
@ -194,8 +198,10 @@ func GetProjectStats(service services.ApplicationService) gin.HandlerFunc {
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Members{}
// @Router /get_project_members/:project_id/:state [get]
//
// GetActiveProjectMembers returns the list of active project members
func GetActiveProjectMembers(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
projectID := c.Param("project_id")
@ -217,7 +223,7 @@ func GetActiveProjectMembers(service services.ApplicationService) gin.HandlerFun
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{"data": members})
c.JSON(http.StatusOK, response.Members{Data: members})
}
}
@ -230,8 +236,10 @@ func GetActiveProjectMembers(service services.ApplicationService) gin.HandlerFun
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Members{}
// @Router /get_project_owners/:project_id/:state [get]
//
// GetActiveProjectOwners returns the list of active project owners
func GetActiveProjectOwners(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
projectID := c.Param("project_id")
@ -240,7 +248,7 @@ func GetActiveProjectOwners(service services.ApplicationService) gin.HandlerFunc
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{"data": owners})
c.JSON(http.StatusOK, response.Members{Data: owners})
}
}
@ -268,7 +276,7 @@ func getInvitation(service services.ApplicationService, member entities.MemberIn
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.ListInvitationResponse{}
// @Router /list_invitations_with_filters/:invitation_state [get]
//
// ListInvitations returns the Invitation status
@ -276,7 +284,7 @@ func ListInvitations(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
uID := c.MustGet("uid").(string)
invitationState := c.Param("invitation_state")
var response []entities.ListInvitationResponse
var res []entities.ListInvitationResponse
projects, err := service.ListInvitations(uID, entities.Invitation(invitationState))
if err != nil {
log.Errorf("Error while fetching invitations: %v", err)
@ -295,9 +303,9 @@ func ListInvitations(service services.ApplicationService) gin.HandlerFunc {
inviteRes.InvitationRole = member.Role
}
}
response = append(response, inviteRes)
res = append(res, inviteRes)
}
c.JSON(http.StatusOK, gin.H{"data": response})
c.JSON(http.StatusOK, response.ListInvitationResponse{Data: res})
}
}
@ -309,8 +317,10 @@ func ListInvitations(service services.ApplicationService) gin.HandlerFunc {
// @Accept json
// @Produce json
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Project{}
// @Router /create_project [post]
//
// CreateProject is used to create a new project
func CreateProject(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var userRequest entities.CreateProjectInput
@ -415,7 +425,7 @@ func CreateProject(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{"data": newProject.GetProjectOutput()})
c.JSON(http.StatusOK, response.Project{Data: *newProject.GetProjectOutput()})
}
@ -433,11 +443,10 @@ func CreateProject(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRole
// @Failure 400 {object} response.ErrUserNotFound
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Member{}
// @Router /send_invitation [post]
//
// SendInvitation sends an invitation to a new user and
// returns an error if the member is already part of the project
// SendInvitation sends an invitation to a new user and returns an error if the member is already part of the project
func SendInvitation(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var member entities.MemberInput
@ -477,7 +486,7 @@ func SendInvitation(service services.ApplicationService) gin.HandlerFunc {
user, err := service.GetUser(member.UserID)
if err == mongo.ErrNoDocuments {
if errors.Is(err, mongo.ErrNoDocuments) {
c.JSON(utils.ErrorStatusCodes[utils.ErrUserNotFound], presenter.CreateErrorResponse(utils.ErrUserNotFound))
return
} else if err != nil {
@ -487,7 +496,7 @@ func SendInvitation(service services.ApplicationService) gin.HandlerFunc {
}
invitation, err := getInvitation(service, member)
if err == mongo.ErrNoDocuments {
if errors.Is(err, mongo.ErrNoDocuments) {
c.JSON(utils.ErrorStatusCodes[utils.ErrProjectNotFound], presenter.CreateErrorResponse(utils.ErrProjectNotFound))
return
} else if err != nil {
@ -527,7 +536,7 @@ func SendInvitation(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{"data": entities.Member{
c.JSON(http.StatusOK, response.Member{Data: entities.Member{
UserID: user.ID,
Username: user.Username,
Name: user.Name,
@ -541,15 +550,15 @@ func SendInvitation(service services.ApplicationService) gin.HandlerFunc {
// AcceptInvitation godoc
//
// @Summary Accept invitaion.
// @Description Accept inviation to a project.
// @Summary Accept invitation.
// @Description Accept invitation to a project.
// @Tags ProjectRouter
// @Accept json
// @Produce json
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /accept_invitation [post]
//
// AcceptInvitation is used to accept an invitation
@ -593,23 +602,21 @@ func AcceptInvitation(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successful",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "Successful"})
}
}
// DeclineInvitation godoc
//
// @Summary Decline invitation.
// @Description Deecline invitation to a project.
// @Description Decline invitation to a project.
// @Tags ProjectRouter
// @Accept json
// @Produce json
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /decline_invitation [post]
//
// DeclineInvitation is used to decline an invitation
@ -653,9 +660,7 @@ func DeclineInvitation(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successful",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successful"})
}
}
@ -669,7 +674,7 @@ func DeclineInvitation(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /leave_project [post]
//
// LeaveProject is used to leave a project
@ -727,9 +732,7 @@ func LeaveProject(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successful",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successful"})
}
}
@ -743,7 +746,7 @@ func LeaveProject(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {obejct} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /remove_invitation [post]
//
// RemoveInvitation removes member or cancels invitation
@ -815,9 +818,7 @@ func RemoveInvitation(service services.ApplicationService) gin.HandlerFunc {
}
}
c.JSON(http.StatusOK, gin.H{
"message": "Successful",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successful"})
}
}
@ -831,7 +832,7 @@ func RemoveInvitation(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /update_project_name [post]
//
// UpdateProjectName is used to update a project's name
@ -890,9 +891,7 @@ func UpdateProjectName(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successful",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successful"})
}
}
@ -906,7 +905,7 @@ func UpdateProjectName(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.MessageResponse{}
// @Router /update_member_role [post]
//
// UpdateMemberRole is used to update a member role in the project
@ -951,9 +950,7 @@ func UpdateMemberRole(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successfully updated Role",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successful"})
}
}
@ -967,7 +964,7 @@ func UpdateMemberRole(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Failure 401 {object} response.ErrUnauthorized
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.Projects{}
// @Router /get_owner_projects [get]
//
// GetOwnerProjects returns an array of projects in which user is an owner
@ -981,9 +978,7 @@ func GetOwnerProjects(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"data": res,
})
c.JSON(http.StatusOK, response.Projects{Data: res})
}
}
@ -998,7 +993,7 @@ func GetOwnerProjects(service services.ApplicationService) gin.HandlerFunc {
// @Produce json
// @Failure 400 {object} response.ErrProjectNotFound
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Success 200 {object} response.ProjectRole{}
// @Router /get_project_role/:project_id [get]
//
// GetProjectRole returns the role of a user in the project
@ -1010,7 +1005,7 @@ func GetProjectRole(service services.ApplicationService) gin.HandlerFunc {
res, err := service.GetProjectRole(projectID, uid)
if err != nil {
log.Error(err)
if err == mongo.ErrNoDocuments {
if errors.Is(err, mongo.ErrNoDocuments) {
c.JSON(utils.ErrorStatusCodes[utils.ErrProjectNotFound], presenter.CreateErrorResponse(utils.ErrProjectNotFound))
return
}
@ -1021,9 +1016,7 @@ func GetProjectRole(service services.ApplicationService) gin.HandlerFunc {
if res != nil {
role = string(*res)
}
c.JSON(http.StatusOK, gin.H{
"role": role,
})
c.JSON(http.StatusOK, response.ProjectRole{Role: role})
}
}
@ -1036,8 +1029,8 @@ func GetProjectRole(service services.ApplicationService) gin.HandlerFunc {
// @Produce json
// @Failure 400 {object} response.ErrProjectNotFound
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.Response{}
// @Router /delete_project/{project_id} [post]
// @Success 200 {object} response.MessageResponse{}
// @Router /delete_project/:project_id [post]
//
// DeleteProject is used to delete a project.
func DeleteProject(service services.ApplicationService) gin.HandlerFunc {
@ -1063,8 +1056,6 @@ func DeleteProject(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successfully deleted project.",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "Successfully deleted project."})
}
}

View File

@ -1,10 +1,12 @@
package rest
import (
"errors"
"net/http"
"strings"
"time"
response "github.com/litmuschaos/litmus/chaoscenter/authentication/api/handlers"
"github.com/litmuschaos/litmus/chaoscenter/authentication/api/presenter"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities"
"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services"
@ -34,6 +36,8 @@ const BearerSchema = "Bearer "
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.UserResponse{}
// @Router /create_user [post]
//
// CreateUser creates a new user
func CreateUser(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
userRole := c.MustGet("role").(string)
@ -94,7 +98,7 @@ func CreateUser(service services.ApplicationService) gin.HandlerFunc {
userRequest.CreatedAt = createdAt
userResponse, err := service.CreateUser(&userRequest)
if err == utils.ErrUserExists {
if errors.Is(err, utils.ErrUserExists) {
log.Error(err)
c.JSON(utils.ErrorStatusCodes[utils.ErrUserExists], presenter.CreateErrorResponse(utils.ErrUserExists))
return
@ -121,6 +125,8 @@ func CreateUser(service services.ApplicationService) gin.HandlerFunc {
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.MessageResponse{}
// @Router /update/details [post]
//
// UpdateUser updates the user details
func UpdateUser(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var userRequest entities.UserDetails
@ -149,7 +155,7 @@ func UpdateUser(service services.ApplicationService) gin.HandlerFunc {
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{"message": "User details updated successfully"})
c.JSON(http.StatusOK, response.MessageResponse{Message: "User details updated successfully"})
}
}
@ -168,8 +174,8 @@ func GetUser(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
uid := c.Param("uid")
// Validating logged in user
// Must be either requesting info from the logged in user
// Validating logged-in user
// Must be either requesting info from the logged-in user
// or any user if it has the admin role
role := c.MustGet("role").(string)
if c.MustGet("uid").(string) != uid && role != string(entities.RoleAdmin) {
@ -199,6 +205,8 @@ func GetUser(service services.ApplicationService) gin.HandlerFunc {
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.UserResponse{}
// @Router /users [get]
//
// FetchUsers fetches all the users
func FetchUsers(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
userRole := c.MustGet("role").(string)
@ -227,6 +235,8 @@ func FetchUsers(service services.ApplicationService) gin.HandlerFunc {
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.UserResponse{}
// @Router /invite_users/:project_id [get]
//
// InviteUsers invites users to the project
func InviteUsers(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
projectID := c.Param("project_id")
@ -245,11 +255,11 @@ func InviteUsers(service services.ApplicationService) gin.HandlerFunc {
projectMembers, err := service.GetProjectMembers(projectID, "all")
var uids []string
var userIds []string
for _, k := range projectMembers {
uids = append(uids, k.UserID)
userIds = append(userIds, k.UserID)
}
users, err := service.InviteUsers(uids)
users, err := service.InviteUsers(userIds)
if err != nil {
log.Error(err)
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
@ -272,6 +282,8 @@ func InviteUsers(service services.ApplicationService) gin.HandlerFunc {
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.LoginResponse{}
// @Router /login [post]
//
// LoginUser returns the token for the user if the credentials are valid
func LoginUser(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var userRequest entities.User
@ -407,9 +419,7 @@ func LogoutUser(service services.ApplicationService) gin.HandlerFunc {
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{
"message": "successfully logged out",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "successfully logged out"})
}
}
@ -423,8 +433,10 @@ func LogoutUser(service services.ApplicationService) gin.HandlerFunc {
// @Failure 401 {object} response.ErrStrictPasswordPolicyViolation
// @Failure 400 {object} response.ErrOldPassword
// @Failure 401 {object} response.ErrInvalidCredentials
// @Success 200 {object} response.MessageResponse{}
// @Success 200 {object} response.ProjectIDWithMessage{}
// @Router /update/password [post]
//
// UpdatePassword updates the user password
func UpdatePassword(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
var userPasswordRequest entities.UserPassword
@ -515,10 +527,8 @@ func UpdatePassword(service services.ApplicationService) gin.HandlerFunc {
}
defaultProject = newProject.ID
}
c.JSON(http.StatusOK, gin.H{
"message": "password has been updated successfully",
"projectID": defaultProject,
})
c.JSON(http.StatusOK, response.ProjectIDWithMessage{Message: "password has been updated successfully", ProjectID: defaultProject})
}
}
@ -534,6 +544,8 @@ func UpdatePassword(service services.ApplicationService) gin.HandlerFunc {
// @Failure 500 {object} response.ErrServerError
// @Success 200 {object} response.MessageResponse{}
// @Router /reset/password [post]
//
// ResetPassword resets the user password
func ResetPassword(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
userRole := c.MustGet("role").(string)
@ -591,9 +603,7 @@ func ResetPassword(service services.ApplicationService) gin.HandlerFunc {
c.AbortWithStatusJSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
}
c.JSON(http.StatusOK, gin.H{
"message": "password has been reset successfully",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "password has been reset successfully"})
}
}
@ -607,6 +617,8 @@ func ResetPassword(service services.ApplicationService) gin.HandlerFunc {
// @Failure 400 {object} response.ErrInvalidRequest
// @Success 200 {object} response.MessageResponse{}
// @Router /update/state [post]
//
// UpdateUserState updates the user state
func UpdateUserState(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
@ -660,9 +672,7 @@ func UpdateUserState(service services.ApplicationService) gin.HandlerFunc {
return
}
c.JSON(http.StatusOK, gin.H{
"message": "user's state updated successfully",
})
c.JSON(http.StatusOK, response.MessageResponse{Message: "user's state updated successfully"})
}
}
@ -689,8 +699,8 @@ func CreateApiToken(service services.ApplicationService) gin.HandlerFunc {
return
}
// Validating logged in user
// Requesting info must be from the logged in user
// Validating logged-in user
// Requesting info must be from the logged-in user
if c.MustGet("uid").(string) != apiTokenRequest.UserID {
log.Error("auth error: unauthorized")
c.JSON(utils.ErrorStatusCodes[utils.ErrUnauthorized],
@ -746,8 +756,8 @@ func GetApiTokens(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
uid := c.Param("uid")
// Validating logged in user
// Requesting info must be from the logged in user
// Validating logged-in user
// Requesting info must be from the logged-in user
if c.MustGet("uid").(string) != uid {
log.Error("auth error: unauthorized")
c.JSON(utils.ErrorStatusCodes[utils.ErrUnauthorized],
@ -789,8 +799,8 @@ func DeleteApiToken(service services.ApplicationService) gin.HandlerFunc {
return
}
// Validating logged in user
// Requesting info must be from the logged in user
// Validating logged-in user
// Requesting info must be from the logged-in user
if c.MustGet("uid").(string) != deleteApiTokenRequest.UserID {
log.Error("auth error: unauthorized")
c.JSON(utils.ErrorStatusCodes[utils.ErrUnauthorized],
@ -821,10 +831,8 @@ func DeleteApiToken(service services.ApplicationService) gin.HandlerFunc {
log.Error(err)
c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError))
return
} else {
c.JSON(http.StatusOK, gin.H{
"message": "api token deleted successfully",
})
}
c.JSON(http.StatusOK, response.MessageResponse{Message: "api token deleted successfully"})
}
}

View File

@ -49,11 +49,6 @@ type UpdateUserState struct {
IsDeactivate *bool `json:"isDeactivate"`
}
// APIStatus defines structure for APIroute status
type APIStatus struct {
Status string `json:"status"`
}
type UserWithProject struct {
Audit `bson:",inline"`
ID string `bson:"_id" json:"id"`

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,164 @@
definitions:
entities.Invitation:
enum:
- Pending
- Accepted
- Declined
- Exited
type: string
x-enum-varnames:
- PendingInvitation
- AcceptedInvitation
- DeclinedInvitation
- ExitedProject
entities.ListInvitationResponse:
properties:
invitationRole:
$ref: '#/definitions/entities.MemberRole'
projectID:
type: string
projectName:
type: string
projectOwner:
$ref: '#/definitions/entities.Member'
type: object
entities.ListProjectResponse:
properties:
projects:
items:
$ref: '#/definitions/entities.Project'
type: array
totalNumberOfProjects:
type: integer
type: object
entities.Member:
properties:
deactivatedAt:
type: integer
email:
type: string
invitation:
$ref: '#/definitions/entities.Invitation'
joinedAt:
type: integer
name:
type: string
role:
$ref: '#/definitions/entities.MemberRole'
userID:
type: string
username:
type: string
type: object
entities.MemberRole:
enum:
- Owner
- Executor
- Viewer
type: string
x-enum-varnames:
- RoleOwner
- RoleExecutor
- RoleViewer
entities.MemberStat:
properties:
owner:
items:
$ref: '#/definitions/entities.Owner'
type: array
total:
type: integer
type: object
entities.Owner:
properties:
deactivatedAt:
type: integer
invitation:
$ref: '#/definitions/entities.Invitation'
joinedAt:
type: integer
userID:
type: string
username:
type: string
type: object
entities.Project:
properties:
createdAt:
type: integer
createdBy:
$ref: '#/definitions/entities.UserDetailResponse'
description:
type: string
isRemoved:
type: boolean
members:
items:
$ref: '#/definitions/entities.Member'
type: array
name:
type: string
projectID:
type: string
state:
type: string
tags:
items:
type: string
type: array
updatedAt:
type: integer
updatedBy:
$ref: '#/definitions/entities.UserDetailResponse'
type: object
entities.ProjectStats:
properties:
members:
$ref: '#/definitions/entities.MemberStat'
name:
type: string
projectID:
type: string
type: object
entities.UserDetailResponse:
properties:
email:
type: string
userID:
type: string
username:
type: string
type: object
entities.UserWithProject:
properties:
createdAt:
type: integer
createdBy:
$ref: '#/definitions/entities.UserDetailResponse'
email:
type: string
id:
type: string
isRemoved:
type: boolean
name:
type: string
projects:
items:
$ref: '#/definitions/entities.Project'
type: array
updatedAt:
type: integer
updatedBy:
$ref: '#/definitions/entities.UserDetailResponse'
username:
type: string
type: object
response.APIStatus:
properties:
status:
type: string
type: object
response.ApiTokenResponse:
properties:
createdAt:
@ -142,8 +302,32 @@ definitions:
example: user does not exist
type: string
type: object
response.ListInvitationResponse:
properties:
data:
items:
$ref: '#/definitions/entities.ListInvitationResponse'
type: array
type: object
response.ListProjectResponse:
properties:
data:
$ref: '#/definitions/entities.ListProjectResponse'
type: object
response.LoginResponse:
type: object
response.Member:
properties:
data:
$ref: '#/definitions/entities.Member'
type: object
response.Members:
properties:
data:
items:
$ref: '#/definitions/entities.Member'
type: array
type: object
response.MessageResponse:
properties:
message:
@ -151,6 +335,44 @@ definitions:
type: object
response.NewApiToken:
type: object
response.Project:
properties:
data:
$ref: '#/definitions/entities.Project'
type: object
response.ProjectIDWithMessage:
properties:
message:
type: string
projectID:
type: string
type: object
response.ProjectRole:
properties:
role:
type: string
type: object
response.ProjectStats:
properties:
data:
items:
$ref: '#/definitions/entities.ProjectStats'
type: array
type: object
response.Projects:
properties:
data:
items:
$ref: '#/definitions/entities.Project'
type: array
type: object
response.ReadinessAPIStatus:
properties:
collections:
type: string
database:
type: string
type: object
response.Response:
properties:
response:
@ -173,22 +395,30 @@ definitions:
username:
type: string
type: object
response.UserWithProject:
properties:
data:
$ref: '#/definitions/entities.UserWithProject'
type: object
info:
contact: {}
title: Chaoscenter API documentation
title: Litmus Portal Authentication API
version: 3.14.0
description: "Litmus Portal Authentication APIs are used to authenticate the identity of a user and to perform several user-specific tasks like: <li>Update Profile</li> <li>Change Password</li> <li>Reset Password</li> <li>Create new users etc.</li>"
paths:
/accept_invitation:
post:
consumes:
- application/json
description: Accept inviation to a project.
description: Accept invitation to a project.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
@ -201,7 +431,7 @@ paths:
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
summary: Accept invitaion.
summary: Accept invitation.
tags:
- ProjectRouter
/capabilities:
@ -235,7 +465,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.Project'
"500":
description: Internal Server Error
schema:
@ -295,14 +525,14 @@ paths:
post:
consumes:
- application/json
description: Deecline invitation to a project.
description: Decline invitation to a project.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
@ -318,6 +548,28 @@ paths:
summary: Decline invitation.
tags:
- ProjectRouter
/delete_project/:project_id:
post:
consumes:
- application/json
description: Delete a project.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrProjectNotFound'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
tags:
- ProjectRouter
/dex/callback:
get:
consumes:
@ -365,7 +617,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.Projects'
"400":
description: Bad Request
schema:
@ -381,6 +633,35 @@ paths:
summary: Get projects owner.
tags:
- ProjectRouter
/get_project/:project_id:
get:
consumes:
- application/json
description: Return a project.
parameters:
- description: Project ID
in: path
name: project_id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Project'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.ErrUnauthorized'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
summary: Get user with project.
tags:
- ProjectRouter
/get_project_members/:project_id/:state:
get:
consumes:
@ -398,7 +679,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.Members'
"500":
description: Internal Server Error
schema:
@ -406,6 +687,31 @@ paths:
summary: Get active project members.
tags:
- ProjectRouter
/get_project_owners/:project_id/:state:
get:
consumes:
- application/json
description: Return list of active project owners.
parameters:
- description: State
in: path
name: state
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Members'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
summary: Get active project Owners.
tags:
- ProjectRouter
/get_project_role/:project_id:
get:
consumes:
@ -423,7 +729,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.ProjectRole'
"400":
description: Bad Request
schema:
@ -446,7 +752,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.ProjectStats'
"500":
description: Internal Server Error
schema:
@ -472,6 +778,39 @@ paths:
$ref: '#/definitions/response.ErrUserNotFound'
tags:
- UserRouter
/get_user_with_project/:username:
get:
consumes:
- application/json
description: Return users who have a project.
parameters:
- description: Username
in: path
name: username
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.UserWithProject'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrUserNotFound'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.ErrUnauthorized'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
summary: Get user with project.
tags:
- ProjectRouter
/invite_users/:project_id:
get:
consumes:
@ -505,7 +844,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
@ -538,7 +877,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.ListInvitationResponse'
"500":
description: Internal Server Error
schema:
@ -557,7 +896,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.ListProjectResponse'
"500":
description: Internal Server Error
schema:
@ -579,6 +918,10 @@ paths:
$ref: '#/definitions/response.LoginResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrUserDeactivated'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.ErrInvalidCredentials'
"500":
@ -620,7 +963,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.ReadinessAPIStatus'
"500":
description: Internal Server Error
schema:
@ -638,7 +981,7 @@ paths:
"200":
description: OK
schema:
type: obejct
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
@ -713,7 +1056,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.Member'
"400":
description: Bad Request
schema:
@ -733,7 +1076,7 @@ paths:
get:
consumes:
- application/json
description: Status will request users list and return, if successful, an http
description: Status will request users list and return, if successful, a http
code 200.
produces:
- application/json
@ -741,7 +1084,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.APIStatus'
"500":
description: Internal Server Error
schema:
@ -803,7 +1146,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.MessageResponse'
$ref: '#/definitions/response.ProjectIDWithMessage'
"400":
description: Bad Request
schema:
@ -836,6 +1179,33 @@ paths:
$ref: '#/definitions/response.ErrUnauthorized'
tags:
- UserRouter
/update_member_role:
post:
consumes:
- application/json
description: Return updated member role.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrInvalidRequest'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.ErrUnauthorized'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrServerError'
summary: Update member role.
tags:
- ProjectRouter
/update_project_name:
post:
consumes:
@ -847,7 +1217,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
$ref: '#/definitions/response.MessageResponse'
"400":
description: Bad Request
schema:

View File

@ -9,7 +9,7 @@
<tr>
<td>AUTH Server</td>
<td>Contains AUTH Server API documentation</td>
<td><a target="_" href="/litmus/auth/v2.0.0/api.html">AUTH Server</a></td>
<td><a target="_" href="/litmus/auth/v3.14.0/api.html">AUTH Server</a></td>
</tr>
<tr>
<td>GraphQL Server</td>