2025-03-06 15:39:45 +05:30
|
|
|
package types
|
|
|
|
|
|
|
|
|
|
import (
|
2025-05-14 23:12:55 +05:30
|
|
|
"context"
|
2025-09-04 17:22:28 +05:30
|
|
|
"encoding/json"
|
2025-05-25 14:16:42 +05:30
|
|
|
"net/url"
|
2025-05-14 23:12:55 +05:30
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/SigNoz/signoz/pkg/errors"
|
|
|
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
2025-05-25 14:16:42 +05:30
|
|
|
"github.com/google/uuid"
|
2025-03-06 15:39:45 +05:30
|
|
|
"github.com/uptrace/bun"
|
|
|
|
|
)
|
|
|
|
|
|
2025-05-14 23:12:55 +05:30
|
|
|
var (
|
|
|
|
|
ErrUserAlreadyExists = errors.MustNewCode("user_already_exists")
|
|
|
|
|
ErrPasswordAlreadyExists = errors.MustNewCode("password_already_exists")
|
|
|
|
|
ErrUserNotFound = errors.MustNewCode("user_not_found")
|
|
|
|
|
ErrResetPasswordTokenAlreadyExists = errors.MustNewCode("reset_password_token_already_exists")
|
|
|
|
|
ErrPasswordNotFound = errors.MustNewCode("password_not_found")
|
|
|
|
|
ErrResetPasswordTokenNotFound = errors.MustNewCode("reset_password_token_not_found")
|
2025-05-21 17:21:19 +05:30
|
|
|
ErrAPIKeyAlreadyExists = errors.MustNewCode("api_key_already_exists")
|
|
|
|
|
ErrAPIKeyNotFound = errors.MustNewCode("api_key_not_found")
|
2025-05-14 23:12:55 +05:30
|
|
|
)
|
|
|
|
|
|
2025-03-06 15:39:45 +05:30
|
|
|
type GettableUser struct {
|
|
|
|
|
User
|
|
|
|
|
Organization string `json:"organization"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
|
bun.BaseModel `bun:"table:users"`
|
|
|
|
|
|
2025-05-14 23:12:55 +05:30
|
|
|
Identifiable
|
2025-03-06 15:39:45 +05:30
|
|
|
TimeAuditable
|
2025-05-14 23:12:55 +05:30
|
|
|
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
|
|
|
|
|
Email string `bun:"email,type:text,notnull,unique:org_email" json:"email"`
|
|
|
|
|
Role string `bun:"role,type:text,notnull" json:"role"`
|
2025-05-21 17:21:19 +05:30
|
|
|
OrgID string `bun:"org_id,type:text,notnull,unique:org_email" json:"orgId"`
|
2025-05-14 23:12:55 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewUser(displayName string, email string, role string, orgID string) (*User, error) {
|
|
|
|
|
if email == "" {
|
|
|
|
|
return nil, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "email is required")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if role == "" {
|
|
|
|
|
return nil, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "role is required")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if orgID == "" {
|
|
|
|
|
return nil, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "orgID is required")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &User{
|
|
|
|
|
Identifiable: Identifiable{
|
|
|
|
|
ID: valuer.GenerateUUID(),
|
|
|
|
|
},
|
|
|
|
|
TimeAuditable: TimeAuditable{
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
},
|
|
|
|
|
DisplayName: displayName,
|
|
|
|
|
Email: email,
|
|
|
|
|
Role: role,
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type PostableRegisterOrgAndAdmin struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
OrgID string `json:"orgId"`
|
|
|
|
|
OrgDisplayName string `json:"orgDisplayName"`
|
|
|
|
|
OrgName string `json:"orgName"`
|
|
|
|
|
Email string `json:"email"`
|
2025-09-04 17:22:28 +05:30
|
|
|
Password string `json:"password"`
|
2025-05-14 23:12:55 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type PostableAcceptInvite struct {
|
|
|
|
|
DisplayName string `json:"displayName"`
|
|
|
|
|
InviteToken string `json:"token"`
|
|
|
|
|
Password string `json:"password"`
|
|
|
|
|
|
|
|
|
|
// reference URL to track where the register request is coming from
|
|
|
|
|
SourceURL string `json:"sourceUrl"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type PostableLoginRequest struct {
|
|
|
|
|
OrgID string `json:"orgId"`
|
|
|
|
|
Email string `json:"email"`
|
|
|
|
|
Password string `json:"password"`
|
|
|
|
|
RefreshToken string `json:"refreshToken"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type GettableUserJwt struct {
|
|
|
|
|
AccessJwt string `json:"accessJwt"`
|
|
|
|
|
AccessJwtExpiry int64 `json:"accessJwtExpiry"`
|
|
|
|
|
RefreshJwt string `json:"refreshJwt"`
|
|
|
|
|
RefreshJwtExpiry int64 `json:"refreshJwtExpiry"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type GettableLoginResponse struct {
|
|
|
|
|
GettableUserJwt
|
|
|
|
|
UserID string `json:"userId"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type GettableLoginPrecheck struct {
|
|
|
|
|
SSO bool `json:"sso"`
|
|
|
|
|
SSOUrl string `json:"ssoUrl"`
|
|
|
|
|
CanSelfRegister bool `json:"canSelfRegister"`
|
|
|
|
|
IsUser bool `json:"isUser"`
|
|
|
|
|
SSOError string `json:"ssoError"`
|
|
|
|
|
SelectOrg bool `json:"selectOrg"`
|
|
|
|
|
Orgs []string `json:"orgs"`
|
2025-03-06 15:39:45 +05:30
|
|
|
}
|
2025-06-18 01:54:55 +05:30
|
|
|
|
|
|
|
|
func NewTraitsFromUser(user *User) map[string]any {
|
|
|
|
|
return map[string]any{
|
|
|
|
|
"name": user.DisplayName,
|
|
|
|
|
"role": user.Role,
|
|
|
|
|
"email": user.Email,
|
|
|
|
|
"display_name": user.DisplayName,
|
|
|
|
|
"created_at": user.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-04 17:22:28 +05:30
|
|
|
|
|
|
|
|
func (request *PostableAcceptInvite) UnmarshalJSON(data []byte) error {
|
|
|
|
|
type Alias PostableAcceptInvite
|
|
|
|
|
|
|
|
|
|
var temp Alias
|
|
|
|
|
if err := json.Unmarshal(data, &temp); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if temp.InviteToken == "" {
|
|
|
|
|
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "invite token is required")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !IsPasswordValid(temp.Password) {
|
|
|
|
|
return ErrInvalidPassword
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*request = PostableAcceptInvite(temp)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (request *PostableRegisterOrgAndAdmin) UnmarshalJSON(data []byte) error {
|
|
|
|
|
type Alias PostableRegisterOrgAndAdmin
|
|
|
|
|
|
|
|
|
|
var temp Alias
|
|
|
|
|
if err := json.Unmarshal(data, &temp); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if temp.Email == "" {
|
|
|
|
|
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "email is required")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !IsPasswordValid(temp.Password) {
|
|
|
|
|
return ErrInvalidPassword
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*request = PostableRegisterOrgAndAdmin(temp)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type UserStore interface {
|
|
|
|
|
// invite
|
|
|
|
|
CreateBulkInvite(ctx context.Context, invites []*Invite) error
|
|
|
|
|
ListInvite(ctx context.Context, orgID string) ([]*Invite, error)
|
|
|
|
|
DeleteInvite(ctx context.Context, orgID string, id valuer.UUID) error
|
|
|
|
|
GetInviteByToken(ctx context.Context, token string) (*GettableInvite, error)
|
|
|
|
|
GetInviteByEmailInOrg(ctx context.Context, orgID string, email string) (*Invite, error)
|
|
|
|
|
|
|
|
|
|
// Creates a user.
|
|
|
|
|
CreateUser(ctx context.Context, user *User) error
|
|
|
|
|
GetUserByID(ctx context.Context, orgID string, id string) (*GettableUser, error)
|
|
|
|
|
GetUserByEmailInOrg(ctx context.Context, orgID string, email string) (*GettableUser, error)
|
|
|
|
|
GetUsersByEmail(ctx context.Context, email string) ([]*GettableUser, error)
|
|
|
|
|
GetUsersByRoleInOrg(ctx context.Context, orgID string, role Role) ([]*GettableUser, error)
|
|
|
|
|
ListUsers(ctx context.Context, orgID string) ([]*GettableUser, error)
|
|
|
|
|
UpdateUser(ctx context.Context, orgID string, id string, user *User) (*User, error)
|
|
|
|
|
DeleteUser(ctx context.Context, orgID string, id string) error
|
|
|
|
|
|
|
|
|
|
// Creates a password.
|
|
|
|
|
CreatePassword(ctx context.Context, password *FactorPassword) error
|
|
|
|
|
CreateResetPasswordToken(ctx context.Context, resetPasswordRequest *ResetPasswordToken) error
|
|
|
|
|
GetPassword(ctx context.Context, id valuer.UUID) (*FactorPassword, error)
|
|
|
|
|
GetPasswordByUserID(ctx context.Context, userID valuer.UUID) (*FactorPassword, error)
|
|
|
|
|
GetResetPasswordToken(ctx context.Context, token string) (*ResetPasswordToken, error)
|
|
|
|
|
GetResetPasswordTokenByPasswordID(ctx context.Context, passwordID valuer.UUID) (*ResetPasswordToken, error)
|
|
|
|
|
UpdatePassword(ctx context.Context, password *FactorPassword) error
|
|
|
|
|
|
|
|
|
|
// Auth Domain
|
|
|
|
|
GetDomainByName(ctx context.Context, name string) (*StorableOrgDomain, error)
|
|
|
|
|
// org domain (auth domains) CRUD ops
|
|
|
|
|
GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*GettableOrgDomain, error)
|
|
|
|
|
ListDomains(ctx context.Context, orgId valuer.UUID) ([]*GettableOrgDomain, error)
|
|
|
|
|
GetDomain(ctx context.Context, id uuid.UUID) (*GettableOrgDomain, error)
|
|
|
|
|
CreateDomain(ctx context.Context, d *GettableOrgDomain) error
|
|
|
|
|
UpdateDomain(ctx context.Context, domain *GettableOrgDomain) error
|
|
|
|
|
DeleteDomain(ctx context.Context, id uuid.UUID) error
|
|
|
|
|
|
|
|
|
|
// Temporary func for SSO
|
|
|
|
|
GetDefaultOrgID(ctx context.Context) (string, error)
|
|
|
|
|
|
|
|
|
|
// API KEY
|
|
|
|
|
CreateAPIKey(ctx context.Context, apiKey *StorableAPIKey) error
|
|
|
|
|
UpdateAPIKey(ctx context.Context, id valuer.UUID, apiKey *StorableAPIKey, updaterID valuer.UUID) error
|
|
|
|
|
ListAPIKeys(ctx context.Context, orgID valuer.UUID) ([]*StorableAPIKeyUser, error)
|
|
|
|
|
RevokeAPIKey(ctx context.Context, id valuer.UUID, revokedByUserID valuer.UUID) error
|
|
|
|
|
GetAPIKey(ctx context.Context, orgID, id valuer.UUID) (*StorableAPIKeyUser, error)
|
|
|
|
|
CountAPIKeyByOrgID(ctx context.Context, orgID valuer.UUID) (int64, error)
|
|
|
|
|
|
|
|
|
|
CountByOrgID(ctx context.Context, orgID valuer.UUID) (int64, error)
|
|
|
|
|
|
|
|
|
|
// Transaction
|
|
|
|
|
RunInTx(ctx context.Context, cb func(ctx context.Context) error) error
|
|
|
|
|
}
|