mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:19:00 +08:00
chore: dashboard locking ee query-service (#3856)
* chore: dashboard locking ee query-service * chore: remove print statements * chore: remove unused imports * chore: no one is allowed to edit/delete the locked dashboard --------- Co-authored-by: Srikanth Chekuri <srikanth@Srikanths-MacBook-Pro.local>
This commit is contained in:
parent
b5654c8bfa
commit
5e349d8294
@ -160,6 +160,9 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew
|
||||
router.HandleFunc("/api/v1/billing", am.AdminAccess(ah.getBilling)).Methods(http.MethodGet)
|
||||
router.HandleFunc("/api/v1/portal", am.AdminAccess(ah.portalSession)).Methods(http.MethodPost)
|
||||
|
||||
router.HandleFunc("/api/v1/dashboards/{uuid}/lock", am.EditAccess(ah.lockDashboard)).Methods(http.MethodPut)
|
||||
router.HandleFunc("/api/v1/dashboards/{uuid}/unlock", am.EditAccess(ah.unlockDashboard)).Methods(http.MethodPut)
|
||||
|
||||
router.HandleFunc("/api/v2/licenses",
|
||||
am.ViewAccess(ah.listLicensesV2)).
|
||||
Methods(http.MethodGet)
|
||||
|
51
ee/query-service/app/api/dashboard.go
Normal file
51
ee/query-service/app/api/dashboard.go
Normal file
@ -0,0 +1,51 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||
"go.signoz.io/signoz/pkg/query-service/common"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (ah *APIHandler) lockDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
ah.lockUnlockDashboard(w, r, true)
|
||||
}
|
||||
|
||||
func (ah *APIHandler) unlockDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
ah.lockUnlockDashboard(w, r, false)
|
||||
}
|
||||
|
||||
func (ah *APIHandler) lockUnlockDashboard(w http.ResponseWriter, r *http.Request, lock bool) {
|
||||
// Locking can only be done by the owner of the dashboard
|
||||
// or an admin
|
||||
|
||||
// - Fetch the dashboard
|
||||
// - Check if the user is the owner or an admin
|
||||
// - If yes, lock/unlock the dashboard
|
||||
// - If no, return 403
|
||||
|
||||
// Get the dashboard UUID from the request
|
||||
uuid := mux.Vars(r)["uuid"]
|
||||
dashboard, err := dashboards.GetDashboard(r.Context(), uuid)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user := common.GetUserFromContext(r.Context())
|
||||
if !auth.IsAdmin(user) || (dashboard.CreateBy != nil && *dashboard.CreateBy != user.Email) {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorForbidden, Err: err}, "You are not authorized to lock/unlock this dashboard")
|
||||
return
|
||||
}
|
||||
|
||||
// Lock/Unlock the dashboard
|
||||
err = dashboards.LockUnlockDashboard(r.Context(), uuid, lock)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ah.Respond(w, "Dashboard updated successfully")
|
||||
}
|
@ -128,6 +128,12 @@ func InitDB(dataSourceName string) (*sqlx.DB, error) {
|
||||
return nil, fmt.Errorf("error in adding column updated_by to dashboards table: %s", err.Error())
|
||||
}
|
||||
|
||||
locked := `ALTER TABLE dashboards ADD COLUMN locked INTEGER DEFAULT 0;`
|
||||
_, err = db.Exec(locked)
|
||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
||||
return nil, fmt.Errorf("error in adding column locked to dashboards table: %s", err.Error())
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@ -141,6 +147,7 @@ type Dashboard struct {
|
||||
UpdateBy *string `json:"updated_by" db:"updated_by"`
|
||||
Title string `json:"-" db:"-"`
|
||||
Data Data `json:"data" db:"data"`
|
||||
Locked *int `json:"isLocked" db:"locked"`
|
||||
}
|
||||
|
||||
type Data map[string]interface{}
|
||||
@ -239,6 +246,12 @@ func DeleteDashboard(ctx context.Context, uuid string, fm interfaces.FeatureLook
|
||||
return dErr
|
||||
}
|
||||
|
||||
if user := common.GetUserFromContext(ctx); user != nil {
|
||||
if dashboard.Locked != nil && *dashboard.Locked == 1 {
|
||||
return model.BadRequest(fmt.Errorf("dashboard is locked, please unlock the dashboard to be able to delete it"))
|
||||
}
|
||||
}
|
||||
|
||||
query := `DELETE FROM dashboards WHERE uuid=?`
|
||||
|
||||
result, err := db.Exec(query, uuid)
|
||||
@ -289,6 +302,14 @@ func UpdateDashboard(ctx context.Context, uuid string, data map[string]interface
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
var userEmail string
|
||||
if user := common.GetUserFromContext(ctx); user != nil {
|
||||
userEmail = user.Email
|
||||
if dashboard.Locked != nil && *dashboard.Locked == 1 {
|
||||
return nil, model.BadRequest(fmt.Errorf("dashboard is locked, please unlock the dashboard to be able to edit it"))
|
||||
}
|
||||
}
|
||||
|
||||
// check if the count of trace and logs QB panel has changed, if yes, then check feature flag count
|
||||
existingCount, existingTotal := countTraceAndLogsPanel(dashboard.Data)
|
||||
newCount, newTotal := countTraceAndLogsPanel(data)
|
||||
@ -306,10 +327,6 @@ func UpdateDashboard(ctx context.Context, uuid string, data map[string]interface
|
||||
}
|
||||
|
||||
dashboard.UpdatedAt = time.Now()
|
||||
var userEmail string
|
||||
if user := common.GetUserFromContext(ctx); user != nil {
|
||||
userEmail = user.Email
|
||||
}
|
||||
dashboard.UpdateBy = &userEmail
|
||||
dashboard.Data = data
|
||||
|
||||
@ -327,6 +344,24 @@ func UpdateDashboard(ctx context.Context, uuid string, data map[string]interface
|
||||
return dashboard, nil
|
||||
}
|
||||
|
||||
func LockUnlockDashboard(ctx context.Context, uuid string, lock bool) *model.ApiError {
|
||||
var query string
|
||||
if lock {
|
||||
query = `UPDATE dashboards SET locked=1 WHERE uuid=?;`
|
||||
} else {
|
||||
query = `UPDATE dashboards SET locked=0 WHERE uuid=?;`
|
||||
}
|
||||
|
||||
_, err := db.Exec(query, uuid)
|
||||
|
||||
if err != nil {
|
||||
zap.S().Errorf("Error in updating dashboard: ", uuid, err)
|
||||
return &model.ApiError{Typ: model.ErrorExec, Err: err}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateFeatureUsage(fm interfaces.FeatureLookup, usage int64) *model.ApiError {
|
||||
feature, err := fm.GetFeatureFlag(model.QueryBuilderPanels)
|
||||
if err != nil {
|
||||
|
@ -91,7 +91,6 @@ func ParseMetricAutocompleteTagParams(r *http.Request) (*model.MetricAutocomplet
|
||||
}
|
||||
|
||||
tagsStr := r.URL.Query().Get("tags")
|
||||
// fmt.Println(tagsStr)
|
||||
|
||||
// parsing tags
|
||||
var tags map[string]string
|
||||
|
@ -2,7 +2,6 @@ package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.signoz.io/signoz/pkg/query-service/model"
|
||||
@ -51,7 +50,6 @@ func (mds *ModelDaoSqlite) GetApdexSettings(ctx context.Context, services []stri
|
||||
|
||||
func (mds *ModelDaoSqlite) SetApdexSettings(ctx context.Context, apdexSettings *model.ApdexSettings) *model.ApiError {
|
||||
|
||||
fmt.Println("apdexSettings:", apdexSettings)
|
||||
_, err := mds.db.NamedExec(`
|
||||
INSERT OR REPLACE INTO apdex_settings (
|
||||
service_name,
|
||||
|
Loading…
x
Reference in New Issue
Block a user