This is an automated email from the ASF dual-hosted git repository.

abeizn pushed a commit to branch release-v1.0
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git

commit e0fab64d2f0a970c9fa9b5853579e86e83953b3d
Author: abeizn <[email protected]>
AuthorDate: Tue Mar 19 18:44:17 2024 +0800

    feat: add onboard keyvalue api (#7189)
    
    * feat: add onboard keyvalue api
    
    * fix: optimize interface
    
    * fix: revert poetry lock
    
    * fix: get json result
    
    * fix: rename onboard storeKey
    
    * fix: word
    
    * fix: some details
---
 .../migrationscripts/20240318_add_devlake_store.go | 54 +++++++++++++++
 backend/core/models/migrationscripts/register.go   |  1 +
 backend/core/models/project.go                     | 14 ++++
 backend/server/api/router.go                       |  4 ++
 backend/server/api/store/store.go                  | 78 ++++++++++++++++++++++
 backend/server/services/store.go                   | 57 ++++++++++++++++
 6 files changed, 208 insertions(+)

diff --git a/backend/core/models/migrationscripts/20240318_add_devlake_store.go 
b/backend/core/models/migrationscripts/20240318_add_devlake_store.go
new file mode 100644
index 000000000..e338fd896
--- /dev/null
+++ b/backend/core/models/migrationscripts/20240318_add_devlake_store.go
@@ -0,0 +1,54 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+       "encoding/json"
+       "time"
+
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/plugin"
+)
+
+var _ plugin.MigrationScript = (*addStore)(nil)
+
+type store20240318 struct {
+       StoreKey   string          `gorm:"primaryKey;type:varchar(255)"`
+       StoreValue json.RawMessage `gorm:"type:json;serializer:json"`
+       CreatedAt  time.Time       `json:"createdAt" mapstructure:"createdAt"`
+       UpdatedAt  time.Time       `json:"updatedAt" mapstructure:"updatedAt"`
+}
+
+func (store20240318) TableName() string {
+       return "_devlake_store"
+}
+
+type addStore struct{}
+
+func (*addStore) Up(basicRes context.BasicRes) errors.Error {
+       return basicRes.GetDal().AutoMigrate(store20240318{})
+}
+
+func (*addStore) Version() uint64 {
+       return 20240318111247
+}
+
+func (*addStore) Name() string {
+       return "add _devlake_store table"
+}
diff --git a/backend/core/models/migrationscripts/register.go 
b/backend/core/models/migrationscripts/register.go
index 03319bf92..26b3ec9bb 100644
--- a/backend/core/models/migrationscripts/register.go
+++ b/backend/core/models/migrationscripts/register.go
@@ -109,5 +109,6 @@ func All() []plugin.MigrationScript {
                new(modifyRefsIdLength),
                
new(addOriginalEnvironmentToCicdDeploymentsAndCicdDeploymentCommits),
                new(addSubtabknameToDeployment),
+               new(addStore),
        }
 }
diff --git a/backend/core/models/project.go b/backend/core/models/project.go
index 6a935e97e..4da6afc67 100644
--- a/backend/core/models/project.go
+++ b/backend/core/models/project.go
@@ -18,6 +18,9 @@ limitations under the License.
 package models
 
 import (
+       "encoding/json"
+       "time"
+
        "github.com/apache/incubator-devlake/core/models/common"
 )
 
@@ -67,3 +70,14 @@ type ApiOutputProject struct {
        Blueprint    *Blueprint    `json:"blueprint" mapstructure:"blueprint"`
        LastPipeline *Pipeline     `json:"lastPipeline,omitempty" 
mapstructure:"lastPipeline"`
 }
