From 2fa5851e80c9b0cdea3db9eea104a8a2fa40af9c Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Wed, 14 Feb 2024 13:24:39 +0900 Subject: [PATCH] implement tks-issues-1038 - make appserving belongs to project - add new APIs to return task list and detail --- internal/delivery/http/app-serve-app.go | 235 +++++++++++++++++++----- internal/repository/app-serve-app.go | 73 ++++++-- internal/usecase/app-serve-app.go | 20 ++ pkg/domain/app-serve-app.go | 9 + pkg/httpErrors/errorCode.go | 1 + 5 files changed, 280 insertions(+), 58 deletions(-) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 2510a768..bfc92b0e 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -84,16 +84,24 @@ func NewAppServeAppHandler(h usecase.IAppServeAppUsecase) *AppServeAppHandler { // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param object body domain.CreateAppServeAppRequest true "Request body to create app" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps [post] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps [post] // @Security JWT func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) organizationId, ok := vars["organizationId"] log.Debugf("organizationId = [%v]\n", organizationId) if !ok { - ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "")) + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "")) + return + } + + projectId, ok := vars["projectId"] + log.Debugf("projectId = [%v]\n", projectId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid projectId"), "C_INVALID_PROJECT_ID", "")) return } @@ -116,6 +124,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re now := time.Now() app.OrganizationId = organizationId + app.ProjectId = projectId app.EndpointUrl = "N/A" app.PreviewEndpointUrl = "N/A" app.Status = "PREPARING" @@ -151,29 +160,29 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re return } - // Create namespace if it's not given by user - if len(strings.TrimSpace(app.Namespace)) == 0 { - // Check if the new namespace is already used in the target cluster - ns := "" - nsExist := true - for nsExist { - // Generate unique namespace based on name and random number - src := rand.NewSource(time.Now().UnixNano()) - r1 := rand.New(src) - ns = fmt.Sprintf("%s-%s", app.Name, strconv.Itoa(r1.Intn(10000))) + // Create namespace if it's not given by user + if len(strings.TrimSpace(app.Namespace)) == 0 { + // Check if the new namespace is already used in the target cluster + ns := "" + nsExist := true + for nsExist { + // Generate unique namespace based on name and random number + src := rand.NewSource(time.Now().UnixNano()) + r1 := rand.New(src) + ns = fmt.Sprintf("%s-%s", app.Name, strconv.Itoa(r1.Intn(10000))) - nsExist, err = h.usecase.IsAppServeAppNamespaceExist(app.TargetClusterId, ns) - if err != nil { - ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) - return - } - } + nsExist, err = h.usecase.IsAppServeAppNamespaceExist(app.TargetClusterId, ns) + if err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + } - log.Infof("Created new namespace: %s", ns) - app.Namespace = ns - } else { - log.Infof("Using existing namespace: %s", app.Namespace) - } + log.Infof("Created new namespace: %s", ns) + app.Namespace = ns + } else { + log.Infof("Using existing namespace: %s", app.Namespace) + } // Validate port param for springboot app if app.AppType == "springboot" { @@ -212,6 +221,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param showAll query boolean false "Show all apps including deleted apps" // @Param limit query string false "pageSize" // @Param page query string false "pageNumber" @@ -219,7 +229,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re // @Param sortOrder query string false "sortOrder" // @Param filters query []string false "filters" // @Success 200 {object} []domain.AppServeApp -// @Router /organizations/{organizationId}/app-serve-apps [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps [get] // @Security JWT func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -273,9 +283,10 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Success 200 {object} domain.GetAppServeAppResponse -// @Router /organizations/{organizationId}/app-serve-apps/{appId} [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId} [get] // @Security JWT func (h *AppServeAppHandler) GetAppServeApp(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -317,7 +328,7 @@ func (h *AppServeAppHandler) GetAppServeApp(w http.ResponseWriter, r *http.Reque var out domain.GetAppServeAppResponse out.AppServeApp = *app - out.Stages = makeStages(app) + //out.Stages = makeStages(app) ResponseJSON(w, r, http.StatusOK, out) } @@ -329,9 +340,10 @@ func (h *AppServeAppHandler) GetAppServeApp(w http.ResponseWriter, r *http.Reque // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Success 200 {object} domain.GetAppServeAppTaskResponse -// @Router /organizations/{organizationId}/app-serve-apps/{appId}/latest-task [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/latest-task [get] // @Security JWT func (h *AppServeAppHandler) GetAppServeAppLatestTask(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -372,9 +384,10 @@ func (h *AppServeAppHandler) GetAppServeAppLatestTask(w http.ResponseWriter, r * // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param stackId query string true "Stack ID" // @Success 200 {object} int64 -// @Router /organizations/{organizationId}/app-serve-apps/count [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/count [get] // @Security JWT func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -402,13 +415,135 @@ func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http. ResponseJSON(w, r, http.StatusOK, numApps) } -func makeStages(app *domain.AppServeApp) []domain.StageResponse { +// New func +// GetAppServeAppTasksByAppId godoc +// @Tags AppServeApps +// @Summary Get appServeAppTask list +// @Description Get appServeAppTask list by giving params +// @Accept json +// @Produce json +// @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param sortColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" +// @Success 200 {object} []domain.AppServeApp +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/tasks [get] +// @Security JWT +func (h *AppServeAppHandler) GetAppServeAppTasksByAppId(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid organizationId: %s", organizationId), "C_INVALID_ORGANIZATION_ID", "")) + return + } + + appId, ok := vars["appId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid appId: %s", appId), "C_INVALID_ASA_ID", "")) + return + } + + urlParams := r.URL.Query() + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } + + tasks, err := h.usecase.GetAppServeAppTasks(appId, pg) + if err != nil { + log.ErrorWithContext(r.Context(), "Failed to get app-serve-app-tasks ", err) + ErrorJSON(w, r, err) + return + } + + var out domain.GetAppServeAppTasksResponse + out.AppServeAppTasks = tasks + + if err := serializer.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + + ResponseJSON(w, r, http.StatusOK, out) +} + +// GetAppServeAppTaskDetail godoc +// @Tags AppServeApps +// @Summary Get task detail from appServeApp +// @Description Get task detail from appServeApp +// @Accept json +// @Produce json +// @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" +// @Param appId path string true "App ID" +// @Param taskId path string true "Task ID" +// @Success 200 {object} domain.GetAppServeAppTaskResponse +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/tasks/{taskId} [get] +// @Security JWT +func (h *AppServeAppHandler) GetAppServeAppTaskDetail(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + organizationId, ok := vars["organizationId"] + log.Debugf("organizationId = [%v]\n", organizationId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid organizationId: [%s]", organizationId), "C_INVALID_ORGANIZATION_ID", "")) + return + } + + projectId, ok := vars["projectId"] + log.Debugf("projectId = [%v]\n", projectId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid projectId: [%s]", projectId), "C_INVALID_PROJECT_ID", "")) + return + } + + appId, ok := vars["appId"] + log.Debugf("appId = [%s]\n", appId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid appId: [%s]", appId), "C_INVALID_ASA_ID", "")) + return + } + + taskId, ok := vars["taskId"] + log.Debugf("taskId = [%s]\n", taskId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid taskId: [%s]", taskId), "C_INVALID_ASA_TASK_ID", "")) + return + } + + task, app, err := h.usecase.GetAppServeAppTaskById(taskId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + if task == nil { + ErrorJSON(w, r, httpErrors.NewNoContentError(fmt.Errorf("No task exists"), "", "")) + return + } + + if strings.Contains(task.Status, "SUCCESS") && task.Status != "ABORT_SUCCESS" && + task.Status != "ROLLBACK_SUCCESS" { + task.AvailableRollback = true + } + + var out domain.GetAppServeAppTaskResponse + out.AppServeApp = *app + out.AppServeAppTask = *task + out.Stages = makeStages(task, app) + + ResponseJSON(w, r, http.StatusOK, out) +} + +func makeStages(task *domain.AppServeAppTask, app *domain.AppServeApp) []domain.StageResponse { stages := make([]domain.StageResponse, 0) var stage domain.StageResponse var pipelines []string - taskStatus := app.AppServeAppTasks[0].Status - strategy := app.AppServeAppTasks[0].Strategy + taskStatus := task.Status + strategy := task.Strategy if taskStatus == "ROLLBACKING" || taskStatus == "ROLLBACK_SUCCESS" || @@ -437,21 +572,21 @@ func makeStages(app *domain.AppServeApp) []domain.StageResponse { fmt.Printf("Pipeline stages: %v\n", pipelines) for _, pl := range pipelines { - stage = makeStage(app, pl) + stage = makeStage(task, app, pl) stages = append(stages, stage) } return stages } -func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { - taskStatus := app.AppServeAppTasks[0].Status - strategy := app.AppServeAppTasks[0].Strategy +func makeStage(task *domain.AppServeAppTask, app *domain.AppServeApp, pl string) domain.StageResponse { + taskStatus := task.Status + strategy := task.Strategy stage := domain.StageResponse{ Name: pl, - Status: StatusStages[app.Status][pl], - Result: StatusResult[StatusStages[app.Status][pl]], + Status: StatusStages[taskStatus][pl], + Result: StatusResult[StatusStages[taskStatus][pl]], } var actions []domain.ActionResponse @@ -480,7 +615,7 @@ func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { action := domain.ActionResponse{ Name: "ABORT", Uri: fmt.Sprintf(internal.API_PREFIX+internal.API_VERSION+ - "/organizations/%v/app-serve-apps/%v", app.OrganizationId, app.ID), + "/organizations/%v/projects/%v/app-serve-apps/%v", app.OrganizationId, app.ProjectId, app.ID), Type: "API", Method: "PUT", Body: map[string]string{"strategy": "blue-green", "abort": "true"}, @@ -490,7 +625,7 @@ func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { action = domain.ActionResponse{ Name: "PROMOTE", Uri: fmt.Sprintf(internal.API_PREFIX+internal.API_VERSION+ - "/organizations/%v/app-serve-apps/%v", app.OrganizationId, app.ID), + "/organizations/%v/projects/%v/app-serve-apps/%v", app.OrganizationId, app.ProjectId, app.ID), Type: "API", Method: "PUT", Body: map[string]string{"strategy": "blue-green", "promote": "true"}, @@ -509,8 +644,10 @@ func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { // @Description Get appServeApp by giving params // @Accept json // @Produce json +// @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Success 200 {object} bool -// @Router /organizations/{organizationId}/app-serve-apps/{appId}/exist [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/exist [get] // @Security JWT func (h *AppServeAppHandler) IsAppServeAppExist(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -549,9 +686,10 @@ func (h *AppServeAppHandler) IsAppServeAppExist(w http.ResponseWriter, r *http.R // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param name path string true "name" // @Success 200 {object} bool -// @Router /organizations/{organizationId}/app-serve-apps/name/{name}/existence [get] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/name/{name}/existence [get] // @Security JWT func (h *AppServeAppHandler) IsAppServeAppNameExist(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -588,10 +726,11 @@ func (h *AppServeAppHandler) IsAppServeAppNameExist(w http.ResponseWriter, r *ht // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Param object body domain.UpdateAppServeAppRequest true "Request body to update app" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps/{appId} [put] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId} [put] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeApp(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -697,10 +836,11 @@ func (h *AppServeAppHandler) UpdateAppServeApp(w http.ResponseWriter, r *http.Re // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Param body body domain.UpdateAppServeAppStatusRequest true "Request body to update app status" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps/{appId}/status [patch] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/status [patch] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeAppStatus(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -740,10 +880,11 @@ func (h *AppServeAppHandler) UpdateAppServeAppStatus(w http.ResponseWriter, r *h // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "appId" // @Param body body domain.UpdateAppServeAppEndpointRequest true "Request body to update app endpoint" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps/{appId}/endpoint [patch] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/endpoint [patch] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeAppEndpoint(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -788,9 +929,10 @@ func (h *AppServeAppHandler) UpdateAppServeAppEndpoint(w http.ResponseWriter, r // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps/{appId} [delete] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId} [delete] // @Security JWT func (h *AppServeAppHandler) DeleteAppServeApp(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -824,10 +966,11 @@ func (h *AppServeAppHandler) DeleteAppServeApp(w http.ResponseWriter, r *http.Re // @Accept json // @Produce json // @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" // @Param appId path string true "App ID" // @Param object body domain.RollbackAppServeAppRequest true "Request body to rollback app" // @Success 200 {object} string -// @Router /organizations/{organizationId}/app-serve-apps/{appId}/rollback [post] +// @Router /organizations/{organizationId}/projects/{projectId}/app-serve-apps/{appId}/rollback [post] // @Security JWT func (h *AppServeAppHandler) RollbackAppServeApp(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index d27adfb6..a24a43fa 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -15,14 +15,18 @@ type IAppServeAppRepository interface { CreateAppServeApp(app *domain.AppServeApp) (appId string, taskId string, err error) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) + + GetAppServeAppTasksByAppId(appId string, pg *pagination.Pagination) ([]domain.AppServeAppTask, error) + GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, *domain.AppServeApp, error) + GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) + IsAppServeAppExist(appId string) (int64, error) IsAppServeAppNameExist(orgId string, appName string) (int64, error) CreateTask(task *domain.AppServeAppTask) (taskId string, err error) UpdateStatus(appId string, taskId string, status string, output string) error UpdateEndpoint(appId string, taskId string, endpoint string, previewEndpoint string, helmRevision int32) error - GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, error) GetTaskCountById(appId string) (int64, error) } @@ -109,9 +113,10 @@ func (r *AppServeAppRepository) GetAppServeAppById(appId string) (*domain.AppSer return nil, res.Error } if res.RowsAffected == 0 { - return nil, nil + return nil, nil, fmt.Errorf("No app with ID %s", appId) } + // Populate tasks into app object if err := r.db.Model(&app).Order("created_at desc").Association("AppServeAppTasks").Find(&app.AppServeAppTasks); err != nil { log.Debug(err) return nil, err @@ -124,9 +129,63 @@ func (r *AppServeAppRepository) GetAppServeAppById(appId string) (*domain.AppSer return &app, nil } +func (r *AppServeAppRepository) GetAppServeAppTasksByAppId(appId string, pg *pagination.Pagination) (tasks []domain.AppServeAppTask, err error) { + if pg == nil { + pg = pagination.NewDefaultPagination() + } + + filterFunc := CombinedGormFilter("app_serve_app_tasks", pg.GetFilters(), pg.CombinedFilter) + db := filterFunc(r.db.Model(&domain.AppServeAppTask{}). + Where("app_serve_app_tasks.app_serve_app_id = ?", appId)) + db.Count(&pg.TotalRows) + + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&tasks) + if res.Error != nil { + return nil, fmt.Errorf("Error while finding tasks with appId: %s", appId) + } + + // If no record is found, just return empty array. + if res.RowsAffected == 0 { + return tasks, nil + } + + return +} + +// Return single task info along with its parent app info +func (r *AppServeAppRepository) GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, *domain.AppServeApp, error) { + var task domain.AppServeAppTask + var app domain.AppServeApp + + // Retrieve task info + res := r.db.Where("id = ?", taskId).First(&task) + if res.Error != nil { + log.Debug(res.Error) + return nil, nil, res.Error + } + if res.RowsAffected == 0 { + return nil, nil, fmt.Errorf("No task with ID %s", taskId) + } + + // Retrieve app info + res = r.db.Where("id = ?", task.AppServeAppId).First(&app) + if res.Error != nil { + log.Debug(res.Error) + return nil, nil, res.Error + } + if res.RowsAffected == 0 { + return nil, nil, fmt.Errorf("Couldn't find app with ID %s associated with task %s", appId, taskId) + } + + return &task, &app, nil +} + func (r *AppServeAppRepository) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) { var task domain.AppServeAppTask + // TODO: Does this work?? where's app ID here? res := r.db.Order("created_at desc").First(&task) if res.Error != nil { log.Debug(res.Error) @@ -267,16 +326,6 @@ func (r *AppServeAppRepository) UpdateEndpoint(appId string, taskId string, endp return nil } -func (r *AppServeAppRepository) GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, error) { - var task domain.AppServeAppTask - - if err := r.db.Where("id = ?", taskId).First(&task).Error; err != nil { - return nil, fmt.Errorf("could not find AppServeAppTask with ID: %s", taskId) - } - - return &task, nil -} - func (r *AppServeAppRepository) GetTaskCountById(appId string) (int64, error) { var count int64 if err := r.db.Model(&domain.AppServeAppTask{}).Where("AppServeAppId = ?", appId).Count(&count); err != nil { diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 38e0b702..b16163f1 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -26,6 +26,8 @@ type IAppServeAppUsecase interface { CreateAppServeApp(app *domain.AppServeApp) (appId string, taskId string, err error) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) + GetAppServeAppTasks(appId string, pg *pagination.Pagination) ([]domain.AppServeAppTask, error) + GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, *domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) IsAppServeAppExist(appId string) (bool, error) @@ -220,6 +222,24 @@ func (u *AppServeAppUsecase) GetAppServeAppById(appId string) (*domain.AppServeA return asa, nil } +func (u *AppServeAppUsecase) GetAppServeAppTasks(appId string, pg *pagination.Pagination) ([]domain.AppServeAppTask, error) { + tasks, err := u.repo.GetAppServeAppTasksByAppId(appId, pg) + if err != nil { + log.Debugf("Tasks: %v", tasks) + } + + return tasks, nil +} + +func (u *AppServeAppUsecase) GetAppServeAppTaskById(taskId string) (*domain.AppServeAppTask, *domain.AppServeApp, error) { + task, app, err := u.repo.GetAppServeAppTaskById(taskId) + if err != nil { + return nil, nil, err + } + + return task, app, nil +} + func (u *AppServeAppUsecase) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) { task, err := u.repo.GetAppServeAppLatestTask(appId) if err != nil { diff --git a/pkg/domain/app-serve-app.go b/pkg/domain/app-serve-app.go index 5cb82ff1..45239154 100644 --- a/pkg/domain/app-serve-app.go +++ b/pkg/domain/app-serve-app.go @@ -12,6 +12,7 @@ type AppServeApp struct { Name string `gorm:"index" json:"name,omitempty"` // application name Namespace string `json:"namespace,omitempty"` // application namespace OrganizationId string `json:"organizationId,omitempty"` // contractId is a contract ID which this app belongs to + ProjectId string `json:"projectId,omitempty"` // project ID which this app belongs to Type string `json:"type,omitempty"` // type (build/deploy/all) AppType string `json:"appType,omitempty"` // appType (spring/springboot) EndpointUrl string `json:"endpointUrl,omitempty"` // endpoint URL of deployed app @@ -161,13 +162,21 @@ type GetAppServeAppsResponse struct { Pagination PaginationResponse `json:"pagination"` } +// TODO: This will be deprecated later type GetAppServeAppResponse struct { AppServeApp AppServeApp `json:"appServeApp"` Stages []StageResponse `json:"stages"` } +type GetAppServeAppTasksResponse struct { + AppServeAppTasks []AppServeAppTask `json:"appServeAppTasks"` + Pagination PaginationResponse `json:"pagination"` +} + type GetAppServeAppTaskResponse struct { + AppServeApp AppServeApp `json:"appServeApp"` AppServeAppTask AppServeAppTask `json:"appServeAppTask"` + Stages []StageResponse `json:"stages"` } type StageResponse struct { diff --git a/pkg/httpErrors/errorCode.go b/pkg/httpErrors/errorCode.go index d4d2b65f..b6c91281 100644 --- a/pkg/httpErrors/errorCode.go +++ b/pkg/httpErrors/errorCode.go @@ -10,6 +10,7 @@ var errorMap = map[ErrorCode]string{ "C_INVALID_CLUSTER_ID": "유효하지 않은 클러스터 아이디입니다. 클러스터 아이디를 확인하세요.", "C_INVALID_APPGROUP_ID": "유효하지 않은 앱그룹 아이디입니다. 앱그룹 아이디를 확인하세요.", "C_INVALID_ORGANIZATION_ID": "유효하지 않은 조직 아이디입니다. 조직 아이디를 확인하세요.", + "C_INVALID_PROJECT_ID": "유효하지 않은 프로젝트 아이디입니다. 아이디를 확인하세요.", "C_INVALID_CLOUD_ACCOUNT_ID": "유효하지 않은 클라우드어카운트 아이디입니다. 클라우드어카운트 아이디를 확인하세요.", "C_INVALID_STACK_TEMPLATE_ID": "유효하지 않은 스택템플릿 아이디입니다. 스택템플릿 아이디를 확인하세요.", "C_INVALID_ASA_ID": "유효하지 않은 앱서빙앱 아이디입니다. 앱서빙앱 아이디를 확인하세요.",