mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
9c2608659f
Signed-off-by: Felix Gateru <felix.gateru@gmail.com> Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
555 lines
14 KiB
Go
555 lines
14 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
|
|
apiutil "github.com/absmach/supermq/api/http/util"
|
|
"github.com/absmach/supermq/pkg/authn"
|
|
"github.com/absmach/supermq/pkg/errors"
|
|
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
|
"github.com/absmach/supermq/users"
|
|
"github.com/go-kit/kit/endpoint"
|
|
)
|
|
|
|
func registrationEndpoint(svc users.Service, selfRegister bool) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(createUserReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
session := authn.Session{}
|
|
|
|
var ok bool
|
|
if !selfRegister {
|
|
session, ok = ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
}
|
|
|
|
user, err := svc.Register(ctx, session, req.User, selfRegister)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return createUserRes{
|
|
User: user,
|
|
created: true,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func sendVerificationEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
_ = request.(sendVerificationReq)
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
if err := svc.SendVerification(ctx, session); err != nil {
|
|
return sendVerificationRes{}, err
|
|
}
|
|
|
|
return sendVerificationRes{}, nil
|
|
}
|
|
}
|
|
|
|
func verifyEmailEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(verifyEmailReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
if _, err := svc.VerifyEmail(ctx, req.token); err != nil {
|
|
return verifyEmailRes{}, err
|
|
}
|
|
|
|
return verifyEmailRes{}, nil
|
|
}
|
|
}
|
|
|
|
func viewEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(viewUserReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
user, err := svc.View(ctx, session, req.id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return viewUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func viewProfileEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
client, err := svc.ViewProfile(ctx, session)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return viewUserRes{User: client}, nil
|
|
}
|
|
}
|
|
|
|
func listUsersEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(listUsersReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
pm := users.Page{
|
|
Status: req.status,
|
|
Offset: req.offset,
|
|
Limit: req.limit,
|
|
OnlyTotal: req.onlyTotal,
|
|
Username: req.userName,
|
|
Tags: req.tags,
|
|
Metadata: req.metadata,
|
|
FirstName: req.firstName,
|
|
LastName: req.lastName,
|
|
Email: req.email,
|
|
Order: req.order,
|
|
Dir: req.dir,
|
|
Id: req.id,
|
|
}
|
|
|
|
page, err := svc.ListUsers(ctx, session, pm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res := usersPageRes{
|
|
pageRes: pageRes{
|
|
Total: page.Total,
|
|
Offset: page.Offset,
|
|
Limit: page.Limit,
|
|
},
|
|
Users: []viewUserRes{},
|
|
}
|
|
for _, user := range page.Users {
|
|
res.Users = append(res.Users, viewUserRes{User: user})
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
func searchUsersEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(searchUsersReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
pm := users.Page{
|
|
Offset: req.Offset,
|
|
Limit: req.Limit,
|
|
Username: req.Username,
|
|
FirstName: req.FirstName,
|
|
LastName: req.LastName,
|
|
Id: req.Id,
|
|
Order: req.Order,
|
|
Dir: req.Dir,
|
|
}
|
|
page, err := svc.SearchUsers(ctx, pm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res := usersPageRes{
|
|
pageRes: pageRes{
|
|
Total: page.Total,
|
|
Offset: page.Offset,
|
|
Limit: page.Limit,
|
|
},
|
|
Users: []viewUserRes{},
|
|
}
|
|
for _, user := range page.Users {
|
|
res.Users = append(res.Users, viewUserRes{User: user})
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
func updateEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateUserReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
usr := users.UserReq{
|
|
FirstName: req.FirstName,
|
|
LastName: req.LastName,
|
|
Metadata: req.Metadata,
|
|
PrivateMetadata: req.PrivateMetadata,
|
|
}
|
|
|
|
user, err := svc.Update(ctx, session, req.id, usr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func updateTagsEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateUserTagsReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
usr := users.UserReq{
|
|
Tags: req.Tags,
|
|
}
|
|
|
|
user, err := svc.UpdateTags(ctx, session, req.id, usr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func updateEmailEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateEmailReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
user, err := svc.UpdateEmail(ctx, session, req.id, req.Email)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
// Password reset request endpoint.
|
|
// When successful password reset link is generated.
|
|
// Link is generated using SMQ_TOKEN_RESET_ENDPOINT env.
|
|
// and value from Referer header for host.
|
|
// {Referer}+{SMQ_TOKEN_RESET_ENDPOINT}+{token=TOKEN}
|
|
// http://supermq.com/reset-request?token=xxxxxxxxxxx.
|
|
// Email with a link is being sent to the user.
|
|
// When user clicks on a link it should get the ui with form to
|
|
// enter new password, when form is submitted token and new password
|
|
// must be sent as PUT request to 'password/reset' passwordResetEndpoint.
|
|
func passwordResetRequestEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(passResetReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
if err := svc.SendPasswordReset(ctx, req.Email); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return passResetReqRes{Msg: MailSent}, nil
|
|
}
|
|
}
|
|
|
|
// This is endpoint that actually sets new password in password reset flow.
|
|
// When user clicks on a link in email finally ends on this endpoint as explained in
|
|
// the comment above.
|
|
func passwordResetEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(resetTokenReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
if err := svc.ResetSecret(ctx, session, req.Password); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return passChangeRes{}, nil
|
|
}
|
|
}
|
|
|
|
func updateSecretEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateUserSecretReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
user, err := svc.UpdateSecret(ctx, session, req.OldSecret, req.NewSecret)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func updateUsernameEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateUsernameReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthorization
|
|
}
|
|
|
|
user, err := svc.UpdateUsername(ctx, session, req.id, req.Username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func updateProfilePictureEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateProfilePictureReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
usr := users.UserReq{
|
|
ProfilePicture: req.ProfilePicture,
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthorization
|
|
}
|
|
|
|
user, err := svc.UpdateProfilePicture(ctx, session, req.id, usr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func updateRoleEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(updateUserRoleReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
user := users.User{
|
|
ID: req.id,
|
|
Role: req.role,
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
user, err := svc.UpdateRole(ctx, session, user)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return updateUserRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func issueTokenEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(loginUserReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
token, err := svc.IssueToken(ctx, req.Username, req.Password, req.Description)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tokenRes{
|
|
AccessToken: token.GetAccessToken(),
|
|
RefreshToken: token.GetRefreshToken(),
|
|
AccessType: token.GetAccessType(),
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func refreshTokenEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(tokenReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
token, err := svc.RefreshToken(ctx, session, req.RefreshToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tokenRes{
|
|
AccessToken: token.GetAccessToken(),
|
|
RefreshToken: token.GetRefreshToken(),
|
|
AccessType: token.GetAccessType(),
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func revokeRefreshTokenEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(revokeTokenReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
err := svc.RevokeRefreshToken(ctx, session, req.TokenID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return revokeRes{}, nil
|
|
}
|
|
}
|
|
|
|
func listActiveRefreshTokensEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
refreshTokens, err := svc.ListActiveRefreshTokens(ctx, session)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return listRefreshTokensRes{RefreshTokens: refreshTokens.GetRefreshTokens()}, nil
|
|
}
|
|
}
|
|
|
|
func enableEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(changeUserStatusReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
user, err := svc.Enable(ctx, session, req.id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return changeUserStatusRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func disableEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(changeUserStatusReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
user, err := svc.Disable(ctx, session, req.id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return changeUserStatusRes{User: user}, nil
|
|
}
|
|
}
|
|
|
|
func deleteEndpoint(svc users.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request any) (any, error) {
|
|
req := request.(changeUserStatusReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
|
}
|
|
|
|
session, ok := ctx.Value(authn.SessionKey).(authn.Session)
|
|
if !ok {
|
|
return nil, svcerr.ErrAuthentication
|
|
}
|
|
|
|
if err := svc.Delete(ctx, session, req.id); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return deleteUserRes{true}, nil
|
|
}
|
|
}
|