mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 17:54:30 +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
|
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)
|
err = a.templates.DeleteAllTemplates(c, uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -204,6 +208,10 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType
|
|||||||
return nil, "", errs.ErrUserNotFound
|
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)
|
accounts, err := a.accounts.GetAllAccountsByUid(c, uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ func (a *ForgetPasswordsApi) UserForgetPasswordRequestHandler(c *core.WebContext
|
|||||||
return nil, errs.ErrUserIsDisabled
|
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 {
|
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||||
log.Warnf(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.Warnf(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
@@ -109,6 +113,10 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.WebContext) (any,
|
|||||||
return nil, errs.ErrUserIsDisabled
|
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 {
|
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||||
log.Warnf(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.Warnf(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
|
|||||||
@@ -135,6 +135,22 @@ func (a *TokensApi) TokenRevokeHandler(c *core.WebContext) (any, *errs.Error) {
|
|||||||
return nil, errs.ErrInvalidTokenId
|
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)
|
err = a.tokens.DeleteToken(c, tokenRecord)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -170,6 +186,24 @@ func (a *TokensApi) TokenRevokeAllHandler(c *core.WebContext) (any, *errs.Error)
|
|||||||
|
|
||||||
tokens = append(tokens[:currentTokenIndex], tokens[currentTokenIndex+1:]...)
|
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)
|
err = a.tokens.DeleteTokens(c, uid, tokens)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1077,6 +1077,10 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
|
|||||||
return nil, errs.ErrUserNotFound
|
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)
|
accounts, err := a.accounts.GetAllAccountsByUid(c, user.Uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1201,6 +1205,10 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
|||||||
return nil, errs.ErrUserNotFound
|
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))
|
newTransactions := make([]*models.Transaction, len(transactionImportReq.Transactions))
|
||||||
|
|
||||||
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.WebCo
|
|||||||
return nil, errs.ErrUserNotFound
|
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)
|
key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -141,6 +145,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableConfirmHandler(c *core.WebCo
|
|||||||
return nil, errs.ErrUserNotFound
|
return nil, errs.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_ENABLE_2FA) {
|
||||||
|
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||||
|
}
|
||||||
|
|
||||||
twoFactorSetting := &models.TwoFactor{
|
twoFactorSetting := &models.TwoFactor{
|
||||||
Uid: uid,
|
Uid: uid,
|
||||||
Secret: confirmReq.Secret,
|
Secret: confirmReq.Secret,
|
||||||
@@ -229,6 +237,10 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorDisableHandler(c *core.WebContext)
|
|||||||
return nil, errs.ErrUserNotFound
|
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) {
|
if !a.users.IsPasswordEqualsUserPassword(disableReq.Password, user) {
|
||||||
return nil, errs.ErrUserPasswordWrong
|
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.Email = strings.TrimSpace(userUpdateReq.Email)
|
||||||
userUpdateReq.Nickname = strings.TrimSpace(userUpdateReq.Nickname)
|
userUpdateReq.Nickname = strings.TrimSpace(userUpdateReq.Nickname)
|
||||||
|
|
||||||
|
modifyProfileBasicInfo := false
|
||||||
anythingUpdate := false
|
anythingUpdate := false
|
||||||
userNew := &models.User{
|
userNew := &models.User{
|
||||||
Uid: user.Uid,
|
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 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
|
user.Email = userUpdateReq.Email
|
||||||
userNew.Email = userUpdateReq.Email
|
userNew.Email = userUpdateReq.Email
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateReq.Password != "" {
|
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) {
|
if !a.users.IsPasswordEqualsUserPassword(userUpdateReq.OldPassword, user) {
|
||||||
return nil, errs.ErrUserPasswordWrong
|
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 {
|
if userUpdateReq.Nickname != "" && userUpdateReq.Nickname != user.Nickname {
|
||||||
user.Nickname = userUpdateReq.Nickname
|
user.Nickname = userUpdateReq.Nickname
|
||||||
userNew.Nickname = userUpdateReq.Nickname
|
userNew.Nickname = userUpdateReq.Nickname
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,12 +309,14 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
|||||||
|
|
||||||
user.DefaultAccountId = userUpdateReq.DefaultAccountId
|
user.DefaultAccountId = userUpdateReq.DefaultAccountId
|
||||||
userNew.DefaultAccountId = userUpdateReq.DefaultAccountId
|
userNew.DefaultAccountId = userUpdateReq.DefaultAccountId
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
|
if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
|
||||||
user.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
user.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||||
userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.TransactionEditScope = models.TRANSACTION_EDIT_SCOPE_INVALID
|
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
|
user.Language = userUpdateReq.Language
|
||||||
userNew.Language = userUpdateReq.Language
|
userNew.Language = userUpdateReq.Language
|
||||||
modifyUserLanguage = true
|
modifyUserLanguage = true
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateReq.DefaultCurrency != "" && userUpdateReq.DefaultCurrency != user.DefaultCurrency {
|
if userUpdateReq.DefaultCurrency != "" && userUpdateReq.DefaultCurrency != user.DefaultCurrency {
|
||||||
user.DefaultCurrency = userUpdateReq.DefaultCurrency
|
user.DefaultCurrency = userUpdateReq.DefaultCurrency
|
||||||
userNew.DefaultCurrency = userUpdateReq.DefaultCurrency
|
userNew.DefaultCurrency = userUpdateReq.DefaultCurrency
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateReq.FirstDayOfWeek != nil && *userUpdateReq.FirstDayOfWeek != user.FirstDayOfWeek {
|
if userUpdateReq.FirstDayOfWeek != nil && *userUpdateReq.FirstDayOfWeek != user.FirstDayOfWeek {
|
||||||
user.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
user.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
||||||
userNew.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
userNew.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.FirstDayOfWeek = core.WEEKDAY_INVALID
|
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 {
|
if userUpdateReq.LongDateFormat != nil && *userUpdateReq.LongDateFormat != user.LongDateFormat {
|
||||||
user.LongDateFormat = *userUpdateReq.LongDateFormat
|
user.LongDateFormat = *userUpdateReq.LongDateFormat
|
||||||
userNew.LongDateFormat = *userUpdateReq.LongDateFormat
|
userNew.LongDateFormat = *userUpdateReq.LongDateFormat
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.LongDateFormat = core.LONG_DATE_FORMAT_INVALID
|
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 {
|
if userUpdateReq.ShortDateFormat != nil && *userUpdateReq.ShortDateFormat != user.ShortDateFormat {
|
||||||
user.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
user.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
||||||
userNew.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
userNew.ShortDateFormat = *userUpdateReq.ShortDateFormat
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.ShortDateFormat = core.SHORT_DATE_FORMAT_INVALID
|
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 {
|
if userUpdateReq.LongTimeFormat != nil && *userUpdateReq.LongTimeFormat != user.LongTimeFormat {
|
||||||
user.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
user.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
||||||
userNew.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
userNew.LongTimeFormat = *userUpdateReq.LongTimeFormat
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.LongTimeFormat = core.LONG_TIME_FORMAT_INVALID
|
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 {
|
if userUpdateReq.ShortTimeFormat != nil && *userUpdateReq.ShortTimeFormat != user.ShortTimeFormat {
|
||||||
user.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
user.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
||||||
userNew.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
userNew.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.ShortTimeFormat = core.SHORT_TIME_FORMAT_INVALID
|
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 {
|
if userUpdateReq.DecimalSeparator != nil && *userUpdateReq.DecimalSeparator != user.DecimalSeparator {
|
||||||
user.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
user.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||||
userNew.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
userNew.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.DecimalSeparator = core.DECIMAL_SEPARATOR_INVALID
|
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 {
|
if userUpdateReq.DigitGroupingSymbol != nil && *userUpdateReq.DigitGroupingSymbol != user.DigitGroupingSymbol {
|
||||||
user.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
user.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
||||||
userNew.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
userNew.DigitGroupingSymbol = *userUpdateReq.DigitGroupingSymbol
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.DigitGroupingSymbol = core.DIGIT_GROUPING_SYMBOL_INVALID
|
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 {
|
if userUpdateReq.DigitGrouping != nil && *userUpdateReq.DigitGrouping != user.DigitGrouping {
|
||||||
user.DigitGrouping = *userUpdateReq.DigitGrouping
|
user.DigitGrouping = *userUpdateReq.DigitGrouping
|
||||||
userNew.DigitGrouping = *userUpdateReq.DigitGrouping
|
userNew.DigitGrouping = *userUpdateReq.DigitGrouping
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.DigitGrouping = core.DIGIT_GROUPING_TYPE_INVALID
|
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 {
|
if userUpdateReq.CurrencyDisplayType != nil && *userUpdateReq.CurrencyDisplayType != user.CurrencyDisplayType {
|
||||||
user.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
user.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||||
userNew.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
userNew.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.CurrencyDisplayType = core.CURRENCY_DISPLAY_TYPE_INVALID
|
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 {
|
if userUpdateReq.ExpenseAmountColor != nil && *userUpdateReq.ExpenseAmountColor != user.ExpenseAmountColor {
|
||||||
user.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
user.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
||||||
userNew.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
userNew.ExpenseAmountColor = *userUpdateReq.ExpenseAmountColor
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.ExpenseAmountColor = models.AMOUNT_COLOR_TYPE_INVALID
|
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 {
|
if userUpdateReq.IncomeAmountColor != nil && *userUpdateReq.IncomeAmountColor != user.IncomeAmountColor {
|
||||||
user.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
user.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
||||||
userNew.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
userNew.IncomeAmountColor = *userUpdateReq.IncomeAmountColor
|
||||||
|
modifyProfileBasicInfo = true
|
||||||
anythingUpdate = true
|
anythingUpdate = true
|
||||||
} else {
|
} else {
|
||||||
userNew.IncomeAmountColor = models.AMOUNT_COLOR_TYPE_INVALID
|
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 {
|
if modifyUserLanguage || userNew.DecimalSeparator != core.DECIMAL_SEPARATOR_INVALID || userNew.DigitGroupingSymbol != core.DIGIT_GROUPING_SYMBOL_INVALID {
|
||||||
decimalSeparator := userNew.DecimalSeparator
|
decimalSeparator := userNew.DecimalSeparator
|
||||||
digitGroupingSymbol := userNew.DigitGroupingSymbol
|
digitGroupingSymbol := userNew.DigitGroupingSymbol
|
||||||
@@ -525,6 +554,10 @@ func (a *UsersApi) UserUpdateAvatarHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
return nil, errs.ErrUserNotFound
|
return nil, errs.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR) {
|
||||||
|
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||||
|
}
|
||||||
|
|
||||||
form, err := c.MultipartForm()
|
form, err := c.MultipartForm()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -588,6 +621,10 @@ func (a *UsersApi) UserRemoveAvatarHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
return nil, errs.ErrUserNotFound
|
return nil, errs.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.FeatureRestriction.Contains(models.USER_FEATURE_RESTRICTION_TYPE_UPDATE_AVATAR) {
|
||||||
|
return nil, errs.ErrNotPermittedToPerformThisAction
|
||||||
|
}
|
||||||
|
|
||||||
if user.CustomAvatarType == "" {
|
if user.CustomAvatarType == "" {
|
||||||
return nil, errs.ErrNothingWillBeUpdated
|
return nil, errs.ErrNothingWillBeUpdated
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,4 +37,5 @@ var (
|
|||||||
ErrUserAvatarNotSet = NewNormalError(NormalSubcategoryUser, 28, http.StatusNotFound, "user avatar not set")
|
ErrUserAvatarNotSet = NewNormalError(NormalSubcategoryUser, 28, http.StatusNotFound, "user avatar not set")
|
||||||
ErrUserAvatarExtensionInvalid = NewNormalError(NormalSubcategoryUser, 29, http.StatusNotFound, "user avatar file extension invalid")
|
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")
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"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
|
// User represents user data stored in database
|
||||||
type User struct {
|
type User struct {
|
||||||
Uid int64 `xorm:"PK"`
|
Uid int64 `xorm:"PK"`
|
||||||
@@ -104,6 +193,7 @@ type User struct {
|
|||||||
CurrencyDisplayType core.CurrencyDisplayType `xorm:"TINYINT"`
|
CurrencyDisplayType core.CurrencyDisplayType `xorm:"TINYINT"`
|
||||||
ExpenseAmountColor AmountColorType `xorm:"TINYINT"`
|
ExpenseAmountColor AmountColorType `xorm:"TINYINT"`
|
||||||
IncomeAmountColor AmountColorType `xorm:"TINYINT"`
|
IncomeAmountColor AmountColorType `xorm:"TINYINT"`
|
||||||
|
FeatureRestriction UserFeatureRestrictions
|
||||||
Disabled bool
|
Disabled bool
|
||||||
Deleted bool `xorm:"NOT NULL"`
|
Deleted bool `xorm:"NOT NULL"`
|
||||||
EmailVerified bool `xorm:"NOT NULL"`
|
EmailVerified bool `xorm:"NOT NULL"`
|
||||||
|
|||||||
@@ -10,6 +10,95 @@ import (
|
|||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
"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) {
|
func TestUserCanEditTransactionByTransactionTime_ScopeIsNone(t *testing.T) {
|
||||||
user := &User{
|
user := &User{
|
||||||
TransactionEditScope: TRANSACTION_EDIT_SCOPE_NONE,
|
TransactionEditScope: TRANSACTION_EDIT_SCOPE_NONE,
|
||||||
|
|||||||
@@ -1023,6 +1023,7 @@
|
|||||||
"user avatar not set": "User avatar is not set",
|
"user avatar not set": "User avatar is not set",
|
||||||
"user avatar file extension invalid": "User avatar file extension is invalid",
|
"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",
|
"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",
|
"unauthorized access": "Unauthorized access",
|
||||||
"current token is invalid": "Current token is invalid",
|
"current token is invalid": "Current token is invalid",
|
||||||
"current token is expired": "Current token is expired",
|
"current token is expired": "Current token is expired",
|
||||||
|
|||||||
@@ -1023,6 +1023,7 @@
|
|||||||
"user avatar not set": "用户没有设置头像",
|
"user avatar not set": "用户没有设置头像",
|
||||||
"user avatar file extension invalid": "用户头像文件扩展名无效",
|
"user avatar file extension invalid": "用户头像文件扩展名无效",
|
||||||
"exceed the maximum size of user avatar file": "上传的用户头像超出了允许的最大文件大小",
|
"exceed the maximum size of user avatar file": "上传的用户头像超出了允许的最大文件大小",
|
||||||
|
"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": "当前认证令牌已过期",
|
||||||
|
|||||||
Reference in New Issue
Block a user