mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 06:19:03 +08:00
feat: preference framework qs changes (#5527)
* feat: query service changes base setup for preferences * feat: added handlers for user and org preferences * chore: added base for all user and all org preferences * feat: added handlers for all user and all org preferences * feat: register the preference routes and initDB in pkg/query-service * feat: code refactor * chore: too much fun code refactor * chore: little little missing attributes * fix: handle range queries better * fix: handle range queries better * chore: address review comments * chore: use struct inheritance for the all preferences struct * chore: address review comments * chore: address review comments * chore: correct preference routes * chore: low hanging optimisations * chore: address review comments * chore: address review comments * chore: added extra validations for the check in allowed values * fix: better handling for the jwt claims * fix: better handling for the jwt claims * chore: move the error to preference apis * chore: move the error to preference apis * fix: move the 401 logic to the auth middleware
This commit is contained in:
parent
4360cd0397
commit
d00024b64a
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -27,6 +28,7 @@ import (
|
|||||||
"go.signoz.io/signoz/ee/query-service/integrations/gateway"
|
"go.signoz.io/signoz/ee/query-service/integrations/gateway"
|
||||||
"go.signoz.io/signoz/ee/query-service/interfaces"
|
"go.signoz.io/signoz/ee/query-service/interfaces"
|
||||||
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
|
||||||
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
||||||
@ -40,6 +42,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||||
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
||||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/healthcheck"
|
"go.signoz.io/signoz/pkg/query-service/healthcheck"
|
||||||
@ -109,6 +112,10 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
|
|
||||||
baseexplorer.InitWithDSN(baseconst.RELATIONAL_DATASOURCE_PATH)
|
baseexplorer.InitWithDSN(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||||
|
|
||||||
|
if err := preferences.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
localDB, err := dashboards.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
localDB, err := dashboards.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -319,7 +326,17 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
|
|||||||
|
|
||||||
// add auth middleware
|
// add auth middleware
|
||||||
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
|
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
|
||||||
return auth.GetUserFromRequest(r, apiHandler)
|
user, err := auth.GetUserFromRequest(r, apiHandler)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.User.OrgId == "" {
|
||||||
|
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
}
|
}
|
||||||
am := baseapp.NewAuthMiddleware(getUserFromRequest)
|
am := baseapp.NewAuthMiddleware(getUserFromRequest)
|
||||||
|
|
||||||
|
@ -29,12 +29,14 @@ import (
|
|||||||
logsv3 "go.signoz.io/signoz/pkg/query-service/app/logs/v3"
|
logsv3 "go.signoz.io/signoz/pkg/query-service/app/logs/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/metrics"
|
"go.signoz.io/signoz/pkg/query-service/app/metrics"
|
||||||
metricsv3 "go.signoz.io/signoz/pkg/query-service/app/metrics/v3"
|
metricsv3 "go.signoz.io/signoz/pkg/query-service/app/metrics/v3"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/querier"
|
"go.signoz.io/signoz/pkg/query-service/app/querier"
|
||||||
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
|
||||||
tracesV3 "go.signoz.io/signoz/pkg/query-service/app/traces/v3"
|
tracesV3 "go.signoz.io/signoz/pkg/query-service/app/traces/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/postprocess"
|
"go.signoz.io/signoz/pkg/query-service/postprocess"
|
||||||
@ -398,6 +400,22 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
|
|||||||
|
|
||||||
router.HandleFunc("/api/v1/disks", am.ViewAccess(aH.getDisks)).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/disks", am.ViewAccess(aH.getDisks)).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
// === Preference APIs ===
|
||||||
|
|
||||||
|
// user actions
|
||||||
|
router.HandleFunc("/api/v1/user/preferences", am.ViewAccess(aH.getAllUserPreferences)).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v1/user/preferences/{preferenceId}", am.ViewAccess(aH.getUserPreference)).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v1/user/preferences/{preferenceId}", am.ViewAccess(aH.updateUserPreference)).Methods(http.MethodPut)
|
||||||
|
|
||||||
|
// org actions
|
||||||
|
router.HandleFunc("/api/v1/org/preferences", am.AdminAccess(aH.getAllOrgPreferences)).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v1/org/preferences/{preferenceId}", am.AdminAccess(aH.getOrgPreference)).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v1/org/preferences/{preferenceId}", am.AdminAccess(aH.updateOrgPreference)).Methods(http.MethodPut)
|
||||||
|
|
||||||
// === Authentication APIs ===
|
// === Authentication APIs ===
|
||||||
router.HandleFunc("/api/v1/invite", am.AdminAccess(aH.inviteUser)).Methods(http.MethodPost)
|
router.HandleFunc("/api/v1/invite", am.AdminAccess(aH.inviteUser)).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/api/v1/invite/{token}", am.OpenAccess(aH.getInvite)).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/invite/{token}", am.OpenAccess(aH.getInvite)).Methods(http.MethodGet)
|
||||||
@ -2192,6 +2210,115 @@ func (aH *APIHandler) WriteJSON(w http.ResponseWriter, r *http.Request, response
|
|||||||
w.Write(resp)
|
w.Write(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preferences
|
||||||
|
|
||||||
|
func (ah *APIHandler) getUserPreference(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
preferenceId := mux.Vars(r)["preferenceId"]
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
|
||||||
|
preference, apiErr := preferences.GetUserPreference(
|
||||||
|
r.Context(), preferenceId, user.User.OrgId, user.User.Id,
|
||||||
|
)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ah *APIHandler) updateUserPreference(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
preferenceId := mux.Vars(r)["preferenceId"]
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
req := preferences.UpdatePreference{}
|
||||||
|
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, model.BadRequest(err), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
preference, apiErr := preferences.UpdateUserPreference(r.Context(), preferenceId, req.PreferenceValue, user.User.Id)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ah *APIHandler) getAllUserPreferences(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
preference, apiErr := preferences.GetAllUserPreferences(
|
||||||
|
r.Context(), user.User.OrgId, user.User.Id,
|
||||||
|
)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ah *APIHandler) getOrgPreference(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
preferenceId := mux.Vars(r)["preferenceId"]
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
preference, apiErr := preferences.GetOrgPreference(
|
||||||
|
r.Context(), preferenceId, user.User.OrgId,
|
||||||
|
)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ah *APIHandler) updateOrgPreference(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
preferenceId := mux.Vars(r)["preferenceId"]
|
||||||
|
req := preferences.UpdatePreference{}
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
RespondError(w, model.BadRequest(err), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
preference, apiErr := preferences.UpdateOrgPreference(r.Context(), preferenceId, req.PreferenceValue, user.User.OrgId)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ah *APIHandler) getAllOrgPreferences(
|
||||||
|
w http.ResponseWriter, r *http.Request,
|
||||||
|
) {
|
||||||
|
user := common.GetUserFromContext(r.Context())
|
||||||
|
preference, apiErr := preferences.GetAllOrgPreferences(
|
||||||
|
r.Context(), user.User.OrgId,
|
||||||
|
)
|
||||||
|
if apiErr != nil {
|
||||||
|
RespondError(w, apiErr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ah.Respond(w, preference)
|
||||||
|
}
|
||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
func (ah *APIHandler) RegisterIntegrationRoutes(router *mux.Router, am *AuthMiddleware) {
|
func (ah *APIHandler) RegisterIntegrationRoutes(router *mux.Router, am *AuthMiddleware) {
|
||||||
subRouter := router.PathPrefix("/api/v1/integrations").Subrouter()
|
subRouter := router.PathPrefix("/api/v1/integrations").Subrouter()
|
||||||
|
37
pkg/query-service/app/preferences/map.go
Normal file
37
pkg/query-service/app/preferences/map.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package preferences
|
||||||
|
|
||||||
|
var preferenceMap = map[string]Preference{
|
||||||
|
"DASHBOARDS_LIST_VIEW": {
|
||||||
|
Key: "DASHBOARDS_LIST_VIEW",
|
||||||
|
Name: "Dashboards List View",
|
||||||
|
Description: "",
|
||||||
|
ValueType: "string",
|
||||||
|
DefaultValue: "grid",
|
||||||
|
AllowedValues: []interface{}{"grid", "list"},
|
||||||
|
IsDiscreteValues: true,
|
||||||
|
AllowedScopes: []string{"user", "org"},
|
||||||
|
},
|
||||||
|
"LOGS_TOOLBAR_COLLAPSED": {
|
||||||
|
Key: "LOGS_TOOLBAR_COLLAPSED",
|
||||||
|
Name: "Logs toolbar",
|
||||||
|
Description: "",
|
||||||
|
ValueType: "boolean",
|
||||||
|
DefaultValue: false,
|
||||||
|
AllowedValues: []interface{}{true, false},
|
||||||
|
IsDiscreteValues: true,
|
||||||
|
AllowedScopes: []string{"user", "org"},
|
||||||
|
},
|
||||||
|
"MAX_DEPTH_ALLOWED": {
|
||||||
|
Key: "MAX_DEPTH_ALLOWED",
|
||||||
|
Name: "Max Depth Allowed",
|
||||||
|
Description: "",
|
||||||
|
ValueType: "integer",
|
||||||
|
DefaultValue: 10,
|
||||||
|
IsDiscreteValues: false,
|
||||||
|
Range: Range{
|
||||||
|
Min: 0,
|
||||||
|
Max: 100,
|
||||||
|
},
|
||||||
|
AllowedScopes: []string{"user", "org"},
|
||||||
|
},
|
||||||
|
}
|
544
pkg/query-service/app/preferences/model.go
Normal file
544
pkg/query-service/app/preferences/model.go
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
package preferences
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Range struct {
|
||||||
|
Min int64 `json:"min"`
|
||||||
|
Max int64 `json:"max"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Preference struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ValueType string `json:"valueType"`
|
||||||
|
DefaultValue interface{} `json:"defaultValue"`
|
||||||
|
AllowedValues []interface{} `json:"allowedValues"`
|
||||||
|
IsDiscreteValues bool `json:"isDiscreteValues"`
|
||||||
|
Range Range `json:"range"`
|
||||||
|
AllowedScopes []string `json:"allowedScopes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Preference) ErrorValueTypeMismatch() *model.ApiError {
|
||||||
|
return &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("the preference value is not of expected type: %s", p.ValueType)}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
PreferenceValueTypeInteger string = "integer"
|
||||||
|
PreferenceValueTypeFloat string = "float"
|
||||||
|
PreferenceValueTypeString string = "string"
|
||||||
|
PreferenceValueTypeBoolean string = "boolean"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrgAllowedScope string = "org"
|
||||||
|
UserAllowedScope string = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Preference) checkIfInAllowedValues(preferenceValue interface{}) (bool, *model.ApiError) {
|
||||||
|
|
||||||
|
switch p.ValueType {
|
||||||
|
case PreferenceValueTypeInteger:
|
||||||
|
_, ok := preferenceValue.(int64)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeFloat:
|
||||||
|
_, ok := preferenceValue.(float64)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeString:
|
||||||
|
_, ok := preferenceValue.(string)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeBoolean:
|
||||||
|
_, ok := preferenceValue.(bool)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isInAllowedValues := false
|
||||||
|
for _, value := range p.AllowedValues {
|
||||||
|
switch p.ValueType {
|
||||||
|
case PreferenceValueTypeInteger:
|
||||||
|
allowedValue, ok := value.(int64)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
if allowedValue == preferenceValue {
|
||||||
|
isInAllowedValues = true
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeFloat:
|
||||||
|
allowedValue, ok := value.(float64)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
if allowedValue == preferenceValue {
|
||||||
|
isInAllowedValues = true
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeString:
|
||||||
|
allowedValue, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
if allowedValue == preferenceValue {
|
||||||
|
isInAllowedValues = true
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeBoolean:
|
||||||
|
allowedValue, ok := value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return false, p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
if allowedValue == preferenceValue {
|
||||||
|
isInAllowedValues = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isInAllowedValues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Preference) IsValidValue(preferenceValue interface{}) *model.ApiError {
|
||||||
|
typeSafeValue := preferenceValue
|
||||||
|
switch p.ValueType {
|
||||||
|
case PreferenceValueTypeInteger:
|
||||||
|
val, ok := preferenceValue.(int64)
|
||||||
|
if !ok {
|
||||||
|
floatVal, ok := preferenceValue.(float64)
|
||||||
|
if !ok || floatVal != float64(int64(floatVal)) {
|
||||||
|
return p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
val = int64(floatVal)
|
||||||
|
typeSafeValue = val
|
||||||
|
}
|
||||||
|
if !p.IsDiscreteValues {
|
||||||
|
if val < p.Range.Min || val > p.Range.Max {
|
||||||
|
return &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("the preference value is not in the range specified, min: %v , max:%v", p.Range.Min, p.Range.Max)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeString:
|
||||||
|
_, ok := preferenceValue.(string)
|
||||||
|
if !ok {
|
||||||
|
return p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeFloat:
|
||||||
|
_, ok := preferenceValue.(float64)
|
||||||
|
if !ok {
|
||||||
|
return p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
case PreferenceValueTypeBoolean:
|
||||||
|
_, ok := preferenceValue.(bool)
|
||||||
|
if !ok {
|
||||||
|
return p.ErrorValueTypeMismatch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the validity of the value being part of allowed values or the range specified if any
|
||||||
|
if p.IsDiscreteValues {
|
||||||
|
if p.AllowedValues != nil {
|
||||||
|
isInAllowedValues, valueMisMatchErr := p.checkIfInAllowedValues(typeSafeValue)
|
||||||
|
|
||||||
|
if valueMisMatchErr != nil {
|
||||||
|
return valueMisMatchErr
|
||||||
|
}
|
||||||
|
if !isInAllowedValues {
|
||||||
|
return &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("the preference value is not in the list of allowedValues: %v", p.AllowedValues)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Preference) IsEnabledForScope(scope string) bool {
|
||||||
|
isPreferenceEnabledForGivenScope := false
|
||||||
|
if p.AllowedScopes != nil {
|
||||||
|
for _, allowedScope := range p.AllowedScopes {
|
||||||
|
if allowedScope == strings.ToLower(scope) {
|
||||||
|
isPreferenceEnabledForGivenScope = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isPreferenceEnabledForGivenScope
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Preference) SanitizeValue(preferenceValue interface{}) interface{} {
|
||||||
|
switch p.ValueType {
|
||||||
|
case PreferenceValueTypeBoolean:
|
||||||
|
if preferenceValue == "1" || preferenceValue == true {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return preferenceValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllPreferences struct {
|
||||||
|
Preference
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PreferenceKV struct {
|
||||||
|
PreferenceId string `json:"preference_id" db:"preference_id"`
|
||||||
|
PreferenceValue interface{} `json:"preference_value" db:"preference_value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdatePreference struct {
|
||||||
|
PreferenceValue interface{} `json:"preference_value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var db *sqlx.DB
|
||||||
|
|
||||||
|
func InitDB(datasourceName string) error {
|
||||||
|
var err error
|
||||||
|
db, err = sqlx.Open("sqlite3", datasourceName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the user preference table
|
||||||
|
tableSchema := `
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
CREATE TABLE IF NOT EXISTS user_preference(
|
||||||
|
preference_id TEXT NOT NULL,
|
||||||
|
preference_value TEXT,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (preference_id,user_id),
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES users(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);`
|
||||||
|
|
||||||
|
_, err = db.Exec(tableSchema)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error in creating user_preference table: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the org preference table
|
||||||
|
tableSchema = `
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
CREATE TABLE IF NOT EXISTS org_preference(
|
||||||
|
preference_id TEXT NOT NULL,
|
||||||
|
preference_value TEXT,
|
||||||
|
org_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (preference_id,org_id),
|
||||||
|
FOREIGN KEY (org_id)
|
||||||
|
REFERENCES organizations(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);`
|
||||||
|
|
||||||
|
_, err = db.Exec(tableSchema)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error in creating org_preference table: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// org preference functions
|
||||||
|
func GetOrgPreference(ctx context.Context, preferenceId string, orgId string) (*PreferenceKV, *model.ApiError) {
|
||||||
|
// check if the preference key exists or not
|
||||||
|
preference, seen := preferenceMap[preferenceId]
|
||||||
|
if !seen {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("no such preferenceId exists: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the preference is enabled for org scope or not
|
||||||
|
isPreferenceEnabled := preference.IsEnabledForScope(OrgAllowedScope)
|
||||||
|
if !isPreferenceEnabled {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("preference is not enabled at org scope: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the value from the database
|
||||||
|
var orgPreference PreferenceKV
|
||||||
|
query := `SELECT preference_id , preference_value FROM org_preference WHERE preference_id=$1 AND org_id=$2;`
|
||||||
|
err := db.Get(&orgPreference, query, preferenceId, orgId)
|
||||||
|
|
||||||
|
// if the value doesn't exist in db then return the default value
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return &PreferenceKV{
|
||||||
|
PreferenceId: preferenceId,
|
||||||
|
PreferenceValue: preference.DefaultValue,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in fetching the org preference: %s", err.Error())}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// else return the value fetched from the org_preference table
|
||||||
|
return &PreferenceKV{
|
||||||
|
PreferenceId: preferenceId,
|
||||||
|
PreferenceValue: preference.SanitizeValue(orgPreference.PreferenceValue),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateOrgPreference(ctx context.Context, preferenceId string, preferenceValue interface{}, orgId string) (*PreferenceKV, *model.ApiError) {
|
||||||
|
// check if the preference key exists or not
|
||||||
|
preference, seen := preferenceMap[preferenceId]
|
||||||
|
if !seen {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("no such preferenceId exists: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the preference is enabled at org scope or not
|
||||||
|
isPreferenceEnabled := preference.IsEnabledForScope(OrgAllowedScope)
|
||||||
|
if !isPreferenceEnabled {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("preference is not enabled at org scope: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := preference.IsValidValue(preferenceValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the values in the org_preference table and return the key and the value
|
||||||
|
query := `INSERT INTO org_preference(preference_id,preference_value,org_id) VALUES($1,$2,$3)
|
||||||
|
ON CONFLICT(preference_id,org_id) DO
|
||||||
|
UPDATE SET preference_value= $2 WHERE preference_id=$1 AND org_id=$3;`
|
||||||
|
|
||||||
|
_, dberr := db.Exec(query, preferenceId, preferenceValue, orgId)
|
||||||
|
|
||||||
|
if dberr != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in setting the preference value: %s", dberr.Error())}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PreferenceKV{
|
||||||
|
PreferenceId: preferenceId,
|
||||||
|
PreferenceValue: preferenceValue,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllOrgPreferences(ctx context.Context, orgId string) (*[]AllPreferences, *model.ApiError) {
|
||||||
|
// filter out all the org enabled preferences from the preference variable
|
||||||
|
allOrgPreferences := []AllPreferences{}
|
||||||
|
|
||||||
|
// fetch all the org preference values stored in org_preference table
|
||||||
|
orgPreferenceValues := []PreferenceKV{}
|
||||||
|
|
||||||
|
query := `SELECT preference_id,preference_value FROM org_preference WHERE org_id=$1;`
|
||||||
|
err := db.Select(&orgPreferenceValues, query, orgId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in getting all org preference values: %s", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a map of key vs values from the above response
|
||||||
|
preferenceValueMap := map[string]interface{}{}
|
||||||
|
|
||||||
|
for _, preferenceValue := range orgPreferenceValues {
|
||||||
|
preferenceValueMap[preferenceValue.PreferenceId] = preferenceValue.PreferenceValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// update in the above filtered list wherver value present in the map
|
||||||
|
for _, preference := range preferenceMap {
|
||||||
|
isEnabledForOrgScope := preference.IsEnabledForScope(OrgAllowedScope)
|
||||||
|
if isEnabledForOrgScope {
|
||||||
|
preferenceWithValue := AllPreferences{}
|
||||||
|
preferenceWithValue.Key = preference.Key
|
||||||
|
preferenceWithValue.Name = preference.Name
|
||||||
|
preferenceWithValue.Description = preference.Description
|
||||||
|
preferenceWithValue.AllowedScopes = preference.AllowedScopes
|
||||||
|
preferenceWithValue.AllowedValues = preference.AllowedValues
|
||||||
|
preferenceWithValue.DefaultValue = preference.DefaultValue
|
||||||
|
preferenceWithValue.Range = preference.Range
|
||||||
|
preferenceWithValue.ValueType = preference.ValueType
|
||||||
|
preferenceWithValue.IsDiscreteValues = preference.IsDiscreteValues
|
||||||
|
value, seen := preferenceValueMap[preference.Key]
|
||||||
|
|
||||||
|
if seen {
|
||||||
|
preferenceWithValue.Value = value
|
||||||
|
} else {
|
||||||
|
preferenceWithValue.Value = preference.DefaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
preferenceWithValue.Value = preference.SanitizeValue(preferenceWithValue.Value)
|
||||||
|
allOrgPreferences = append(allOrgPreferences, preferenceWithValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &allOrgPreferences, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// user preference functions
|
||||||
|
func GetUserPreference(ctx context.Context, preferenceId string, orgId string, userId string) (*PreferenceKV, *model.ApiError) {
|
||||||
|
// check if the preference key exists
|
||||||
|
preference, seen := preferenceMap[preferenceId]
|
||||||
|
if !seen {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("no such preferenceId exists: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
preferenceValue := PreferenceKV{
|
||||||
|
PreferenceId: preferenceId,
|
||||||
|
PreferenceValue: preference.DefaultValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the preference is enabled at user scope
|
||||||
|
isPreferenceEnabledAtUserScope := preference.IsEnabledForScope(UserAllowedScope)
|
||||||
|
if !isPreferenceEnabledAtUserScope {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("preference is not enabled at user scope: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
isPreferenceEnabledAtOrgScope := preference.IsEnabledForScope(OrgAllowedScope)
|
||||||
|
// get the value from the org scope if enabled at org scope
|
||||||
|
if isPreferenceEnabledAtOrgScope {
|
||||||
|
orgPreference := PreferenceKV{}
|
||||||
|
|
||||||
|
query := `SELECT preference_id , preference_value FROM org_preference WHERE preference_id=$1 AND org_id=$2;`
|
||||||
|
|
||||||
|
err := db.Get(&orgPreference, query, preferenceId, orgId)
|
||||||
|
|
||||||
|
// if there is error in getting values and its not an empty rows error return from here
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in getting org preference values: %s", err.Error())}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is no error update the preference value with value from org preference
|
||||||
|
if err == nil {
|
||||||
|
preferenceValue.PreferenceValue = orgPreference.PreferenceValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the value from the user_preference table, if exists return this value else the one calculated in the above step
|
||||||
|
userPreference := PreferenceKV{}
|
||||||
|
|
||||||
|
query := `SELECT preference_id, preference_value FROM user_preference WHERE preference_id=$1 AND user_id=$2;`
|
||||||
|
err := db.Get(&userPreference, query, preferenceId, userId)
|
||||||
|
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in getting user preference values: %s", err.Error())}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
preferenceValue.PreferenceValue = userPreference.PreferenceValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PreferenceKV{
|
||||||
|
PreferenceId: preferenceValue.PreferenceId,
|
||||||
|
PreferenceValue: preference.SanitizeValue(preferenceValue.PreferenceValue),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUserPreference(ctx context.Context, preferenceId string, preferenceValue interface{}, userId string) (*PreferenceKV, *model.ApiError) {
|
||||||
|
// check if the preference id is valid
|
||||||
|
preference, seen := preferenceMap[preferenceId]
|
||||||
|
if !seen {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("no such preferenceId exists: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the preference is enabled at user scope
|
||||||
|
isPreferenceEnabledAtUserScope := preference.IsEnabledForScope(UserAllowedScope)
|
||||||
|
if !isPreferenceEnabledAtUserScope {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: fmt.Errorf("preference is not enabled at user scope: %s", preferenceId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := preference.IsValidValue(preferenceValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// update the user preference values
|
||||||
|
query := `INSERT INTO user_preference(preference_id,preference_value,user_id) VALUES($1,$2,$3)
|
||||||
|
ON CONFLICT(preference_id,user_id) DO
|
||||||
|
UPDATE SET preference_value= $2 WHERE preference_id=$1 AND user_id=$3;`
|
||||||
|
|
||||||
|
_, dberrr := db.Exec(query, preferenceId, preferenceValue, userId)
|
||||||
|
|
||||||
|
if dberrr != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in setting the preference value: %s", dberrr.Error())}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PreferenceKV{
|
||||||
|
PreferenceId: preferenceId,
|
||||||
|
PreferenceValue: preferenceValue,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllUserPreferences(ctx context.Context, orgId string, userId string) (*[]AllPreferences, *model.ApiError) {
|
||||||
|
allUserPreferences := []AllPreferences{}
|
||||||
|
|
||||||
|
// fetch all the org preference values stored in org_preference table
|
||||||
|
orgPreferenceValues := []PreferenceKV{}
|
||||||
|
|
||||||
|
query := `SELECT preference_id,preference_value FROM org_preference WHERE org_id=$1;`
|
||||||
|
err := db.Select(&orgPreferenceValues, query, orgId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in getting all org preference values: %s", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a map of key vs values from the above response
|
||||||
|
preferenceOrgValueMap := map[string]interface{}{}
|
||||||
|
|
||||||
|
for _, preferenceValue := range orgPreferenceValues {
|
||||||
|
preferenceOrgValueMap[preferenceValue.PreferenceId] = preferenceValue.PreferenceValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch all the user preference values stored in user_preference table
|
||||||
|
userPreferenceValues := []PreferenceKV{}
|
||||||
|
|
||||||
|
query = `SELECT preference_id,preference_value FROM user_preference WHERE user_id=$1;`
|
||||||
|
err = db.Select(&userPreferenceValues, query, userId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("error in getting all user preference values: %s", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a map of key vs values from the above response
|
||||||
|
preferenceUserValueMap := map[string]interface{}{}
|
||||||
|
|
||||||
|
for _, preferenceValue := range userPreferenceValues {
|
||||||
|
preferenceUserValueMap[preferenceValue.PreferenceId] = preferenceValue.PreferenceValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// update in the above filtered list wherver value present in the map
|
||||||
|
for _, preference := range preferenceMap {
|
||||||
|
isEnabledForUserScope := preference.IsEnabledForScope(UserAllowedScope)
|
||||||
|
|
||||||
|
if isEnabledForUserScope {
|
||||||
|
preferenceWithValue := AllPreferences{}
|
||||||
|
preferenceWithValue.Key = preference.Key
|
||||||
|
preferenceWithValue.Name = preference.Name
|
||||||
|
preferenceWithValue.Description = preference.Description
|
||||||
|
preferenceWithValue.AllowedScopes = preference.AllowedScopes
|
||||||
|
preferenceWithValue.AllowedValues = preference.AllowedValues
|
||||||
|
preferenceWithValue.DefaultValue = preference.DefaultValue
|
||||||
|
preferenceWithValue.Range = preference.Range
|
||||||
|
preferenceWithValue.ValueType = preference.ValueType
|
||||||
|
preferenceWithValue.IsDiscreteValues = preference.IsDiscreteValues
|
||||||
|
preferenceWithValue.Value = preference.DefaultValue
|
||||||
|
|
||||||
|
isEnabledForOrgScope := preference.IsEnabledForScope(OrgAllowedScope)
|
||||||
|
if isEnabledForOrgScope {
|
||||||
|
value, seen := preferenceOrgValueMap[preference.Key]
|
||||||
|
if seen {
|
||||||
|
preferenceWithValue.Value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value, seen := preferenceUserValueMap[preference.Key]
|
||||||
|
|
||||||
|
if seen {
|
||||||
|
preferenceWithValue.Value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
preferenceWithValue.Value = preference.SanitizeValue(preferenceWithValue.Value)
|
||||||
|
allUserPreferences = append(allUserPreferences, preferenceWithValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &allUserPreferences, nil
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -27,6 +28,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||||
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
|
||||||
@ -94,6 +96,10 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := preferences.InitDB(constants.RELATIONAL_DATASOURCE_PATH); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
localDB, err := dashboards.InitDB(constants.RELATIONAL_DATASOURCE_PATH)
|
localDB, err := dashboards.InitDB(constants.RELATIONAL_DATASOURCE_PATH)
|
||||||
explorer.InitWithDSN(constants.RELATIONAL_DATASOURCE_PATH)
|
explorer.InitWithDSN(constants.RELATIONAL_DATASOURCE_PATH)
|
||||||
|
|
||||||
@ -268,7 +274,21 @@ func (s *Server) createPublicServer(api *APIHandler) (*http.Server, error) {
|
|||||||
r.Use(s.analyticsMiddleware)
|
r.Use(s.analyticsMiddleware)
|
||||||
r.Use(loggingMiddleware)
|
r.Use(loggingMiddleware)
|
||||||
|
|
||||||
am := NewAuthMiddleware(auth.GetUserFromRequest)
|
// add auth middleware
|
||||||
|
getUserFromRequest := func(r *http.Request) (*model.UserPayload, error) {
|
||||||
|
user, err := auth.GetUserFromRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.User.OrgId == "" {
|
||||||
|
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
am := NewAuthMiddleware(getUserFromRequest)
|
||||||
|
|
||||||
api.RegisterRoutes(r, am)
|
api.RegisterRoutes(r, am)
|
||||||
api.RegisterLogsRoutes(r, am)
|
api.RegisterLogsRoutes(r, am)
|
||||||
|
@ -467,6 +467,10 @@ func authenticateLogin(ctx context.Context, req *model.LoginRequest) (*model.Use
|
|||||||
return nil, errors.Wrap(err, "failed to validate refresh token")
|
return nil, errors.Wrap(err, "failed to validate refresh token")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.OrgId == "" {
|
||||||
|
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
||||||
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,6 +509,7 @@ func GenerateJWTForUser(user *model.User) (model.UserJwtObject, error) {
|
|||||||
"gid": user.GroupId,
|
"gid": user.GroupId,
|
||||||
"email": user.Email,
|
"email": user.Email,
|
||||||
"exp": j.AccessJwtExpiry,
|
"exp": j.AccessJwtExpiry,
|
||||||
|
"orgId": user.OrgId,
|
||||||
})
|
})
|
||||||
|
|
||||||
j.AccessJwt, err = token.SignedString([]byte(JwtSecret))
|
j.AccessJwt, err = token.SignedString([]byte(JwtSecret))
|
||||||
@ -518,6 +523,7 @@ func GenerateJWTForUser(user *model.User) (model.UserJwtObject, error) {
|
|||||||
"gid": user.GroupId,
|
"gid": user.GroupId,
|
||||||
"email": user.Email,
|
"email": user.Email,
|
||||||
"exp": j.RefreshJwtExpiry,
|
"exp": j.RefreshJwtExpiry,
|
||||||
|
"orgId": user.OrgId,
|
||||||
})
|
})
|
||||||
|
|
||||||
j.RefreshJwt, err = token.SignedString([]byte(JwtSecret))
|
j.RefreshJwt, err = token.SignedString([]byte(JwtSecret))
|
||||||
|
@ -20,6 +20,8 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
|
func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
|
||||||
|
// TODO[@vikrantgupta25] : to update this to the claims check function for better integrity of JWT
|
||||||
|
// reference - https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Parser.ParseWithClaims
|
||||||
token, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, errors.Errorf("unknown signing algo: %v", token.Header["alg"])
|
return nil, errors.Errorf("unknown signing algo: %v", token.Header["alg"])
|
||||||
@ -35,6 +37,7 @@ func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
|
|||||||
if !ok || !token.Valid {
|
if !ok || !token.Valid {
|
||||||
return nil, errors.Errorf("Not a valid jwt claim")
|
return nil, errors.Errorf("Not a valid jwt claim")
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +50,18 @@ func validateUser(tok string) (*model.UserPayload, error) {
|
|||||||
if !claims.VerifyExpiresAt(now, true) {
|
if !claims.VerifyExpiresAt(now, true) {
|
||||||
return nil, model.ErrorTokenExpired
|
return nil, model.ErrorTokenExpired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var orgId string
|
||||||
|
if claims["orgId"] != nil {
|
||||||
|
orgId = claims["orgId"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
return &model.UserPayload{
|
return &model.UserPayload{
|
||||||
User: model.User{
|
User: model.User{
|
||||||
Id: claims["id"].(string),
|
Id: claims["id"].(string),
|
||||||
GroupId: claims["gid"].(string),
|
GroupId: claims["gid"].(string),
|
||||||
Email: claims["email"].(string),
|
Email: claims["email"].(string),
|
||||||
|
OrgId: orgId,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user