mirror of
https://github.com/gravitl/netmaker.git
synced 2026-04-22 16:07:11 +08:00
feat(go): add schema for user invites table;
1. Schema Definition for User Invites table. 2. Use the newer table everywhere. 3. Migration code for User Invites table;
This commit is contained in:
+3
-3
@@ -1144,7 +1144,7 @@ func listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body models.User true "User details"
|
||||
// @Param body body schema.User true "User details"
|
||||
// @Success 200 {object} models.ReturnUser
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
@@ -1259,7 +1259,7 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param username path string true "Username of the user to create"
|
||||
// @Param body body models.User true "User details"
|
||||
// @Param body body schema.User true "User details"
|
||||
// @Success 200 {object} models.ReturnUser
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
// @Failure 403 {object} models.ErrorResponse
|
||||
@@ -1355,7 +1355,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param username path string true "Username of the user to update"
|
||||
// @Param body body models.User true "User details"
|
||||
// @Param body body schema.User true "User details"
|
||||
// @Success 200 {object} models.ReturnUser
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
// @Failure 403 {object} models.ErrorResponse
|
||||
|
||||
+11
-31
@@ -2,11 +2,9 @@ package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/db"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/schema"
|
||||
@@ -125,41 +123,23 @@ func GetUserMap() (map[string]schema.User, error) {
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func InsertUserInvite(invite models.UserInvite) error {
|
||||
data, err := json.Marshal(invite)
|
||||
func GetUserInvite(email string) (*schema.UserInvite, error) {
|
||||
userInvite := &schema.UserInvite{
|
||||
Email: email,
|
||||
}
|
||||
err := userInvite.GetByEmail(db.WithContext(context.TODO()))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
return database.Insert(invite.Email, string(data), database.USER_INVITES_TABLE_NAME)
|
||||
}
|
||||
|
||||
func GetUserInvite(email string) (in models.UserInvite, err error) {
|
||||
d, err := database.FetchRecord(database.USER_INVITES_TABLE_NAME, email)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal([]byte(d), &in)
|
||||
return
|
||||
}
|
||||
|
||||
func ListUserInvites() ([]models.UserInvite, error) {
|
||||
invites := []models.UserInvite{}
|
||||
records, err := database.FetchRecords(database.USER_INVITES_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return invites, err
|
||||
}
|
||||
for _, record := range records {
|
||||
in := models.UserInvite{}
|
||||
err = json.Unmarshal([]byte(record), &in)
|
||||
if err == nil {
|
||||
invites = append(invites, in)
|
||||
}
|
||||
}
|
||||
return invites, nil
|
||||
return userInvite, nil
|
||||
}
|
||||
|
||||
func DeleteUserInvite(email string) error {
|
||||
return database.DeleteRecord(database.USER_INVITES_TABLE_NAME, email)
|
||||
userInvite := &schema.UserInvite{
|
||||
Email: email,
|
||||
}
|
||||
return userInvite.DeleteByEmail(db.WithContext(context.TODO()))
|
||||
}
|
||||
|
||||
func ValidateAndApproveUserInvite(email, code string) error {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/schema"
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
func migrateV1_5_2(ctx context.Context) error {
|
||||
@@ -51,5 +52,34 @@ func migratePendingUsers(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func migrateUserInvites(ctx context.Context) error {
|
||||
records, err := database.FetchRecords(database.USER_INVITES_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
var userInvite models.UserInvite
|
||||
err = json.Unmarshal([]byte(record), &userInvite)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_userInvite := &schema.UserInvite{
|
||||
InviteCode: userInvite.InviteCode,
|
||||
InviteURL: userInvite.InviteURL,
|
||||
Email: userInvite.Email,
|
||||
PlatformRoleID: userInvite.PlatformRoleID,
|
||||
UserGroups: datatypes.NewJSONType(userInvite.UserGroups),
|
||||
}
|
||||
|
||||
logger.Log(4, fmt.Sprintf("migrating user invite %s", _userInvite.InviteCode))
|
||||
|
||||
err = _userInvite.Create(ctx)
|
||||
if err != nil {
|
||||
logger.Log(4, fmt.Sprintf("migrating user invite (%s/%s) failed: %v", _userInvite.InviteCode, _userInvite.Email, err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+11
-13
@@ -11,7 +11,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
dbtypes "github.com/gravitl/netmaker/db/types"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
@@ -90,7 +89,7 @@ func UserHandlers(r *mux.Router) {
|
||||
// @Produce json
|
||||
// @Param email query string true "Invitee email"
|
||||
// @Param invite_code query string true "Invite code"
|
||||
// @Param body body models.User true "User signup data"
|
||||
// @Param body body schema.User true "User signup data"
|
||||
// @Success 200 {object} models.SuccessResponse
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -130,7 +129,7 @@ func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user.UserGroups = datatypes.NewJSONType(in.UserGroups)
|
||||
user.UserGroups = in.UserGroups
|
||||
user.PlatformRoleID = schema.UserRoleID(in.PlatformRoleID)
|
||||
if user.PlatformRoleID == "" {
|
||||
user.PlatformRoleID = schema.ServiceUser
|
||||
@@ -240,12 +239,11 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// user exists already, so ignore
|
||||
continue
|
||||
}
|
||||
invite := models.UserInvite{
|
||||
invite := &schema.UserInvite{
|
||||
InviteCode: logic.RandomString(8),
|
||||
Email: inviteeEmail,
|
||||
PlatformRoleID: inviteReq.PlatformRoleID,
|
||||
UserGroups: inviteReq.UserGroups,
|
||||
NetworkRoles: inviteReq.NetworkRoles,
|
||||
InviteCode: logic.RandomString(8),
|
||||
UserGroups: datatypes.NewJSONType(inviteReq.UserGroups),
|
||||
}
|
||||
frontendURL := strings.TrimSuffix(servercfg.GetFrontendURL(), "/")
|
||||
if frontendURL == "" {
|
||||
@@ -266,7 +264,7 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
invite.InviteURL = u.String()
|
||||
err = logic.InsertUserInvite(invite)
|
||||
err = invite.Create(r.Context())
|
||||
if err != nil {
|
||||
slog.Error("failed to insert invite for user", "email", invite.Email, "error", err)
|
||||
}
|
||||
@@ -287,7 +285,7 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
Origin: schema.Dashboard,
|
||||
})
|
||||
// notify user with magic link
|
||||
go func(invite models.UserInvite) {
|
||||
go func(invite *schema.UserInvite) {
|
||||
// Set E-Mail body. You can set plain text or html with text/html
|
||||
|
||||
e := email.UserInvitedMail{
|
||||
@@ -316,7 +314,7 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {array} models.UserInvite
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
func listUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
usersInvites, err := logic.ListUserInvites()
|
||||
usersInvites, err := (&schema.UserInvite{}).ListAll(r.Context())
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
@@ -373,7 +371,7 @@ func deleteUserInvite(w http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} models.SuccessResponse
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
func deleteAllUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
err := database.DeleteAllRecords(database.USER_INVITES_TABLE_NAME)
|
||||
err := (&schema.UserInvite{}).DeleteAll(r.Context())
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending user invites "+err.Error()), "internal"))
|
||||
return
|
||||
@@ -816,7 +814,7 @@ func listUnAssignedNetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// @Produce json
|
||||
// @Param username query string true "Username"
|
||||
// @Param network_id query string true "Network ID"
|
||||
// @Success 200 {object} models.User
|
||||
// @Success 200 {object} schema.User
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
func addUsertoNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
username := r.URL.Query().Get("username")
|
||||
@@ -872,7 +870,7 @@ func addUsertoNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
// @Produce json
|
||||
// @Param username query string true "Username"
|
||||
// @Param network_id query string true "Network ID"
|
||||
// @Success 200 {object} models.User
|
||||
// @Success 200 {object} schema.User
|
||||
// @Failure 400 {object} models.ErrorResponse
|
||||
func removeUserfromNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
username := r.URL.Query().Get("username")
|
||||
|
||||
@@ -833,7 +833,7 @@ func IsNetworkRolesValid(networkRoles map[schema.NetworkID]map[schema.UserRoleID
|
||||
}
|
||||
|
||||
// PrepareOauthUserFromInvite - init oauth user before create
|
||||
func PrepareOauthUserFromInvite(in models.UserInvite) (schema.User, error) {
|
||||
func PrepareOauthUserFromInvite(in *schema.UserInvite) (schema.User, error) {
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return schema.User{}, fetchErr
|
||||
@@ -842,7 +842,7 @@ func PrepareOauthUserFromInvite(in models.UserInvite) (schema.User, error) {
|
||||
Username: in.Email,
|
||||
Password: newPass,
|
||||
}
|
||||
user.UserGroups = datatypes.NewJSONType(in.UserGroups)
|
||||
user.UserGroups = in.UserGroups
|
||||
user.PlatformRoleID = schema.UserRoleID(in.PlatformRoleID)
|
||||
if user.PlatformRoleID == "" {
|
||||
user.PlatformRoleID = schema.ServiceUser
|
||||
|
||||
@@ -18,5 +18,6 @@ func ListModels() []interface{} {
|
||||
&JITGrant{},
|
||||
&Host{},
|
||||
&PendingUser{},
|
||||
&UserInvite{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/db"
|
||||
dbtypes "github.com/gravitl/netmaker/db/types"
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserInviteIdentifiersNotProvided = errors.New("user invite identifiers not provided")
|
||||
)
|
||||
|
||||
type UserInvite struct {
|
||||
ID string `gorm:"primaryKey" json:"id"`
|
||||
InviteCode string `gorm:"unique" json:"invite_code"`
|
||||
InviteURL string `json:"invite_url"`
|
||||
Email string `json:"email"`
|
||||
PlatformRoleID string `json:"platform_role_id"`
|
||||
UserGroups datatypes.JSONType[map[UserGroupID]struct{}] `json:"user_group_ids"`
|
||||
}
|
||||
|
||||
func (u *UserInvite) TableName() string {
|
||||
return "user_invites_v1"
|
||||
}
|
||||
|
||||
func (u *UserInvite) Create(ctx context.Context) error {
|
||||
if u.ID == "" {
|
||||
u.ID = uuid.NewString()
|
||||
}
|
||||
|
||||
return db.FromContext(ctx).Model(&UserInvite{}).Create(u).Error
|
||||
}
|
||||
|
||||
func (u *UserInvite) GetByEmail(ctx context.Context) error {
|
||||
return db.FromContext(ctx).Model(&UserInvite{}).
|
||||
Where("email = ?", u.Email).
|
||||
First(u).
|
||||
Error
|
||||
}
|
||||
|
||||
func (u *UserInvite) ListAll(ctx context.Context, options ...dbtypes.Option) ([]UserInvite, error) {
|
||||
var userInvites []UserInvite
|
||||
query := db.FromContext(ctx).Model(&UserInvite{})
|
||||
|
||||
for _, option := range options {
|
||||
query = option(query)
|
||||
}
|
||||
|
||||
err := query.Find(&userInvites).Error
|
||||
return userInvites, err
|
||||
}
|
||||
|
||||
func (u *UserInvite) DeleteByEmail(ctx context.Context) error {
|
||||
return db.FromContext(ctx).Model(&UserInvite{}).
|
||||
Where("email = ?", u.Email).
|
||||
Delete(u).
|
||||
Error
|
||||
}
|
||||
|
||||
func (u *UserInvite) DeleteAll(ctx context.Context) error {
|
||||
return db.FromContext(ctx).Exec("DELETE FROM user_invites_v1").Error
|
||||
}
|
||||
Reference in New Issue
Block a user