+
+type Store struct {
+       StoreKey   string          `gorm:"primaryKey;type:varchar(255)"`
+       StoreValue json.RawMessage `gorm:"type:json;serializer:json"`
+       CreatedAt  time.Time       `json:"createdAt" mapstructure:"createdAt"`
+       UpdatedAt  time.Time       `json:"updatedAt" mapstructure:"updatedAt"`
+}
+
+func (Store) TableName() string {
+       return "_devlake_store"
+}
diff --git a/backend/server/api/router.go b/backend/server/api/router.go
index 6957044de..188c29e4c 100644
--- a/backend/server/api/router.go
+++ b/backend/server/api/router.go
@@ -26,6 +26,7 @@ import (
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/impls/logruslog"
        "github.com/apache/incubator-devlake/server/api/apikeys"
+       "github.com/apache/incubator-devlake/server/api/store"
 
        "github.com/apache/incubator-devlake/core/plugin"
        "github.com/apache/incubator-devlake/server/api/blueprints"
@@ -73,6 +74,9 @@ func RegisterRouter(r *gin.Engine, basicRes context.BasicRes) 
{
        r.DELETE("/projects/*projectName", project.DeleteProject)
        r.POST("/projects", project.PostProject)
        r.GET("/projects", project.GetProjects)
+       // on board api
+       r.GET("/store/:storeKey", store.GetStore)
+       r.PUT("/store/:storeKey", store.PutStore)
 
        // api keys api
        r.GET("/api-keys", apikeys.GetApiKeys)
diff --git a/backend/server/api/store/store.go 
b/backend/server/api/store/store.go
new file mode 100644
index 000000000..0c7ab3778
--- /dev/null
+++ b/backend/server/api/store/store.go
@@ -0,0 +1,78 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package store
+
+import (
+       "fmt"
+       "net/http"
+
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/models"
+       "github.com/apache/incubator-devlake/server/api/shared"
+       "github.com/apache/incubator-devlake/server/services"
+
+       "github.com/gin-gonic/gin"
+)
+
+// @Summary Get the value by given key
+// @Description Get the value by given key
+// @Tags framework/projects
+// @Param storeKey path string true "storeKey"
+// @Success 200  {object} json.RawMessage
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /store/{storeKey} [get]
+func GetStore(c *gin.Context) {
+       storeKey := c.Param("storeKey")
+       result, err := services.GetStore(storeKey)
+       if err != nil {
+               c.JSON(http.StatusInternalServerError, gin.H{"error": 
fmt.Sprintf("Error fetching %s data", storeKey)})
+               return
+       }
+
+       shared.ApiOutputSuccess(c, result.StoreValue, http.StatusOK)
+}
+
+// @Summary Put the value by given key
+// @Description Put the value by given key
+// @Tags framework/projects
+// @Accept application/json
+// @Param storeKey path string true "storeKey"
+// @Param project body json.RawMessage false "json"
+// @Success 200  {object} json.RawMessage
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /store/{storeKey} [PUT]
+func PutStore(c *gin.Context) {
+       storeKey := c.Param("storeKey")
+       var body models.Store
+       err := c.ShouldBind(&body.StoreValue)
+       if err != nil {
+               shared.ApiOutputError(c, errors.BadInput.Wrap(err, 
shared.BadRequestBody))
+               return
+       }
+       body.StoreKey = storeKey
+
+       result, err := services.PutStore(storeKey, &body)
+       if err != nil {
+               shared.ApiOutputError(c, errors.Default.Wrap(err, 
fmt.Sprintf("PutStore: failed to put %s", storeKey)))
+               return
+       }
+
+       shared.ApiOutputSuccess(c, result.StoreValue, http.StatusCreated)
+}
diff --git a/backend/server/services/store.go b/backend/server/services/store.go
new file mode 100644
index 000000000..1eb4b717c
--- /dev/null
+++ b/backend/server/services/store.go
@@ -0,0 +1,57 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package services
+
+import (
+       "fmt"
+
+       "github.com/apache/incubator-devlake/core/dal"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/models"
+)
+
+// GetProjects returns a paginated list of Projects based on `query`
+func GetStore(storeKey string) (*models.Store, errors.Error) {
+       clauses := []dal.Clause{
+               dal.From(&models.Store{}),
+               dal.Where("store_key = ?", storeKey),
+       }
+
+       kvstore := &models.Store{}
+       err := db.All(&kvstore, clauses...)
+       if err != nil {
+               return nil, errors.Default.Wrap(err, fmt.Sprintf("error finding 
%s on _devlake_store table", storeKey))
+       }
+
+       return kvstore, nil
+}
+
+// PutOnboard accepts a project instance and insert it to database
+func PutStore(storeKey string, storeValue *models.Store) (*models.Store, 
errors.Error) {
+       // verify input
+       if err := VerifyStruct(storeValue); err != nil {
+               return nil, err
+       }
+
+       err := db.CreateOrUpdate(storeValue, dal.Where("store_key = ?", 
storeKey))
+       if err != nil {
+               return nil, err
+       }
+
+       return storeValue, nil
+}

Reply via email to