Skip to content

Commit

Permalink
feat: added two api endpoints i.e, create and update
Browse files Browse the repository at this point in the history
    Create License:
        to create an open-source license and add it to the database
        to make a license we need some required field
    Update License:
        to update an open-source license and modify it to database
        License to be updated using shortname
  • Loading branch information
k-avy committed Jul 11, 2023
1 parent 75aed0b commit 554165e
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 19 deletions.
19 changes: 11 additions & 8 deletions cmd/laas/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/fossology/LicenseDb/pkg/api"
"github.com/fossology/LicenseDb/pkg/models"
"github.com/fossology/LicenseDb/pkg/utils"
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
Expand All @@ -23,15 +24,15 @@ var (
dbhost = flag.String("host", "localhost", "host name")
// port number of the host
port = flag.String("port", "5432", "port number")
// database user
// argument to enter the database user
user = flag.String("user", "fossy", "user name")
// name of database to be connected
dbname = flag.String("dbname", "fossology", "database name")
// password of the user
// password of the database
password = flag.String("password", "fossy", "password")
// path of data file
datafile = flag.String("datafile", "licenseRef.json", "datafile path")
// boolean agument to whether update the database or not
// auto-update the database
populatedb = flag.Bool("populatedb", false, "boolean variable to update database")
)

Expand All @@ -45,12 +46,12 @@ func main() {
log.Fatalf("Failed to connect to database: %v", err)
}

