mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support user features restrictions
This commit is contained in:
@@ -147,6 +147,10 @@ func (a *DataManagementsApi) ClearDataHandler(c *core.WebContext) (any, *errs.Er
|
||||
return nil, errs.ErrUserPasswordWrong
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_CLEAR_ALL_DATA) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
err = a.templates.DeleteAllTemplates(c, uid)
|
||||
|
||||
if err != nil {
|
||||
@@ -204,6 +208,10 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType
|
||||
return nil, "", errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_EXPORT_TRANSACTION) {
|
||||
return nil, "", errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
accounts, err := a.accounts.GetAllAccountsByUid(c, uid)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -56,6 +56,10 @@ func (a *ForgetPasswordsApi) UserForgetPasswordRequestHandler(c *core.WebContext
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||
log.Warnf(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
@@ -109,6 +113,10 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.WebContext) (any,
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||
log.Warnf(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
|
||||
@@ -135,6 +135,22 @@ func (a *TokensApi) TokenRevokeHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
return nil, errs.ErrInvalidTokenId
|
||||
}
|
||||
|
||||
if utils.Int64ToString(tokenRecord.UserTokenId) != c.GetTokenClaims().UserTokenId || tokenRecord.CreatedUnixTime != c.GetTokenClaims().IssuedAt {
|
||||
user, err := a.users.GetUserById(c, uid)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.Errorf(c, "[token.TokenRevokeHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
}
|
||||
|
||||
err = a.tokens.DeleteToken(c, tokenRecord)
|
||||
|
||||
if err != nil {
|
||||
@@ -170,6 +186,24 @@ func (a *TokensApi) TokenRevokeAllHandler(c *core.WebContext) (any, *errs.Error)
|
||||
|
||||
tokens = append(tokens[:currentTokenIndex], tokens[currentTokenIndex+1:]...)
|
||||
|
||||
if len(tokens) < 1 {
|
||||
return nil, errs.ErrTokenRecordNotFound
|
||||
}
|
||||
|
||||
user, err := a.users.GetUserById(c, uid)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.Errorf(c, "[token.TokenRevokeAllHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
err = a.tokens.DeleteTokens(c, uid, tokens)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -1077,6 +1077,10 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_IMPORT_TRANSACTION) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
accounts, err := a.accounts.GetAllAccountsByUid(c, user.Uid)
|
||||
|
||||
if err != nil {
|
||||
@@ -1201,6 +1205,10 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_IMPORT_TRANSACTION) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
newTransactions := make([]*models.Transaction, len(transactionImportReq.Transactions))
|
||||
|
||||
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
||||
|
||||
@@ -81,6 +81,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.WebCo
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user)
|
||||
|
||||
if err != nil {
|
||||
@@ -141,6 +145,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableConfirmHandler(c *core.WebCo
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
twoFactorSetting := &models.TwoFactor{
|
||||
Uid: uid,
|
||||
Secret: confirmReq.Secret,
|
||||
@@ -229,6 +237,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorDisableHandler(c *core.WebContext)
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if !a.users.IsPasswordEqualsUserPassword(disableReq.Password, user) {
|
||||
return nil, errs.ErrUserPasswordWrong
|
||||
}
|
||||
|
||||
@@ -251,6 +251,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
userUpdateReq.Email = strings.TrimSpace(userUpdateReq.Email)
|
||||
userUpdateReq.Nickname = strings.TrimSpace(userUpdateReq.Nickname)
|
||||
|
||||
modifyProfileBasicInfo := false
|
||||
anythingUpdate := false
|
||||
userNew := &models.User{
|
||||
Uid: user.Uid,
|
||||
@@ -258,12 +259,20 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
}
|
||||
|
||||
if userUpdateReq.Email != "" && userUpdateReq.Email != user.Email {
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
user.Email = userUpdateReq.Email
|
||||
userNew.Email = userUpdateReq.Email
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
if userUpdateReq.Password != "" {
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if !a.users.IsPasswordEqualsUserPassword(userUpdateReq.OldPassword, user) {
|
||||
return nil, errs.ErrUserPasswordWrong
|
||||
}
|
||||
@@ -277,6 +286,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.Nickname != "" && userUpdateReq.Nickname != user.Nickname {
|
||||
user.Nickname = userUpdateReq.Nickname
|
||||
userNew.Nickname = userUpdateReq.Nickname
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
@@ -299,12 +309,14 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
|
||||
user.DefaultAccountId = userUpdateReq.DefaultAccountId
|
||||
userNew.DefaultAccountId = userUpdateReq.DefaultAccountId
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
|
||||
user.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||
userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.TransactionEditScope = models.TRANSACTION_EDIT_SCOPE_INVALID
|
||||
@@ -316,18 +328,21 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
user.Language = userUpdateReq.Language
|
||||
userNew.Language = userUpdateReq.Language
|
||||
modifyUserLanguage = true
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
if userUpdateReq.DefaultCurrency != "" && userUpdateReq.DefaultCurrency != user.DefaultCurrency {
|
||||
user.DefaultCurrency = userUpdateReq.DefaultCurrency
|
||||
userNew.DefaultCurrency = userUpdateReq.DefaultCurrency
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
if userUpdateReq.FirstDayOfWeek != nil && *userUpdateReq.FirstDayOfWeek != user.FirstDayOfWeek {
|
||||
user.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
||||
userNew.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.FirstDayOfWeek = core.WEEKDAY_INVALID
|
||||
@@ -336,6 +351,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.LongDateFormat != nil && *userUpdateReq.LongDateFormat != user.LongDateFormat {
|
||||
user.LongDateFormat = *userUpdateReq.LongDateFormat
|
||||
userNew.LongDateFormat = *userUpdateReq.LongDateFormat
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.LongDateFormat = core.LONG_DATE_FORMAT_INVALID
|
||||
@@ -344,6 +360,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.ShortDateFormat != nil && *userUpdateReq.ShortDateFormat != user.ShortDateFormat {
|
||||
user.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
||||
userNew.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.ShortDateFormat = core.SHORT_DATE_FORMAT_INVALID
|
||||
@@ -352,6 +369,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.LongTimeFormat != nil && *userUpdateReq.LongTimeFormat != user.LongTimeFormat {
|
||||
user.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
||||
userNew.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.LongTimeFormat = core.LONG_TIME_FORMAT_INVALID
|
||||
@@ -360,6 +378,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.ShortTimeFormat != nil && *userUpdateReq.ShortTimeFormat != user.ShortTimeFormat {
|
||||
user.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
||||
userNew.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.ShortTimeFormat = core.SHORT_TIME_FORMAT_INVALID
|
||||
@@ -368,6 +387,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.DecimalSeparator != nil && *userUpdateReq.DecimalSeparator != user.DecimalSeparator {
|
||||
user.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||
userNew.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.DecimalSeparator = core.DECIMAL_SEPARATOR_INVALID
|
||||
@@ -376,6 +396,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.DigitGroupingSymbol != nil && *userUpdateReq.DigitGroupingSymbol != user.DigitGroupingSymbol {
|
||||
user.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
||||
userNew.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.DigitGroupingSymbol = core.DIGIT_GROUPING_SYMBOL_INVALID
|
||||
@@ -384,6 +405,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.DigitGrouping != nil && *userUpdateReq.DigitGrouping != user.DigitGrouping {
|
||||
user.DigitGrouping = *userUpdateReq.DigitGrouping
|
||||
userNew.DigitGrouping = *userUpdateReq.DigitGrouping
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.DigitGrouping = core.DIGIT_GROUPING_TYPE_INVALID
|
||||
@@ -392,6 +414,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.CurrencyDisplayType != nil && *userUpdateReq.CurrencyDisplayType != user.CurrencyDisplayType {
|
||||
user.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
userNew.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.CurrencyDisplayType = core.CURRENCY_DISPLAY_TYPE_INVALID
|
||||
@@ -400,6 +423,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.ExpenseAmountColor != nil && *userUpdateReq.ExpenseAmountColor != user.ExpenseAmountColor {
|
||||
user.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
||||
userNew.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.ExpenseAmountColor = models.AMOUNT_COLOR_TYPE_INVALID
|
||||
@@ -408,11 +432,16 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
if userUpdateReq.IncomeAmountColor != nil && *userUpdateReq.IncomeAmountColor != user.IncomeAmountColor {
|
||||
user.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
||||
userNew.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.IncomeAmountColor = models.AMOUNT_COLOR_TYPE_INVALID
|
||||
}
|
||||
|
||||
if modifyProfileBasicInfo && user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if modifyUserLanguage || userNew.DecimalSeparator != core.DECIMAL_SEPARATOR_INVALID || userNew.DigitGroupingSymbol != core.DIGIT_GROUPING_SYMBOL_INVALID {
|
||||
decimalSeparator := userNew.DecimalSeparator
|
||||
digitGroupingSymbol := userNew.DigitGroupingSymbol
|
||||
@@ -525,6 +554,10 @@ func (a *UsersApi) UserUpdateAvatarHandler(c *core.WebContext) (any, *errs.Error
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
form, err := c.MultipartForm()
|
||||
|
||||
if err != nil {
|
||||
@@ -588,6 +621,10 @@ func (a *UsersApi) UserRemoveAvatarHandler(c *core.WebContext) (any, *errs.Error
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR) {
|
||||
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||
}
|
||||
|
||||
if user.CustomAvatarType == "" {
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
}
|
||||
|
||||
@@ -37,4 +37,5 @@ var (
|
||||
ErrUserAvatarNotSet = NewNormalError(NormalSubcategoryUser, 28, http.StatusNotFound, "user avatar not set")
|
||||
ErrUserAvatarExtensionInvalid = NewNormalError(NormalSubcategoryUser, 29, http.StatusNotFound, "user avatar file extension invalid")
|
||||
ErrExceedMaxUserAvatarFileSize = NewNormalError(NormalSubcategoryUser, 30, http.StatusBadRequest, "exceed the maximum size of user avatar file")
|
||||
ErrNotPermittedToPerformThisAction = NewNormalError(NormalSubcategoryUser, 31, http.StatusBadRequest, "not permitted to perform this action")
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||
@@ -80,6 +81,94 @@ func (s AmountColorType) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// UserFeatureRestrictions represents all the restrictions of user features
|
||||
type UserFeatureRestrictions int64
|
||||
|
||||
// Add returns a new feature restrictions with the specified feature
|
||||
func (r UserFeatureRestrictions) Add(featureRestrictionType UserFeatureRestrictionType) UserFeatureRestrictions {
|
||||
typeValue := int64(1 << (featureRestrictionType - 1))
|
||||
return UserFeatureRestrictions(int64(r) | typeValue)
|
||||
}
|
||||
|
||||
// Remove returns a new feature restrictions without the specified feature
|
||||
func (r UserFeatureRestrictions) Remove(featureRestrictionType UserFeatureRestrictionType) UserFeatureRestrictions {
|
||||
typeValue := int64(1 << (featureRestrictionType - 1))
|
||||
return UserFeatureRestrictions(int64(r) & (^typeValue))
|
||||
}
|
||||
|
||||
// Contains returns whether contains the specified feature
|
||||
func (r UserFeatureRestrictions) Contains(featureRestrictionType UserFeatureRestrictionType) bool {
|
||||
typeValue := int64(1 << (featureRestrictionType - 1))
|
||||
return int64(r)&typeValue == typeValue
|
||||
}
|
||||
|
||||
// String returns a textual representation of all the restrictions of user features
|
||||
func (r UserFeatureRestrictions) String() string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
for restrictionType := USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD; restrictionType <= USER_FEATURE_RESTRICTION_TYPE_CLEAR_ALL_DATA; restrictionType++ {
|
||||
if !r.Contains(restrictionType) {
|
||||
continue
|
||||
}
|
||||
|
||||
if builder.Len() > 0 {
|
||||
builder.WriteRune(',')
|
||||
}
|
||||
|
||||
builder.WriteString(restrictionType.String())
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// UserFeatureRestrictionType represents the restriction type of user features
|
||||
type UserFeatureRestrictionType int64
|
||||
|
||||
// User Feature Restriction Type
|
||||
const (
|
||||
USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD UserFeatureRestrictionType = 1
|
||||
USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL UserFeatureRestrictionType = 2
|
||||
USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO UserFeatureRestrictionType = 3
|
||||
USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR UserFeatureRestrictionType = 4
|
||||
USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION UserFeatureRestrictionType = 5
|
||||
USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA UserFeatureRestrictionType = 6
|
||||
USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA UserFeatureRestrictionType = 7
|
||||
USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD UserFeatureRestrictionType = 8
|
||||
USER_FEATURE_RESTRICTION_TYPE_IMPORT_TRANSACTION UserFeatureRestrictionType = 9
|
||||
USER_FEATURE_RESTRICTION_TYPE_EXPORT_TRANSACTION UserFeatureRestrictionType = 10
|
||||
USER_FEATURE_RESTRICTION_TYPE_CLEAR_ALL_DATA UserFeatureRestrictionType = 11
|
||||
)
|
||||
|
||||
// String returns a textual representation of the restriction type of user features
|
||||
func (t UserFeatureRestrictionType) String() string {
|
||||
switch t {
|
||||
case USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD:
|
||||
return "Update Password"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL:
|
||||
return "Update Email"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO:
|
||||
return "Update Profile Basic Info"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR:
|
||||
return "Update Avatar"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION:
|
||||
return "Logout Other Session"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA:
|
||||
return "Enable Two-Factor Authentication"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA:
|
||||
return "Disable Enable Two-Factor Authentication"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD:
|
||||
return "Forget Password"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_IMPORT_TRANSACTION:
|
||||
return "Import Transactions"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_EXPORT_TRANSACTION:
|
||||
return "Export Transactions"
|
||||
case USER_FEATURE_RESTRICTION_TYPE_CLEAR_ALL_DATA:
|
||||
return "Clear All Data"
|
||||
default:
|
||||
return fmt.Sprintf("Invalid(%d)", int(t))
|
||||
}
|
||||
}
|
||||
|
||||
// User represents user data stored in database
|
||||
type User struct {
|
||||
Uid int64 `xorm:"PK"`
|
||||
@@ -104,6 +193,7 @@ type User struct {
|
||||
CurrencyDisplayType core.CurrencyDisplayType `xorm:"TINYINT"`
|
||||
ExpenseAmountColor AmountColorType `xorm:"TINYINT"`
|
||||
IncomeAmountColor AmountColorType `xorm:"TINYINT"`
|
||||
FeatureRestriction UserFeatureRestrictions
|
||||
Disabled bool
|
||||
Deleted bool `xorm:"NOT NULL"`
|
||||
EmailVerified bool `xorm:"NOT NULL"`
|
||||
|
||||
@@ -10,6 +10,95 @@ import (
|
||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||
)
|
||||
|
||||
func TestUserFeatureRestrictionsAdd(t *testing.T) {
|
||||
var featureRestrictions UserFeatureRestrictions
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD)
|
||||
expectedValue := UserFeatureRestrictions(1)
|
||||
assert.Equal(t, expectedValue, featureRestrictions)
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD)
|
||||
expectedValue = UserFeatureRestrictions(255)
|
||||
assert.Equal(t, expectedValue, featureRestrictions)
|
||||
}
|
||||
|
||||
func TestUserFeatureRestrictionsRemove(t *testing.T) {
|
||||
var featureRestrictions UserFeatureRestrictions
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION)
|
||||
expectedValue := UserFeatureRestrictions(1)
|
||||
assert.Equal(t, expectedValue, featureRestrictions)
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Remove(USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA)
|
||||
expectedValue = UserFeatureRestrictions(153)
|
||||
assert.Equal(t, expectedValue, featureRestrictions)
|
||||
}
|
||||
|
||||
func TestUserFeatureRestrictionsContains(t *testing.T) {
|
||||
var featureRestrictions UserFeatureRestrictions
|
||||
assert.False(t, featureRestrictions.Contains(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD))
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD)
|
||||
assert.True(t, featureRestrictions.Contains(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD))
|
||||
assert.False(t, featureRestrictions.Contains(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO))
|
||||
}
|
||||
|
||||
func TestUserFeatureRestrictionsString(t *testing.T) {
|
||||
var featureRestrictions UserFeatureRestrictions
|
||||
expectedValue := ""
|
||||
actualValue := featureRestrictions.String()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD)
|
||||
expectedValue = "Update Password"
|
||||
actualValue = featureRestrictions.String()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_FORGET_PASSWORD)
|
||||
expectedValue = "Update Password,Forget Password"
|
||||
actualValue = featureRestrictions.String()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_EMAIL)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_PROFILE_BASIC_INFO)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_REVOKE_OTHER_SESSION)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_DISABLE_2FA)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_IMPORT_TRANSACTION)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_EXPORT_TRANSACTION)
|
||||
featureRestrictions = featureRestrictions.Add(USER_FEATURE_RESTRICTION_TYPE_CLEAR_ALL_DATA)
|
||||
expectedValue = "Update Password," +
|
||||
"Update Email," +
|
||||
"Update Profile Basic Info," +
|
||||
"Update Avatar," +
|
||||
"Logout Other Session," +
|
||||
"Enable Two-Factor Authentication," +
|
||||
"Disable Enable Two-Factor Authentication," +
|
||||
"Forget Password," +
|
||||
"Import Transactions," +
|
||||
"Export Transactions," +
|
||||
"Clear All Data"
|
||||
actualValue = featureRestrictions.String()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsNone(t *testing.T) {
|
||||
user := &User{
|
||||
TransactionEditScope: TRANSACTION_EDIT_SCOPE_NONE,
|
||||
|
||||
@@ -1023,6 +1023,7 @@
|
||||
"user avatar not set": "User avatar is not set",
|
||||
"user avatar file extension invalid": "User avatar file extension is invalid",
|
||||
"exceed the maximum size of user avatar file": "The uploaded user avatar exceeds the maximum allowed file size",
|
||||
"not permitted to perform this action": "You are not permitted to perform this action",
|
||||
"unauthorized access": "Unauthorized access",
|
||||
"current token is invalid": "Current token is invalid",
|
||||
"current token is expired": "Current token is expired",
|
||||
|
||||
@@ -1023,6 +1023,7 @@
|
||||
"user avatar not set": "用户没有设置头像",
|
||||
"user avatar file extension invalid": "用户头像文件扩展名无效",
|
||||
"exceed the maximum size of user avatar file": "上传的用户头像超出了允许的最大文件大小",
|
||||
"not permitted to perform this action": "您不能执行该操作",
|
||||
"unauthorized access": "未授权的登录",
|
||||
"current token is invalid": "当前认证令牌无效",
|
||||
"current token is expired": "当前认证令牌已过期",
|
||||
|
||||
Reference in New Issue
Block a user