From 304650d0409ea2d5c37708417ce4d508245dee89 Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Mon, 5 Jan 2026 19:38:53 +0530 Subject: [PATCH 01/10] Dynamic Apptype handlers --- .../application_type_handler.go | 173 ++++++++++++++++++ .../application_type_handler_test.go | 89 +++++++++ .../application_type_service.go | 57 ++++++ .../application_type_service_test.go | 36 ++++ 4 files changed, 355 insertions(+) create mode 100644 adminapi/applicationtype/application_type_handler.go create mode 100644 adminapi/applicationtype/application_type_handler_test.go create mode 100644 adminapi/applicationtype/application_type_service.go create mode 100644 adminapi/applicationtype/application_type_service_test.go diff --git a/adminapi/applicationtype/application_type_handler.go b/adminapi/applicationtype/application_type_handler.go new file mode 100644 index 0000000..0522219 --- /dev/null +++ b/adminapi/applicationtype/application_type_handler.go @@ -0,0 +1,173 @@ +package applicationtype + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/gorilla/mux" + "github.com/rdkcentral/xconfadmin/adminapi/auth" + xhttp "github.com/rdkcentral/xconfadmin/http" + xapptype "github.com/rdkcentral/xconfadmin/shared/applicationtype" + xwhttp "github.com/rdkcentral/xconfwebconfig/http" +) + +func CreateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { + _, err := auth.CanWrite(r, auth.CHANGE_ENTITY) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusForbidden, err.Error()) + return + } + var appType xapptype.ApplicationType + xw, ok := w.(*xwhttp.XResponseWriter) + if !ok { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "responsewriter cast error") + return + } + body := xw.Body() + err = json.Unmarshal([]byte(body), &appType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + exists, _ := xapptype.GetApplicationTypeByName(appType.Name) + if exists { + xhttp.WriteAdminErrorResponse(w, http.StatusConflict, "Application type already exists") + return + } + createdAppType, err := CreateApplicationType(r, &appType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + data, err := json.Marshal(createdAppType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + xhttp.WriteXconfResponse(w, http.StatusCreated, data) +} + +func GetAllApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { + _, err := auth.CanRead(r, auth.CHANGE_ENTITY) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusForbidden, err.Error()) + return + } + appTypes, err := xapptype.GetAllApplicationTypeAsList() + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + data, err := json.Marshal(appTypes) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + xhttp.WriteXconfResponse(w, http.StatusOK, data) +} + +func GetApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { + _, err := auth.CanRead(r, auth.CHANGE_ENTITY) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusForbidden, err.Error()) + return + } + id := mux.Vars(r)["id"] + appType, err := xapptype.GetOneApplicationType(id) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + if appType == nil { + xhttp.WriteAdminErrorResponse(w, http.StatusNotFound, "Application type not found") + return + } + data, err := json.Marshal(appType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + xhttp.WriteXconfResponse(w, http.StatusOK, data) +} + +func DeleteApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { + _, err := auth.CanWrite(r, auth.CHANGE_ENTITY) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusForbidden, err.Error()) + return + } + id := mux.Vars(r)["id"] + appType, err := xapptype.GetOneApplicationType(id) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + if xapptype.IsDefaultAppType(appType.Name) { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Default application types cannot be deleted") + return + } + err = xapptype.DeleteOneApplicationType(id) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + response := map[string]string{ + "message": fmt.Sprintf("Application type '%s' deleted successfully", appType.Name), + } + data, _ := json.Marshal(response) + xhttp.WriteXconfResponse(w, http.StatusOK, data) +} + +func UpdateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { + _, err := auth.CanWrite(r, auth.CHANGE_ENTITY) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusForbidden, err.Error()) + return + } + id := mux.Vars(r)["id"] + xw, ok := w.(*xwhttp.XResponseWriter) + if !ok { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "responsewriter cast error") + return + } + body := xw.Body() + var updateRequest xapptype.ApplicationType + err = json.Unmarshal([]byte(body), &updateRequest) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + err = ValidateApplicationType(&updateRequest) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + existingAppType, err := xapptype.GetOneApplicationType(id) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + if xapptype.IsDefaultAppType(existingAppType.Name) { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Default application types cannot be updated") + return + } + existingAppType.ID = id + existingAppType.Name = updateRequest.Name + existingAppType.UpdatedAt = time.Now().Unix() + + err = xapptype.SetOneApplicationType(existingAppType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + data, err := json.Marshal(existingAppType) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + xhttp.WriteXconfResponse(w, http.StatusOK, data) +} diff --git a/adminapi/applicationtype/application_type_handler_test.go b/adminapi/applicationtype/application_type_handler_test.go new file mode 100644 index 0000000..729dfc1 --- /dev/null +++ b/adminapi/applicationtype/application_type_handler_test.go @@ -0,0 +1,89 @@ +package applicationtype + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/mux" + xwhttp "github.com/rdkcentral/xconfwebconfig/http" + "github.com/stretchr/testify/assert" +) + +func TestCreateApplicationTypeHandler(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "/api/applicationtype", nil) + rec := httptest.NewRecorder() + + CreateApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) + w := xwhttp.NewXResponseWriter(rec) + + invalidJson := `{invalid json}` + w.SetBody(invalidJson) + CreateApplicationTypeHandler(w, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) + + // valid Json + validJson := `{"name": "testAppType"}` + w.SetBody(validJson) + CreateApplicationTypeHandler(w, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) + + w.SetBody(validJson) + CreateApplicationTypeHandler(w, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) +} + +func TestGetAllApplicationTypeHandler(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "/api/applicationtype", nil) + rec := httptest.NewRecorder() + GetAllApplicationTypeHandler(rec, req) + assert.True(t, rec.Code == http.StatusOK || rec.Code == http.StatusInternalServerError) +} + +func TestGetApplicationTypeHandler(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "/api/applicationtype/{id}", nil) + req = mux.SetURLVars(req, map[string]string{"id": "nonexistentID"}) + rec := httptest.NewRecorder() + GetApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusInternalServerError, rec.Code) +} + +func TestUpdateApplicationTypeHandler(t *testing.T) { + req := httptest.NewRequest(http.MethodPut, "/api/applicationtype/123", nil) + req = mux.SetURLVars(req, map[string]string{"id": "123"}) + rec := httptest.NewRecorder() + + UpdateApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) + assert.Contains(t, rec.Body.String(), "responsewriter cast error") + + rec = httptest.NewRecorder() + w := xwhttp.NewXResponseWriter(rec) + invalidJson := `{invalid json}` + w.SetBody(invalidJson) + UpdateApplicationTypeHandler(w, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) + + rec = httptest.NewRecorder() + w = xwhttp.NewXResponseWriter(rec) + validJson := `{"name": "updatedApp"}` + w.SetBody(validJson) + UpdateApplicationTypeHandler(w, req) + assert.True(t, rec.Code == http.StatusOK || rec.Code == http.StatusBadRequest || rec.Code == http.StatusInternalServerError) + + rec = httptest.NewRecorder() + w = xwhttp.NewXResponseWriter(rec) + validJson = `{"name": "updatedAppType"}` + w.SetBody(validJson) + UpdateApplicationTypeHandler(w, req) + assert.True(t, rec.Code == http.StatusOK || rec.Code == http.StatusBadRequest || rec.Code == http.StatusInternalServerError) +} + +func TestDeleteApplicationTypeHandler(t *testing.T) { + req := httptest.NewRequest(http.MethodDelete, "/api/applicationtype/{id}", nil) + req = mux.SetURLVars(req, map[string]string{"id": "nonexistentID"}) + rec := httptest.NewRecorder() + DeleteApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusInternalServerError, rec.Code) +} diff --git a/adminapi/applicationtype/application_type_service.go b/adminapi/applicationtype/application_type_service.go new file mode 100644 index 0000000..f8e4379 --- /dev/null +++ b/adminapi/applicationtype/application_type_service.go @@ -0,0 +1,57 @@ +package applicationtype + +import ( + "fmt" + "net/http" + "regexp" + "time" + + "github.com/google/uuid" + "github.com/rdkcentral/xconfadmin/adminapi/auth" + xapptype "github.com/rdkcentral/xconfadmin/shared/applicationtype" + xwcommon "github.com/rdkcentral/xconfwebconfig/common" + log "github.com/sirupsen/logrus" +) + +const ( + applicationRegexPattern = "^[a-zA-Z]{3,12}$" +) + +func CreateApplicationType(r *http.Request, appType *xapptype.ApplicationType) (*xapptype.ApplicationType, error) { + _, err := auth.CanWrite(r, auth.CHANGE_ENTITY) + if err != nil { + return nil, err + } + + if err := ValidateApplicationType(appType); err != nil { + return nil, err + } + + appType.ID = uuid.New().String() + appType.CreatedBy = auth.GetUserNameOrUnknown(r) + appType.CreatedAt = time.Now().Unix() + + err = xapptype.SetOneApplicationType(appType) + if err != nil { + log.Error(fmt.Sprintf("CreateApplicationType error: %v", err)) + return nil, xwcommon.NewRemoteErrorAS(http.StatusInternalServerError, err.Error()) + } + + log.Info(fmt.Sprintf("Application type created: %s by %s", appType.Name, appType.CreatedBy)) + return appType, nil +} + +func ValidateApplicationType(appType *xapptype.ApplicationType) error { + if appType == nil { + return xwcommon.NewRemoteErrorAS(http.StatusBadRequest, "Application type cannot be nil") + } + if appType.Name == "" { + return xwcommon.NewRemoteErrorAS(http.StatusBadRequest, "Application type name cannot be empty") + } + + matched, _ := regexp.MatchString(applicationRegexPattern, appType.Name) + if !matched { + return xwcommon.NewRemoteErrorAS(http.StatusBadRequest, "Application type name must be 3-10 alphabetic characters") + } + return nil +} diff --git a/adminapi/applicationtype/application_type_service_test.go b/adminapi/applicationtype/application_type_service_test.go new file mode 100644 index 0000000..964df84 --- /dev/null +++ b/adminapi/applicationtype/application_type_service_test.go @@ -0,0 +1,36 @@ +package applicationtype + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + xapptype "github.com/rdkcentral/xconfadmin/shared/applicationtype" + "github.com/stretchr/testify/assert" +) + +func TestCreateApplicationType(t *testing.T) { + appType := &xapptype.ApplicationType{ + Name: "testApp", + } + req := httptest.NewRequest(http.MethodPost, "/api/applicationtype", nil) + req.Header.Set("X-User-Name", "testuser") + createdAppType, err := CreateApplicationType(req, appType) + if err != nil { + if strings.Contains(err.Error(), "Table configuration not found") { + t.Skip("Skipping test: database not configured") + return + } + } + assert.NotNil(t, createdAppType) + assert.NoError(t, err) +} + +func TestValidateApplicationType(t *testing.T) { + err := ValidateApplicationType(nil) + assert.Error(t, err) + + err = ValidateApplicationType(&xapptype.ApplicationType{Name: ""}) + assert.Error(t, err) +} From d8f96bb5ce20642c5df1a7298b726754e29ac57c Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Mon, 5 Jan 2026 19:40:22 +0530 Subject: [PATCH 02/10] Added logic for CRUD operations --- shared/applicationtype/application_type.go | 21 +++++ .../applicationtype/application_type_dao.go | 85 +++++++++++++++++++ .../application_type_dao_test.go | 80 +++++++++++++++++ .../applicationtype/application_type_test.go | 12 +++ 4 files changed, 198 insertions(+) create mode 100644 shared/applicationtype/application_type.go create mode 100644 shared/applicationtype/application_type_dao.go create mode 100644 shared/applicationtype/application_type_dao_test.go create mode 100644 shared/applicationtype/application_type_test.go diff --git a/shared/applicationtype/application_type.go b/shared/applicationtype/application_type.go new file mode 100644 index 0000000..7ed67d7 --- /dev/null +++ b/shared/applicationtype/application_type.go @@ -0,0 +1,21 @@ +package applicationtype + +import "strings" + +type ApplicationType struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + CreatedBy string `json:"createdBy"` + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt,omitempty"` +} + +func IsDefaultAppType(name string) bool { + for _, dt := range defaultTypes { + if strings.Contains(name, dt) { + return true + } + } + return false +} diff --git a/shared/applicationtype/application_type_dao.go b/shared/applicationtype/application_type_dao.go new file mode 100644 index 0000000..c6da50e --- /dev/null +++ b/shared/applicationtype/application_type_dao.go @@ -0,0 +1,85 @@ +package applicationtype + +import ( + "encoding/json" + "strings" + + db "github.com/rdkcentral/xconfwebconfig/db" +) + +const ( + TABLE_APPLICATION_TYPES = "ApplicationTypes" +) + +var defaultTypes = []string{"stb", "xhome", "rdkcloud"} + +// Get one application type +func GetOneApplicationType(id string) (*ApplicationType, error) { + result, err := db.GetCachedSimpleDao().GetOne(TABLE_APPLICATION_TYPES, id) //better to take it from cache(DS changes) + if err != nil { + return nil, err + } + if result == nil { + return nil, nil + } + appType, err := toApplicationType(result) + if err != nil { + return nil, err + } + return appType, nil +} + +func SetOneApplicationType(appType *ApplicationType) error { + DeleteOneApplicationType(appType.ID) + return db.GetCachedSimpleDao().SetOne(TABLE_APPLICATION_TYPES, appType.ID, appType) +} + +func DeleteOneApplicationType(id string) error { + return db.GetCachedSimpleDao().DeleteOne(TABLE_APPLICATION_TYPES, id) +} + +func GetApplicationTypeByName(name string) (bool, error) { + appTypes, err := GetAllApplicationTypeAsList() + if err != nil { + return false, err + } + + for _, appType := range appTypes { + if strings.EqualFold(appType.Name, name) { + return true, nil + } + } + return false, nil +} + +// Get all application types as list +func GetAllApplicationTypeAsList() ([]*ApplicationType, error) { + appTypeMap, err := db.GetCachedSimpleDao().GetAllAsMap(TABLE_APPLICATION_TYPES) + if err != nil { + return nil, err + } + + var appTypeList []*ApplicationType + for _, v := range appTypeMap { + appType, err := toApplicationType(v) + if err != nil { + return nil, err + } + appTypeList = append(appTypeList, appType) + } + return appTypeList, nil +} + +func toApplicationType(v interface{}) (*ApplicationType, error) { + if appType, ok := v.(*ApplicationType); ok { + return appType, nil + } + + jsonBytes, err := json.Marshal(v) + if err != nil { + return nil, err + } + + appType := &ApplicationType{} + return appType, json.Unmarshal(jsonBytes, appType) +} diff --git a/shared/applicationtype/application_type_dao_test.go b/shared/applicationtype/application_type_dao_test.go new file mode 100644 index 0000000..52f51b7 --- /dev/null +++ b/shared/applicationtype/application_type_dao_test.go @@ -0,0 +1,80 @@ +package applicationtype + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSetOneApplicationType(t *testing.T) { + appType := &ApplicationType{ + ID: "testAppTypeID", + Name: "testAppType", + } + err := SetOneApplicationType(appType) + if err != nil && strings.Contains(err.Error(), "Table configuration not found") { + t.Skip("Skipping test: database not configured") + return + } + assert.NoError(t, err) +} + +func TestToApplicationType(t *testing.T) { + appType := &ApplicationType{ + ID: "test123", + Name: "testApp", + } + result, err := toApplicationType(appType) + assert.NoError(t, err) + assert.Equal(t, "test123", result.ID) + assert.Equal(t, "testApp", result.Name) + assert.Equal(t, appType, result) + + inputMap := map[string]interface{}{ + "id": "test456", + "name": "testApp2", + } + result, err = toApplicationType(inputMap) + assert.NoError(t, err) + assert.Equal(t, "test456", result.ID) + assert.Equal(t, "testApp2", result.Name) + + invalidInput := make(chan int) + result, err = toApplicationType(invalidInput) + assert.Error(t, err) + assert.Nil(t, result) +} + +func TestGetOneApplicationType(t *testing.T) { + result, err := GetOneApplicationType("7a3rf34ff1d9fa9qa") + if err != nil && (strings.Contains(err.Error(), "Table configuration not found") || + strings.Contains(err.Error(), "cache not found or configured")) { + t.Skip("Skipping test: database not configured") + return + } + assert.NoError(t, err) + assert.Nil(t, result) +} + +func TestGetApplicationTypeByName(t *testing.T) { + exists, err := GetApplicationTypeByName("test") + if err != nil && (strings.Contains(err.Error(), "Table configuration not found") || + strings.Contains(err.Error(), "cache not found or configured")) { + t.Skip("Skipping test: database not configured") + return + } + assert.NoError(t, err) + assert.False(t, exists) +} + +func TestGetAllApplicationTypeAsList(t *testing.T) { + result, err := GetAllApplicationTypeAsList() + if err != nil && (strings.Contains(err.Error(), "Table configuration not found") || + strings.Contains(err.Error(), "cache not found or configured")) { + t.Skip("Skipping test: database not configured") + return + } + assert.NoError(t, err) + assert.IsType(t, []*ApplicationType{}, result) +} diff --git a/shared/applicationtype/application_type_test.go b/shared/applicationtype/application_type_test.go new file mode 100644 index 0000000..89352f8 --- /dev/null +++ b/shared/applicationtype/application_type_test.go @@ -0,0 +1,12 @@ +package applicationtype + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_IsDefaultAppType(t *testing.T) { + assert.True(t, IsDefaultAppType("stb")) + assert.False(t, IsDefaultAppType("customApp")) +} From 9754f24e5da8969850cc364e976f5ebaddf238e3 Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Tue, 6 Jan 2026 14:15:12 +0530 Subject: [PATCH 03/10] Dynamic Applicationtype code changes --- README.md | 2 +- adminapi/adminapi_common.go | 21 +++++++++++++++---- .../application_type_service.go | 2 +- adminapi/router.go | 10 +++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 18b47a2..f9ad0cf 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ bin/xconfadmin-linux-amd64 -f config/xconfadmin.conf Test the server is running: ```bash -curl http://localhost:9001/api/v1/version +curl http://localhost:9001/api/version ``` Expected response: diff --git a/adminapi/adminapi_common.go b/adminapi/adminapi_common.go index 60fe419..95786dd 100644 --- a/adminapi/adminapi_common.go +++ b/adminapi/adminapi_common.go @@ -26,6 +26,7 @@ import ( queries "github.com/rdkcentral/xconfadmin/adminapi/queries" common "github.com/rdkcentral/xconfadmin/common" xhttp "github.com/rdkcentral/xconfadmin/http" + xapptype "github.com/rdkcentral/xconfadmin/shared/applicationtype" log "github.com/sirupsen/logrus" ) @@ -52,11 +53,9 @@ func WebServerInjection(ws *xhttp.WebconfigServer, xc *dataapi.XconfConfigs) { common.WakeupPoolTagName = "t_canary_wakeup" } else { common.AuthProvider = ws.XW_XconfServer.ServerConfig.GetString("xconfwebconfig.xconf.authprovider") - applicationTypeString := ws.XW_XconfServer.ServerConfig.GetString("xconfwebconfig.xconf.application_types") - if applicationTypeString == "" { - applicationTypeString = "stb" + if len(common.ApplicationTypes) == 0 { + common.ApplicationTypes = []string{"stb"} } - common.ApplicationTypes = strings.Split(applicationTypeString, ",") common.CacheUpdateWindowSize = ws.XW_XconfServer.ServerConfig.GetInt64("xconfwebconfig.xconf.cache_update_window_size") common.SatOn = ws.XW_XconfServer.ServerConfig.GetBoolean("xconfwebconfig.sat.SAT_ON") common.AllowedNumberOfFeatures = int(ws.XW_XconfServer.ServerConfig.GetInt32("xconfwebconfig.xconf.allowedNumberOfFeatures", 100)) @@ -115,8 +114,22 @@ func WebServerInjection(ws *xhttp.WebconfigServer, xc *dataapi.XconfConfigs) { func initDB() { queries.CreateFirmwareRuleTemplates() // Initialize FirmwareRule templates initAppSettings() // Initialize Application settings + loadApplicationTypes() // Load Application Types from DB } +func loadApplicationTypes() { + appTypes, err := xapptype.GetAllApplicationTypeAsList() + if err != nil { + log.Errorf("Error loading application types from DB: %v", err) + return + } + var at []string + for _, appName := range appTypes { + at = append(at, appName.Name) + } + common.ApplicationTypes = at + log.Info("Loaded application types from DB") +} func initAppSettings() { settings, err := common.GetAppSettings() if err != nil { diff --git a/adminapi/applicationtype/application_type_service.go b/adminapi/applicationtype/application_type_service.go index f8e4379..f461174 100644 --- a/adminapi/applicationtype/application_type_service.go +++ b/adminapi/applicationtype/application_type_service.go @@ -51,7 +51,7 @@ func ValidateApplicationType(appType *xapptype.ApplicationType) error { matched, _ := regexp.MatchString(applicationRegexPattern, appType.Name) if !matched { - return xwcommon.NewRemoteErrorAS(http.StatusBadRequest, "Application type name must be 3-10 alphabetic characters") + return xwcommon.NewRemoteErrorAS(http.StatusBadRequest, "Application type name must be 3-12 alphabetic characters") } return nil } diff --git a/adminapi/router.go b/adminapi/router.go index ae3152c..26f2831 100644 --- a/adminapi/router.go +++ b/adminapi/router.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/gorilla/mux" + "github.com/rdkcentral/xconfadmin/adminapi/applicationtype" "github.com/rdkcentral/xconfadmin/adminapi/auth" "github.com/rdkcentral/xconfadmin/adminapi/canary" "github.com/rdkcentral/xconfadmin/adminapi/change" @@ -112,6 +113,15 @@ func RouteXconfAdminserviceApis(s *xhttp.WebconfigServer, r *mux.Router) { urlPath.HandleFunc("", auth.LoginUrlHandler).Methods("GET").Name("Auth-Xerxes") authPaths = append(authPaths, urlPath) + //Application Type APIs + applicationTypePath := r.PathPrefix("/xconfAdminService/applicationtype").Subrouter() + applicationTypePath.HandleFunc("", applicationtype.CreateApplicationTypeHandler).Methods("POST").Name("Application-Type") + applicationTypePath.HandleFunc("/all", applicationtype.GetAllApplicationTypeHandler).Methods("GET").Name("Application-Type") + applicationTypePath.HandleFunc("/{id}", applicationtype.GetApplicationTypeHandler).Methods("GET").Name("Application-Type") + applicationTypePath.HandleFunc("/{id}", applicationtype.DeleteApplicationTypeHandler).Methods("DELETE").Name("Application-Type") + applicationTypePath.HandleFunc("/{id}", applicationtype.UpdateApplicationTypeHandler).Methods("PUT").Name("Application-Type") + paths = append(paths, applicationTypePath) + // DataService bypass APIs dsBypassPathPrefix := r.PathPrefix("/xconfAdminService/dataService").Subrouter() dsBypassPathPrefix.HandleFunc("/xconf/swu/{applicationType}", dataapi.GetEstbFirmwareSwuHandler).Methods("GET").Name("DataServiceByPass") From c00e73917a6b950d78e703b5e3ab34bbe32c5aa7 Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Tue, 6 Jan 2026 14:24:35 +0530 Subject: [PATCH 04/10] Update Go module and dependencies to latest versions --- go.mod | 2 +- go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f9d42d5..a81bac5 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/mitchellh/copystructure v1.2.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 - github.com/rdkcentral/xconfwebconfig v0.0.0-20251110232019-da9146c7aedc + github.com/rdkcentral/xconfwebconfig v0.0.0-20260105061036-e75e3af8c1a3 github.com/sirupsen/logrus v1.9.3 github.com/xeipuuv/gojsonschema v1.2.0 go.uber.org/automaxprocs v1.5.3 diff --git a/go.sum b/go.sum index 7d76c91..62f540f 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rdkcentral/xconfwebconfig v0.0.0-20251110232019-da9146c7aedc h1:jBmY1q/0pZIKfr5MivlW4g/JT4ZUXGzQKBnih9sJTps= -github.com/rdkcentral/xconfwebconfig v0.0.0-20251110232019-da9146c7aedc/go.mod h1:e6kwCd+4ru5tDy190JGGcNtc6LyOSdmVaHDRbOcX+5Y= +github.com/rdkcentral/xconfwebconfig v0.0.0-20260105061036-e75e3af8c1a3 h1:dzXvBOAUEtstyYxPNYZHgfnlaX4TU9KCQ9h9maBj1jA= +github.com/rdkcentral/xconfwebconfig v0.0.0-20260105061036-e75e3af8c1a3/go.mod h1:GU7c3D0c5KEEj/F+1/5O3GUdVIbK5JSlYpFrMKMOZDQ= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= @@ -107,6 +107,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= From b5600f8473fe30d76b85997adb6f2926c1014677 Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Tue, 6 Jan 2026 14:37:44 +0530 Subject: [PATCH 05/10] removed comment line --- shared/applicationtype/application_type_dao.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/applicationtype/application_type_dao.go b/shared/applicationtype/application_type_dao.go index c6da50e..d8500d5 100644 --- a/shared/applicationtype/application_type_dao.go +++ b/shared/applicationtype/application_type_dao.go @@ -15,7 +15,7 @@ var defaultTypes = []string{"stb", "xhome", "rdkcloud"} // Get one application type func GetOneApplicationType(id string) (*ApplicationType, error) { - result, err := db.GetCachedSimpleDao().GetOne(TABLE_APPLICATION_TYPES, id) //better to take it from cache(DS changes) + result, err := db.GetCachedSimpleDao().GetOne(TABLE_APPLICATION_TYPES, id) if err != nil { return nil, err } From 2935ff901295c7b8b5620a1dd7201b7af7bf2d7b Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Tue, 6 Jan 2026 14:59:25 +0530 Subject: [PATCH 06/10] updated default apptypes --- shared/applicationtype/application_type.go | 2 ++ shared/applicationtype/application_type_dao.go | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/applicationtype/application_type.go b/shared/applicationtype/application_type.go index 7ed67d7..e900f58 100644 --- a/shared/applicationtype/application_type.go +++ b/shared/applicationtype/application_type.go @@ -11,6 +11,8 @@ type ApplicationType struct { UpdatedAt int64 `json:"updatedAt,omitempty"` } +var defaultTypes = []string{"stb", "xhome", "sky"} + func IsDefaultAppType(name string) bool { for _, dt := range defaultTypes { if strings.Contains(name, dt) { diff --git a/shared/applicationtype/application_type_dao.go b/shared/applicationtype/application_type_dao.go index d8500d5..7452055 100644 --- a/shared/applicationtype/application_type_dao.go +++ b/shared/applicationtype/application_type_dao.go @@ -11,8 +11,6 @@ const ( TABLE_APPLICATION_TYPES = "ApplicationTypes" ) -var defaultTypes = []string{"stb", "xhome", "rdkcloud"} - // Get one application type func GetOneApplicationType(id string) (*ApplicationType, error) { result, err := db.GetCachedSimpleDao().GetOne(TABLE_APPLICATION_TYPES, id) From 93e8614d46e58ecd61ddfc2624429f0c80df613b Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Fri, 9 Jan 2026 12:35:28 +0530 Subject: [PATCH 07/10] Enhance application type creation validation and update default type check --- adminapi/applicationtype/application_type_handler.go | 5 +++++ adminapi/applicationtype/application_type_handler_test.go | 5 +++++ shared/applicationtype/application_type.go | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/adminapi/applicationtype/application_type_handler.go b/adminapi/applicationtype/application_type_handler.go index 0522219..8206b60 100644 --- a/adminapi/applicationtype/application_type_handler.go +++ b/adminapi/applicationtype/application_type_handler.go @@ -31,6 +31,11 @@ func CreateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, err.Error()) return } + isDefault := xapptype.IsDefaultAppType(appType.Name) + if isDefault { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Cannot create default application type") + return + } exists, _ := xapptype.GetApplicationTypeByName(appType.Name) if exists { xhttp.WriteAdminErrorResponse(w, http.StatusConflict, "Application type already exists") diff --git a/adminapi/applicationtype/application_type_handler_test.go b/adminapi/applicationtype/application_type_handler_test.go index 729dfc1..8e223c4 100644 --- a/adminapi/applicationtype/application_type_handler_test.go +++ b/adminapi/applicationtype/application_type_handler_test.go @@ -32,6 +32,11 @@ func TestCreateApplicationTypeHandler(t *testing.T) { w.SetBody(validJson) CreateApplicationTypeHandler(w, req) assert.Equal(t, http.StatusBadRequest, rec.Code) + + validJson = `{"name": "stb"}` + w.SetBody(validJson) + CreateApplicationTypeHandler(w, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) } func TestGetAllApplicationTypeHandler(t *testing.T) { diff --git a/shared/applicationtype/application_type.go b/shared/applicationtype/application_type.go index e900f58..3edcf8c 100644 --- a/shared/applicationtype/application_type.go +++ b/shared/applicationtype/application_type.go @@ -15,7 +15,7 @@ var defaultTypes = []string{"stb", "xhome", "sky"} func IsDefaultAppType(name string) bool { for _, dt := range defaultTypes { - if strings.Contains(name, dt) { + if strings.EqualFold(name, dt) { return true } } From be303ada77b8e5ab4121917e599a53c295262186 Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Mon, 19 Jan 2026 11:52:11 +0530 Subject: [PATCH 08/10] Update application type API path to use hyphenated format --- adminapi/router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adminapi/router.go b/adminapi/router.go index 26f2831..ae813f6 100644 --- a/adminapi/router.go +++ b/adminapi/router.go @@ -114,7 +114,7 @@ func RouteXconfAdminserviceApis(s *xhttp.WebconfigServer, r *mux.Router) { authPaths = append(authPaths, urlPath) //Application Type APIs - applicationTypePath := r.PathPrefix("/xconfAdminService/applicationtype").Subrouter() + applicationTypePath := r.PathPrefix("/xconfAdminService/application-types").Subrouter() applicationTypePath.HandleFunc("", applicationtype.CreateApplicationTypeHandler).Methods("POST").Name("Application-Type") applicationTypePath.HandleFunc("/all", applicationtype.GetAllApplicationTypeHandler).Methods("GET").Name("Application-Type") applicationTypePath.HandleFunc("/{id}", applicationtype.GetApplicationTypeHandler).Methods("GET").Name("Application-Type") From f990acd01f73eb4d84cfb0dc6b12129444c1574c Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Mon, 19 Jan 2026 17:15:18 +0530 Subject: [PATCH 09/10] Copilot changes resolved --- adminapi/adminapi_common.go | 8 +++---- .../application_type_handler.go | 24 ++++++++++++++++--- .../application_type_handler_test.go | 10 ++++---- .../application_type_service_test.go | 15 ++++++------ adminapi/router.go | 2 +- .../applicationtype/application_type_dao.go | 9 ++++--- .../application_type_dao_test.go | 7 +++--- 7 files changed, 48 insertions(+), 27 deletions(-) diff --git a/adminapi/adminapi_common.go b/adminapi/adminapi_common.go index 95786dd..4bb91c7 100644 --- a/adminapi/adminapi_common.go +++ b/adminapi/adminapi_common.go @@ -123,11 +123,11 @@ func loadApplicationTypes() { log.Errorf("Error loading application types from DB: %v", err) return } - var at []string - for _, appName := range appTypes { - at = append(at, appName.Name) + var appTypeNames []string + for _, appType := range appTypes { + appTypeNames = append(appTypeNames, appType.Name) } - common.ApplicationTypes = at + common.ApplicationTypes = appTypeNames log.Info("Loaded application types from DB") } func initAppSettings() { diff --git a/adminapi/applicationtype/application_type_handler.go b/adminapi/applicationtype/application_type_handler.go index 8206b60..ed409c5 100644 --- a/adminapi/applicationtype/application_type_handler.go +++ b/adminapi/applicationtype/application_type_handler.go @@ -36,7 +36,7 @@ func CreateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Cannot create default application type") return } - exists, _ := xapptype.GetApplicationTypeByName(appType.Name) + exists, _ := xapptype.ApplicationTypeNameExists(appType.Name) if exists { xhttp.WriteAdminErrorResponse(w, http.StatusConflict, "Application type already exists") return @@ -109,6 +109,10 @@ func DeleteApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) return } + if appType == nil { + xhttp.WriteAdminErrorResponse(w, http.StatusNotFound, "Application type not found") + return + } if xapptype.IsDefaultAppType(appType.Name) { xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Default application types cannot be deleted") return @@ -121,7 +125,11 @@ func DeleteApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { response := map[string]string{ "message": fmt.Sprintf("Application type '%s' deleted successfully", appType.Name), } - data, _ := json.Marshal(response) + data, err := json.Marshal(response) + if err != nil { + xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } xhttp.WriteXconfResponse(w, http.StatusOK, data) } @@ -155,13 +163,23 @@ func UpdateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - + if existingAppType.Name != updateRequest.Name { + nameExists, _ := xapptype.ApplicationTypeNameExists(updateRequest.Name) + if nameExists { + xhttp.WriteAdminErrorResponse(w, http.StatusConflict, + fmt.Sprintf("Application type with name '%s' already exists", updateRequest.Name)) + return + } + } if xapptype.IsDefaultAppType(existingAppType.Name) { xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Default application types cannot be updated") return } existingAppType.ID = id existingAppType.Name = updateRequest.Name + if updateRequest.Description != "" { + existingAppType.Description = updateRequest.Description + } existingAppType.UpdatedAt = time.Now().Unix() err = xapptype.SetOneApplicationType(existingAppType) diff --git a/adminapi/applicationtype/application_type_handler_test.go b/adminapi/applicationtype/application_type_handler_test.go index 8e223c4..66b2eac 100644 --- a/adminapi/applicationtype/application_type_handler_test.go +++ b/adminapi/applicationtype/application_type_handler_test.go @@ -11,7 +11,7 @@ import ( ) func TestCreateApplicationTypeHandler(t *testing.T) { - req := httptest.NewRequest(http.MethodPost, "/api/applicationtype", nil) + req := httptest.NewRequest(http.MethodPost, "/api/application-types", nil) rec := httptest.NewRecorder() CreateApplicationTypeHandler(rec, req) @@ -40,14 +40,14 @@ func TestCreateApplicationTypeHandler(t *testing.T) { } func TestGetAllApplicationTypeHandler(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/api/applicationtype", nil) + req := httptest.NewRequest(http.MethodGet, "/api/application-types", nil) rec := httptest.NewRecorder() GetAllApplicationTypeHandler(rec, req) assert.True(t, rec.Code == http.StatusOK || rec.Code == http.StatusInternalServerError) } func TestGetApplicationTypeHandler(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/api/applicationtype/{id}", nil) + req := httptest.NewRequest(http.MethodGet, "/api/application-types/{id}", nil) req = mux.SetURLVars(req, map[string]string{"id": "nonexistentID"}) rec := httptest.NewRecorder() GetApplicationTypeHandler(rec, req) @@ -55,7 +55,7 @@ func TestGetApplicationTypeHandler(t *testing.T) { } func TestUpdateApplicationTypeHandler(t *testing.T) { - req := httptest.NewRequest(http.MethodPut, "/api/applicationtype/123", nil) + req := httptest.NewRequest(http.MethodPut, "/api/application-types/123", nil) req = mux.SetURLVars(req, map[string]string{"id": "123"}) rec := httptest.NewRecorder() @@ -86,7 +86,7 @@ func TestUpdateApplicationTypeHandler(t *testing.T) { } func TestDeleteApplicationTypeHandler(t *testing.T) { - req := httptest.NewRequest(http.MethodDelete, "/api/applicationtype/{id}", nil) + req := httptest.NewRequest(http.MethodDelete, "/api/application-types/{id}", nil) req = mux.SetURLVars(req, map[string]string{"id": "nonexistentID"}) rec := httptest.NewRecorder() DeleteApplicationTypeHandler(rec, req) diff --git a/adminapi/applicationtype/application_type_service_test.go b/adminapi/applicationtype/application_type_service_test.go index 964df84..e653318 100644 --- a/adminapi/applicationtype/application_type_service_test.go +++ b/adminapi/applicationtype/application_type_service_test.go @@ -14,17 +14,16 @@ func TestCreateApplicationType(t *testing.T) { appType := &xapptype.ApplicationType{ Name: "testApp", } - req := httptest.NewRequest(http.MethodPost, "/api/applicationtype", nil) + req := httptest.NewRequest(http.MethodPost, "/api/application-types", nil) req.Header.Set("X-User-Name", "testuser") createdAppType, err := CreateApplicationType(req, appType) - if err != nil { - if strings.Contains(err.Error(), "Table configuration not found") { - t.Skip("Skipping test: database not configured") - return - } + + if err == nil || (err != nil && !strings.Contains(err.Error(), "cache not found") && !strings.Contains(err.Error(), "Table configuration not found")) { + assert.NotNil(t, createdAppType) + assert.NoError(t, err) + } else { + t.Skip("Skipping: database not configured") } - assert.NotNil(t, createdAppType) - assert.NoError(t, err) } func TestValidateApplicationType(t *testing.T) { diff --git a/adminapi/router.go b/adminapi/router.go index ea93266..573bb35 100644 --- a/adminapi/router.go +++ b/adminapi/router.go @@ -117,7 +117,7 @@ func RouteXconfAdminserviceApis(s *xhttp.WebconfigServer, r *mux.Router) { //Application Type APIs applicationTypePath := r.PathPrefix("/xconfAdminService/application-types").Subrouter() applicationTypePath.HandleFunc("", applicationtype.CreateApplicationTypeHandler).Methods("POST").Name("Application-Type") - applicationTypePath.HandleFunc("/all", applicationtype.GetAllApplicationTypeHandler).Methods("GET").Name("Application-Type") + applicationTypePath.HandleFunc("", applicationtype.GetAllApplicationTypeHandler).Methods("GET").Name("Application-Type") applicationTypePath.HandleFunc("/{id}", applicationtype.GetApplicationTypeHandler).Methods("GET").Name("Application-Type") applicationTypePath.HandleFunc("/{id}", applicationtype.DeleteApplicationTypeHandler).Methods("DELETE").Name("Application-Type") applicationTypePath.HandleFunc("/{id}", applicationtype.UpdateApplicationTypeHandler).Methods("PUT").Name("Application-Type") diff --git a/shared/applicationtype/application_type_dao.go b/shared/applicationtype/application_type_dao.go index 7452055..9e052fb 100644 --- a/shared/applicationtype/application_type_dao.go +++ b/shared/applicationtype/application_type_dao.go @@ -2,6 +2,7 @@ package applicationtype import ( "encoding/json" + "fmt" "strings" db "github.com/rdkcentral/xconfwebconfig/db" @@ -18,7 +19,7 @@ func GetOneApplicationType(id string) (*ApplicationType, error) { return nil, err } if result == nil { - return nil, nil + return nil, fmt.Errorf("application type with id %s not found", id) } appType, err := toApplicationType(result) if err != nil { @@ -28,7 +29,9 @@ func GetOneApplicationType(id string) (*ApplicationType, error) { } func SetOneApplicationType(appType *ApplicationType) error { - DeleteOneApplicationType(appType.ID) + if err := DeleteOneApplicationType(appType.ID); err != nil { + return err + } return db.GetCachedSimpleDao().SetOne(TABLE_APPLICATION_TYPES, appType.ID, appType) } @@ -36,7 +39,7 @@ func DeleteOneApplicationType(id string) error { return db.GetCachedSimpleDao().DeleteOne(TABLE_APPLICATION_TYPES, id) } -func GetApplicationTypeByName(name string) (bool, error) { +func ApplicationTypeNameExists(name string) (bool, error) { appTypes, err := GetAllApplicationTypeAsList() if err != nil { return false, err diff --git a/shared/applicationtype/application_type_dao_test.go b/shared/applicationtype/application_type_dao_test.go index 52f51b7..76d8e4d 100644 --- a/shared/applicationtype/application_type_dao_test.go +++ b/shared/applicationtype/application_type_dao_test.go @@ -13,7 +13,8 @@ func TestSetOneApplicationType(t *testing.T) { Name: "testAppType", } err := SetOneApplicationType(appType) - if err != nil && strings.Contains(err.Error(), "Table configuration not found") { + if err != nil && (strings.Contains(err.Error(), "Table configuration not found") || + strings.Contains(err.Error(), "cache not found or configured")) { t.Skip("Skipping test: database not configured") return } @@ -57,8 +58,8 @@ func TestGetOneApplicationType(t *testing.T) { assert.Nil(t, result) } -func TestGetApplicationTypeByName(t *testing.T) { - exists, err := GetApplicationTypeByName("test") +func TestApplicationTypeNameExists(t *testing.T) { + exists, err := ApplicationTypeNameExists("test") if err != nil && (strings.Contains(err.Error(), "Table configuration not found") || strings.Contains(err.Error(), "cache not found or configured")) { t.Skip("Skipping test: database not configured") From 7d139fd8d5452ce3bd0911ba2be783295d5c266a Mon Sep 17 00:00:00 2001 From: yeswanth2420 Date: Tue, 20 Jan 2026 13:08:38 +0530 Subject: [PATCH 10/10] Add validation for application type ID in handlers and corresponding tests --- .../applicationtype/application_type_handler.go | 12 ++++++++++++ .../application_type_handler_test.go | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/adminapi/applicationtype/application_type_handler.go b/adminapi/applicationtype/application_type_handler.go index ed409c5..a4c0fe7 100644 --- a/adminapi/applicationtype/application_type_handler.go +++ b/adminapi/applicationtype/application_type_handler.go @@ -80,6 +80,10 @@ func GetApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { return } id := mux.Vars(r)["id"] + if id == "" { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Application type ID is required") + return + } appType, err := xapptype.GetOneApplicationType(id) if err != nil { xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) @@ -104,6 +108,10 @@ func DeleteApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { return } id := mux.Vars(r)["id"] + if id == "" { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Application type ID is required") + return + } appType, err := xapptype.GetOneApplicationType(id) if err != nil { xhttp.WriteAdminErrorResponse(w, http.StatusInternalServerError, err.Error()) @@ -140,6 +148,10 @@ func UpdateApplicationTypeHandler(w http.ResponseWriter, r *http.Request) { return } id := mux.Vars(r)["id"] + if id == "" { + xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "Application type ID is required") + return + } xw, ok := w.(*xwhttp.XResponseWriter) if !ok { xhttp.WriteAdminErrorResponse(w, http.StatusBadRequest, "responsewriter cast error") diff --git a/adminapi/applicationtype/application_type_handler_test.go b/adminapi/applicationtype/application_type_handler_test.go index 66b2eac..f025abd 100644 --- a/adminapi/applicationtype/application_type_handler_test.go +++ b/adminapi/applicationtype/application_type_handler_test.go @@ -52,6 +52,11 @@ func TestGetApplicationTypeHandler(t *testing.T) { rec := httptest.NewRecorder() GetApplicationTypeHandler(rec, req) assert.Equal(t, http.StatusInternalServerError, rec.Code) + + req = mux.SetURLVars(req, map[string]string{"id": ""}) + rec = httptest.NewRecorder() + GetApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) } func TestUpdateApplicationTypeHandler(t *testing.T) { @@ -83,6 +88,11 @@ func TestUpdateApplicationTypeHandler(t *testing.T) { w.SetBody(validJson) UpdateApplicationTypeHandler(w, req) assert.True(t, rec.Code == http.StatusOK || rec.Code == http.StatusBadRequest || rec.Code == http.StatusInternalServerError) + + req = mux.SetURLVars(req, map[string]string{"id": ""}) + rec = httptest.NewRecorder() + UpdateApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) } func TestDeleteApplicationTypeHandler(t *testing.T) { @@ -91,4 +101,9 @@ func TestDeleteApplicationTypeHandler(t *testing.T) { rec := httptest.NewRecorder() DeleteApplicationTypeHandler(rec, req) assert.Equal(t, http.StatusInternalServerError, rec.Code) + + req = mux.SetURLVars(req, map[string]string{"id": ""}) + rec = httptest.NewRecorder() + DeleteApplicationTypeHandler(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code) }