From e95a79e643b8d4f73846d27b5a6c107c8a16fadc Mon Sep 17 00:00:00 2001 From: Kavya Shukla Date: Mon, 26 Jun 2023 22:07:29 +0530 Subject: [PATCH 1/2] feat: updated the project structure and added test case updated project structure to avoid import cycle added a different package for database where: there is function related to migration of database and populating database added basic test cases: added API test cases for create, update, get license by shortname and search in licenses added user test cases for create and get user by id updated meta to pagination meta for better discription Signed-off-by: Kavya Shukla --- cmd/laas/main.go | 50 ++-------- go.mod | 3 + pkg/api/api.go | 55 ++++++++--- pkg/api/api_test.go | 221 ++++++++++++++++++++++++++++++++++++++++++++ pkg/auth/auth.go | 32 +++---- pkg/db/db.go | 47 ++++++++++ pkg/models/types.go | 16 ++-- pkg/utils/util.go | 2 +- 8 files changed, 338 insertions(+), 88 deletions(-) create mode 100644 pkg/api/api_test.go create mode 100644 pkg/db/db.go diff --git a/cmd/laas/main.go b/cmd/laas/main.go index a127849..c17ff99 100644 --- a/cmd/laas/main.go +++ b/cmd/laas/main.go @@ -4,19 +4,12 @@ package main import ( - "encoding/json" "flag" - "fmt" - "io/ioutil" "log" "github.com/fossology/LicenseDb/pkg/api" - "github.com/fossology/LicenseDb/pkg/auth" + "github.com/fossology/LicenseDb/pkg/db" "github.com/fossology/LicenseDb/pkg/models" - "github.com/fossology/LicenseDb/pkg/utils" - "github.com/gin-gonic/gin" - "gorm.io/driver/postgres" - "gorm.io/gorm" ) // declare flags to input the basic requirement of database connection and the path of the data file @@ -40,47 +33,18 @@ var ( func main() { flag.Parse() - dburi := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s", *dbhost, *port, *user, *dbname, *password) - gormConfig := &gorm.Config{} - database, err := gorm.Open(postgres.Open(dburi), gormConfig) - if err != nil { - log.Fatalf("Failed to connect to database: %v", err) - } + db.Connect(dbhost, port, user, dbname, password) - if err := database.AutoMigrate(&models.LicenseDB{}); err != nil { + if err := db.DB.AutoMigrate(&models.LicenseDB{}); err != nil { log.Fatalf("Failed to automigrate database: %v", err) } - if err := database.AutoMigrate(&models.User{}); err != nil { + if err := db.DB.AutoMigrate(&models.User{}); err != nil { log.Fatalf("Failed to automigrate database: %v", err) } - if *populatedb { - var licenses []models.LicenseJson - // read the file of data - byteResult, _ := ioutil.ReadFile(*datafile) - // unmarshal the json file and it into the struct format - if err := json.Unmarshal(byteResult, &licenses); err != nil { - log.Fatalf("error reading from json file: %v", err) - } - for _, license := range licenses { - // populate the data in the database table - result := utils.Converter(license) - database.Create(&result) - } - } - api.DB = database - r := gin.Default() - r.NoRoute(api.HandleInvalidUrl) - authorized := r.Group("/") - authorized.Use(auth.AuthenticationMiddleware()) - r.GET("/api/licenses/:shortname", api.GetLicense) - authorized.POST("/api/licenses", api.CreateLicense) - authorized.PATCH("/api/licenses/:shortname", api.UpdateLicense) - r.GET("/api/licenses", api.FilterLicense) - r.POST("/api/licenses/search", api.SearchInLicense) - authorized.POST("/api/users", auth.CreateUser) - authorized.GET("/api/users", auth.GetAllUser) - authorized.GET("/api/users/:id", auth.GetUser) + db.Populatedb(*populatedb, *datafile) + + r := api.Router() r.Run() } diff --git a/go.mod b/go.mod index 03f5281..6f32d2f 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/gin-gonic/gin v1.9.1 + github.com/stretchr/testify v1.8.3 gorm.io/driver/postgres v1.5.2 gorm.io/gorm v1.25.1 ) @@ -11,6 +12,7 @@ require ( require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -30,6 +32,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect diff --git a/pkg/api/api.go b/pkg/api/api.go index 69e598f..8bd71b9 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -8,12 +8,36 @@ import ( "net/http" "time" + "github.com/fossology/LicenseDb/pkg/auth" + "github.com/fossology/LicenseDb/pkg/db" "github.com/fossology/LicenseDb/pkg/models" "github.com/gin-gonic/gin" - "gorm.io/gorm" ) -var DB *gorm.DB +func Router() *gin.Engine { + // r is a default instance of gin engine + r := gin.Default() + + // return error for invalid routes + r.NoRoute(HandleInvalidUrl) + + // authorization not required for these routes + r.GET("/api/licenses/:shortname", GetLicense) + r.POST("/api/search", SearchInLicense) + r.GET("/api/licenses", FilterLicense) + + // set up authentication + authorized := r.Group("/") + authorized.Use(auth.AuthenticationMiddleware()) + + authorized.POST("/api/licenses", CreateLicense) + authorized.PATCH("/api/licenses/:shortname", UpdateLicense) + authorized.POST("/api/users", auth.CreateUser) + authorized.GET("/api/users", auth.GetAllUser) + authorized.GET("/api/users/:id", auth.GetUser) + + return r +} func HandleInvalidUrl(c *gin.Context) { @@ -27,9 +51,10 @@ func HandleInvalidUrl(c *gin.Context) { c.JSON(http.StatusNotFound, er) } func GetAllLicense(c *gin.Context) { + var licenses []models.LicenseDB - err := DB.Find(&licenses).Error + err := db.DB.Find(&licenses).Error if err != nil { er := models.LicenseError{ Status: http.StatusBadRequest, @@ -44,7 +69,7 @@ func GetAllLicense(c *gin.Context) { res := models.LicenseResponse{ Data: licenses, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: len(licenses), }, } @@ -60,7 +85,7 @@ func GetLicense(c *gin.Context) { return } - err := DB.Where("shortname = ?", queryParam).First(&license).Error + err := db.DB.Where("shortname = ?", queryParam).First(&license).Error if err != nil { er := models.LicenseError{ @@ -77,7 +102,7 @@ func GetLicense(c *gin.Context) { res := models.LicenseResponse{ Data: []models.LicenseDB{license}, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: 1, }, } @@ -105,7 +130,7 @@ func CreateLicense(c *gin.Context) { } license := models.LicenseDB(input) - result := DB.FirstOrCreate(&license) + result := db.DB.FirstOrCreate(&license) if result.RowsAffected == 0 { er := models.LicenseError{ @@ -132,7 +157,7 @@ func CreateLicense(c *gin.Context) { res := models.LicenseResponse{ Data: []models.LicenseDB{license}, Status: http.StatusCreated, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: 1, }, } @@ -144,7 +169,7 @@ func UpdateLicense(c *gin.Context) { var update models.LicenseDB var license models.LicenseDB shortname := c.Param("shortname") - if err := DB.Where("shortname = ?", shortname).First(&license).Error; err != nil { + if err := db.DB.Where("shortname = ?", shortname).First(&license).Error; err != nil { er := models.LicenseError{ Status: http.StatusBadRequest, Message: fmt.Sprintf("license with shortname '%s' not found", shortname), @@ -166,7 +191,7 @@ func UpdateLicense(c *gin.Context) { c.JSON(http.StatusBadRequest, er) return } - if err := DB.Model(&license).Updates(update).Error; err != nil { + if err := db.DB.Model(&license).Updates(update).Error; err != nil { er := models.LicenseError{ Status: http.StatusInternalServerError, Message: "Failed to update license", @@ -180,7 +205,7 @@ func UpdateLicense(c *gin.Context) { res := models.LicenseResponse{ Data: []models.LicenseDB{license}, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: 1, }, } @@ -200,7 +225,7 @@ func FilterLicense(c *gin.Context) { fsffree := c.Query("fsffree") copyleft := c.Query("copyleft") var license []models.LicenseDB - query := DB.Model(&license) + query := db.DB.Model(&license) if SpdxId == "" && GPLv2compatible == "" && GPLv3compatible == "" && DetectorType == "" && marydone == "" && active == "" && fsffree == "" && OSIapproved == "" && copyleft == "" { GetAllLicense(c) @@ -258,7 +283,7 @@ func FilterLicense(c *gin.Context) { res := models.LicenseResponse{ Data: license, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: len(license), }, } @@ -282,7 +307,7 @@ func SearchInLicense(c *gin.Context) { } var license []models.LicenseDB - query := DB.Model(&license) + query := db.DB.Model(&license) if input.SearchType == "fuzzy" { query = query.Where(fmt.Sprintf("%s ILIKE ?", input.Field), fmt.Sprintf("%%%s%%", input.SearchTerm)) @@ -305,7 +330,7 @@ func SearchInLicense(c *gin.Context) { res := models.LicenseResponse{ Data: license, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: len(license), }, } diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go new file mode 100644 index 0000000..746039d --- /dev/null +++ b/pkg/api/api_test.go @@ -0,0 +1,221 @@ +// SPDX-FileCopyrightText: 2023 Kavya Shukla +// SPDX-License-Identifier: GPL-2.0-only + +package api + +import ( + "bytes" + "encoding/base64" + "encoding/json" + + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/fossology/LicenseDb/pkg/db" + "github.com/fossology/LicenseDb/pkg/models" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" +) + +func TestMain(m *testing.M) { + gin.SetMode(gin.TestMode) + dbname := "fossology" + user := "fossy" + password := "fossy" + port := "5432" + dbhost := "localhost" + db.Connect(&dbhost, &port, &user, &dbname, &password) + + exitcode := m.Run() + os.Exit(exitcode) +} + +func makeRequest(method, path string, body interface{}, isAuthanticated bool) *httptest.ResponseRecorder { + reqBody, _ := json.Marshal(body) + req := httptest.NewRequest(method, path, bytes.NewBuffer(reqBody)) + req.Header.Set("Content-Type", "application/json") + if isAuthanticated { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("fossy:fossy"))) + } + w := httptest.NewRecorder() + Router().ServeHTTP(w, req) + return w +} +func TestGetLicense(t *testing.T) { + expectLicense := models.LicenseDB{ + Shortname: "MIT", + Fullname: "MIT License", + Text: "MIT License\n\nCopyright (c) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + Url: "https://opensource.org/licenses/MIT", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + Flag: "1", + Marydone: "t", + SpdxId: "MIT", + } + w := makeRequest("GET", "/api/licenses/MIT", nil, false) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.LicenseResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, expectLicense, res.Data[0]) + +} + +func TestCreateLicense(t *testing.T) { + License := models.LicenseDB{ + Shortname: "ABCD", + Fullname: "ABCD License", + Text: "just a license", + Url: "https://abcdlicense/ABCD", + SpdxId: "1", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + } + w := makeRequest("POST", "/api/licenses", License, true) + assert.Equal(t, http.StatusCreated, w.Code) + type response struct { + Data models.LicenseDB `json:"data"` + } + + var res models.LicenseResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, License, res.Data[0]) + +} + +func TestUpdateLicense(t *testing.T) { + License := models.LicenseDB{ + Marydone: "t", + } + expectedLicense := models.LicenseDB{ + Shortname: "MIT", + Fullname: "MIT License", + Text: "MIT License\n\nCopyright (c) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + Url: "https://opensource.org/licenses/MIT", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + Flag: "1", + Marydone: "t", + SpdxId: "MIT", + } + w := makeRequest("PATCH", "/api/licenses/MIT", License, true) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.LicenseResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, expectedLicense, res.Data[0]) + +} + +func TestSearchInLicense(t *testing.T) { + expectLicense := models.LicenseDB{ + Shortname: "PostgreSQL", + Fullname: "PostgreSQL License", + Text: "PostgreSQL Database Management System\n(formerly known as Postgres, then as Postgres95)\n\nPortions Copyright (c) 1996-2010, The PostgreSQL Global Development Group\n\nPortions Copyright (c) 1994, The Regents of the University of California\n\nPermission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies.\n\nIN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nTHE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN \"AS IS\" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\n", + Url: "http://www.postgresql.org/about/licence", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + Flag: "1", + Marydone: "f", + SpdxId: "PostgreSQL", + } + search := models.SearchLicense{ + Field: "fullname", + SearchTerm: "Postgresql", + SearchType: "", + } + w := makeRequest("POST", "/api/search", search, false) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.LicenseResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, expectLicense, res.Data[0]) + +} + +func TestSearchInLicense2(t *testing.T) { + expectLicense := []models.LicenseDB{ + { + Shortname: "GPL-2.0-with-autoconf-exception", + Fullname: "GNU General Public License v2.0 w/Autoconf exception", + Text: "insert GPL v2 license text here\n\nAutoconf Exception\n\nAs a special exception, the Free Software Foundation gives unlimited permission to copy, distribute and modify the configure scripts that are the output of Autoconf. You need not follow the terms of the GNU General Public License when using or distributing such scripts, even though portions of the text of Autoconf appear in them. The GNU General Public License (GPL) does govern all other use of the material that constitutes the Autoconf program.\n\nCertain portions of the Autoconf source text are designed to be copied (in certain cases, depending on the input) into the output of Autoconf. We call these the \"data\" portions. The rest of the Autoconf source text consists of comments plus executable code that decides which of the data portions to output in any given case. We call these comments and executable code the \"non-data\" portions. Autoconf never copies any of the non-data portions into its output.\n\nThis special exception to the GPL applies to versions of Autoconf released by the Free Software Foundation. When you make and distribute a modified version of Autoconf, you may extend this special exception to the GPL to apply to your modified version as well, *unless* your modified version has the potential to copy into its output some of the text that was the non-data portion of the version that you started with. (In other words, unless your change moves or copies text from the non-data portions to the data portions.) If your modification has such potential, you must delete any notice of this special exception to the GPL from your modified version.\n\n", + Url: "http://ac-archive.sourceforge.net/doc/copyright.html", + Notes: "DEPRECATED: Use license expression including main license, \"WITH\" operator, and identifier: Autoconf-exception-2.0", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + Flag: "1", + Marydone: "f", + SpdxId: "LicenseRef-fossology-GPL-2.0-with-autoconf-exception", + }, + { + Shortname: "Autoconf-exception-2.0", + Fullname: "Autoconf exception 2.0", + Text: "As a special exception, the Free Software Foundation gives unlimited permission to copy, distribute and modify the configure scripts that are the output of Autoconf. You need not follow the terms of the GNU General Public License when using or distributing such scripts, even though portions of the text of Autoconf appear in them. The GNU General Public License (GPL) does govern all other use of the material that constitutes the Autoconf program.\n\nCertain portions of the Autoconf source text are designed to be copied (in certain cases, depending on the input) into the output of Autoconf. We call these the \"data\" portions. The rest of the Autoconf source text consists of comments plus executable code that decides which of the data portions to output in any given case. We call these comments and executable code the \"non-data\" portions. Autoconf never copies any of the non-data portions into its output.\n\nThis special exception to the GPL applies to versions of Autoconf released by the Free Software Foundation. When you make and distribute a modified version of Autoconf, you may extend this special exception to the GPL to apply to your modified version as well, *unless* your modified version has the potential to copy into its output some of the text that was the non-data portion of the version that you started with. (In other words, unless your change moves or copies text from the non-data portions to the data portions.) If your modification has such potential, you must delete any notice of this special exception to the GPL from your modified version.\n", + Url: "http://ac-archive.sourceforge.net/doc/copyright.html", + Notes: "Typically used with GPL-2.0", + TextUpdatable: "f", + DetectorType: "1", + Active: "t", + Flag: "1", + Marydone: "f", + SpdxId: "Autoconf-exception-2.0", + }, + } + search := models.SearchLicense{ + Field: "url", + SearchTerm: "http://ac-archive.sourceforge.net/doc/copyright.html", + SearchType: "", + } + w := makeRequest("POST", "/api/search", search, false) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.LicenseResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, expectLicense, res.Data) +} + +func TestGetUser(t *testing.T) { + expectUser := models.User{ + Userid: "1", + Username: "fossy", + Userpassword: "fossy", + Userlevel: "admin", + } + w := makeRequest("GET", "/api/user/1", nil, false) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.UserResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, expectUser, res.Data[0]) + +} + +func TestCreateUser(t *testing.T) { + user := models.User{ + Userid: "2", + Username: "general_user", + Userpassword: "abc123", + Userlevel: "participant", + } + w := makeRequest("POST", "/api/user", user, true) + assert.Equal(t, http.StatusOK, w.Code) + + var res models.UserResponse + json.Unmarshal(w.Body.Bytes(), &res) + + assert.Equal(t, user, res.Data[0]) +} diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 7891e80..79843d4 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/fossology/LicenseDb/pkg/api" + "github.com/fossology/LicenseDb/pkg/db" "github.com/fossology/LicenseDb/pkg/models" "github.com/gin-gonic/gin" ) @@ -28,7 +28,7 @@ func CreateUser(c *gin.Context) { c.JSON(http.StatusBadRequest, er) return } - result := api.DB.FirstOrCreate(&user) + result := db.DB.FirstOrCreate(&user) if result.RowsAffected == 0 { er := models.LicenseError{ Status: http.StatusBadRequest, @@ -40,21 +40,11 @@ func CreateUser(c *gin.Context) { c.JSON(http.StatusBadRequest, er) return } - if result.Error != nil { - er := models.LicenseError{ - Status: http.StatusInternalServerError, - Message: "Failed to create user", - Error: result.Error.Error(), - Path: c.Request.URL.Path, - Timestamp: time.Now().Format(time.RFC3339), - } - c.JSON(http.StatusInternalServerError, er) - return - } + res := models.UserResponse{ Data: []models.User{user}, Status: http.StatusCreated, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: 1, }, } @@ -64,7 +54,8 @@ func CreateUser(c *gin.Context) { func GetAllUser(c *gin.Context) { var users []models.User - if err := api.DB.Find(&users).Error; err != nil { + + if err := db.DB.Find(&users).Error; err != nil { er := models.LicenseError{ Status: http.StatusInternalServerError, Message: "can not create user", @@ -77,7 +68,7 @@ func GetAllUser(c *gin.Context) { res := models.UserResponse{ Data: users, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: len(users), }, } @@ -89,7 +80,7 @@ func GetUser(c *gin.Context) { var user models.User id := c.Param("id") - if err := api.DB.Where("userid = ?", id).First(&user).Error; err != nil { + if err := db.DB.Where("userid = ?", id).First(&user).Error; err != nil { er := models.LicenseError{ Status: http.StatusBadRequest, Message: "no user with such user id exists", @@ -102,7 +93,7 @@ func GetUser(c *gin.Context) { res := models.UserResponse{ Data: []models.User{user}, Status: http.StatusOK, - Meta: models.Meta{ + Meta: models.PaginationMeta{ ResourceCount: 1, }, } @@ -152,9 +143,8 @@ func AuthenticationMiddleware() gin.HandlerFunc { password := auth[1] var user models.User - - err = api.DB.Where("username = ?", username).First(&user).Error - if err != nil { + result := db.DB.Where("username = ?", username).First(&user) + if result.Error != nil { er := models.LicenseError{ Status: http.StatusUnauthorized, Message: "User name not found", diff --git a/pkg/db/db.go b/pkg/db/db.go new file mode 100644 index 0000000..4ec7f72 --- /dev/null +++ b/pkg/db/db.go @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2023 Kavya Shukla +// SPDX-License-Identifier: GPL-2.0-only + +package db + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + + "github.com/fossology/LicenseDb/pkg/models" + "github.com/fossology/LicenseDb/pkg/utils" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +var DB *gorm.DB + +func Connect(dbhost, port, user, dbname, password *string) { + + dburi := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s", *dbhost, *port, *user, *dbname, *password) + gormConfig := &gorm.Config{} + database, err := gorm.Open(postgres.Open(dburi), gormConfig) + if err != nil { + log.Fatalf("Failed to connect to database: %v", err) + } + + DB = database +} + +func Populatedb(populatedb bool, datafile string) { + if populatedb { + var licenses []models.LicenseJson + // read the file of data + byteResult, _ := ioutil.ReadFile(datafile) + // unmarshal the json file and it into the struct format + if err := json.Unmarshal(byteResult, &licenses); err != nil { + log.Fatalf("error reading from json file: %v", err) + } + for _, license := range licenses { + // populate the data in the database table + result := utils.Converter(license) + DB.Create(&result) + } + } +} diff --git a/pkg/models/types.go b/pkg/models/types.go index 1455502..bbef2a4 100644 --- a/pkg/models/types.go +++ b/pkg/models/types.go @@ -56,7 +56,7 @@ type LicenseJson struct { // license retrieval operation. // It contains information that provides context and supplementary details // about the retrieved license data. -type Meta struct { +type PaginationMeta struct { ResourceCount int `json:"resource_count"` Page int `json:"page,omitempty"` PerPage int `json:"per_page,omitempty"` @@ -67,9 +67,9 @@ type Meta struct { // retrieving license information. // It is used to encapsulate license-related data in an organized manner. type LicenseResponse struct { - Status int `json:"status"` - Data []LicenseDB `json:"data"` - Meta Meta `json:"meta"` + Status int `json:"status"` + Data []LicenseDB `json:"data"` + Meta PaginationMeta `json:"paginationmeta"` } // The LicenseError struct represents an error response related to license operations. @@ -89,7 +89,7 @@ type LicenseInput struct { Shortname string `json:"rf_shortname" binding:"required"` Fullname string `json:"rf_fullname" binding:"required"` Text string `json:"rf_text" binding:"required"` - Url string `json:"rf_url" binding:"required"` + Url string `json:"rf_url" ` AddDate string `json:"rf_add_date"` Copyleft string `json:"rf_copyleft"` FSFfree string `json:"rf_FSFfree"` @@ -118,9 +118,9 @@ type User struct { // UserResponse struct is representation of design API response of user. type UserResponse struct { - Status int `json:"status"` - Data []User `json:"data"` - Meta Meta `json:"meta"` + Status int `json:"status"` + Data []User `json:"data"` + Meta PaginationMeta `json:"paginationmeta"` } type SearchLicense struct { diff --git a/pkg/utils/util.go b/pkg/utils/util.go index 08b12bf..3f1fadc 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -15,7 +15,7 @@ func Converter(input models.LicenseJson) models.LicenseDB { Shortname: input.Shortname, Fullname: input.Fullname, Text: input.Text, - Url: input.Fullname, + Url: input.Url, Copyleft: input.Copyleft, AddDate: input.AddDate, FSFfree: input.FSFfree, From e725b8390b878e59114b77fac242e74acd39e241 Mon Sep 17 00:00:00 2001 From: Gaurav Mishra Date: Mon, 4 Dec 2023 11:15:26 +0530 Subject: [PATCH 2/2] fix(types): remove space Co-authored-by: Avinal Kumar Signed-off-by: Gaurav Mishra --- pkg/models/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/models/types.go b/pkg/models/types.go index bbef2a4..7935a1a 100644 --- a/pkg/models/types.go +++ b/pkg/models/types.go @@ -89,7 +89,7 @@ type LicenseInput struct { Shortname string `json:"rf_shortname" binding:"required"` Fullname string `json:"rf_fullname" binding:"required"` Text string `json:"rf_text" binding:"required"` - Url string `json:"rf_url" ` + Url string `json:"rf_url"` AddDate string `json:"rf_add_date"` Copyleft string `json:"rf_copyleft"` FSFfree string `json:"rf_FSFfree"`