github.com/litesolutions/justifay-api@v1.0.0-2.0.20220707114139-46f28a909481/server/user.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"regexp"
     8  	"strings"
     9  	"time"
    10  
    11  	uuid "github.com/google/uuid"
    12  	uuidpkg "github.com/litesolutions/justifay-api/pkg/uuid"
    13  
    14  	"github.com/litesolutions/justifay-api/model"
    15  	pbUser "github.com/litesolutions/justifay-api/proto/user"
    16  )
    17  
    18  // AddUser adds a user to the DB
    19  func (s *Server) AddUser(ctx context.Context, user *pbUser.UserAddRequest) (*pbUser.UserRequest, error) {
    20  	err := checkRequiredAddAttributes(user)
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	err = s.db.NewSelect().Model(&model.User{}).
    26  		Where("username = ?", strings.ToLower(user.Username)).
    27  		Scan(ctx)
    28  
    29  	if err == nil {
    30  		return nil, errors.New("Email is taken")
    31  	}
    32  
    33  	var thisRole int32
    34  
    35  	// if requested role is not admin, grant it
    36  	if user.RoleId != nil && *user.RoleId >= int32(model.LabelRole) {
    37  		thisRole = *user.RoleId
    38  	} else {
    39  
    40  		defaultRole := new(model.Role)
    41  
    42  		err = s.db.NewSelect().
    43  			Model(defaultRole).
    44  			Where("is_default = TRUE").
    45  			Scan(ctx)
    46  
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  
    51  		thisRole = int32(defaultRole.ID)
    52  	}
    53  
    54  	// defaults to User Role, must update with greater privileges to change role
    55  	newUser := &model.User{
    56  		Username:               strings.ToLower(user.Username),
    57  		RoleID:                 thisRole,
    58  		FullName:               user.FullName,
    59  		FirstName:              user.FirstName,
    60  		LastName:               user.LastName,
    61  		Member:                 user.Member,
    62  		Country:                user.Country,
    63  		NewsletterNotification: user.NewsletterNotification,
    64  	}
    65  
    66  	newUser.ID = uuid.Must(uuid.NewRandom())
    67  
    68  	_, err = s.db.NewInsert().
    69  		Column(
    70  			"id",
    71  			"username",
    72  			"full_name",
    73  			"first_name",
    74  			"last_name",
    75  			"role_id",
    76  			"tenant_id",
    77  			"member",
    78  			"country",
    79  			"newsletter_notification",
    80  		).
    81  		Model(newUser).
    82  		Exec(ctx)
    83  
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	res := &pbUser.UserRequest{Id: newUser.ID.String()}
    89  
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	return res, nil
    95  }
    96  
    97  // GetUser Gets a user from the DB
    98  func (s *Server) GetUser(ctx context.Context, user *pbUser.UserRequest) (*pbUser.UserPublicResponse, error) {
    99  
   100  	u := new(model.User)
   101  
   102  	err := s.db.NewSelect().Model(u).
   103  		Column("user.*").
   104  		Where("id = ?", user.Id).
   105  		Scan(ctx)
   106  
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	return &pbUser.UserPublicResponse{
   112  		Id:             u.ID.String(),
   113  		Username:       u.Username,
   114  		FullName:       u.FullName,
   115  		FirstName:      u.FirstName,
   116  		LastName:       u.LastName,
   117  		Member:         u.Member,
   118  		Country:        u.Country,
   119  		FollowedGroups: uuidpkg.ConvertUUIDToStrArray(u.FollowedGroups),
   120  	}, nil
   121  }
   122  
   123  // GetUserRestricted intended for privileged roles only supplies more detailed, private info about user.
   124  func (s *Server) GetUserRestricted(ctx context.Context, user *pbUser.UserRequest) (*pbUser.UserPrivateResponse, error) {
   125  
   126  	u := new(model.User)
   127  
   128  	err := s.db.NewSelect().Model(u).
   129  		Column("user.*").
   130  		Where("id = ?", user.Id).
   131  		Scan(ctx)
   132  
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	return &pbUser.UserPrivateResponse{
   138  		Id:                     u.ID.String(),
   139  		Username:               u.Username,
   140  		FullName:               u.FullName,
   141  		FirstName:              u.FirstName,
   142  		LastName:               u.LastName,
   143  		Member:                 u.Member,
   144  		RoleId:                 u.RoleID,
   145  		TenantId:               u.TenantID,
   146  		FollowedGroups:         uuidpkg.ConvertUUIDToStrArray(u.FollowedGroups),
   147  		NewsletterNotification: u.NewsletterNotification,
   148  	}, nil
   149  }
   150  
   151  // DeleteUser Deletes a user from the DB
   152  func (s *Server) DeleteUser(ctx context.Context, user *pbUser.UserRequest) (*pbUser.Empty, error) {
   153  	u := new(model.User)
   154  
   155  	_, err := s.db.NewDelete().
   156  		Model(u).
   157  		Where("id = ?", user.Id).
   158  		Exec(ctx)
   159  
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return &pbUser.Empty{}, nil
   165  }
   166  
   167  // UpdateUser updates a users basic attributes
   168  func (s *Server) UpdateUser(ctx context.Context, UserUpdateRequest *pbUser.UserUpdateRequest) (*pbUser.Empty, error) {
   169  
   170  	var updatedUserValues = make(map[string]interface{})
   171  
   172  	if UserUpdateRequest.Username != nil {
   173  		updatedUserValues["username"] = *UserUpdateRequest.Username
   174  		re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
   175  		if !re.MatchString(*UserUpdateRequest.Username) {
   176  			return nil, errors.New("username must be a valid email")
   177  		}
   178  	}
   179  
   180  	if UserUpdateRequest.RoleId != nil && *UserUpdateRequest.RoleId >= int32(model.LabelRole) {
   181  		updatedUserValues["role_id"] = *UserUpdateRequest.RoleId
   182  	}
   183  	if UserUpdateRequest.FirstName != nil {
   184  		updatedUserValues["first_name"] = *UserUpdateRequest.FirstName
   185  	}
   186  	if UserUpdateRequest.LastName != nil {
   187  		updatedUserValues["last_name"] = *UserUpdateRequest.LastName
   188  	}
   189  	if UserUpdateRequest.FullName != nil {
   190  		updatedUserValues["full_name"] = *UserUpdateRequest.FullName
   191  	}
   192  	if UserUpdateRequest.NewsletterNotification != nil {
   193  		updatedUserValues["newsletter_notification"] = *UserUpdateRequest.NewsletterNotification
   194  	}
   195  
   196  	updatedUserValues["updated_at"] = time.Now().UTC()
   197  
   198  	rows, err := s.db.NewUpdate().Model(&updatedUserValues).TableExpr("users").Where("id = ?", UserUpdateRequest.Id).Exec(ctx)
   199  
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	number, _ := rows.RowsAffected()
   205  
   206  	if number == 0 {
   207  		return nil, errors.New("warning: no rows were updated")
   208  	}
   209  
   210  	return &pbUser.Empty{}, nil
   211  }
   212  
   213  // UpdateUserRestricted updates a users more restricted attributes
   214  func (s *Server) UpdateUserRestricted(ctx context.Context, UserUpdateRestrictedRequest *pbUser.UserUpdateRestrictedRequest) (*pbUser.Empty, error) {
   215  
   216  	var updatedUserValues = make(map[string]interface{})
   217  
   218  	if UserUpdateRestrictedRequest.Username != nil {
   219  		updatedUserValues["username"] = *UserUpdateRestrictedRequest.Username
   220  		re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
   221  		if !re.MatchString(*UserUpdateRestrictedRequest.Username) {
   222  			return nil, errors.New("username must be a valid email")
   223  		}
   224  	}
   225  	if UserUpdateRestrictedRequest.FirstName != nil {
   226  		updatedUserValues["first_name"] = *UserUpdateRestrictedRequest.FirstName
   227  	}
   228  	if UserUpdateRestrictedRequest.LastName != nil {
   229  		updatedUserValues["last_name"] = *UserUpdateRestrictedRequest.LastName
   230  	}
   231  	if UserUpdateRestrictedRequest.FullName != nil {
   232  		updatedUserValues["full_name"] = *UserUpdateRestrictedRequest.FullName
   233  	}
   234  	if UserUpdateRestrictedRequest.Member != nil {
   235  		updatedUserValues["member"] = *UserUpdateRestrictedRequest.Member
   236  	}
   237  	if UserUpdateRestrictedRequest.RoleId != nil {
   238  		updatedUserValues["role_id"] = *UserUpdateRestrictedRequest.RoleId
   239  	}
   240  	if UserUpdateRestrictedRequest.TenantId != nil {
   241  		updatedUserValues["tenant_id"] = *UserUpdateRestrictedRequest.TenantId
   242  	}
   243  	if UserUpdateRestrictedRequest.NewsletterNotification != nil {
   244  		updatedUserValues["newsletter_notification"] = *UserUpdateRestrictedRequest.NewsletterNotification
   245  	}
   246  
   247  	updatedUserValues["updated_at"] = time.Now().UTC()
   248  
   249  	rows, err := s.db.NewUpdate().Model(&updatedUserValues).TableExpr("users").Where("id = ?", UserUpdateRestrictedRequest.Id).Exec(ctx)
   250  
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	number, _ := rows.RowsAffected()
   256  
   257  	if number == 0 {
   258  		return nil, errors.New("warning: no rows were updated")
   259  	}
   260  
   261  	return &pbUser.Empty{}, nil
   262  }
   263  
   264  // ListUsers lists all users in the store.
   265  func (s *Server) ListUsers(ctx context.Context, Empty *pbUser.Empty) (*pbUser.UserListResponse, error) {
   266  
   267  	var users []model.User
   268  	var results pbUser.UserListResponse
   269  
   270  	err := s.db.NewSelect().
   271  		Model(&users).
   272  		Scan(ctx)
   273  
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	for _, user := range users {
   279  		var result pbUser.UserPrivateResponse
   280  		result.Id = uuid.UUID.String(user.ID)
   281  		result.Username = user.Username
   282  		result.FullName = user.FullName
   283  		result.FirstName = user.FirstName
   284  		result.LastName = user.LastName
   285  		result.Member = user.Member
   286  		result.RoleId = user.RoleID
   287  		result.TenantId = user.TenantID
   288  		result.NewsletterNotification = user.NewsletterNotification
   289  		result.FollowedGroups = uuidpkg.ConvertUUIDToStrArray(user.FollowedGroups)
   290  		results.User = append(results.User, &result)
   291  	}
   292  
   293  	return &results, nil
   294  }
   295  
   296  func checkRequiredAddAttributes(user *pbUser.UserAddRequest) error {
   297  	if user.Username == "" {
   298  		argument := "username"
   299  		return fmt.Errorf("argument %v is required", argument)
   300  	}
   301  	re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
   302  	if !re.MatchString(user.Username) {
   303  		return errors.New("username must be a valid email")
   304  	}
   305  	return nil
   306  }
   307  
   308  func getUserGroupResponse(ownerOfGroup []model.UserGroup) []*pbUser.RelatedUserGroup {
   309  	groups := make([]*pbUser.RelatedUserGroup, len(ownerOfGroup))
   310  	for i, group := range ownerOfGroup {
   311  		groups[i] = &pbUser.RelatedUserGroup{Id: group.ID.String(), DisplayName: group.DisplayName}
   312  	}
   313  	return groups
   314  }
   315  
   316  func (s *Server) DerefString(str *string) string {
   317  	if str != nil {
   318  		return *str
   319  	}
   320  
   321  	return ""
   322  }