Files
magistrala/users/users.go
T
Dušan Borovčanin 61d0427898 NOISSUE - Rename to Magistrala (#3427)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 15:23:42 +02:00

289 lines
11 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package users
import (
"context"
"net/mail"
"strings"
"time"
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
"github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/pkg/postgres"
)
type User struct {
ID string `json:"id"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Tags []string `json:"tags,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
PrivateMetadata Metadata `json:"private_metadata,omitempty"`
Status Status `json:"status"` // 0 for enabled, 1 for disabled
Role Role `json:"role"` // 0 for normal user, 1 for admin
ProfilePicture string `json:"profile_picture,omitempty"` // profile picture URL
Credentials Credentials `json:"credentials,omitempty"`
Permissions []string `json:"permissions,omitempty"`
Email string `json:"email,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
VerifiedAt time.Time `json:"verified_at,omitempty"`
AuthProvider string `json:"auth_provider,omitempty"`
}
type Credentials struct {
Username string `json:"username,omitempty"` // username or profile name
Secret string `json:"secret,omitempty"` // password or token
}
type UsersPage struct {
Page
Users []User
}
// Metadata represents arbitrary JSON.
type Metadata map[string]any
type UserReq struct {
FirstName *string `json:"first_name,omitempty"`
LastName *string `json:"last_name,omitempty"`
Metadata *Metadata `json:"metadata,omitempty"`
PrivateMetadata *Metadata `json:"private_metadata,omitempty"`
Tags *[]string `json:"tags,omitempty"`
ProfilePicture *string `json:"profile_picture,omitempty"`
UpdatedBy *string `json:"updated_by,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// MembersPage contains page related metadata as well as list of members that
// belong to this page.
type MembersPage struct {
Page
Members []User
}
// UserRepository struct implements the Repository interface.
type UserRepository struct {
DB postgres.Database
}
type Repository interface {
// RetrieveByID retrieves user by their unique ID.
RetrieveByID(ctx context.Context, id string) (User, error)
// RetrieveAll retrieves all users.
RetrieveAll(ctx context.Context, pm Page) (UsersPage, error)
// RetrieveByEmail retrieves user by its unique credentials.
RetrieveByEmail(ctx context.Context, email string) (User, error)
// RetrieveByUsername retrieves user by its unique credentials.
RetrieveByUsername(ctx context.Context, username string) (User, error)
// Update updates the user name and metadata.
Update(ctx context.Context, id string, user UserReq) (User, error)
// UpdateUsername updates the User's names.
UpdateUsername(ctx context.Context, user User) (User, error)
// UpdateSecret updates secret for user with given email.
UpdateSecret(ctx context.Context, user User) (User, error)
// UpdateEmail updates email for user with given id.
UpdateEmail(ctx context.Context, user User) (User, error)
// UpdateRole updates role for user with given id.
UpdateRole(ctx context.Context, user User) (User, error)
// UpdateVerifiedAt updates the verified time for user with given id.
UpdateVerifiedAt(ctx context.Context, user User) (User, error)
// ChangeStatus changes user status to enabled or disabled
ChangeStatus(ctx context.Context, user User) (User, error)
// Delete deletes user with given id
Delete(ctx context.Context, id string) error
// Searchusers retrieves users based on search criteria.
SearchUsers(ctx context.Context, pm Page) (UsersPage, error)
// RetrieveAllByIDs retrieves for given user IDs .
RetrieveAllByIDs(ctx context.Context, pm Page) (UsersPage, error)
CheckSuperAdmin(ctx context.Context, adminID string) error
// Save persists the user account. A non-nil error is returned to indicate
// operation failure.
Save(ctx context.Context, user User) (User, error)
// AddUserVerification adds new verification for given user id and email
AddUserVerification(ctx context.Context, uv UserVerification) error
// RetrieveVerificationToken retrieves verification token of given user id and email.
RetrieveUserVerification(ctx context.Context, userID, email string) (UserVerification, error)
// UpdateUserVerificationDetails update verification details for the given user id and email.
UpdateUserVerification(ctx context.Context, uv UserVerification) error
}
// Validate returns an error if user representation is invalid.
func (u User) Validate() error {
if !isEmail(u.Email) {
return errors.ErrMalformedEntity
}
return nil
}
func isEmail(email string) bool {
_, err := mail.ParseAddress(email)
return err == nil
}
type Operator uint8
const (
OrOp Operator = iota
AndOp
)
type TagsQuery struct {
Elements []string
Operator Operator
}
func ToTagsQuery(s string) TagsQuery {
switch {
case strings.Contains(s, "+"):
elements := strings.Split(s, "+")
for i := range elements {
elements[i] = strings.TrimSpace(elements[i])
}
return TagsQuery{Elements: elements, Operator: AndOp}
case strings.Contains(s, ","):
elements := strings.Split(s, ",")
for i := range elements {
elements[i] = strings.TrimSpace(elements[i])
}
return TagsQuery{Elements: elements, Operator: OrOp}
default:
return TagsQuery{Elements: []string{s}, Operator: OrOp}
}
}
// Page contains page metadata that helps navigation.
type Page struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
OnlyTotal bool `json:"only_total"`
Id string `json:"id,omitempty"`
Order string `json:"order,omitempty"`
Dir string `json:"dir,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Domain string `json:"domain,omitempty"`
Tags TagsQuery `json:"tag,omitempty"`
Permission string `json:"permission,omitempty"`
Status Status `json:"status,omitempty"`
IDs []string `json:"ids,omitempty"`
Role Role `json:"-"`
ListPerms bool `json:"-"`
Username string `json:"username,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Email string `json:"email,omitempty"`
Verified bool `json:"verified,omitempty"`
CreatedFrom time.Time `json:"created_from,omitempty"`
CreatedTo time.Time `json:"created_to,omitempty"`
}
// Service specifies an API that must be fullfiled by the domain service
// implementation, and all of its decorators (e.g. logging & metrics).
type Service interface {
// Register creates new user. In case of the failed registration, a
// non-nil error value is returned.
Register(ctx context.Context, session authn.Session, user User, selfRegister bool) (User, error)
// SendVerification sends a verification email to the user.
SendVerification(ctx context.Context, session authn.Session) error
// VerifyEmail verifies user's email using the verification token.
VerifyEmail(ctx context.Context, verificationToken string) (User, error)
// View retrieves user info for a given user ID and an authorized token.
View(ctx context.Context, session authn.Session, id string) (User, error)
// ViewProfile retrieves user info for a given token.
ViewProfile(ctx context.Context, session authn.Session) (User, error)
// ListUsers retrieves users list for a valid auth token.
ListUsers(ctx context.Context, session authn.Session, pm Page) (UsersPage, error)
// SearchUsers searches for users with provided filters for a valid auth token.
SearchUsers(ctx context.Context, pm Page) (UsersPage, error)
// Update updates the user's name and metadata.
Update(ctx context.Context, session authn.Session, id string, user UserReq) (User, error)
// UpdateTags updates the user's tags.
UpdateTags(ctx context.Context, session authn.Session, id string, user UserReq) (User, error)
// UpdateEmail updates the user's email.
UpdateEmail(ctx context.Context, session authn.Session, id, email string) (User, error)
// UpdateUsername updates the user's username.
UpdateUsername(ctx context.Context, session authn.Session, id, username string) (User, error)
// UpdateProfilePicture updates the user's profile picture.
UpdateProfilePicture(ctx context.Context, session authn.Session, id string, usr UserReq) (User, error)
// SendPasswordReset generates reset password link and sends it to the user via email.
SendPasswordReset(ctx context.Context, email string) error
// UpdateSecret updates the user's secret.
UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (User, error)
// ResetSecret change users secret in reset flow.
// token can be authentication token or secret reset token.
ResetSecret(ctx context.Context, session authn.Session, secret string) error
// UpdateRole updates the user's Role.
UpdateRole(ctx context.Context, session authn.Session, user User) (User, error)
// Enable logically enables the user identified with the provided ID.
Enable(ctx context.Context, session authn.Session, id string) (User, error)
// Disable logically disables the user identified with the provided ID.
Disable(ctx context.Context, session authn.Session, id string) (User, error)
// Delete deletes user with given ID.
Delete(ctx context.Context, session authn.Session, id string) error
// Identify returns the user id from the given token.
Identify(ctx context.Context, session authn.Session) (string, error)
// IssueToken issues a new access and refresh token when provided with either a username or email.
IssueToken(ctx context.Context, identity, secret, description string) (*grpcTokenV1.Token, error)
// RefreshToken refreshes expired access tokens.
// After an access token expires, the refresh token is used to get
// a new pair of access and refresh tokens.
RefreshToken(ctx context.Context, session authn.Session, refreshToken string) (*grpcTokenV1.Token, error)
// RevokeRefreshToken revokes a refresh token by its ID.
RevokeRefreshToken(ctx context.Context, session authn.Session, tokenID string) error
// ListActiveRefreshTokens lists all active refresh tokens for the authenticated user.
ListActiveRefreshTokens(ctx context.Context, session authn.Session) (*grpcTokenV1.ListUserRefreshTokensRes, error)
// OAuthCallback handles the callback from any supported OAuth provider.
// It processes the OAuth tokens and either signs in or signs up the user based on the provided state.
OAuthCallback(ctx context.Context, user User) (User, error)
// OAuthAddUserPolicy adds a policy to the user for an OAuth request.
OAuthAddUserPolicy(ctx context.Context, user User) error
}