if err := database.AutoMigrate(&models.License{}); err != nil {
if err := database.AutoMigrate(&models.LicenseDB{}); err != nil {
log.Fatalf("Failed to automigrate database: %v", err)
}

if *populatedb {
var licenses []models.License
var licenses []models.LicenseJson
// read the file of data
byteResult, _ := ioutil.ReadFile(*datafile)
// unmarshal the json file and it into the struct format
Expand All @@ -59,15 +60,17 @@ func main() {
}
for _, license := range licenses {
// populate the data in the database table
database.Create(&license)
result := utils.Converter(license)
database.Create(&result)
}
}
api.DB = database

r := gin.Default()

r.NoRoute(api.HandleInvalidUrl)
r.GET("/api/licenses", api.GetAllLicense)
r.GET("/api/license/:shortname", api.GetLicense)

r.POST("/api/license", api.CreateLicense)
r.PATCH("/api/license/:shortname", api.UpdateLicense)
r.Run()
}
131 changes: 126 additions & 5 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,27 @@ import (

var DB *gorm.DB

func HandleInvalidUrl(c *gin.Context) {

er := models.LicenseError{
Status: http.StatusNotFound,
Message: "No such path exists please check URL",
Error: "invalid path",
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusNotFound, er)
}
func GetAllLicense(c *gin.Context) {
var licenses []models.License
var licenses []models.LicenseDB

err := DB.Find(&licenses).Error
if err != nil {
er := models.LicenseError{
Status: http.StatusBadRequest,
Message: "Licenses not found",
Error: err.Error(),
Path: "/api/licenses",
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
Expand All @@ -33,13 +44,16 @@ func GetAllLicense(c *gin.Context) {
res := models.LicenseResponse{
Data: licenses,
Status: http.StatusOK,
Meta: models.Meta{
ResourceCount: len(licenses),
},
}

c.JSON(http.StatusOK, res)
}

func GetLicense(c *gin.Context) {
var license models.License
var license models.LicenseDB

queryParam := c.Param("shortname")
if queryParam == "" {
Expand All @@ -53,17 +67,124 @@ func GetLicense(c *gin.Context) {
Status: http.StatusBadRequest,
Message: fmt.Sprintf("no license with shortname '%s' exists", queryParam),
Error: err.Error(),
Path: fmt.Sprintf("/api/license/%s", queryParam),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
return
}

res := models.LicenseResponse{
Data: []models.License{license},
Data: []models.LicenseDB{license},
Status: http.StatusOK,
Meta: models.Meta{
ResourceCount: 1,
},
}

c.JSON(http.StatusOK, res)
}

func CreateLicense(c *gin.Context) {
var input models.LicenseInput

if err := c.ShouldBindJSON(&input); err != nil {
er := models.LicenseError{
Status: http.StatusBadRequest,
Message: "invalid json body",
Error: err.Error(),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
return
}

if input.Active == "" {
input.Active = "t"
}
license := models.LicenseDB(input)

result := DB.FirstOrCreate(&license)
if result.RowsAffected == 0 {

er := models.LicenseError{
Status: http.StatusBadRequest,
Message: "can not create license with same shortname",
Error: fmt.Sprintf("Error: License with shortname '%s' already exists", input.Shortname),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
return
}
if result.Error != nil {
er := models.LicenseError{
Status: http.StatusInternalServerError,
Message: "Failed to create license",
Error: result.Error.Error(),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusInternalServerError, er)
return
}
res := models.LicenseResponse{
Data: []models.LicenseDB{license},
Status: http.StatusCreated,
Meta: models.Meta{
ResourceCount: 1,
},
}

c.JSON(http.StatusCreated, res)
}

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 {
er := models.LicenseError{
Status: http.StatusBadRequest,
Message: fmt.Sprintf("license with shortname '%s' not found", shortname),
Error: err.Error(),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
return
}
if err := c.ShouldBindJSON(&update); err != nil {
er := models.LicenseError{
Status: http.StatusBadRequest,
Message: "invalid json body",
Error: err.Error(),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusBadRequest, er)
return
}
if err := DB.Model(&license).Updates(update).Error; err != nil {
er := models.LicenseError{
Status: http.StatusInternalServerError,
Message: "Failed to update license",
Error: err.Error(),
Path: c.Request.URL.Path,
Timestamp: time.Now().Format(time.RFC3339),
}
c.JSON(http.StatusInternalServerError, er)
return
}
res := models.LicenseResponse{
Data: []models.LicenseDB{license},
Status: http.StatusOK,
Meta: models.Meta{
ResourceCount: 1,
},
}

c.JSON(http.StatusOK, res)

}
3 changes: 1 addition & 2 deletions pkg/models/doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-FileCopyrightText: 2023 Kavya Shukla <[email protected]>
// SPDX-License-Identifier: GPL-2.0-only

// Package models is made to connect the database and to store the structs of
// different data.
// Package models is made to store the structs of different data.
package models
70 changes: 66 additions & 4 deletions pkg/models/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

package models

type License struct {
// The License struct represents a license entity with various attributes and
// properties associated with it.
// It provides structured storage for license-related information.
type LicenseDB struct {
Shortname string `json:"rf_shortname" gorm:"primary_key"`
Fullname string `json:"rf_fullname"`
Text string `json:"rf_text"`
Expand All @@ -26,22 +29,81 @@ type License struct {
Marydone string `json:"marydone"`
}

type LicenseJson struct {
Shortname string `json:"rf_shortname"`
Fullname string `json:"rf_fullname"`
Text string `json:"rf_text"`
Url string `json:"rf_url"`
AddDate string `json:"rf_add_date"`
Copyleft string `json:"rf_copyleft"`
FSFfree string `json:"rf_FSFfree"`
OSIapproved string `json:"rf_OSIapproved"`
GPLv2compatible string `json:"rf_GPLv2compatible"`
GPLv3compatible string `json:"rf_GPLv3compatible"`
Notes string `json:"rf_notes"`
Fedora string `json:"rf_Fedora"`
TextUpdatable string `json:"rf_text_updatable"`
DetectorType string `json:"rf_detector_type"`
Active string `json:"rf_active"`
Source string `json:"rf_source"`
SpdxCompatible string `json:"rf_spdx_compatible"`
Risk string `json:"rf_risk"`
Flag string `json:"rf_flag"`
Marydone string `json:"marydone"`
}

// The Meta struct represents additional metadata associated with a
// license retrieval operation.
// It contains information that provides context and supplementary details
// about the retrieved license data.
type Meta struct {
ResourceCount int `json:"resource_count"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}

// LicenseResponse struct is representation of design API response of license.
// The LicenseResponse struct represents the response data structure for
// retrieving license information.
// It is used to encapsulate license-related data in an organized manner.
type LicenseResponse struct {
Status int `json:"status"`
Data []License `json:"data"`
Meta Meta `json:"meta,omitempty"`
Status int `json:"status"`
Data []LicenseDB `json:"data"`
Meta Meta `json:"meta"`
}

// The LicenseError struct represents an error response related to license operations.
// It provides information about the encountered error, including details such as
// status, error message, error type, path, and timestamp.
type LicenseError struct {
Status int `json:"status"`
Message string `json:"message"`
Error string `json:"error"`
Path string `json:"path"`
Timestamp string `json:"timestamp"`
}

// The LicenseInput struct represents the input or payload required for creating a license.
// It contains various fields that capture the necessary information for defining a license entity.
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"`
AddDate string `json:"rf_add_date"`
Copyleft string `json:"rf_copyleft"`
FSFfree string `json:"rf_FSFfree"`
OSIapproved string `json:"rf_OSIapproved"`
GPLv2compatible string `json:"rf_GPLv2compatible"`
GPLv3compatible string `json:"rf_GPLv3compatible"`
Notes string `json:"rf_notes"`
Fedora string `json:"rf_Fedora"`
TextUpdatable string `json:"rf_text_updatable"`
DetectorType string `json:"rf_detector_type"`
Active string `json:"rf_active"`
Source string `json:"rf_source"`
SpdxId string `json:"rf_spdx_id" binding:"required"`
Risk string `json:"rf_risk"`
Flag string `json:"rf_flag"`
Marydone string `json:"marydone"`
}
37 changes: 37 additions & 0 deletions pkg/utils/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2023 Kavya Shukla <[email protected]>
// SPDX-License-Identifier: GPL-2.0-only

package utils

import "github.com/fossology/LicenseDb/pkg/models"

func Converter(input models.LicenseJson) models.LicenseDB {
if input.SpdxCompatible == "t" {
input.SpdxCompatible = input.Shortname
} else {
input.SpdxCompatible = "LicenseRef-fossology-" + input.Shortname
}
result := models.LicenseDB{
Shortname: input.Shortname,
Fullname: input.Fullname,
Text: input.Text,
Url: input.Fullname,
Copyleft: input.Copyleft,
AddDate: input.AddDate,
FSFfree: input.FSFfree,
OSIapproved: input.OSIapproved,
GPLv2compatible: input.GPLv2compatible,
GPLv3compatible: input.GPLv3compatible,
Notes: input.Notes,
Fedora: input.Fedora,
TextUpdatable: input.TextUpdatable,
DetectorType: input.DetectorType,
Active: input.Active,
Source: input.Source,
SpdxId: input.SpdxCompatible,
Risk: input.Risk,
Flag: input.Flag,
Marydone: input.Marydone,
}
return result
}

0 comments on commit 554165e

Please sign in to comment.